From 4cf8505d22f1f323a6af0ac8f33a24aa9e242a91 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Mon, 20 May 2019 16:11:23 +0300 Subject: [PATCH 01/47] build: fix Launchpad typo (#19597) --- build/ci.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/ci.go b/build/ci.go index 50433c892b..8be5233898 100644 --- a/build/ci.go +++ b/build/ci.go @@ -133,10 +133,10 @@ var ( // Distros for which packages are created. // Note: vivid is unsupported because there is no golang-1.6 package for it. - // Note: wily is unsupported because it was officially deprecated on lanchpad. - // Note: yakkety is unsupported because it was officially deprecated on lanchpad. - // Note: zesty is unsupported because it was officially deprecated on lanchpad. - // Note: artful is unsupported because it was officially deprecated on lanchpad. + // Note: wily is unsupported because it was officially deprecated on Launchpad. + // Note: yakkety is unsupported because it was officially deprecated on Launchpad. + // Note: zesty is unsupported because it was officially deprecated on Launchpad. + // Note: artful is unsupported because it was officially deprecated on Launchpad. debDistros = []string{"trusty", "xenial", "bionic", "cosmic", "disco"} ) From a54142987c913f47de4dcec9d9b2dc4bb3654f22 Mon Sep 17 00:00:00 2001 From: Nikifor Seryakov Date: Mon, 20 May 2019 17:26:29 +0400 Subject: [PATCH 02/47] log: do not pad values longer than 40 characters (#19592) * log: Do not pad too long values * log: gofmt --- log/format.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/log/format.go b/log/format.go index 7902b296e6..a1b5dac629 100644 --- a/log/format.go +++ b/log/format.go @@ -14,10 +14,11 @@ import ( ) const ( - timeFormat = "2006-01-02T15:04:05-0700" - termTimeFormat = "01-02|15:04:05.000" - floatFormat = 'f' - termMsgJust = 40 + timeFormat = "2006-01-02T15:04:05-0700" + termTimeFormat = "01-02|15:04:05.000" + floatFormat = 'f' + termMsgJust = 40 + termCtxMaxPadding = 40 ) // locationTrims are trimmed for display to avoid unwieldy log lines. @@ -175,7 +176,7 @@ func logfmt(buf *bytes.Buffer, ctx []interface{}, color int, term bool) { fieldPaddingLock.RUnlock() length := utf8.RuneCountInString(v) - if padding < length { + if padding < length && length <= termCtxMaxPadding { padding = length fieldPaddingLock.Lock() @@ -189,7 +190,7 @@ func logfmt(buf *bytes.Buffer, ctx []interface{}, color int, term bool) { buf.WriteByte('=') } buf.WriteString(v) - if i < len(ctx)-2 { + if i < len(ctx)-2 && padding > length { buf.Write(bytes.Repeat([]byte{' '}, padding-length)) } } From 2cd6059e51e823012f756112e6e9b2d2920bab74 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 21 May 2019 13:58:06 +0200 Subject: [PATCH 03/47] tests: make transaction tests run again, fix #19033 (#19529) * tests: make transaction tests run again, fix #19033 * tests: refactor transaction tests --- tests/gen_tttransaction.go | 95 -------------------- tests/transaction_test.go | 38 ++++---- tests/transaction_test_util.go | 158 ++++++++++++++------------------- 3 files changed, 86 insertions(+), 205 deletions(-) delete mode 100644 tests/gen_tttransaction.go diff --git a/tests/gen_tttransaction.go b/tests/gen_tttransaction.go deleted file mode 100644 index 2948842d97..0000000000 --- a/tests/gen_tttransaction.go +++ /dev/null @@ -1,95 +0,0 @@ -// Code generated by github.com/fjl/gencodec. DO NOT EDIT. - -package tests - -import ( - "encoding/json" - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" -) - -var _ = (*ttTransactionMarshaling)(nil) - -func (t ttTransaction) MarshalJSON() ([]byte, error) { - type ttTransaction struct { - Data hexutil.Bytes `gencodec:"required"` - GasLimit math.HexOrDecimal64 `gencodec:"required"` - GasPrice *math.HexOrDecimal256 `gencodec:"required"` - Nonce math.HexOrDecimal64 `gencodec:"required"` - Value *math.HexOrDecimal256 `gencodec:"required"` - R *math.HexOrDecimal256 `gencodec:"required"` - S *math.HexOrDecimal256 `gencodec:"required"` - V *math.HexOrDecimal256 `gencodec:"required"` - To common.Address `gencodec:"required"` - } - var enc ttTransaction - enc.Data = t.Data - enc.GasLimit = math.HexOrDecimal64(t.GasLimit) - enc.GasPrice = (*math.HexOrDecimal256)(t.GasPrice) - enc.Nonce = math.HexOrDecimal64(t.Nonce) - enc.Value = (*math.HexOrDecimal256)(t.Value) - enc.R = (*math.HexOrDecimal256)(t.R) - enc.S = (*math.HexOrDecimal256)(t.S) - enc.V = (*math.HexOrDecimal256)(t.V) - enc.To = t.To - return json.Marshal(&enc) -} - -func (t *ttTransaction) UnmarshalJSON(input []byte) error { - type ttTransaction struct { - Data *hexutil.Bytes `gencodec:"required"` - GasLimit *math.HexOrDecimal64 `gencodec:"required"` - GasPrice *math.HexOrDecimal256 `gencodec:"required"` - Nonce *math.HexOrDecimal64 `gencodec:"required"` - Value *math.HexOrDecimal256 `gencodec:"required"` - R *math.HexOrDecimal256 `gencodec:"required"` - S *math.HexOrDecimal256 `gencodec:"required"` - V *math.HexOrDecimal256 `gencodec:"required"` - To *common.Address `gencodec:"required"` - } - var dec ttTransaction - if err := json.Unmarshal(input, &dec); err != nil { - return err - } - if dec.Data == nil { - return errors.New("missing required field 'data' for ttTransaction") - } - t.Data = *dec.Data - if dec.GasLimit == nil { - return errors.New("missing required field 'gasLimit' for ttTransaction") - } - t.GasLimit = uint64(*dec.GasLimit) - if dec.GasPrice == nil { - return errors.New("missing required field 'gasPrice' for ttTransaction") - } - t.GasPrice = (*big.Int)(dec.GasPrice) - if dec.Nonce == nil { - return errors.New("missing required field 'nonce' for ttTransaction") - } - t.Nonce = uint64(*dec.Nonce) - if dec.Value == nil { - return errors.New("missing required field 'value' for ttTransaction") - } - t.Value = (*big.Int)(dec.Value) - if dec.R == nil { - return errors.New("missing required field 'r' for ttTransaction") - } - t.R = (*big.Int)(dec.R) - if dec.S == nil { - return errors.New("missing required field 's' for ttTransaction") - } - t.S = (*big.Int)(dec.S) - if dec.V == nil { - return errors.New("missing required field 'v' for ttTransaction") - } - t.V = (*big.Int)(dec.V) - if dec.To == nil { - return errors.New("missing required field 'to' for ttTransaction") - } - t.To = *dec.To - return nil -} diff --git a/tests/transaction_test.go b/tests/transaction_test.go index 42ad81877e..0e3670d04b 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -17,7 +17,6 @@ package tests import ( - "math/big" "testing" "github.com/ethereum/go-ethereum/params" @@ -27,26 +26,27 @@ func TestTransaction(t *testing.T) { t.Parallel() txt := new(testMatcher) - txt.config(`^Homestead/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - }) - txt.config(`^EIP155/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ChainID: big.NewInt(1), - }) - txt.config(`^Byzantium/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - }) + // These can't be parsed, invalid hex in RLP + txt.skipLoad("^ttWrongRLP/.*") + // We don't allow more than uint64 in gas amount + // This is a pseudo-consensus vulnerability, but not in practice + // because of the gas limit + txt.skipLoad("^ttGasLimit/TransactionWithGasLimitxPriceOverflow.json") + // We _do_ allow more than uint64 in gas price, as opposed to the tests + // This is also not a concern, as long as tx.Cost() uses big.Int for + // calculating the final cozt + txt.skipLoad(".*TransactionWithGasPriceOverflow.*") + // The nonce is too large for uint64. Not a concern, it means geth won't + // accept transactions at a certain point in the distant future + txt.skipLoad("^ttNonce/TransactionWithHighNonce256.json") + + // The value is larger than uint64, which according to the test is invalid. + // Geth accepts it, which is not a consensus issue since we use big.Int's + // internally to calculate the cost + txt.skipLoad("^ttValue/TransactionWithHighValueOverflow.json") txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) { - cfg := txt.findConfig(name) + cfg := params.MainnetChainConfig if err := txt.checkFailure(t, name, test.Run(cfg)); err != nil { t.Error(err) } diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 8c3dac088c..12444720cc 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -17,14 +17,11 @@ package tests import ( - "bytes" - "errors" "fmt" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -32,101 +29,80 @@ import ( // TransactionTest checks RLP decoding and sender derivation of transactions. type TransactionTest struct { - json ttJSON + RLP hexutil.Bytes `json:"rlp"` + Byzantium ttFork + Constantinople ttFork + EIP150 ttFork + EIP158 ttFork + Frontier ttFork + Homestead ttFork } -type ttJSON struct { - BlockNumber math.HexOrDecimal64 `json:"blockNumber"` - RLP hexutil.Bytes `json:"rlp"` - Sender hexutil.Bytes `json:"sender"` - Transaction *ttTransaction `json:"transaction"` -} - -//go:generate gencodec -type ttTransaction -field-override ttTransactionMarshaling -out gen_tttransaction.go - -type ttTransaction struct { - Data []byte `gencodec:"required"` - GasLimit uint64 `gencodec:"required"` - GasPrice *big.Int `gencodec:"required"` - Nonce uint64 `gencodec:"required"` - Value *big.Int `gencodec:"required"` - R *big.Int `gencodec:"required"` - S *big.Int `gencodec:"required"` - V *big.Int `gencodec:"required"` - To common.Address `gencodec:"required"` -} - -type ttTransactionMarshaling struct { - Data hexutil.Bytes - GasLimit math.HexOrDecimal64 - GasPrice *math.HexOrDecimal256 - Nonce math.HexOrDecimal64 - Value *math.HexOrDecimal256 - R *math.HexOrDecimal256 - S *math.HexOrDecimal256 - V *math.HexOrDecimal256 +type ttFork struct { + Sender common.UnprefixedAddress `json:"sender"` + Hash common.UnprefixedHash `json:"hash"` } func (tt *TransactionTest) Run(config *params.ChainConfig) error { - tx := new(types.Transaction) - if err := rlp.DecodeBytes(tt.json.RLP, tx); err != nil { - if tt.json.Transaction == nil { - return nil - } - return fmt.Errorf("RLP decoding failed: %v", err) - } - // Check sender derivation. - signer := types.MakeSigner(config, new(big.Int).SetUint64(uint64(tt.json.BlockNumber))) - sender, err := types.Sender(signer, tx) - if err != nil { - return err - } - if sender != common.BytesToAddress(tt.json.Sender) { - return fmt.Errorf("Sender mismatch: got %x, want %x", sender, tt.json.Sender) - } - // Check decoded fields. - err = tt.json.Transaction.verify(signer, tx) - if tt.json.Sender == nil && err == nil { - return errors.New("field validations succeeded but should fail") - } - if tt.json.Sender != nil && err != nil { - return fmt.Errorf("field validations failed after RLP decoding: %s", err) - } - return nil -} -func (tt *ttTransaction) verify(signer types.Signer, tx *types.Transaction) error { - if !bytes.Equal(tx.Data(), tt.Data) { - return fmt.Errorf("Tx input data mismatch: got %x want %x", tx.Data(), tt.Data) - } - if tx.Gas() != tt.GasLimit { - return fmt.Errorf("GasLimit mismatch: got %d, want %d", tx.Gas(), tt.GasLimit) - } - if tx.GasPrice().Cmp(tt.GasPrice) != 0 { - return fmt.Errorf("GasPrice mismatch: got %v, want %v", tx.GasPrice(), tt.GasPrice) - } - if tx.Nonce() != tt.Nonce { - return fmt.Errorf("Nonce mismatch: got %v, want %v", tx.Nonce(), tt.Nonce) - } - v, r, s := tx.RawSignatureValues() - if r.Cmp(tt.R) != 0 { - return fmt.Errorf("R mismatch: got %v, want %v", r, tt.R) - } - if s.Cmp(tt.S) != 0 { - return fmt.Errorf("S mismatch: got %v, want %v", s, tt.S) - } - if v.Cmp(tt.V) != 0 { - return fmt.Errorf("V mismatch: got %v, want %v", v, tt.V) - } - if tx.To() == nil { - if tt.To != (common.Address{}) { - return fmt.Errorf("To mismatch when recipient is nil (contract creation): %x", tt.To) + validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead bool) (*common.Address, *common.Hash, error) { + tx := new(types.Transaction) + if err := rlp.DecodeBytes(rlpData, tx); err != nil { + return nil, nil, err } - } else if *tx.To() != tt.To { - return fmt.Errorf("To mismatch: got %x, want %x", *tx.To(), tt.To) + sender, err := types.Sender(signer, tx) + if err != nil { + return nil, nil, err + } + // Intrinsic gas + requiredGas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, isHomestead) + if err != nil { + return nil, nil, err + } + if requiredGas > tx.Gas() { + return nil, nil, fmt.Errorf("insufficient gas ( %d < %d )", tx.Gas(), requiredGas) + } + h := tx.Hash() + return &sender, &h, nil } - if tx.Value().Cmp(tt.Value) != 0 { - return fmt.Errorf("Value mismatch: got %x, want %x", tx.Value(), tt.Value) + + for _, testcase := range []struct { + name string + signer types.Signer + fork ttFork + isHomestead bool + }{ + {"Frontier", types.FrontierSigner{}, tt.Frontier, false}, + {"Homestead", types.HomesteadSigner{}, tt.Homestead, true}, + {"EIP150", types.HomesteadSigner{}, tt.EIP150, true}, + {"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true}, + {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true}, + {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true}, + } { + sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead) + + if testcase.fork.Sender == (common.UnprefixedAddress{}) { + if err == nil { + return fmt.Errorf("Expected error, got none (address %v)", sender.String()) + } + continue + } + // Should resolve the right address + if err != nil { + return fmt.Errorf("Got error, expected none: %v", err) + } + if sender == nil { + return fmt.Errorf("sender was nil, should be %x", common.Address(testcase.fork.Sender)) + } + if *sender != common.Address(testcase.fork.Sender) { + return fmt.Errorf("Sender mismatch: got %x, want %x", sender, testcase.fork.Sender) + } + if txhash == nil { + return fmt.Errorf("txhash was nil, should be %x", common.Hash(testcase.fork.Hash)) + } + if *txhash != common.Hash(testcase.fork.Hash) { + return fmt.Errorf("Hash mismatch: got %x, want %x", *txhash, testcase.fork.Hash) + } } return nil } From 4b622b277ed2d708c2dffbb538adc64a13a06321 Mon Sep 17 00:00:00 2001 From: Mohanson Date: Sun, 26 May 2019 05:52:10 +0800 Subject: [PATCH 04/47] core/state: unified function receiver names (#19615) --- core/state/state_object.go | 236 ++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 7fbb45b3df..852c340b82 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -33,23 +33,23 @@ var emptyCodeHash = crypto.Keccak256(nil) type Code []byte -func (self Code) String() string { - return string(self) //strings.Join(Disassemble(self), " ") +func (c Code) String() string { + return string(c) //strings.Join(Disassemble(c), " ") } type Storage map[common.Hash]common.Hash -func (self Storage) String() (str string) { - for key, value := range self { +func (s Storage) String() (str string) { + for key, value := range s { str += fmt.Sprintf("%X : %X\n", key, value) } return } -func (self Storage) Copy() Storage { +func (s Storage) Copy() Storage { cpy := make(Storage) - for key, value := range self { + for key, value := range s { cpy[key] = value } @@ -123,210 +123,210 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject { } // EncodeRLP implements rlp.Encoder. -func (c *stateObject) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, c.data) +func (s *stateObject) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, s.data) } // setError remembers the first non-nil error it is called with. -func (self *stateObject) setError(err error) { - if self.dbErr == nil { - self.dbErr = err +func (s *stateObject) setError(err error) { + if s.dbErr == nil { + s.dbErr = err } } -func (self *stateObject) markSuicided() { - self.suicided = true +func (s *stateObject) markSuicided() { + s.suicided = true } -func (c *stateObject) touch() { - c.db.journal.append(touchChange{ - account: &c.address, +func (s *stateObject) touch() { + s.db.journal.append(touchChange{ + account: &s.address, }) - if c.address == ripemd { + if s.address == ripemd { // Explicitly put it in the dirty-cache, which is otherwise generated from // flattened journals. - c.db.journal.dirty(c.address) + s.db.journal.dirty(s.address) } } -func (c *stateObject) getTrie(db Database) Trie { - if c.trie == nil { +func (s *stateObject) getTrie(db Database) Trie { + if s.trie == nil { var err error - c.trie, err = db.OpenStorageTrie(c.addrHash, c.data.Root) + s.trie, err = db.OpenStorageTrie(s.addrHash, s.data.Root) if err != nil { - c.trie, _ = db.OpenStorageTrie(c.addrHash, common.Hash{}) - c.setError(fmt.Errorf("can't create storage trie: %v", err)) + s.trie, _ = db.OpenStorageTrie(s.addrHash, common.Hash{}) + s.setError(fmt.Errorf("can't create storage trie: %v", err)) } } - return c.trie + return s.trie } // GetState retrieves a value from the account storage trie. -func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { +func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { // If we have a dirty value for this state entry, return it - value, dirty := self.dirtyStorage[key] + value, dirty := s.dirtyStorage[key] if dirty { return value } // Otherwise return the entry's original value - return self.GetCommittedState(db, key) + return s.GetCommittedState(db, key) } // GetCommittedState retrieves a value from the committed account storage trie. -func (self *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { +func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { // If we have the original value cached, return that - value, cached := self.originStorage[key] + value, cached := s.originStorage[key] if cached { return value } // Track the amount of time wasted on reading the storge trie if metrics.EnabledExpensive { - defer func(start time.Time) { self.db.StorageReads += time.Since(start) }(time.Now()) + defer func(start time.Time) { s.db.StorageReads += time.Since(start) }(time.Now()) } // Otherwise load the value from the database - enc, err := self.getTrie(db).TryGet(key[:]) + enc, err := s.getTrie(db).TryGet(key[:]) if err != nil { - self.setError(err) + s.setError(err) return common.Hash{} } if len(enc) > 0 { _, content, _, err := rlp.Split(enc) if err != nil { - self.setError(err) + s.setError(err) } value.SetBytes(content) } - self.originStorage[key] = value + s.originStorage[key] = value return value } // SetState updates a value in account storage. -func (self *stateObject) SetState(db Database, key, value common.Hash) { +func (s *stateObject) SetState(db Database, key, value common.Hash) { // If the new value is the same as old, don't set - prev := self.GetState(db, key) + prev := s.GetState(db, key) if prev == value { return } // New value is different, update and journal the change - self.db.journal.append(storageChange{ - account: &self.address, + s.db.journal.append(storageChange{ + account: &s.address, key: key, prevalue: prev, }) - self.setState(key, value) + s.setState(key, value) } -func (self *stateObject) setState(key, value common.Hash) { - self.dirtyStorage[key] = value +func (s *stateObject) setState(key, value common.Hash) { + s.dirtyStorage[key] = value } // updateTrie writes cached storage modifications into the object's storage trie. -func (self *stateObject) updateTrie(db Database) Trie { +func (s *stateObject) updateTrie(db Database) Trie { // Track the amount of time wasted on updating the storge trie if metrics.EnabledExpensive { - defer func(start time.Time) { self.db.StorageUpdates += time.Since(start) }(time.Now()) + defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) } // Update all the dirty slots in the trie - tr := self.getTrie(db) - for key, value := range self.dirtyStorage { - delete(self.dirtyStorage, key) + tr := s.getTrie(db) + for key, value := range s.dirtyStorage { + delete(s.dirtyStorage, key) // Skip noop changes, persist actual changes - if value == self.originStorage[key] { + if value == s.originStorage[key] { continue } - self.originStorage[key] = value + s.originStorage[key] = value if (value == common.Hash{}) { - self.setError(tr.TryDelete(key[:])) + s.setError(tr.TryDelete(key[:])) continue } // Encoding []byte cannot fail, ok to ignore the error. v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00")) - self.setError(tr.TryUpdate(key[:], v)) + s.setError(tr.TryUpdate(key[:], v)) } return tr } // UpdateRoot sets the trie root to the current root hash of -func (self *stateObject) updateRoot(db Database) { - self.updateTrie(db) +func (s *stateObject) updateRoot(db Database) { + s.updateTrie(db) // Track the amount of time wasted on hashing the storge trie if metrics.EnabledExpensive { - defer func(start time.Time) { self.db.StorageHashes += time.Since(start) }(time.Now()) + defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) } - self.data.Root = self.trie.Hash() + s.data.Root = s.trie.Hash() } // CommitTrie the storage trie of the object to db. // This updates the trie root. -func (self *stateObject) CommitTrie(db Database) error { - self.updateTrie(db) - if self.dbErr != nil { - return self.dbErr +func (s *stateObject) CommitTrie(db Database) error { + s.updateTrie(db) + if s.dbErr != nil { + return s.dbErr } // Track the amount of time wasted on committing the storge trie if metrics.EnabledExpensive { - defer func(start time.Time) { self.db.StorageCommits += time.Since(start) }(time.Now()) + defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) } - root, err := self.trie.Commit(nil) + root, err := s.trie.Commit(nil) if err == nil { - self.data.Root = root + s.data.Root = root } return err } // AddBalance removes amount from c's balance. // It is used to add funds to the destination account of a transfer. -func (c *stateObject) AddBalance(amount *big.Int) { +func (s *stateObject) AddBalance(amount *big.Int) { // EIP158: We must check emptiness for the objects such that the account // clearing (0,0,0 objects) can take effect. if amount.Sign() == 0 { - if c.empty() { - c.touch() + if s.empty() { + s.touch() } return } - c.SetBalance(new(big.Int).Add(c.Balance(), amount)) + s.SetBalance(new(big.Int).Add(s.Balance(), amount)) } // SubBalance removes amount from c's balance. // It is used to remove funds from the origin account of a transfer. -func (c *stateObject) SubBalance(amount *big.Int) { +func (s *stateObject) SubBalance(amount *big.Int) { if amount.Sign() == 0 { return } - c.SetBalance(new(big.Int).Sub(c.Balance(), amount)) + s.SetBalance(new(big.Int).Sub(s.Balance(), amount)) } -func (self *stateObject) SetBalance(amount *big.Int) { - self.db.journal.append(balanceChange{ - account: &self.address, - prev: new(big.Int).Set(self.data.Balance), +func (s *stateObject) SetBalance(amount *big.Int) { + s.db.journal.append(balanceChange{ + account: &s.address, + prev: new(big.Int).Set(s.data.Balance), }) - self.setBalance(amount) + s.setBalance(amount) } -func (self *stateObject) setBalance(amount *big.Int) { - self.data.Balance = amount +func (s *stateObject) setBalance(amount *big.Int) { + s.data.Balance = amount } // Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *stateObject) ReturnGas(gas *big.Int) {} +func (s *stateObject) ReturnGas(gas *big.Int) {} -func (self *stateObject) deepCopy(db *StateDB) *stateObject { - stateObject := newObject(db, self.address, self.data) - if self.trie != nil { - stateObject.trie = db.db.CopyTrie(self.trie) +func (s *stateObject) deepCopy(db *StateDB) *stateObject { + stateObject := newObject(db, s.address, s.data) + if s.trie != nil { + stateObject.trie = db.db.CopyTrie(s.trie) } - stateObject.code = self.code - stateObject.dirtyStorage = self.dirtyStorage.Copy() - stateObject.originStorage = self.originStorage.Copy() - stateObject.suicided = self.suicided - stateObject.dirtyCode = self.dirtyCode - stateObject.deleted = self.deleted + stateObject.code = s.code + stateObject.dirtyStorage = s.dirtyStorage.Copy() + stateObject.originStorage = s.originStorage.Copy() + stateObject.suicided = s.suicided + stateObject.dirtyCode = s.dirtyCode + stateObject.deleted = s.deleted return stateObject } @@ -335,69 +335,69 @@ func (self *stateObject) deepCopy(db *StateDB) *stateObject { // // Returns the address of the contract/account -func (c *stateObject) Address() common.Address { - return c.address +func (s *stateObject) Address() common.Address { + return s.address } // Code returns the contract code associated with this object, if any. -func (self *stateObject) Code(db Database) []byte { - if self.code != nil { - return self.code +func (s *stateObject) Code(db Database) []byte { + if s.code != nil { + return s.code } - if bytes.Equal(self.CodeHash(), emptyCodeHash) { + if bytes.Equal(s.CodeHash(), emptyCodeHash) { return nil } - code, err := db.ContractCode(self.addrHash, common.BytesToHash(self.CodeHash())) + code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) if err != nil { - self.setError(fmt.Errorf("can't load code hash %x: %v", self.CodeHash(), err)) + s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) } - self.code = code + s.code = code return code } -func (self *stateObject) SetCode(codeHash common.Hash, code []byte) { - prevcode := self.Code(self.db.db) - self.db.journal.append(codeChange{ - account: &self.address, - prevhash: self.CodeHash(), +func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { + prevcode := s.Code(s.db.db) + s.db.journal.append(codeChange{ + account: &s.address, + prevhash: s.CodeHash(), prevcode: prevcode, }) - self.setCode(codeHash, code) + s.setCode(codeHash, code) } -func (self *stateObject) setCode(codeHash common.Hash, code []byte) { - self.code = code - self.data.CodeHash = codeHash[:] - self.dirtyCode = true +func (s *stateObject) setCode(codeHash common.Hash, code []byte) { + s.code = code + s.data.CodeHash = codeHash[:] + s.dirtyCode = true } -func (self *stateObject) SetNonce(nonce uint64) { - self.db.journal.append(nonceChange{ - account: &self.address, - prev: self.data.Nonce, +func (s *stateObject) SetNonce(nonce uint64) { + s.db.journal.append(nonceChange{ + account: &s.address, + prev: s.data.Nonce, }) - self.setNonce(nonce) + s.setNonce(nonce) } -func (self *stateObject) setNonce(nonce uint64) { - self.data.Nonce = nonce +func (s *stateObject) setNonce(nonce uint64) { + s.data.Nonce = nonce } -func (self *stateObject) CodeHash() []byte { - return self.data.CodeHash +func (s *stateObject) CodeHash() []byte { + return s.data.CodeHash } -func (self *stateObject) Balance() *big.Int { - return self.data.Balance +func (s *stateObject) Balance() *big.Int { + return s.data.Balance } -func (self *stateObject) Nonce() uint64 { - return self.data.Nonce +func (s *stateObject) Nonce() uint64 { + return s.data.Nonce } // Never called, but must be present to allow stateObject to be used // as a vm.Account interface that also satisfies the vm.ContractRef // interface. Interfaces are awesome. -func (self *stateObject) Value() *big.Int { +func (s *stateObject) Value() *big.Int { panic("Value on stateObject should never be called") } From 9efc1a847e53b63847f6f95e0857b1a6300786eb Mon Sep 17 00:00:00 2001 From: Antoine Rondelet Date: Sat, 25 May 2019 22:57:07 +0100 Subject: [PATCH 05/47] crypto/bn256/cloudflare: checks for nil pointers in Marshal functions (#19609) * Added checks for nil pointers in Marshal functions * Set nil pointer to identity in GT before marshaling --- crypto/bn256/cloudflare/bn256.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crypto/bn256/cloudflare/bn256.go b/crypto/bn256/cloudflare/bn256.go index c6ea2d07e0..38822a76bf 100644 --- a/crypto/bn256/cloudflare/bn256.go +++ b/crypto/bn256/cloudflare/bn256.go @@ -100,6 +100,10 @@ func (e *G1) Marshal() []byte { // Each value is a 256-bit number. const numBytes = 256 / 8 + if e.p == nil { + e.p = &curvePoint{} + } + e.p.MakeAffine() ret := make([]byte, numBytes*2) if e.p.IsInfinity() { @@ -382,6 +386,11 @@ func (e *GT) Marshal() []byte { // Each value is a 256-bit number. const numBytes = 256 / 8 + if e.p == nil { + e.p = &gfP12{} + e.p.SetOne() + } + ret := make([]byte, numBytes*12) temp := &gfP{} From fec3b56f7f440b635787f740b527f15b818c0e1b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 26 May 2019 00:07:10 +0200 Subject: [PATCH 06/47] accounts, p2p, rpc: make CGO_ENABLED=0 build again (#19593) * p2p: remove direct import of cgo-library * accounts, rpc: more nocgo alternatives * rpc: move unix path constant into separate file * accounts/scwallet: address review concerns, remove copy-pasta --- accounts/scwallet/wallet.go | 25 ++++++++----------------- p2p/discover/node.go | 3 +-- p2p/rlpx.go | 3 +-- rpc/constants_unix.go | 33 +++++++++++++++++++++++++++++++++ rpc/constants_unix_nocgo.go | 25 +++++++++++++++++++++++++ rpc/ipc_unix.go | 16 +++------------- 6 files changed, 71 insertions(+), 34 deletions(-) create mode 100644 rpc/constants_unix.go create mode 100644 rpc/constants_unix_nocgo.go diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 4c0824eb92..71b2c68af1 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -37,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/log" pcsc "github.com/gballet/go-libpcsclite" "github.com/status-im/keycard-go/derivationpath" @@ -1050,33 +1049,25 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error // determinePublicKey uses a signature and the X component of a public key to // recover the entire public key. func determinePublicKey(sig, pubkeyX []byte) ([]byte, error) { - for v := 0; v < 2; v++ { - sig[64] = byte(v) - pubkey, err := crypto.Ecrecover(DerivationSignatureHash[:], sig) - if err == nil { - if bytes.Equal(pubkey, pubkeyX) { - return pubkey, nil - } - } else if v == 1 || err != secp256k1.ErrRecoverFailed { - return nil, err - } - } - return nil, ErrPubkeyMismatch + return makeRecoverableSignature(DerivationSignatureHash[:], sig, pubkeyX) } // makeRecoverableSignature uses a signature and an expected public key to // recover the v value and produce a recoverable signature. func makeRecoverableSignature(hash, sig, expectedPubkey []byte) ([]byte, error) { + var libraryError error for v := 0; v < 2; v++ { sig[64] = byte(v) - pubkey, err := crypto.Ecrecover(hash, sig) - if err == nil { + if pubkey, err := crypto.Ecrecover(hash, sig); err == nil { if bytes.Equal(pubkey, expectedPubkey) { return sig, nil } - } else if v == 1 || err != secp256k1.ErrRecoverFailed { - return nil, err + } else { + libraryError = err } } + if libraryError != nil { + return nil, libraryError + } return nil, ErrPubkeyMismatch } diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 8d4af166bb..a7d9ce7368 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -25,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/p2p/enode" ) @@ -64,7 +63,7 @@ func (e encPubkey) id() enode.ID { // recoverNodeKey computes the public key used to sign the // given hash from the signature. func recoverNodeKey(hash, sig []byte) (key encPubkey, err error) { - pubkey, err := secp256k1.RecoverPubkey(hash, sig) + pubkey, err := crypto.Ecrecover(hash, sig) if err != nil { return key, err } diff --git a/p2p/rlpx.go b/p2p/rlpx.go index 0697ef3b01..0636431f53 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -38,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/rlp" "github.com/golang/snappy" "golang.org/x/crypto/sha3" @@ -400,7 +399,7 @@ func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) erro return err } signedMsg := xor(token, h.initNonce) - remoteRandomPub, err := secp256k1.RecoverPubkey(signedMsg, msg.Signature[:]) + remoteRandomPub, err := crypto.Ecrecover(signedMsg, msg.Signature[:]) if err != nil { return err } diff --git a/rpc/constants_unix.go b/rpc/constants_unix.go new file mode 100644 index 0000000000..2f98d6499b --- /dev/null +++ b/rpc/constants_unix.go @@ -0,0 +1,33 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package rpc + +/* +#include + +int max_socket_path_size() { +struct sockaddr_un s; +return sizeof(s.sun_path); +} +*/ +import "C" + +var ( + max_path_size = C.max_socket_path_size() +) diff --git a/rpc/constants_unix_nocgo.go b/rpc/constants_unix_nocgo.go new file mode 100644 index 0000000000..ecb231f927 --- /dev/null +++ b/rpc/constants_unix_nocgo.go @@ -0,0 +1,25 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// +build !cgo,!windows + +package rpc + +var ( + // On Linux, sun_path is 108 bytes in size + // see http://man7.org/linux/man-pages/man7/unix.7.html + max_path_size = 108 +) diff --git a/rpc/ipc_unix.go b/rpc/ipc_unix.go index 707b47fd77..da6ce294d7 100644 --- a/rpc/ipc_unix.go +++ b/rpc/ipc_unix.go @@ -1,4 +1,4 @@ -// Copyright 2015 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -28,20 +28,10 @@ import ( "github.com/ethereum/go-ethereum/log" ) -/* -#include - -int max_socket_path_size() { -struct sockaddr_un s; -return sizeof(s.sun_path); -} -*/ -import "C" - // ipcListen will create a Unix socket on the given endpoint. func ipcListen(endpoint string) (net.Listener, error) { - if len(endpoint) > int(C.max_socket_path_size()) { - log.Warn(fmt.Sprintf("The ipc endpoint is longer than %d characters. ", C.max_socket_path_size()), + if len(endpoint) > int(max_path_size) { + log.Warn(fmt.Sprintf("The ipc endpoint is longer than %d characters. ", max_path_size), "endpoint", endpoint) } From 922e757f193a773548e2c6f6f7e503d6f8a7e373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sun, 26 May 2019 07:57:55 +0300 Subject: [PATCH 07/47] accounts/usbwallet: enable the Nano X and upcoming Ledger IDs (#19623) --- accounts/usbwallet/hub.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index a91340b4fc..fc711bb3e9 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -68,7 +68,20 @@ type Hub struct { // NewLedgerHub creates a new hardware wallet manager for Ledger devices. func NewLedgerHub() (*Hub, error) { - return newHub(LedgerScheme, 0x2c97, []uint16{0x0000 /* Ledger Blue */, 0x0001 /* Ledger Nano S */}, 0xffa0, 0, newLedgerDriver) + return newHub(LedgerScheme, 0x2c97, []uint16{ + // Original product IDs + 0x0000, /* Ledger Blue */ + 0x0001, /* Ledger Nano S */ + 0x0004, /* Ledger Nano X */ + + // Upcoming product IDs: https://www.ledger.com/2019/05/17/windows-10-update-sunsetting-u2f-tunnel-transport-for-ledger-devices/ + 0x0015, /* HID + U2F + WebUSB Ledger Blue */ + 0x1015, /* HID + U2F + WebUSB Ledger Nano S */ + 0x4015, /* HID + U2F + WebUSB Ledger Nano X */ + 0x0011, /* HID + WebUSB Ledger Blue */ + 0x1011, /* HID + WebUSB Ledger Nano S */ + 0x4011, /* HID + WebUSB Ledger Nano X */ + }, 0xffa0, 0, newLedgerDriver) } // NewTrezorHub creates a new hardware wallet manager for Trezor devices. From 4e0c1a1a6b97ad062d79c7c8717273cc51f0111c Mon Sep 17 00:00:00 2001 From: gary rong Date: Mon, 27 May 2019 00:15:05 +0800 Subject: [PATCH 08/47] eth, les: reject light client connection is server is not synced (#19616) * eth, les: reject light client connection is server is not synced * eth, les: rename function and variables * les: format --- eth/backend.go | 1 + les/backend.go | 3 ++- les/handler.go | 52 ++++++++++++++++++++++++-------------------- les/helper_test.go | 2 +- les/server.go | 3 ++- les/transactions.rlp | 0 les/ulc.go | 25 ++++++++++++++++----- les/ulc_test.go | 16 ++++++++++++++ 8 files changed, 71 insertions(+), 31 deletions(-) create mode 100755 les/transactions.rlp diff --git a/eth/backend.go b/eth/backend.go index 6b9c98bf2a..fbf4dd7bbc 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -480,6 +480,7 @@ func (s *Ethereum) IsListening() bool { return true } // Always func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } func (s *Ethereum) NetVersion() uint64 { return s.networkID } func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } +func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 } // Protocols implements node.Service, returning all the currently configured // network protocols to start. diff --git a/les/backend.go b/les/backend.go index 887f882108..ed0f45057f 100644 --- a/les/backend.go +++ b/les/backend.go @@ -158,7 +158,8 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { leth.serverPool, quitSync, &leth.wg, - config.ULC); err != nil { + config.ULC, + nil); err != nil { return nil, err } diff --git a/les/handler.go b/les/handler.go index 0d235e7a52..f53a4722f1 100644 --- a/les/handler.go +++ b/les/handler.go @@ -87,12 +87,16 @@ type txPool interface { } type ProtocolManager struct { - lightSync bool + // Configs + chainConfig *params.ChainConfig + iConfig *light.IndexerConfig + + client bool // The indicator whether the node is light client + maxPeers int // The maximum number peers allowed to connect. + networkId uint64 // The identity of network. + txpool txPool txrelay *LesTxRelay - networkId uint64 - chainConfig *params.ChainConfig - iConfig *light.IndexerConfig blockchain BlockChain chainDb ethdb.Database odr *LesOdr @@ -102,23 +106,21 @@ type ProtocolManager struct { reqDist *requestDistributor retriever *retrieveManager servingQueue *servingQueue - - downloader *downloader.Downloader - fetcher *lightFetcher - peers *peerSet - maxPeers int - - eventMux *event.TypeMux + downloader *downloader.Downloader + fetcher *lightFetcher + ulc *ulc + peers *peerSet // channels for fetcher, syncer, txsyncLoop newPeerCh chan *peer quitSync chan struct{} noMorePeers chan struct{} - // wait group is used for graceful shutdowns during downloading - // and processing - wg *sync.WaitGroup - ulc *ulc + wg *sync.WaitGroup + eventMux *event.TypeMux + + // Callbacks + synced func() bool } // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable @@ -126,7 +128,7 @@ type ProtocolManager struct { func NewProtocolManager( chainConfig *params.ChainConfig, indexerConfig *light.IndexerConfig, - lightSync bool, + client bool, networkId uint64, mux *event.TypeMux, engine consensus.Engine, @@ -139,10 +141,10 @@ func NewProtocolManager( serverPool *serverPool, quitSync chan struct{}, wg *sync.WaitGroup, - ulcConfig *eth.ULCConfig) (*ProtocolManager, error) { + ulcConfig *eth.ULCConfig, synced func() bool) (*ProtocolManager, error) { // Create the protocol manager with the base fields manager := &ProtocolManager{ - lightSync: lightSync, + client: client, eventMux: mux, blockchain: blockchain, chainConfig: chainConfig, @@ -158,6 +160,7 @@ func NewProtocolManager( quitSync: quitSync, wg: wg, noMorePeers: make(chan struct{}), + synced: synced, } if odr != nil { manager.retriever = odr.retriever @@ -174,7 +177,7 @@ func NewProtocolManager( if disableClientRemovePeer { removePeer = func(id string) {} } - if lightSync { + if client { var checkpoint uint64 if cht, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok { checkpoint = (cht.SectionIndex+1)*params.CHTFrequency - 1 @@ -193,7 +196,7 @@ func (pm *ProtocolManager) removePeer(id string) { func (pm *ProtocolManager) Start(maxPeers int) { pm.maxPeers = maxPeers - if pm.lightSync { + if pm.client { go pm.syncer() } else { go func() { @@ -268,10 +271,13 @@ func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgRea func (pm *ProtocolManager) handle(p *peer) error { // Ignore maxPeers if this is a trusted peer // In server mode we try to check into the client pool after handshake - if pm.lightSync && pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted { + if pm.client && pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted { return p2p.DiscTooManyPeers } - + // Reject light clients if server is not synced. + if !pm.client && !pm.synced() { + return p2p.DiscRequested + } p.Log().Debug("Light Ethereum peer connected", "name", p.Name()) // Execute the LES handshake @@ -304,7 +310,7 @@ func (pm *ProtocolManager) handle(p *peer) error { }() // Register the peer in the downloader. If the downloader considers it banned, we disconnect - if pm.lightSync { + if pm.client { p.lock.Lock() head := p.headInfo p.lock.Unlock() diff --git a/les/helper_test.go b/les/helper_test.go index 9a302f8370..878e44404c 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -170,7 +170,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor if lightSync { indexConfig = light.TestClientIndexerConfig } - pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkId, evmux, engine, peers, chain, pool, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), ulcConfig) + pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkId, evmux, engine, peers, chain, pool, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), ulcConfig, func() bool { return true }) if err != nil { return nil, err } diff --git a/les/server.go b/les/server.go index 6c2b227f42..6b93b846db 100644 --- a/les/server.go +++ b/les/server.go @@ -74,7 +74,7 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { nil, quitSync, new(sync.WaitGroup), - config.ULC) + config.ULC, eth.Synced) if err != nil { return nil, err } @@ -243,6 +243,7 @@ func (s *LesServer) Stop() { s.protocolManager.Stop() } +// todo(rjl493456442) separate client and server implementation. func (pm *ProtocolManager) blockLoop() { pm.wg.Add(1) headCh := make(chan core.ChainHeadEvent, 10) diff --git a/les/transactions.rlp b/les/transactions.rlp new file mode 100755 index 0000000000..e69de29bb2 diff --git a/les/ulc.go b/les/ulc.go index d9f7dc76c9..c6d4155529 100644 --- a/les/ulc.go +++ b/les/ulc.go @@ -1,9 +1,24 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + package les import ( - "fmt" - "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" ) @@ -12,24 +27,24 @@ type ulc struct { minTrustedFraction int } +// newULC creates and returns a ultra light client instance. func newULC(ulcConfig *eth.ULCConfig) *ulc { if ulcConfig == nil { return nil } - m := make(map[string]struct{}, len(ulcConfig.TrustedServers)) for _, id := range ulcConfig.TrustedServers { node, err := enode.ParseV4(id) if err != nil { - fmt.Println("node:", id, " err:", err) + log.Debug("Failed to parse trusted server", "id", id, "err", err) continue } m[node.ID().String()] = struct{}{} } - return &ulc{m, ulcConfig.MinTrustedFraction} } +// isTrusted return an indicator that whether the specified peer is trusted. func (u *ulc) isTrusted(p enode.ID) bool { if u.trustedKeys == nil { return false diff --git a/les/ulc_test.go b/les/ulc_test.go index 81986fa1e8..38adeb95f1 100644 --- a/les/ulc_test.go +++ b/les/ulc_test.go @@ -1,3 +1,19 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + package les import ( From 611113e9678b8118e5ec624d9e9f0999f1d4a081 Mon Sep 17 00:00:00 2001 From: gary rong Date: Mon, 27 May 2019 17:05:45 +0800 Subject: [PATCH 09/47] core: never delete genesis block (#19617) --- core/blockchain.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 7ab6806c2f..60707281c2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1076,8 +1076,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // Wipe out canonical block data. for _, block := range append(deleted, blockChain...) { - rawdb.DeleteBlockWithoutNumber(batch, block.Hash(), block.NumberU64()) - rawdb.DeleteCanonicalHash(batch, block.NumberU64()) + // Always keep genesis block in active database. + if block.NumberU64() != 0 { + rawdb.DeleteBlockWithoutNumber(batch, block.Hash(), block.NumberU64()) + rawdb.DeleteCanonicalHash(batch, block.NumberU64()) + } } if err := batch.Write(); err != nil { return 0, err @@ -1086,8 +1089,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // Wipe out side chain too. for _, block := range append(deleted, blockChain...) { - for _, hash := range rawdb.ReadAllHashes(bc.db, block.NumberU64()) { - rawdb.DeleteBlock(batch, hash, block.NumberU64()) + // Always keep genesis block in active database. + if block.NumberU64() != 0 { + for _, hash := range rawdb.ReadAllHashes(bc.db, block.NumberU64()) { + rawdb.DeleteBlock(batch, hash, block.NumberU64()) + } } } if err := batch.Write(); err != nil { From 7392f59e7ce15c17a1194ae82cd90de101f0ab40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 27 May 2019 12:25:24 +0300 Subject: [PATCH 10/47] core/rawdb: keep genesis in key-value store for full sync too --- core/rawdb/freezer.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 33da53787a..741ff9adbf 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -335,8 +335,11 @@ func (f *freezer) freeze(db ethdb.KeyValueStore) { // Wipe out all data from the active database batch := db.NewBatch() for i := 0; i < len(ancients); i++ { - DeleteBlockWithoutNumber(batch, ancients[i], first+uint64(i)) - DeleteCanonicalHash(batch, first+uint64(i)) + // Always keep the genesis block in active database + if first+uint64(i) != 0 { + DeleteBlockWithoutNumber(batch, ancients[i], first+uint64(i)) + DeleteCanonicalHash(batch, first+uint64(i)) + } } if err := batch.Write(); err != nil { log.Crit("Failed to delete frozen canonical blocks", "err", err) @@ -344,8 +347,11 @@ func (f *freezer) freeze(db ethdb.KeyValueStore) { batch.Reset() // Wipe out side chain also. for number := first; number < f.frozen; number++ { - for _, hash := range ReadAllHashes(db, number) { - DeleteBlock(batch, hash, number) + // Always keep the genesis block in active database + if number != 0 { + for _, hash := range ReadAllHashes(db, number) { + DeleteBlock(batch, hash, number) + } } } if err := batch.Write(); err != nil { From a184ab7a61884409a4deea2419c5307a0dc7c49d Mon Sep 17 00:00:00 2001 From: Jeremy Schlatter Date: Mon, 27 May 2019 03:28:06 -0700 Subject: [PATCH 11/47] accounts/keystore: enable fallback for darwin,!cgo (#19614) Without this, accounts/keystore fails to build for Darwin with CGO_ENABLED=0. --- accounts/keystore/watch.go | 2 +- accounts/keystore/watch_fallback.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/keystore/watch.go b/accounts/keystore/watch.go index bbcfb99257..d6ef53327d 100644 --- a/accounts/keystore/watch.go +++ b/accounts/keystore/watch.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build darwin,!ios freebsd linux,!arm64 netbsd solaris +// +build darwin,!ios,cgo freebsd linux,!arm64 netbsd solaris package keystore diff --git a/accounts/keystore/watch_fallback.go b/accounts/keystore/watch_fallback.go index 7c5e9cb2e2..de0e87f8a5 100644 --- a/accounts/keystore/watch_fallback.go +++ b/accounts/keystore/watch_fallback.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build ios linux,arm64 windows !darwin,!freebsd,!linux,!netbsd,!solaris +// +build darwin,!cgo ios linux,arm64 windows !darwin,!freebsd,!linux,!netbsd,!solaris // This is the fallback implementation of directory watching. // It is used on unsupported platforms. From fc85777a219acd12620fe9b76a3b7e585800300c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 27 May 2019 15:48:30 +0300 Subject: [PATCH 12/47] core: concurrent database reinit from freezer dump * core: reinit chain from freezer in batches * core/rawdb: concurrent database reinit from freezer dump * core/rawdb: reinit from freezer in sequential order --- common/prque/prque.go | 25 ++++++- common/prque/sstack.go | 18 +++-- core/blockchain.go | 43 ++--------- core/rawdb/accessors_indexes.go | 3 +- core/rawdb/freezer_reinit.go | 127 ++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 45 deletions(-) create mode 100644 core/rawdb/freezer_reinit.go diff --git a/common/prque/prque.go b/common/prque/prque.go index 9fd31a2e5d..3cc5a1adaf 100755 --- a/common/prque/prque.go +++ b/common/prque/prque.go @@ -1,5 +1,20 @@ +// CookieJar - A contestant's algorithm toolbox +// Copyright (c) 2013 Peter Szilagyi. All rights reserved. +// +// CookieJar is dual licensed: use of this source code is governed by a BSD +// license that can be found in the LICENSE file. Alternatively, the CookieJar +// toolbox may be used in accordance with the terms and conditions contained +// in a signed written agreement between you and the author(s). + // This is a duplicated and slightly modified version of "gopkg.in/karalabe/cookiejar.v2/collections/prque". +// Package prque implements a priority queue data structure supporting arbitrary +// value types and int64 priorities. +// +// If you would like to use a min-priority queue, simply negate the priorities. +// +// Internally the queue is based on the standard heap package working on a +// sortable version of the block based stack. package prque import ( @@ -11,8 +26,8 @@ type Prque struct { cont *sstack } -// Creates a new priority queue. -func New(setIndex setIndexCallback) *Prque { +// New creates a new priority queue. +func New(setIndex SetIndexCallback) *Prque { return &Prque{newSstack(setIndex)} } @@ -21,6 +36,12 @@ func (p *Prque) Push(data interface{}, priority int64) { heap.Push(p.cont, &item{data, priority}) } +// Peek returns the value with the greates priority but does not pop it off. +func (p *Prque) Peek() (interface{}, int64) { + item := p.cont.blocks[0][0] + return item.value, item.priority +} + // Pops the value with the greates priority off the stack and returns it. // Currently no shrinking is done. func (p *Prque) Pop() (interface{}, int64) { diff --git a/common/prque/sstack.go b/common/prque/sstack.go index 4875dae99d..8518af54ff 100755 --- a/common/prque/sstack.go +++ b/common/prque/sstack.go @@ -1,3 +1,11 @@ +// CookieJar - A contestant's algorithm toolbox +// Copyright (c) 2013 Peter Szilagyi. All rights reserved. +// +// CookieJar is dual licensed: use of this source code is governed by a BSD +// license that can be found in the LICENSE file. Alternatively, the CookieJar +// toolbox may be used in accordance with the terms and conditions contained +// in a signed written agreement between you and the author(s). + // This is a duplicated and slightly modified version of "gopkg.in/karalabe/cookiejar.v2/collections/prque". package prque @@ -14,16 +22,16 @@ type item struct { priority int64 } -// setIndexCallback is called when the element is moved to a new index. -// Providing setIndexCallback is optional, it is needed only if the application needs +// SetIndexCallback is called when the element is moved to a new index. +// Providing SetIndexCallback is optional, it is needed only if the application needs // to delete elements other than the top one. -type setIndexCallback func(a interface{}, i int) +type SetIndexCallback func(data interface{}, index int) // Internal sortable stack data structure. Implements the Push and Pop ops for // the stack (heap) functionality and the Len, Less and Swap methods for the // sortability requirements of the heaps. type sstack struct { - setIndex setIndexCallback + setIndex SetIndexCallback size int capacity int offset int @@ -33,7 +41,7 @@ type sstack struct { } // Creates a new, empty stack. -func newSstack(setIndex setIndexCallback) *sstack { +func newSstack(setIndex SetIndexCallback) *sstack { result := new(sstack) result.setIndex = setIndex result.active = make([]*item, blockSize) diff --git a/core/blockchain.go b/core/blockchain.go index 60707281c2..7119596928 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -220,47 +220,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } // Initialize the chain with ancient data if it isn't empty. if bc.empty() { - if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 { - var ( - start = time.Now() - logged time.Time - ) - for i := uint64(0); i < frozen; i++ { - // Inject hash<->number mapping. - hash := rawdb.ReadCanonicalHash(bc.db, i) - if hash == (common.Hash{}) { - return nil, errors.New("broken ancient database") - } - rawdb.WriteHeaderNumber(bc.db, hash, i) - - // Inject txlookup indexes. - block := rawdb.ReadBlock(bc.db, hash, i) - if block == nil { - return nil, errors.New("broken ancient database") - } - rawdb.WriteTxLookupEntries(bc.db, block) - - // If we've spent too much time already, notify the user of what we're doing - if time.Since(logged) > 8*time.Second { - log.Info("Initializing chain from ancient data", "number", i, "hash", hash, "total", frozen-1, "elapsed", common.PrettyDuration(time.Since(start))) - logged = time.Now() - } - } - hash := rawdb.ReadCanonicalHash(bc.db, frozen-1) - rawdb.WriteHeadHeaderHash(bc.db, hash) - rawdb.WriteHeadFastBlockHash(bc.db, hash) - - // The first thing the node will do is reconstruct the verification data for - // the head block (ethash cache or clique voting snapshot). Might as well do - // it in advance. - bc.engine.VerifyHeader(bc, rawdb.ReadHeader(bc.db, hash, frozen-1), true) - - log.Info("Initialized chain from ancient data", "number", frozen-1, "hash", hash, "elapsed", common.PrettyDuration(time.Since(start))) - } + rawdb.InitDatabaseFromFreezer(bc.db) } if err := bc.loadLastState(); err != nil { return nil, err } + // The first thing the node will do is reconstruct the verification data for + // the head block (ethash cache or clique voting snapshot). Might as well do + // it in advance. + bc.engine.VerifyHeader(bc, bc.CurrentHeader(), true) + if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 { var ( needRewind bool diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index ed1f1bca6e..38f8fe10ea 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -55,8 +55,9 @@ func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { // WriteTxLookupEntries stores a positional metadata for every transaction from // a block, enabling hash based transaction and receipt lookups. func WriteTxLookupEntries(db ethdb.KeyValueWriter, block *types.Block) { + number := block.Number().Bytes() for _, tx := range block.Transactions() { - if err := db.Put(txLookupKey(tx.Hash()), block.Number().Bytes()); err != nil { + if err := db.Put(txLookupKey(tx.Hash()), number); err != nil { log.Crit("Failed to store transaction lookup entry", "err", err) } } diff --git a/core/rawdb/freezer_reinit.go b/core/rawdb/freezer_reinit.go new file mode 100644 index 0000000000..ea4dd33d1d --- /dev/null +++ b/core/rawdb/freezer_reinit.go @@ -0,0 +1,127 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rawdb + +import ( + "errors" + "runtime" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/prque" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" +) + +// InitDatabaseFromFreezer reinitializes an empty database from a previous batch +// of frozen ancient blocks. The method iterates over all the frozen blocks and +// injects into the database the block hash->number mappings and the transaction +// lookup entries. +func InitDatabaseFromFreezer(db ethdb.Database) error { + // If we can't access the freezer or it's empty, abort + frozen, err := db.Ancients() + if err != nil || frozen == 0 { + return err + } + // Blocks previously frozen, iterate over- and hash them concurrently + var ( + number = ^uint64(0) // -1 + results = make(chan *types.Block, 4*runtime.NumCPU()) + ) + abort := make(chan struct{}) + defer close(abort) + + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + for { + // Fetch the next task number, terminating if everything's done + n := atomic.AddUint64(&number, 1) + if n >= frozen { + return + } + // Retrieve the block from the freezer (no need for the hash, we pull by + // number from the freezer). If successful, pre-cache the block hash and + // the individual transaction hashes for storing into the database. + block := ReadBlock(db, common.Hash{}, n) + if block != nil { + block.Hash() + for _, tx := range block.Transactions() { + tx.Hash() + } + } + // Feed the block to the aggregator, or abort on interrupt + select { + case results <- block: + case <-abort: + return + } + } + }() + } + // Reassemble the blocks into a contiguous stream and push them out to disk + var ( + queue = prque.New(nil) + next = int64(0) + + batch = db.NewBatch() + start = time.Now() + logged time.Time + ) + for i := uint64(0); i < frozen; i++ { + // Retrieve the next result and bail if it's nil + block := <-results + if block == nil { + return errors.New("broken ancient database") + } + // Push the block into the import queue and process contiguous ranges + queue.Push(block, -int64(block.NumberU64())) + for !queue.Empty() { + // If the next available item is gapped, return + if _, priority := queue.Peek(); -priority != next { + break + } + // Next block available, pop it off and index it + block = queue.PopItem().(*types.Block) + next++ + + // Inject hash<->number mapping and txlookup indexes + WriteHeaderNumber(batch, block.Hash(), block.NumberU64()) + WriteTxLookupEntries(batch, block) + + // If enough data was accumulated in memory or we're at the last block, dump to disk + if batch.ValueSize() > ethdb.IdealBatchSize || uint64(next) == frozen { + if err := batch.Write(); err != nil { + return err + } + batch.Reset() + } + // If we've spent too much time already, notify the user of what we're doing + if time.Since(logged) > 8*time.Second { + log.Info("Initializing chain from ancient data", "number", block.Number(), "hash", block.Hash(), "total", frozen-1, "elapsed", common.PrettyDuration(time.Since(start))) + logged = time.Now() + } + } + } + hash := ReadCanonicalHash(db, frozen-1) + WriteHeadHeaderHash(db, hash) + WriteHeadFastBlockHash(db, hash) + + log.Info("Initialized chain from ancient data", "number", frozen-1, "hash", hash, "elapsed", common.PrettyDuration(time.Since(start))) + return nil +} From 9cd338054fc7d16617901ba12581f3d9cf4ac8c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 27 May 2019 16:36:06 +0300 Subject: [PATCH 13/47] vendor: update go-duktape to v2.3.0 --- vendor/gopkg.in/olebedev/go-duktape.v3/api.go | 50 +- .../gopkg.in/olebedev/go-duktape.v3/conts.go | 148 +- .../olebedev/go-duktape.v3/duk_alloc_pool.h | 8 + .../olebedev/go-duktape.v3/duk_config.h | 136 +- .../olebedev/go-duktape.v3/duk_console.c | 40 +- .../olebedev/go-duktape.v3/duk_console.h | 19 +- .../olebedev/go-duktape.v3/duk_logging.h | 10 +- .../go-duktape.v3/duk_minimal_printf.h | 8 + .../go-duktape.v3/duk_module_duktape.c | 4 +- .../go-duktape.v3/duk_module_duktape.h | 8 + .../olebedev/go-duktape.v3/duk_module_node.h | 8 + .../olebedev/go-duktape.v3/duk_print_alert.h | 8 + .../olebedev/go-duktape.v3/duk_v1_compat.h | 8 + .../gopkg.in/olebedev/go-duktape.v3/duktape.c | 6049 +++++++++++------ .../olebedev/go-duktape.v3/duktape.go | 2 +- .../gopkg.in/olebedev/go-duktape.v3/duktape.h | 144 +- vendor/vendor.json | 6 +- 17 files changed, 4248 insertions(+), 2408 deletions(-) diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/api.go b/vendor/gopkg.in/olebedev/go-duktape.v3/api.go index 924b5c32fc..706fdc48b1 100644 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/api.go +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/api.go @@ -247,16 +247,16 @@ func (d *Context) CompileFile(flags uint, path string) { } // See: http://duktape.org/api.html#duk_compile_lstring -func (d *Context) CompileLstring(flags uint, src string, len int) { +func (d *Context) CompileLstring(flags uint, src string, lenght int) { __src__ := C.CString(src) - C._duk_compile_lstring(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(len)) + C._duk_compile_lstring(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(lenght)) C.free(unsafe.Pointer(__src__)) } // See: http://duktape.org/api.html#duk_compile_lstring_filename -func (d *Context) CompileLstringFilename(flags uint, src string, len int) { +func (d *Context) CompileLstringFilename(flags uint, src string, lenght int) { __src__ := C.CString(src) - C._duk_compile_lstring_filename(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(len)) + C._duk_compile_lstring_filename(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(lenght)) C.free(unsafe.Pointer(__src__)) } @@ -395,16 +395,16 @@ func (d *Context) EvalFileNoresult(path string) { } // See: http://duktape.org/api.html#duk_eval_lstring -func (d *Context) EvalLstring(src string, len int) { +func (d *Context) EvalLstring(src string, lenght int) { __src__ := C.CString(src) - C._duk_eval_lstring(d.duk_context, __src__, C.duk_size_t(len)) + C._duk_eval_lstring(d.duk_context, __src__, C.duk_size_t(lenght)) C.free(unsafe.Pointer(__src__)) } // See: http://duktape.org/api.html#duk_eval_lstring_noresult -func (d *Context) EvalLstringNoresult(src string, len int) { +func (d *Context) EvalLstringNoresult(src string, lenght int) { __src__ := C.CString(src) - C._duk_eval_lstring_noresult(d.duk_context, __src__, C.duk_size_t(len)) + C._duk_eval_lstring_noresult(d.duk_context, __src__, C.duk_size_t(lenght)) C.free(unsafe.Pointer(__src__)) } @@ -801,17 +801,17 @@ func (d *Context) PcompileFile(flags uint, path string) error { } // See: http://duktape.org/api.html#duk_pcompile_lstring -func (d *Context) PcompileLstring(flags uint, src string, len int) error { +func (d *Context) PcompileLstring(flags uint, src string, lenght int) error { __src__ := C.CString(src) - result := int(C._duk_pcompile_lstring(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(len))) + result := int(C._duk_pcompile_lstring(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(lenght))) C.free(unsafe.Pointer(__src__)) return d.castStringToError(result) } // See: http://duktape.org/api.html#duk_pcompile_lstring_filename -func (d *Context) PcompileLstringFilename(flags uint, src string, len int) error { +func (d *Context) PcompileLstringFilename(flags uint, src string, lenght int) error { __src__ := C.CString(src) - result := int(C._duk_pcompile_lstring_filename(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(len))) + result := int(C._duk_pcompile_lstring_filename(d.duk_context, C.duk_uint_t(flags), __src__, C.duk_size_t(lenght))) C.free(unsafe.Pointer(__src__)) return d.castStringToError(result) } @@ -821,8 +821,7 @@ func (d *Context) PcompileString(flags uint, src string) error { __src__ := C.CString(src) result := int(C._duk_pcompile_string(d.duk_context, C.duk_uint_t(flags), __src__)) C.free(unsafe.Pointer(__src__)) - fmt.Println("result herhehreh", result) - return nil //d.castStringToError(result) + return d.castStringToError(result) } // See: http://duktape.org/api.html#duk_pcompile_string_filename @@ -856,18 +855,18 @@ func (d *Context) PevalFileNoresult(path string) int { } // See: http://duktape.org/api.html#duk_peval_lstring -func (d *Context) PevalLstring(src string, len int) error { +func (d *Context) PevalLstring(src string, lenght int) error { __src__ := C.CString(src) - result := int(C._duk_peval_lstring(d.duk_context, __src__, C.duk_size_t(len))) + result := int(C._duk_peval_lstring(d.duk_context, __src__, C.duk_size_t(lenght))) C.free(unsafe.Pointer(__src__)) return d.castStringToError(result) } // See: http://duktape.org/api.html#duk_peval_lstring_noresult -func (d *Context) PevalLstringNoresult(src string, len int) int { +func (d *Context) PevalLstringNoresult(src string, lenght int) int { __src__ := C.CString(src) - result := int(C._duk_peval_lstring_noresult(d.duk_context, __src__, C.duk_size_t(len))) + result := int(C._duk_peval_lstring_noresult(d.duk_context, __src__, C.duk_size_t(lenght))) C.free(unsafe.Pointer(__src__)) return result } @@ -1040,10 +1039,10 @@ func (d *Context) PushInt(val int) { } // See: http://duktape.org/api.html#duk_push_lstring -func (d *Context) PushLstring(str string, len int) string { +func (d *Context) PushLstring(str string, lenght int) string { __str__ := C.CString(str) var result string - if s := C.duk_push_lstring(d.duk_context, __str__, C.duk_size_t(len)); s != nil { + if s := C.duk_push_lstring(d.duk_context, __str__, C.duk_size_t(lenght)); s != nil { result = C.GoString(s) } C.free(unsafe.Pointer(__str__)) @@ -1590,6 +1589,16 @@ func (d *Context) PushExternalBuffer() { C._duk_push_external_buffer(d.duk_context) } +// See: http://duktape.org/api.html#duk_config_buffer +func (d *Context) ConfigBuffer(bufferIdx int, buffer []byte) { + C.duk_config_buffer( + d.duk_context, + C.duk_idx_t(bufferIdx), + unsafe.Pointer(&buffer[0]), + C.duk_size_t(len(buffer)), + ) +} + /** * Unimplemented. * @@ -1608,7 +1617,6 @@ func (d *Context) PushExternalBuffer() { * Realloc see: http://duktape.org/api.html#duk_realloc * ReallocRaw see: http://duktape.org/api.html#duk_realloc_raw * RequireCFunction see: http://duktape.org/api.html#duk_require_c_function - * ConfigBuffer see: http://duktape.org/api.html#duk_config_buffer * GetBufferData see: http://duktape.org/api.html#duk_get_buffer_data * StealBuffer see: http://duktape.org/api.html#duk_steal_buffer * RequireBufferData see: http://duktape.org/api.html#duk_require_buffer_data diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/conts.go b/vendor/gopkg.in/olebedev/go-duktape.v3/conts.go index f3dbd8bc84..6eed641d2f 100644 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/conts.go +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/conts.go @@ -1,72 +1,75 @@ package duktape +/* +#cgo !windows CFLAGS: -std=c99 -O3 -Wall -Wno-unused-value -fomit-frame-pointer -fstrict-aliasing +#cgo windows CFLAGS: -O3 -Wall -Wno-unused-value -fomit-frame-pointer -fstrict-aliasing + +#include "duktape.h" +*/ +import "C" + const ( - CompileEval uint = 1 << iota - CompileFunction - CompileStrict - CompileSafe - CompileNoResult - CompileNoSource - CompileStrlen + CompileEval uint = C.DUK_COMPILE_EVAL + CompileFunction uint = C.DUK_COMPILE_FUNCTION + CompileStrict uint = C.DUK_COMPILE_STRICT + CompileShebang uint = C.DUK_COMPILE_SHEBANG + CompileSafe uint = C.DUK_COMPILE_SAFE + CompileNoResult uint = C.DUK_COMPILE_NORESULT + CompileNoSource uint = C.DUK_COMPILE_NOSOURCE + CompileStrlen uint = C.DUK_COMPILE_STRLEN + CompileNoFileName uint = C.DUK_COMPILE_NOFILENAME + CompileFuncExpr uint = C.DUK_COMPILE_FUNCEXPR ) const ( - TypeNone Type = iota - TypeUndefined - TypeNull - TypeBoolean - TypeNumber - TypeString - TypeObject - TypeBuffer - TypePointer - TypeLightFunc + TypeNone Type = C.DUK_TYPE_NONE + TypeUndefined Type = C.DUK_TYPE_UNDEFINED + TypeNull Type = C.DUK_TYPE_NULL + TypeBoolean Type = C.DUK_TYPE_BOOLEAN + TypeNumber Type = C.DUK_TYPE_NUMBER + TypeString Type = C.DUK_TYPE_STRING + TypeObject Type = C.DUK_TYPE_OBJECT + TypeBuffer Type = C.DUK_TYPE_BUFFER + TypePointer Type = C.DUK_TYPE_POINTER + TypeLightFunc Type = C.DUK_TYPE_LIGHTFUNC ) const ( - TypeMaskNone uint = 1 << iota - TypeMaskUndefined - TypeMaskNull - TypeMaskBoolean - TypeMaskNumber - TypeMaskString - TypeMaskObject - TypeMaskBuffer - TypeMaskPointer - TypeMaskLightFunc + TypeMaskNone uint = C.DUK_TYPE_MASK_NONE + TypeMaskUndefined uint = C.DUK_TYPE_MASK_UNDEFINED + TypeMaskNull uint = C.DUK_TYPE_MASK_NULL + TypeMaskBoolean uint = C.DUK_TYPE_MASK_BOOLEAN + TypeMaskNumber uint = C.DUK_TYPE_MASK_NUMBER + TypeMaskString uint = C.DUK_TYPE_MASK_STRING + TypeMaskObject uint = C.DUK_TYPE_MASK_OBJECT + TypeMaskBuffer uint = C.DUK_TYPE_MASK_BUFFER + TypeMaskPointer uint = C.DUK_TYPE_MASK_POINTER + TypeMaskLightFunc uint = C.DUK_TYPE_MASK_LIGHTFUNC ) const ( - EnumIncludeNonenumerable uint = 1 << iota - EnumIncludeInternal - EnumOwnPropertiesOnly - EnumArrayIndicesOnly - EnumSortArrayIndices - NoProxyBehavior + EnumIncludeNonenumerable uint = C.DUK_ENUM_INCLUDE_NONENUMERABLE + EnumIncludeHidden uint = C.DUK_ENUM_INCLUDE_HIDDEN + EnumIncludeSymbols uint = C.DUK_ENUM_INCLUDE_SYMBOLS + EnumExcludeStrings uint = C.DUK_ENUM_EXCLUDE_STRINGS + EnumOwnPropertiesOnly uint = C.DUK_ENUM_OWN_PROPERTIES_ONLY + EnumArrayIndicesOnly uint = C.DUK_ENUM_ARRAY_INDICES_ONLY + EnumSortArrayIndices uint = C.DUK_ENUM_SORT_ARRAY_INDICES + NoProxyBehavior uint = C.DUK_ENUM_NO_PROXY_BEHAVIOR ) const ( - ErrNone int = 0 - - // Internal to Duktape ErrUnimplemented int = 50 + iota ErrUnsupported - ErrInternal - ErrAlloc - ErrAssertion - ErrAPI - ErrUncaughtError -) -const ( - // Common prototypes - ErrError int = 1 + iota - ErrEval - ErrRange - ErrReference - ErrSyntax - ErrType - ErrURI + ErrNone int = C.DUK_ERR_NONE + ErrError int = C.DUK_ERR_ERROR + ErrEval int = C.DUK_ERR_EVAL_ERROR + ErrRange int = C.DUK_ERR_RANGE_ERROR + ErrReference int = C.DUK_ERR_REFERENCE_ERROR + ErrSyntax int = C.DUK_ERR_SYNTAX_ERROR + ErrType int = C.DUK_ERR_TYPE_ERROR + ErrURI int = C.DUK_ERR_URI_ERROR ) const ( @@ -81,18 +84,18 @@ const ( ) const ( - ErrRetError int = -(ErrError + iota) - ErrRetEval - ErrRetRange - ErrRetReference - ErrRetSyntax - ErrRetType - ErrRetURI + ErrRetError int = -(ErrError) + ErrRetEval int = -(ErrEval) + ErrRetRange int = -(ErrRange) + ErrRetReference int = -(ErrReference) + ErrRetSyntax int = -(ErrSyntax) + ErrRetType int = -(ErrType) + ErrRetURI int = -(ErrURI) ) const ( - ExecSuccess = iota - ExecError + ExecSuccess int = C.DUK_EXEC_SUCCESS + ExecError int = C.DUK_EXEC_ERROR ) const ( @@ -105,17 +108,16 @@ const ( ) const ( - BufobjDuktapeAuffer = 0 - BufobjNodejsAuffer = 1 - BufobjArraybuffer = 2 - BufobjDataview = 3 - BufobjInt8array = 4 - BufobjUint8array = 5 - BufobjUint8clampedarray = 6 - BufobjInt16array = 7 - BufobjUint16array = 8 - BufobjInt32array = 9 - BufobjUint32array = 10 - BufobjFloat32array = 11 - BufobjFloat64array = 12 + BufObjArrayBuffer int = C.DUK_BUFOBJ_ARRAYBUFFER + BufObjNodejsBuffer int = C.DUK_BUFOBJ_NODEJS_BUFFER + BufObjDataView int = C.DUK_BUFOBJ_DATAVIEW + BufobjInt8Array int = C.DUK_BUFOBJ_INT8ARRAY + BufobjUint8Array int = C.DUK_BUFOBJ_UINT8ARRAY + BufobjUint8ClampedArray int = C.DUK_BUFOBJ_UINT8CLAMPEDARRAY + BufObjInt16Array int = C.DUK_BUFOBJ_INT16ARRAY + BufObjUint16Array int = C.DUK_BUFOBJ_UINT16ARRAY + BufObjInt32Array int = C.DUK_BUFOBJ_INT32ARRAY + BufObjUint32Array int = C.DUK_BUFOBJ_UINT32ARRAY + BufObjFloat32Array int = C.DUK_BUFOBJ_FLOAT32ARRAY + BufObjFloat64Array int = C.DUK_BUFOBJ_FLOAT64ARRAY ) diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_alloc_pool.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_alloc_pool.h index 286ec0166a..671f7610d8 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_alloc_pool.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_alloc_pool.h @@ -3,6 +3,10 @@ #include "duktape.h" +#if defined(__cplusplus) +extern "C" { +#endif + /* 32-bit (big endian) marker used at the end of pool entries so that wasted * space can be detected. Waste tracking must be enabled explicitly. */ @@ -220,4 +224,8 @@ static DUK__ALLOC_POOL_ALWAYS_INLINE void *duk_alloc_pool_dec16(duk_uint16_t val } #endif +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_ALLOC_POOL_H_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_config.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_config.h index 3f217ef7d2..141414abea 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_config.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_config.h @@ -1,8 +1,8 @@ /* * duk_config.h configuration header generated by genconfig.py. * - * Git commit: a459cf3c9bd1779fc01b435d69302b742675a08f - * Git describe: v2.2.0 + * Git commit: d7fdb67f18561a50e06bafd196c6b423af9ad6fe + * Git describe: v2.3.0 * Git branch: master * * Supported platforms: @@ -218,12 +218,6 @@ #define DUK_F_UNIX #endif -/* C++ */ -#undef DUK_F_CPP -#if defined(__cplusplus) -#define DUK_F_CPP -#endif - /* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. * https://sites.google.com/site/x32abi/ @@ -301,6 +295,12 @@ #define DUK_F_CLANG #endif +/* C++ */ +#undef DUK_F_CPP +#if defined(__cplusplus) +#define DUK_F_CPP +#endif + /* C99 or above */ #undef DUK_F_C99 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) @@ -836,9 +836,7 @@ #include #endif -#if defined(DUK_F_CPP) -#include /* std::exception */ -#endif +/* is only included if needed, based on DUK_USE_xxx flags. */ /* * Architecture autodetection @@ -850,13 +848,16 @@ #if !defined(DUK_USE_BYTEORDER) #define DUK_USE_BYTEORDER 1 #endif -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 1 -#endif + #define DUK_USE_PACKED_TVAL + +/* FreeBSD, -m32, and clang prior to 5.0 has union aliasing issues which + * break duk_tval copying. Disable packed duk_tval automatically. + */ +#if defined(DUK_F_FREEBSD) && defined(DUK_F_X86) && \ + defined(__clang__) && defined(__clang_major__) && (__clang_major__ < 5) +#undef DUK_USE_PACKED_TVAL +#endif #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_X64) /* --- x64 --- */ @@ -864,12 +865,6 @@ #if !defined(DUK_USE_BYTEORDER) #define DUK_USE_BYTEORDER 1 #endif -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 1 -#endif #undef DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_X32) @@ -878,48 +873,30 @@ #if !defined(DUK_USE_BYTEORDER) #define DUK_USE_BYTEORDER 1 #endif -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 1 -#endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_ARM32) /* --- ARM 32-bit --- */ #define DUK_USE_ARCH_STRING "arm32" /* Byte order varies, so rely on autodetect. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 -#endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_ARM64) /* --- ARM 64-bit --- */ #define DUK_USE_ARCH_STRING "arm64" /* Byte order varies, so rely on autodetect. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #undef DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_MIPS32) /* --- MIPS 32-bit --- */ #define DUK_USE_ARCH_STRING "mips32" /* MIPS byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_MIPS64) /* --- MIPS 64-bit --- */ #define DUK_USE_ARCH_STRING "mips64" /* MIPS byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #undef DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_PPC32) @@ -928,9 +905,6 @@ #if !defined(DUK_USE_BYTEORDER) #define DUK_USE_BYTEORDER 3 #endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_PPC64) @@ -939,39 +913,24 @@ #if !defined(DUK_USE_BYTEORDER) #define DUK_USE_BYTEORDER 3 #endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #undef DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_SPARC32) /* --- SPARC 32-bit --- */ #define DUK_USE_ARCH_STRING "sparc32" /* SPARC byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_SPARC64) /* --- SPARC 64-bit --- */ #define DUK_USE_ARCH_STRING "sparc64" /* SPARC byte order varies so rely on autodetection. */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #undef DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_SUPERH) /* --- SuperH --- */ #define DUK_USE_ARCH_STRING "sh" /* Byte order varies, rely on autodetection. */ -/* Based on 'make checkalign' there are no alignment requirements on - * Linux SH4, but align by 4 is probably a good basic default. - */ -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 4 -#endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_M68K) @@ -980,9 +939,6 @@ #if !defined(DUK_USE_BYTEORDER) #define DUK_USE_BYTEORDER 3 #endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #define DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #elif defined(DUK_F_EMSCRIPTEN) @@ -991,9 +947,6 @@ #if !defined(DUK_USE_BYTEORDER) #define DUK_USE_BYTEORDER 1 #endif -#if !defined(DUK_USE_ALIGN_BY) -#define DUK_USE_ALIGN_BY 8 -#endif #undef DUK_USE_PACKED_TVAL #define DUK_F_PACKED_TVAL_PROVIDED #else @@ -2005,8 +1958,8 @@ typedef duk_uint_fast16_t duk_small_uint_fast_t; /* Boolean values are represented with the platform 'unsigned int'. */ typedef duk_small_uint_t duk_bool_t; -#define DUK_BOOL_MIN DUK_SMALL_INT_MIN -#define DUK_BOOL_MAX DUK_SMALL_INT_MAX +#define DUK_BOOL_MIN DUK_SMALL_UINT_MIN +#define DUK_BOOL_MAX DUK_SMALL_UINT_MAX /* Index values must have at least 32-bit signed range. */ typedef duk_int_t duk_idx_t; @@ -2540,10 +2493,13 @@ typedef struct duk_hthread duk_context; * * Assume unaligned accesses are not supported unless specifically allowed * in the target platform. Some platforms may support unaligned accesses - * but alignment to 4 or 8 may still be desirable. + * but alignment to 4 or 8 may still be desirable. Note that unaligned + * accesses (and even pointers) relative to natural alignment (regardless + * of target alignment) are technically undefined behavior and thus + * compiler/architecture specific. */ -/* If not provided, use safe default for alignment. */ +/* If not forced, use safe default for alignment. */ #if !defined(DUK_USE_ALIGN_BY) #define DUK_USE_ALIGN_BY 8 #endif @@ -2595,6 +2551,7 @@ typedef struct duk_hthread duk_context; */ #define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0) #endif + #if !defined(DUK_UNREF) /* Macro for suppressing warnings for potentially unreferenced variables. * The variables can be actually unreferenced or unreferenced in some @@ -2604,9 +2561,24 @@ typedef struct duk_hthread duk_context; */ #define DUK_UNREF(x) do { (void) (x); } while (0) #endif -#if !defined(DUK_NORETURN) + +/* Fillin for DUK_NORETURN; DUK_WO_NORETURN() is used to insert dummy + * dummy statements after noreturn calls to silence harmless compiler + * warnings, e.g.: + * + * DUK_ERROR_TYPE(thr, "aiee"); + * DUK_WO_NORETURN(return 0;); + * + * Statements inside DUK_WO_NORETURN() must NEVER be actually reachable, + * and they're only included to satisfy the compiler. + */ +#if defined(DUK_NORETURN) +#define DUK_WO_NORETURN(stmt) do { } while (0) +#else #define DUK_NORETURN(decl) decl +#define DUK_WO_NORETURN(stmt) do { stmt } while (0) #endif + #if !defined(DUK_UNREACHABLE) /* Don't know how to declare unreachable point, so don't do it; this * may cause some spurious compilation warnings (e.g. "variable used @@ -2614,6 +2586,7 @@ typedef struct duk_hthread duk_context; */ #define DUK_UNREACHABLE() do { } while (0) #endif + #if !defined(DUK_LOSE_CONST) /* Convert any input pointer into a "void *", losing a const qualifier. * This is not fully portable because casting through duk_uintptr_t may @@ -2781,8 +2754,8 @@ typedef struct duk_hthread duk_context; #if defined(DUK_F_PACKED_TVAL_POSSIBLE) #define DUK_USE_PACKED_TVAL #endif - #undef DUK_F_PACKED_TVAL_POSSIBLE + #endif /* DUK_F_PACKED_TVAL_PROVIDED */ /* Object property allocation layout has implications for memory and code * footprint and generated code size/speed. The best layout also depends @@ -2817,6 +2790,7 @@ typedef struct duk_hthread duk_context; * Autogenerated defaults */ +#undef DUK_USE_ALLOW_UNDEFINED_BEHAVIOR #define DUK_USE_ARRAY_BUILTIN #define DUK_USE_ARRAY_FASTPATH #define DUK_USE_ARRAY_PROP_FASTPATH @@ -2825,6 +2799,7 @@ typedef struct duk_hthread duk_context; #define DUK_USE_AUGMENT_ERROR_THROW #define DUK_USE_AVOID_PLATFORM_FUNCPTRS #define DUK_USE_BASE64_FASTPATH +#define DUK_USE_BASE64_SUPPORT #define DUK_USE_BOOLEAN_BUILTIN #define DUK_USE_BUFFEROBJECT_SUPPORT #undef DUK_USE_BUFLEN16 @@ -2902,6 +2877,7 @@ typedef struct duk_hthread duk_context; #undef DUK_USE_HEAPPTR_DEC16 #undef DUK_USE_HEAPPTR_ENC16 #define DUK_USE_HEX_FASTPATH +#define DUK_USE_HEX_SUPPORT #define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2 #define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9 #define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16 @@ -2932,11 +2908,10 @@ typedef struct duk_hthread duk_context; #define DUK_USE_JX #define DUK_USE_LEXER_SLIDING_WINDOW #undef DUK_USE_LIGHTFUNC_BUILTINS +#define DUK_USE_LITCACHE_SIZE 256 #define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256 #define DUK_USE_MATH_BUILTIN #define DUK_USE_NATIVE_CALL_RECLIMIT 1000 -#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER #define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT #undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY #undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY @@ -3011,6 +2986,15 @@ typedef struct duk_hthread duk_context; /* __OVERRIDE_DEFINES__ */ +/* + * Conditional includes + */ + +#if defined(DUK_F_CPP) && defined(DUK_USE_CPP_EXCEPTIONS) +#include /* std::exception */ +#include /* std::runtime_error */ +#endif + /* * Date provider selection * @@ -3552,6 +3536,12 @@ typedef struct duk_hthread duk_context; #if defined(DUK_USE_MS_STRINGTABLE_RESIZE) #error unsupported config option used (option has been removed): DUK_USE_MS_STRINGTABLE_RESIZE #endif +#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER) +#error unsupported config option used (option has been removed): DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER +#endif +#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER) +#error unsupported config option used (option has been removed): DUK_USE_NONSTD_ARRAY_MAP_TRAILER +#endif #if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE) #error unsupported config option used (option has been removed): DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE #endif diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.c b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.c index 9a29903cfb..7d39eaec1a 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.c +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.c @@ -13,10 +13,6 @@ /* XXX: Add some form of log level filtering. */ -/* XXX: For now logs everything to stdout, V8/Node.js logs debug/info level - * to stdout, warn and above to stderr. Should this extra do the same? - */ - /* XXX: Should all output be written via e.g. console.write(formattedMsg)? * This would make it easier for user code to redirect all console output * to a custom backend. @@ -25,12 +21,10 @@ /* XXX: Init console object using duk_def_prop() when that call is available. */ static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) { - duk_idx_t i, n; - duk_uint_t flags; - - flags = (duk_uint_t) duk_get_current_magic(ctx); - - n = duk_get_top(ctx); + duk_uint_t flags = (duk_uint_t) duk_get_current_magic(ctx); + FILE *output = (flags & DUK_CONSOLE_STDOUT_ONLY) ? stdout : stderr; + duk_idx_t n = duk_get_top(ctx); + duk_idx_t i; duk_get_global_string(ctx, "console"); duk_get_prop_string(ctx, -1, "format"); @@ -59,9 +53,9 @@ static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_nam duk_get_prop_string(ctx, -1, "stack"); } - fprintf(stdout, "%s\n", duk_to_string(ctx, -1)); + fprintf(output, "%s\n", duk_to_string(ctx, -1)); if (flags & DUK_CONSOLE_FLUSH) { - fflush(stdout); + fflush(output); } return 0; } @@ -110,6 +104,17 @@ static void duk__console_reg_vararg_func(duk_context *ctx, duk_c_function func, } void duk_console_init(duk_context *ctx, duk_uint_t flags) { + duk_uint_t flags_orig; + + /* If both DUK_CONSOLE_STDOUT_ONLY and DUK_CONSOLE_STDERR_ONLY where specified, + * just turn off DUK_CONSOLE_STDOUT_ONLY and keep DUK_CONSOLE_STDERR_ONLY. + */ + if ((flags & DUK_CONSOLE_STDOUT_ONLY) && (flags & DUK_CONSOLE_STDERR_ONLY)) { + flags &= ~DUK_CONSOLE_STDOUT_ONLY; + } + /* Remember the (possibly corrected) flags we received. */ + flags_orig = flags; + duk_push_object(ctx); /* Custom function to format objects; user can replace. @@ -128,11 +133,22 @@ void duk_console_init(duk_context *ctx, duk_uint_t flags) { "})(Duktape.enc)"); duk_put_prop_string(ctx, -2, "format"); + flags = flags_orig; + if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) { + /* No output indicators were specified; these levels go to stdout. */ + flags |= DUK_CONSOLE_STDOUT_ONLY; + } duk__console_reg_vararg_func(ctx, duk__console_assert, "assert", flags); duk__console_reg_vararg_func(ctx, duk__console_log, "log", flags); duk__console_reg_vararg_func(ctx, duk__console_log, "debug", flags); /* alias to console.log */ duk__console_reg_vararg_func(ctx, duk__console_trace, "trace", flags); duk__console_reg_vararg_func(ctx, duk__console_info, "info", flags); + + flags = flags_orig; + if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) { + /* No output indicators were specified; these levels go to stderr. */ + flags |= DUK_CONSOLE_STDERR_ONLY; + } duk__console_reg_vararg_func(ctx, duk__console_warn, "warn", flags); duk__console_reg_vararg_func(ctx, duk__console_error, "error", flags); duk__console_reg_vararg_func(ctx, duk__console_error, "exception", flags); /* alias to console.error */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.h index 1488a95fa6..d341e22602 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_console.h @@ -3,12 +3,27 @@ #include "duktape.h" +#if defined(__cplusplus) +extern "C" { +#endif + /* Use a proxy wrapper to make undefined methods (console.foo()) no-ops. */ -#define DUK_CONSOLE_PROXY_WRAPPER (1 << 0) +#define DUK_CONSOLE_PROXY_WRAPPER (1U << 0) /* Flush output after every call. */ -#define DUK_CONSOLE_FLUSH (1 << 1) +#define DUK_CONSOLE_FLUSH (1U << 1) +/* Send output to stdout only (default is mixed stdout/stderr). */ +#define DUK_CONSOLE_STDOUT_ONLY (1U << 2) + +/* Send output to stderr only (default is mixed stdout/stderr). */ +#define DUK_CONSOLE_STDERR_ONLY (1U << 3) + +/* Initialize the console system */ extern void duk_console_init(duk_context *ctx, duk_uint_t flags); +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_CONSOLE_H_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.h index 741fc9cb1e..e92f50869f 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_logging.h @@ -3,7 +3,11 @@ #include "duktape.h" -/* Log levels */ +#if defined(__cplusplus) +extern "C" { +#endif + +/* Log levels. */ #define DUK_LOG_TRACE 0 #define DUK_LOG_DEBUG 1 #define DUK_LOG_INFO 2 @@ -17,4 +21,8 @@ extern void duk_logging_init(duk_context *ctx, duk_uint_t flags); extern void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap); extern void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...); +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_LOGGING_H_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.h index f0aa6b5863..dc49000a6a 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.h @@ -4,9 +4,17 @@ #include /* va_list etc */ #include /* size_t */ +#if defined(__cplusplus) +extern "C" { +#endif + extern int duk_minimal_sprintf(char *str, const char *format, ...); extern int duk_minimal_snprintf(char *str, size_t size, const char *format, ...); extern int duk_minimal_vsnprintf(char *str, size_t size, const char *format, va_list ap); extern int duk_minimal_sscanf(const char *str, const char *format, ...); +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_MINIMAL_PRINTF_H_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.c b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.c index e2616ba196..2b9ff08dbc 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.c +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.c @@ -263,7 +263,7 @@ static duk_ret_t duk__require(duk_context *ctx) { * done with Object.defineProperty(). * * XXX: require.id could also be just made non-configurable, as there - * is no practical reason to touch it (at least from Ecmascript code). + * is no practical reason to touch it (at least from ECMAScript code). */ duk_push_c_function(ctx, duk__require, 1 /*nargs*/); duk_push_string(ctx, "name"); @@ -307,7 +307,7 @@ static duk_ret_t duk__require(duk_context *ctx) { * Call user provided module search function and build the wrapped * module source code (if necessary). The module search function * can be used to implement pure Ecmacsript, pure C, and mixed - * Ecmascript/C modules. + * ECMAScript/C modules. * * The module search function can operate on the exports table directly * (e.g. DLL code can register values to it). It can also return a diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.h index 8c88081041..f6dc57a43d 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_duktape.h @@ -3,6 +3,10 @@ #include "duktape.h" +#if defined(__cplusplus) +extern "C" { +#endif + /* Maximum length of CommonJS module identifier to resolve. Length includes * both current module ID, requested (possibly relative) module ID, and a * slash in between. @@ -11,4 +15,8 @@ extern void duk_module_duktape_init(duk_context *ctx); +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_MODULE_DUKTAPE_H_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_node.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_node.h index aeaeaa6468..12772bf67b 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_node.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_module_node.h @@ -3,7 +3,15 @@ #include "duktape.h" +#if defined(__cplusplus) +extern "C" { +#endif + extern duk_ret_t duk_module_node_peval_main(duk_context *ctx, const char *path); extern void duk_module_node_init(duk_context *ctx); +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_MODULE_NODE_H_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_print_alert.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_print_alert.h index fe04073683..6bb69d8fd3 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_print_alert.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_print_alert.h @@ -3,8 +3,16 @@ #include "duktape.h" +#if defined(__cplusplus) +extern "C" { +#endif + /* No flags at the moment. */ extern void duk_print_alert_init(duk_context *ctx, duk_uint_t flags); +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_PRINT_ALERT_H_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_v1_compat.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_v1_compat.h index 884883c85e..09aa5a97ca 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_v1_compat.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_v1_compat.h @@ -3,6 +3,10 @@ #include "duktape.h" +#if defined(__cplusplus) +extern "C" { +#endif + /* Straight flag rename */ #if !defined(DUK_ENUM_INCLUDE_INTERNAL) #define DUK_ENUM_INCLUDE_INTERNAL DUK_ENUM_INCLUDE_HIDDEN @@ -25,4 +29,8 @@ extern void duk_to_defaultvalue(duk_context *ctx, duk_idx_t idx, duk_int_t hint) #define duk_push_string_file(ctx,path) \ duk_push_string_file_raw((ctx), (path), 0) +#if defined(__cplusplus) +} +#endif /* end 'extern "C"' wrapper */ + #endif /* DUK_V1_COMPAT_INCLUDED */ diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.c b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.c index 05e4b1d99c..c3781f766f 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.c +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.c @@ -1,7 +1,7 @@ /* - * Single source autogenerated distributable for Duktape 2.2.0. + * Single source autogenerated distributable for Duktape 2.3.0. * - * Git commit a459cf3c9bd1779fc01b435d69302b742675a08f (v2.2.0). + * Git commit d7fdb67f18561a50e06bafd196c6b423af9ad6fe (v2.3.0). * Git branch master. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and @@ -16,7 +16,7 @@ * * (http://opensource.org/licenses/MIT) * -* Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst) +* Copyright (c) 2013-2018 by Duktape authors (see AUTHORS.rst) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -87,6 +87,14 @@ * * Steven Don (https://github.com/shdon) * * Simon Stone (https://github.com/sstone1) * * \J. McC. (https://github.com/jmhmccr) +* * Jakub Nowakowski (https://github.com/jimvonmoon) +* * Tommy Nguyen (https://github.com/tn0502) +* * Fabrice Fontaine (https://github.com/ffontaine) +* * Christopher Hiller (https://github.com/boneskull) +* * Gonzalo Diethelm (https://github.com/gonzus) +* * Michal Kasperek (https://github.com/michalkas) +* * Andrew Janke (https://github.com/apjanke) +* * Steve Fan (https://github.com/stevefan1999) * * Other contributions * =================== @@ -125,6 +133,8 @@ * * https://github.com/chris-y * * Laurent Zubiaur (https://github.com/lzubiaur) * * Neil Kolban (https://github.com/nkolban) +* * Wilhelm Wanecek (https://github.com/wanecek) +* * Andrew Janke (https://github.com/apjanke) * * If you are accidentally missing from this list, send me an e-mail * (``sami.vaarala@iki.fi``) and I'll fix the omission. @@ -669,20 +679,32 @@ struct duk_jmpbuf { /* #include duk_exception.h */ #line 1 "duk_exception.h" /* - * Exception for Duktape internal throws when C++ exceptions are used + * Exceptions for Duktape internal throws when C++ exceptions are used * for long control transfers. - * - * Doesn't inherit from any exception base class to minimize the chance - * that user code would accidentally catch this exception. */ #if !defined(DUK_EXCEPTION_H_INCLUDED) #define DUK_EXCEPTION_H_INCLUDED #if defined(DUK_USE_CPP_EXCEPTIONS) +/* Internal exception used as a setjmp-longjmp replacement. User code should + * NEVER see or catch this exception, so it doesn't inherit from any base + * class which should minimize the chance of user code accidentally catching + * the exception. + */ class duk_internal_exception { /* intentionally empty */ }; + +/* Fatal error, thrown as a specific C++ exception with C++ exceptions + * enabled. It is unsafe to continue; doing so may cause crashes or memory + * leaks. This is intended to be either uncaught, or caught by user code + * aware of the "unsafe to continue" semantics. + */ +class duk_fatal_exception : public virtual std::runtime_error { + public: + duk_fatal_exception(const char *message) : std::runtime_error(message) {} +}; #endif #endif /* DUK_EXCEPTION_H_INCLUDED */ @@ -734,8 +756,9 @@ struct duk_breakpoint; struct duk_activation; struct duk_catcher; -struct duk_strcache; struct duk_ljstate; +struct duk_strcache_entry; +struct duk_litcache_entry; struct duk_strtab_entry; #if defined(DUK_USE_DEBUG) @@ -794,8 +817,9 @@ typedef struct duk_breakpoint duk_breakpoint; typedef struct duk_activation duk_activation; typedef struct duk_catcher duk_catcher; -typedef struct duk_strcache duk_strcache; typedef struct duk_ljstate duk_ljstate; +typedef struct duk_strcache_entry duk_strcache_entry; +typedef struct duk_litcache_entry duk_litcache_entry; typedef struct duk_strtab_entry duk_strtab_entry; #if defined(DUK_USE_DEBUG) @@ -1694,278 +1718,290 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double #define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */ #define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS) #define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS) -#define DUK_STRIDX_SET_PROTOTYPE_OF 76 /* 'setPrototypeOf' */ +#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE 76 /* '\x81Symbol.toPrimitive\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE) +#define DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE 77 /* '\x81Symbol.hasInstance\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE) +#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG 78 /* '\x81Symbol.toStringTag\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG) +#define DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE 79 /* '\x81Symbol.isConcatSpreadable\xff' */ +#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE) +#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE) +#define DUK_STRIDX_SET_PROTOTYPE_OF 80 /* 'setPrototypeOf' */ #define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF) #define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF) -#define DUK_STRIDX___PROTO__ 77 /* '__proto__' */ +#define DUK_STRIDX___PROTO__ 81 /* '__proto__' */ #define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__) #define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__) -#define DUK_STRIDX_TO_STRING 78 /* 'toString' */ +#define DUK_STRIDX_TO_STRING 82 /* 'toString' */ #define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING) #define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING) -#define DUK_STRIDX_TO_JSON 79 /* 'toJSON' */ +#define DUK_STRIDX_TO_JSON 83 /* 'toJSON' */ #define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON) #define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON) -#define DUK_STRIDX_TYPE 80 /* 'type' */ +#define DUK_STRIDX_TYPE 84 /* 'type' */ #define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE) #define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE) -#define DUK_STRIDX_DATA 81 /* 'data' */ +#define DUK_STRIDX_DATA 85 /* 'data' */ #define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA) #define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA) -#define DUK_STRIDX_LENGTH 82 /* 'length' */ +#define DUK_STRIDX_LENGTH 86 /* 'length' */ #define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH) #define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH) -#define DUK_STRIDX_SET 83 /* 'set' */ +#define DUK_STRIDX_SET 87 /* 'set' */ #define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET) #define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET) -#define DUK_STRIDX_STACK 84 /* 'stack' */ +#define DUK_STRIDX_STACK 88 /* 'stack' */ #define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK) #define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK) -#define DUK_STRIDX_PC 85 /* 'pc' */ +#define DUK_STRIDX_PC 89 /* 'pc' */ #define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC) #define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC) -#define DUK_STRIDX_LINE_NUMBER 86 /* 'lineNumber' */ +#define DUK_STRIDX_LINE_NUMBER 90 /* 'lineNumber' */ #define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER) #define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER) -#define DUK_STRIDX_INT_TRACEDATA 87 /* '\x82Tracedata' */ +#define DUK_STRIDX_INT_TRACEDATA 91 /* '\x82Tracedata' */ #define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA) #define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA) -#define DUK_STRIDX_NAME 88 /* 'name' */ +#define DUK_STRIDX_NAME 92 /* 'name' */ #define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME) #define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME) -#define DUK_STRIDX_FILE_NAME 89 /* 'fileName' */ +#define DUK_STRIDX_FILE_NAME 93 /* 'fileName' */ #define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME) #define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME) -#define DUK_STRIDX_LC_POINTER 90 /* 'pointer' */ +#define DUK_STRIDX_LC_POINTER 94 /* 'pointer' */ #define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER) #define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER) -#define DUK_STRIDX_INT_TARGET 91 /* '\x82Target' */ +#define DUK_STRIDX_INT_TARGET 95 /* '\x82Target' */ #define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET) #define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET) -#define DUK_STRIDX_INT_NEXT 92 /* '\x82Next' */ +#define DUK_STRIDX_INT_NEXT 96 /* '\x82Next' */ #define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT) #define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT) -#define DUK_STRIDX_INT_BYTECODE 93 /* '\x82Bytecode' */ +#define DUK_STRIDX_INT_BYTECODE 97 /* '\x82Bytecode' */ #define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE) #define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE) -#define DUK_STRIDX_INT_FORMALS 94 /* '\x82Formals' */ +#define DUK_STRIDX_INT_FORMALS 98 /* '\x82Formals' */ #define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS) #define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS) -#define DUK_STRIDX_INT_VARMAP 95 /* '\x82Varmap' */ +#define DUK_STRIDX_INT_VARMAP 99 /* '\x82Varmap' */ #define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP) #define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP) -#define DUK_STRIDX_INT_SOURCE 96 /* '\x82Source' */ +#define DUK_STRIDX_INT_SOURCE 100 /* '\x82Source' */ #define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE) #define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE) -#define DUK_STRIDX_INT_PC2LINE 97 /* '\x82Pc2line' */ +#define DUK_STRIDX_INT_PC2LINE 101 /* '\x82Pc2line' */ #define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE) #define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE) -#define DUK_STRIDX_INT_MAP 98 /* '\x82Map' */ +#define DUK_STRIDX_INT_MAP 102 /* '\x82Map' */ #define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP) #define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP) -#define DUK_STRIDX_INT_VARENV 99 /* '\x82Varenv' */ +#define DUK_STRIDX_INT_VARENV 103 /* '\x82Varenv' */ #define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV) #define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV) -#define DUK_STRIDX_INT_FINALIZER 100 /* '\x82Finalizer' */ +#define DUK_STRIDX_INT_FINALIZER 104 /* '\x82Finalizer' */ #define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER) #define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER) -#define DUK_STRIDX_INT_VALUE 101 /* '\x82Value' */ +#define DUK_STRIDX_INT_VALUE 105 /* '\x82Value' */ #define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE) #define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE) -#define DUK_STRIDX_COMPILE 102 /* 'compile' */ +#define DUK_STRIDX_COMPILE 106 /* 'compile' */ #define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE) #define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE) -#define DUK_STRIDX_INPUT 103 /* 'input' */ +#define DUK_STRIDX_INPUT 107 /* 'input' */ #define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT) #define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT) -#define DUK_STRIDX_ERR_CREATE 104 /* 'errCreate' */ +#define DUK_STRIDX_ERR_CREATE 108 /* 'errCreate' */ #define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE) #define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE) -#define DUK_STRIDX_ERR_THROW 105 /* 'errThrow' */ +#define DUK_STRIDX_ERR_THROW 109 /* 'errThrow' */ #define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW) #define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW) -#define DUK_STRIDX_ENV 106 /* 'env' */ +#define DUK_STRIDX_ENV 110 /* 'env' */ #define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV) #define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV) -#define DUK_STRIDX_HEX 107 /* 'hex' */ +#define DUK_STRIDX_HEX 111 /* 'hex' */ #define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX) #define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX) -#define DUK_STRIDX_BASE64 108 /* 'base64' */ +#define DUK_STRIDX_BASE64 112 /* 'base64' */ #define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64) #define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64) -#define DUK_STRIDX_JX 109 /* 'jx' */ +#define DUK_STRIDX_JX 113 /* 'jx' */ #define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX) #define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX) -#define DUK_STRIDX_JC 110 /* 'jc' */ +#define DUK_STRIDX_JC 114 /* 'jc' */ #define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC) #define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC) -#define DUK_STRIDX_JSON_EXT_UNDEFINED 111 /* '{"_undef":true}' */ +#define DUK_STRIDX_JSON_EXT_UNDEFINED 115 /* '{"_undef":true}' */ #define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED) #define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED) -#define DUK_STRIDX_JSON_EXT_NAN 112 /* '{"_nan":true}' */ +#define DUK_STRIDX_JSON_EXT_NAN 116 /* '{"_nan":true}' */ #define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN) #define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN) -#define DUK_STRIDX_JSON_EXT_POSINF 113 /* '{"_inf":true}' */ +#define DUK_STRIDX_JSON_EXT_POSINF 117 /* '{"_inf":true}' */ #define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF) #define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF) -#define DUK_STRIDX_JSON_EXT_NEGINF 114 /* '{"_ninf":true}' */ +#define DUK_STRIDX_JSON_EXT_NEGINF 118 /* '{"_ninf":true}' */ #define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF) #define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF) -#define DUK_STRIDX_JSON_EXT_FUNCTION1 115 /* '{"_func":true}' */ +#define DUK_STRIDX_JSON_EXT_FUNCTION1 119 /* '{"_func":true}' */ #define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1) #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1) -#define DUK_STRIDX_JSON_EXT_FUNCTION2 116 /* '{_func:true}' */ +#define DUK_STRIDX_JSON_EXT_FUNCTION2 120 /* '{_func:true}' */ #define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2) #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2) -#define DUK_STRIDX_BREAK 117 /* 'break' */ +#define DUK_STRIDX_BREAK 121 /* 'break' */ #define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK) #define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK) -#define DUK_STRIDX_CASE 118 /* 'case' */ +#define DUK_STRIDX_CASE 122 /* 'case' */ #define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE) #define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE) -#define DUK_STRIDX_CATCH 119 /* 'catch' */ +#define DUK_STRIDX_CATCH 123 /* 'catch' */ #define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH) #define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH) -#define DUK_STRIDX_CONTINUE 120 /* 'continue' */ +#define DUK_STRIDX_CONTINUE 124 /* 'continue' */ #define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE) #define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE) -#define DUK_STRIDX_DEBUGGER 121 /* 'debugger' */ +#define DUK_STRIDX_DEBUGGER 125 /* 'debugger' */ #define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER) #define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER) -#define DUK_STRIDX_DEFAULT 122 /* 'default' */ +#define DUK_STRIDX_DEFAULT 126 /* 'default' */ #define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT) #define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT) -#define DUK_STRIDX_DELETE 123 /* 'delete' */ +#define DUK_STRIDX_DELETE 127 /* 'delete' */ #define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE) #define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE) -#define DUK_STRIDX_DO 124 /* 'do' */ +#define DUK_STRIDX_DO 128 /* 'do' */ #define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO) #define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO) -#define DUK_STRIDX_ELSE 125 /* 'else' */ +#define DUK_STRIDX_ELSE 129 /* 'else' */ #define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE) #define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE) -#define DUK_STRIDX_FINALLY 126 /* 'finally' */ +#define DUK_STRIDX_FINALLY 130 /* 'finally' */ #define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY) #define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY) -#define DUK_STRIDX_FOR 127 /* 'for' */ +#define DUK_STRIDX_FOR 131 /* 'for' */ #define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR) #define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR) -#define DUK_STRIDX_LC_FUNCTION 128 /* 'function' */ +#define DUK_STRIDX_LC_FUNCTION 132 /* 'function' */ #define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION) #define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION) -#define DUK_STRIDX_IF 129 /* 'if' */ +#define DUK_STRIDX_IF 133 /* 'if' */ #define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF) #define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF) -#define DUK_STRIDX_IN 130 /* 'in' */ +#define DUK_STRIDX_IN 134 /* 'in' */ #define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN) #define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN) -#define DUK_STRIDX_INSTANCEOF 131 /* 'instanceof' */ +#define DUK_STRIDX_INSTANCEOF 135 /* 'instanceof' */ #define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF) #define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF) -#define DUK_STRIDX_NEW 132 /* 'new' */ +#define DUK_STRIDX_NEW 136 /* 'new' */ #define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW) #define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW) -#define DUK_STRIDX_RETURN 133 /* 'return' */ +#define DUK_STRIDX_RETURN 137 /* 'return' */ #define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN) #define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN) -#define DUK_STRIDX_SWITCH 134 /* 'switch' */ +#define DUK_STRIDX_SWITCH 138 /* 'switch' */ #define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH) #define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH) -#define DUK_STRIDX_THIS 135 /* 'this' */ +#define DUK_STRIDX_THIS 139 /* 'this' */ #define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS) #define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS) -#define DUK_STRIDX_THROW 136 /* 'throw' */ +#define DUK_STRIDX_THROW 140 /* 'throw' */ #define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW) #define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW) -#define DUK_STRIDX_TRY 137 /* 'try' */ +#define DUK_STRIDX_TRY 141 /* 'try' */ #define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY) #define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY) -#define DUK_STRIDX_TYPEOF 138 /* 'typeof' */ +#define DUK_STRIDX_TYPEOF 142 /* 'typeof' */ #define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF) #define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) -#define DUK_STRIDX_VAR 139 /* 'var' */ +#define DUK_STRIDX_VAR 143 /* 'var' */ #define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR) #define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR) -#define DUK_STRIDX_CONST 140 /* 'const' */ +#define DUK_STRIDX_CONST 144 /* 'const' */ #define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) #define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) -#define DUK_STRIDX_VOID 141 /* 'void' */ +#define DUK_STRIDX_VOID 145 /* 'void' */ #define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID) #define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID) -#define DUK_STRIDX_WHILE 142 /* 'while' */ +#define DUK_STRIDX_WHILE 146 /* 'while' */ #define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) #define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE) -#define DUK_STRIDX_WITH 143 /* 'with' */ +#define DUK_STRIDX_WITH 147 /* 'with' */ #define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH) #define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) -#define DUK_STRIDX_CLASS 144 /* 'class' */ +#define DUK_STRIDX_CLASS 148 /* 'class' */ #define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS) #define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS) -#define DUK_STRIDX_ENUM 145 /* 'enum' */ +#define DUK_STRIDX_ENUM 149 /* 'enum' */ #define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM) #define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM) -#define DUK_STRIDX_EXPORT 146 /* 'export' */ +#define DUK_STRIDX_EXPORT 150 /* 'export' */ #define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) #define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT) -#define DUK_STRIDX_EXTENDS 147 /* 'extends' */ +#define DUK_STRIDX_EXTENDS 151 /* 'extends' */ #define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS) #define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS) -#define DUK_STRIDX_IMPORT 148 /* 'import' */ +#define DUK_STRIDX_IMPORT 152 /* 'import' */ #define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT) #define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT) -#define DUK_STRIDX_SUPER 149 /* 'super' */ +#define DUK_STRIDX_SUPER 153 /* 'super' */ #define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER) #define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER) -#define DUK_STRIDX_LC_NULL 150 /* 'null' */ +#define DUK_STRIDX_LC_NULL 154 /* 'null' */ #define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL) #define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL) -#define DUK_STRIDX_TRUE 151 /* 'true' */ +#define DUK_STRIDX_TRUE 155 /* 'true' */ #define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE) #define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE) -#define DUK_STRIDX_FALSE 152 /* 'false' */ +#define DUK_STRIDX_FALSE 156 /* 'false' */ #define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE) #define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE) -#define DUK_STRIDX_IMPLEMENTS 153 /* 'implements' */ +#define DUK_STRIDX_IMPLEMENTS 157 /* 'implements' */ #define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS) #define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS) -#define DUK_STRIDX_INTERFACE 154 /* 'interface' */ +#define DUK_STRIDX_INTERFACE 158 /* 'interface' */ #define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE) #define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE) -#define DUK_STRIDX_LET 155 /* 'let' */ +#define DUK_STRIDX_LET 159 /* 'let' */ #define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET) #define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET) -#define DUK_STRIDX_PACKAGE 156 /* 'package' */ +#define DUK_STRIDX_PACKAGE 160 /* 'package' */ #define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE) #define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE) -#define DUK_STRIDX_PRIVATE 157 /* 'private' */ +#define DUK_STRIDX_PRIVATE 161 /* 'private' */ #define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE) #define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE) -#define DUK_STRIDX_PROTECTED 158 /* 'protected' */ +#define DUK_STRIDX_PROTECTED 162 /* 'protected' */ #define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED) #define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED) -#define DUK_STRIDX_PUBLIC 159 /* 'public' */ +#define DUK_STRIDX_PUBLIC 163 /* 'public' */ #define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC) #define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC) -#define DUK_STRIDX_STATIC 160 /* 'static' */ +#define DUK_STRIDX_STATIC 164 /* 'static' */ #define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC) #define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC) -#define DUK_STRIDX_YIELD 161 /* 'yield' */ +#define DUK_STRIDX_YIELD 165 /* 'yield' */ #define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD) #define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD) -#define DUK_HEAP_NUM_STRINGS 162 -#define DUK_STRIDX_START_RESERVED 117 -#define DUK_STRIDX_START_STRICT_RESERVED 153 -#define DUK_STRIDX_END_RESERVED 162 /* exclusive endpoint */ +#define DUK_HEAP_NUM_STRINGS 166 +#define DUK_STRIDX_START_RESERVED 121 +#define DUK_STRIDX_START_STRICT_RESERVED 157 +#define DUK_STRIDX_END_RESERVED 166 /* exclusive endpoint */ /* To convert a heap stridx to a token number, subtract * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. */ #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[892]; +DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[967]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_STRDATA_MAX_STRLEN 17 -#define DUK_STRDATA_DATA_LENGTH 892 +#define DUK_STRDATA_MAX_STRLEN 27 +#define DUK_STRDATA_DATA_LENGTH 967 #endif /* DUK_USE_ROM_STRINGS */ #if defined(DUK_USE_ROM_OBJECTS) @@ -1982,6 +2018,8 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx); @@ -1992,8 +2030,6 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx); @@ -2065,6 +2101,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_cont DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_number_check_shared(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx); @@ -2147,7 +2184,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_conte DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx); #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[177]; #endif /* !DUK_SINGLE_FILE */ #define DUK_BIDX_GLOBAL 0 #define DUK_BIDX_GLOBAL_ENV 1 @@ -2202,22 +2239,22 @@ DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176]; #define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50 #define DUK_NUM_BUILTINS 51 #define DUK_NUM_BIDX_BUILTINS 51 -#define DUK_NUM_ALL_BUILTINS 76 +#define DUK_NUM_ALL_BUILTINS 78 #if defined(DUK_USE_DOUBLE_LE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3972 +#define DUK_BUILTINS_DATA_LENGTH 4116 #elif defined(DUK_USE_DOUBLE_BE) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3972 +#define DUK_BUILTINS_DATA_LENGTH 4116 #elif defined(DUK_USE_DOUBLE_ME) #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972]; +DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116]; #endif /* !DUK_SINGLE_FILE */ -#define DUK_BUILTINS_DATA_LENGTH 3972 +#define DUK_BUILTINS_DATA_LENGTH 4116 #else #error invalid endianness defines #endif @@ -2544,12 +2581,13 @@ struct duk_bufwriter_ctx { (bw_ctx)->p += duk__enc_len; \ } while (0) /* XXX: add temporary duk__p pointer here too; sharing */ +/* XXX: avoid unsafe variants */ #define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \ const void *duk__valptr; \ duk_size_t duk__valsz; \ duk__valptr = (const void *) (valptr); \ duk__valsz = (duk_size_t) (valsz); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ (bw_ctx)->p += duk__valsz; \ } while (0) #define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \ @@ -2557,31 +2595,31 @@ struct duk_bufwriter_ctx { duk_size_t duk__val_len; \ duk__val = (const duk_uint8_t *) (val); \ duk__val_len = DUK_STRLEN((const char *) duk__val); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) @@ -2645,13 +2683,14 @@ struct duk_bufwriter_ctx { DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \ } while (0) /* XXX: add temporary duk__p pointer here too; sharing */ +/* XXX: avoid unsafe */ #define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \ const void *duk__valptr; \ duk_size_t duk__valsz; \ duk__valptr = (const void *) (valptr); \ duk__valsz = (duk_size_t) (valsz); \ DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ (bw_ctx)->p += duk__valsz; \ } while (0) #define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \ @@ -2660,35 +2699,35 @@ struct duk_bufwriter_ctx { duk__val = (const duk_uint8_t *) (val); \ duk__val_len = DUK_STRLEN((const char *) duk__val); \ DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) #define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ duk_size_t duk__val_len; \ duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ - DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ + duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ (bw_ctx)->p += duk__val_len; \ } while (0) @@ -2717,10 +2756,6 @@ DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256]; DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256]; DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256]; #endif -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64]; -DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256]; -#endif #endif /* !DUK_SINGLE_FILE */ /* Note: assumes that duk_util_probe_steps size is 32 */ @@ -2775,6 +2810,127 @@ DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); #endif +/* memcpy(), memmove() etc wrappers. The plain variants like duk_memcpy() + * assume C99+ and 'src' and 'dst' pointers must be non-NULL even when the + * operation size is zero. The unsafe variants like duk_memcpy_safe() deal + * with the zero size case explicitly, and allow NULL pointers in that case + * (which is undefined behavior in C99+). For the majority of actual targets + * a NULL pointer with a zero length is fine in practice. These wrappers are + * macros to force inlining; because there are hundreds of call sites, even a + * few extra bytes per call site adds up to ~1kB footprint. + */ +#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) +#define duk_memcpy(dst,src,len) do { \ + void *duk__dst = (dst); \ + const void *duk__src = (src); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ + (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ + } while (0) +#define duk_memcpy_unsafe(dst,src,len) duk_memcpy((dst), (src), (len)) +#define duk_memmove(dst,src,len) do { \ + void *duk__dst = (dst); \ + const void *duk__src = (src); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ + (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ + } while (0) +#define duk_memmove_unsafe(dst,src,len) duk_memmove((dst), (src), (len)) +#define duk_memset(dst,val,len) do { \ + void *duk__dst = (dst); \ + duk_small_int_t duk__val = (val); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ + } while (0) +#define duk_memset_unsafe(dst,val,len) duk_memset((dst), (val), (len)) +#define duk_memzero(dst,len) do { \ + void *duk__dst = (dst); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ + } while (0) +#define duk_memzero_unsafe(dst,len) duk_memzero((dst), (len)) +#else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ +#define duk_memcpy(dst,src,len) do { \ + void *duk__dst = (dst); \ + const void *duk__src = (src); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL); \ + DUK_ASSERT(duk__src != NULL); \ + (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ + } while (0) +#define duk_memcpy_unsafe(dst,src,len) do { \ + void *duk__dst = (dst); \ + const void *duk__src = (src); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ + if (DUK_LIKELY(duk__len > 0U)) { \ + DUK_ASSERT(duk__dst != NULL); \ + DUK_ASSERT(duk__src != NULL); \ + (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ + } \ + } while (0) +#define duk_memmove(dst,src,len) do { \ + void *duk__dst = (dst); \ + const void *duk__src = (src); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL); \ + DUK_ASSERT(duk__src != NULL); \ + (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ + } while (0) +#define duk_memmove_unsafe(dst,src,len) do { \ + void *duk__dst = (dst); \ + const void *duk__src = (src); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ + if (DUK_LIKELY(duk__len > 0U)) { \ + DUK_ASSERT(duk__dst != NULL); \ + DUK_ASSERT(duk__src != NULL); \ + (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ + } \ + } while (0) +#define duk_memset(dst,val,len) do { \ + void *duk__dst = (dst); \ + duk_small_int_t duk__val = (val); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL); \ + (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ + } while (0) +#define duk_memset_unsafe(dst,val,len) do { \ + void *duk__dst = (dst); \ + duk_small_int_t duk__val = (val); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + if (DUK_LIKELY(duk__len > 0U)) { \ + DUK_ASSERT(duk__dst != NULL); \ + (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ + } \ + } while (0) +#define duk_memzero(dst,len) do { \ + void *duk__dst = (dst); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL); \ + (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ + } while (0) +#define duk_memzero_unsafe(dst,len) do { \ + void *duk__dst = (dst); \ + duk_size_t duk__len = (len); \ + DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ + if (DUK_LIKELY(duk__len > 0U)) { \ + DUK_ASSERT(duk__dst != NULL); \ + (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ + } \ + } while (0) +#endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ + +DUK_INTERNAL_DECL duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len); +DUK_INTERNAL_DECL duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len); + DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival); DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival); DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x); @@ -2789,6 +2945,33 @@ DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x); DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y); DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y); DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_finite(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_integer(duk_double_t x); +DUK_INTERNAL_DECL duk_bool_t duk_double_is_safe_integer(duk_double_t x); + +DUK_INTERNAL_DECL duk_double_t duk_double_div(duk_double_t x, duk_double_t y); +DUK_INTERNAL_DECL duk_int_t duk_double_to_int_t(duk_double_t x); +DUK_INTERNAL_DECL duk_uint_t duk_double_to_uint_t(duk_double_t x); +DUK_INTERNAL_DECL duk_int32_t duk_double_to_int32_t(duk_double_t x); +DUK_INTERNAL_DECL duk_uint32_t duk_double_to_uint32_t(duk_double_t x); +DUK_INTERNAL_DECL duk_float_t duk_double_to_float_t(duk_double_t x); + +/* + * Miscellaneous + */ + +/* Example: x = 0x10 = 0b00010000 + * x - 1 = 0x0f = 0b00001111 + * x & (x - 1) == 0 + * + * x = 0x07 = 0b00000111 + * x - 1 = 0x06 = 0b00000110 + * x & (x - 1) != 0 + * + * However, incorrectly true for x == 0 so check for that explicitly. + */ +#define DUK_IS_POWER_OF_TWO(x) \ + ((x) != 0U && ((x) & ((x) - 1U)) == 0U) #endif /* DUK_UTIL_H_INCLUDED */ /* #include duk_strings.h */ @@ -2963,7 +3146,7 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y); /* #include duk_js_bytecode.h */ #line 1 "duk_js_bytecode.h" /* - * Ecmascript bytecode + * ECMAScript bytecode */ #if !defined(DUK_JS_BYTECODE_H_INCLUDED) @@ -3836,7 +4019,7 @@ struct duk_lexer_codepoint { duk_int_t line; }; -/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */ +/* Lexer context. Same context is used for ECMAScript and Regexp parsing. */ struct duk_lexer_ctx { #if defined(DUK_USE_LEXER_SLIDING_WINDOW) duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */ @@ -3887,13 +4070,13 @@ DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_ /* #include duk_js_compiler.h */ #line 1 "duk_js_compiler.h" /* - * Ecmascript compiler. + * ECMAScript compiler. */ #if !defined(DUK_JS_COMPILER_H_INCLUDED) #define DUK_JS_COMPILER_H_INCLUDED -/* ecmascript compiler limits */ +/* ECMAScript compiler limits */ #define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */ /* maximum loopcount for peephole optimization */ @@ -4075,6 +4258,7 @@ struct duk_compiler_func { duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */ duk_uint8_t needs_shuffle; /* function needs shuffle registers */ duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */ + duk_uint8_t allow_regexp_in_adv; /* allow RegExp literal on next advance() call */ }; struct duk_compiler_ctx { @@ -5378,10 +5562,12 @@ DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx); DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr); DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr); +DUK_INTERNAL_DECL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr); + #if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx); #endif -DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv); +DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects); DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */ DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval); @@ -5519,6 +5705,8 @@ DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ +DUK_INTERNAL_DECL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx); + DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count); DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx); #if 0 @@ -5555,6 +5743,10 @@ DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr); DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags); +#if defined(DUK_USE_SYMBOL_BUILTIN) +DUK_INTERNAL_DECL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint); +#endif + /* Raw internal valstack access macros: access is unsafe so call site * must have a guarantee that the index is valid. When that is the case, * using these macro results in faster and smaller code than duk_get_tval(). @@ -5594,7 +5786,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); * strings used as internal property names and raw buffers converted to * strings. In such cases the 'clen' field contains an inaccurate value. * - * Ecmascript requires support for 32-bit long strings. However, since each + * ECMAScript requires support for 32-bit long strings. However, since each * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only * support about 1.4G codepoint long strings in extreme cases. This is not * really a practical issue. @@ -5618,12 +5810,15 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); #define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL) #endif -/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings), +/* XXX: could add flags for "is valid CESU-8" (ECMAScript compatible strings), * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not, * regexp bytecode is), and "contains non-BMP characters". These are not * needed right now. */ +/* With lowmem builds the high 16 bits of duk_heaphdr are used for other + * purposes, so this leaves 7 duk_heaphdr flags and 9 duk_hstring flags. + */ #define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */ #define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */ #define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */ @@ -5632,6 +5827,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); #define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */ #define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */ #define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */ +#define DUK_HSTRING_FLAG_PINNED_LITERAL DUK_HEAPHDR_USER_FLAG(8) /* string is a literal, and pinned */ #define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) #define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) @@ -5641,6 +5837,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); #define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) #define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) #define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) +#define DUK_HSTRING_HAS_PINNED_LITERAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL) #define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) #define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) @@ -5650,6 +5847,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); #define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) #define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) #define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) +#define DUK_HSTRING_SET_PINNED_LITERAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL) #define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) #define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) @@ -5659,6 +5857,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); #define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) #define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) #define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) +#define DUK_HSTRING_CLEAR_PINNED_LITERAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL) #if 0 /* Slightly smaller code without explicit flag, but explicit flag * is very useful when 'clen' is dropped. @@ -5827,12 +6026,12 @@ DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h); /* * Heap object representation. * - * Heap objects are used for Ecmascript objects, arrays, and functions, + * Heap objects are used for ECMAScript objects, arrays, and functions, * but also for internal control like declarative and object environment * records. Compiled functions, native functions, and threads are also * objects but with an extended C struct. * - * Objects provide the required Ecmascript semantics and exotic behaviors + * Objects provide the required ECMAScript semantics and exotic behaviors * especially for property access. * * Properties are stored in three conceptual parts: @@ -6461,7 +6660,7 @@ DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h); #define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L /* - * Ecmascript [[Class]] + * ECMAScript [[Class]] */ /* range check not necessary because all 4-bit values are mapped */ @@ -6825,9 +7024,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr); /* #include duk_hcompfunc.h */ #line 1 "duk_hcompfunc.h" /* - * Heap compiled function (Ecmascript function) representation. + * Heap compiled function (ECMAScript function) representation. * - * There is a single data buffer containing the Ecmascript function's + * There is a single data buffer containing the ECMAScript function's * bytecode, constants, and inner functions. */ @@ -7221,7 +7420,8 @@ struct duk_hboundfunc { } while (0) /* Get the current data pointer (caller must ensure buf != NULL) as a - * duk_uint8_t ptr. + * duk_uint8_t ptr. Note that the result may be NULL if the underlying + * buffer has zero size and is not a fixed buffer. */ #define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \ (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ @@ -7540,14 +7740,14 @@ struct duk_activation { duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */ /* bottom_byteoff and retval_byteoff are only used for book-keeping - * of Ecmascript-initiated calls, to allow returning to an Ecmascript + * of ECMAScript-initiated calls, to allow returning to an ECMAScript * function properly. */ /* Bottom of valstack for this activation, used to reset * valstack_bottom on return; offset is absolute. There's * no need to track 'top' because native call handling deals - * with that using locals, and for Ecmascript returns 'nregs' + * with that using locals, and for ECMAScript returns 'nregs' * indicates the necessary top. */ duk_size_t bottom_byteoff; @@ -7934,7 +8134,7 @@ struct duk_hobjenv { #define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) #define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v)) -#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1)) +#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (void *) (x)) + 1)) #if defined(DUK_USE_HEAPPTR16) #define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \ @@ -7989,7 +8189,7 @@ struct duk_hobjenv { DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \ DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \ ) : \ - DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \ + DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \ ) #else /* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external @@ -7998,7 +8198,7 @@ struct duk_hobjenv { #define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \ DUK_HBUFFER_HAS_DYNAMIC((x)) ? \ DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \ - DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \ + DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \ ) #endif @@ -8072,7 +8272,10 @@ struct duk_hbuffer_fixed { #if (DUK_USE_ALIGN_BY == 4) duk_uint32_t dummy_for_align4; #elif (DUK_USE_ALIGN_BY == 8) - duk_double_t dummy_for_align8; + duk_double_t dummy_for_align8_1; +#if defined(DUK_USE_64BIT_OPS) + duk_uint64_t dummy_for_align8_2; +#endif #elif (DUK_USE_ALIGN_BY == 1) /* no extra padding */ #else @@ -8489,7 +8692,7 @@ struct duk_breakpoint { * Thus, string caches are now at the heap level now. */ -struct duk_strcache { +struct duk_strcache_entry { duk_hstring *h; duk_uint32_t bidx; duk_uint32_t cidx; @@ -8520,6 +8723,15 @@ struct duk_ljstate { DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \ } while (0) +/* + * Literal intern cache + */ + +struct duk_litcache_entry { + const duk_uint8_t *addr; + duk_hstring *h; +}; + /* * Main heap structure */ @@ -8746,7 +8958,15 @@ struct duk_heap { /* String access cache (codepoint offset -> byte offset) for fast string * character looping; 'weak' reference which needs special handling in GC. */ - duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; + duk_strcache_entry strcache[DUK_HEAP_STRCACHE_SIZE]; + +#if defined(DUK_USE_LITCACHE_SIZE) + /* Literal intern cache. When enabled, strings interned as literals + * (e.g. duk_push_literal()) will be pinned and cached for the lifetime + * of the heap. + */ + duk_litcache_entry litcache[DUK_USE_LITCACHE_SIZE]; +#endif /* Built-in strings. */ #if defined(DUK_USE_ROM_STRINGS) @@ -8778,6 +8998,9 @@ struct duk_heap { duk_int_t stats_strtab_resize_check; duk_int_t stats_strtab_resize_grow; duk_int_t stats_strtab_resize_shrink; + duk_int_t stats_strtab_litcache_hit; + duk_int_t stats_strtab_litcache_miss; + duk_int_t stats_strtab_litcache_pin; duk_int_t stats_object_realloc_props; duk_int_t stats_object_abandon_array; duk_int_t stats_getownpropdesc_count; @@ -8838,6 +9061,9 @@ DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_t DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); +#if defined(DUK_USE_LITCACHE_SIZE) +DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen); +#endif DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val); DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); #if defined(DUK_USE_REFERENCE_COUNTING) @@ -9242,8 +9468,8 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); * Error codes: defined in duktape.h * * Error codes are used as a shorthand to throw exceptions from inside - * the implementation. The appropriate Ecmascript object is constructed - * based on the code. Ecmascript code throws objects directly. The error + * the implementation. The appropriate ECMAScript object is constructed + * based on the code. ECMAScript code throws objects directly. The error * codes are defined in the public API header because they are also used * by calling code. */ @@ -9645,7 +9871,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); #if defined(DUK_USE_ASSERTIONS) #define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \ - DUK_MEMSET((void *) (ptr), 0x5a, size); \ + duk_memset_unsafe((void *) (ptr), 0x5a, size); \ } while (0) #else #define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0) @@ -9924,13 +10150,13 @@ DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, d * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_ids_noa[1036]; +extern const duk_uint8_t duk_unicode_ids_noa[1063]; #else /* * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_ids_noabmp[625]; +extern const duk_uint8_t duk_unicode_ids_noabmp[626]; #endif #if defined(DUK_USE_SOURCE_NONBMP) @@ -9952,13 +10178,13 @@ extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24]; * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_idp_m_ids_noa[530]; +extern const duk_uint8_t duk_unicode_idp_m_ids_noa[549]; #else /* * Automatically generated by extract_chars.py, do not edit! */ -extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357]; +extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358]; #endif /* @@ -10101,7 +10327,7 @@ typedef struct { /* #include duk_js.h */ #line 1 "duk_js.h" /* - * Ecmascript execution, support primitives. + * ECMAScript execution, support primitives. */ #if !defined(DUK_JS_H_INCLUDED) @@ -10145,6 +10371,9 @@ DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuf #endif DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags); DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); +#if defined(DUK_USE_SYMBOL_BUILTIN) +DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); +#endif DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x); @@ -10214,7 +10443,7 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr); #line 1 "duk_numconv.h" /* * Number-to-string conversion. The semantics of these is very tightly - * bound with the Ecmascript semantics required for call sites. + * bound with the ECMAScript semantics required for call sites. */ #if !defined(DUK_NUMCONV_H_INCLUDED) @@ -10247,9 +10476,13 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr); /* Maximum exponent value when parsing numbers. This is not strictly * compliant as there should be no upper limit, but as we parse the - * exponent without a bigint, impose some limit. + * exponent without a bigint, impose some limit. The limit should be + * small enough that multiplying it (or limit-1 to be precise) won't + * overflow signed 32-bit integer range. Exponent is only parsed with + * radix 10, but with maximum radix (36) a safe limit is: + * (10000000*36).toString(16) -> '15752a00' */ -#define DUK_S2N_MAX_EXPONENT 1000000000 +#define DUK_S2N_MAX_EXPONENT 10000000L /* Trim white space (= allow leading and trailing whitespace) */ #define DUK_S2N_FLAG_TRIM_WHITE (1U << 0) @@ -10525,7 +10758,7 @@ DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t lin va_start(ap, fmt); - DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); + duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); arg_level = (long) level; @@ -10556,7 +10789,7 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { va_start(ap, fmt); - DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); + duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); arg_level = (long) duk_debug_level_stash; @@ -10597,7 +10830,7 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { #if defined(DUK_USE_ROM_STRINGS) #error ROM support not enabled, rerun configure.py with --rom-support #else /* DUK_USE_ROM_STRINGS */ -DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = { +DUK_INTERNAL const duk_uint8_t duk_strings_data[967] = { 79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103, 35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31, 129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132, @@ -10619,36 +10852,40 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = { 249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190, 186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12, 32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226, -231,146,51,192,204,73,140,224,145,221,102,241,68,196,157,34,79,143,139,166, -233,225,228,227,138,157,173,167,197,211,118,214,210,38,238,74,113,67,76, -105,187,169,147,154,73,225,228,32,193,48,25,100,105,166,113,200,147,44,166, -1,40,79,18,150,134,147,141,163,2,72,171,115,147,136,4,65,130,96,35,64,194, -32,168,89,56,208,48,135,123,144,217,146,39,220,228,193,19,18,101,220,227, -73,121,167,115,129,196,200,39,12,136,220,225,93,22,1,114,62,231,42,8,176, -15,62,231,36,234,68,68,70,231,30,45,37,161,164,38,231,24,7,159,115,149,4, -72,218,171,115,133,67,64,180,100,145,54,231,42,5,208,135,19,152,244,44,133, -67,95,73,164,145,143,5,18,2,100,65,35,30,76,241,117,134,70,212,103,37,204, -16,72,154,218,130,77,196,145,63,127,123,106,141,25,11,189,243,169,198,132, -251,235,119,247,182,154,6,239,124,234,113,161,62,250,221,253,237,164,52, -187,223,58,156,104,79,190,187,127,123,105,168,105,119,190,117,56,208,159, -125,118,254,246,209,104,209,111,124,234,113,161,62,250,205,253,162,209,162, -249,212,227,66,125,244,161,137,0,162,8,18,33,68,9,136,232,19,155,52,54,132, -64,200,26,24,196,137,198,66,130,139,153,134,69,146,100,16,220,66,46,68,57, -80,208,45,120,25,93,20,22,141,20,208,230,137,5,18,26,164,54,83,3,68,71,20, -109,37,141,18,78,145,105,165,100,76,71,36,206,137,22,103,139,172,57,199,6, -158,30,71,20,117,4,74,39,54,83,37,92,129,150,199,66,200,75,34,103,40,150,9, -72,132,109,24,98,93,238,140,206,75,204,141,28,140,134,61,209,153,101,71, -146,36,109,22,178,78,52,33,74,5,200,138,67,30,178,48,141,156,146,134,204, -145,40,4,65,172,147,59,192,37,0,196,59,226,138,130,100,75,226,233,144,83, -32,204,250,5,104,17,165,48,77,2,46,16,69,140, +231,146,51,192,204,73,140,224,145,221,102,241,68,196,169,248,30,75,12,11, +151,242,233,187,143,138,24,137,162,164,255,253,63,3,201,97,129,114,254,92, +112,75,136,108,166,6,136,159,255,167,224,121,44,48,46,95,203,166,238,74, +113,67,77,201,128,223,255,223,224,121,44,48,46,95,203,145,46,9,205,16,39, +201,62,36,0,192,21,147,255,238,145,39,199,197,211,116,240,242,113,197,78, +214,211,226,233,187,107,105,19,119,37,56,161,166,52,221,212,201,205,36,240, +242,16,96,152,12,178,52,211,56,228,73,150,83,0,148,39,137,75,67,73,198,209, +129,36,85,185,201,196,2,32,193,48,17,160,97,16,84,44,156,104,24,67,189,200, +108,201,19,238,114,96,137,137,50,238,113,164,188,211,185,192,226,100,19, +134,68,110,112,174,139,0,185,31,115,149,4,88,7,159,115,146,117,34,34,35, +115,143,22,146,208,210,19,115,140,3,207,185,202,130,36,109,85,185,194,161, +160,90,50,72,155,115,149,2,232,67,137,204,122,22,66,161,175,164,210,72,199, +130,137,1,50,32,145,143,38,120,186,195,35,106,51,146,230,8,36,77,109,65,38, +226,72,159,191,189,181,70,140,133,222,249,212,227,66,125,245,187,251,219, +77,3,119,190,117,56,208,159,125,110,254,246,210,26,93,239,157,78,52,39,223, +93,191,189,180,212,52,187,223,58,156,104,79,190,187,127,123,104,180,104, +183,190,117,56,208,159,125,102,254,209,104,209,124,234,113,161,62,250,80, +196,128,81,4,9,16,162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33, +65,69,204,195,34,201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70, +138,104,115,68,130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180, +210,178,38,35,146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37, +19,155,41,146,174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46, +247,70,103,37,230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26, +16,165,2,228,69,33,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224, +18,128,98,29,241,69,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38, +129,23,8,34,198, }; #endif /* DUK_USE_ROM_STRINGS */ #if defined(DUK_USE_ROM_OBJECTS) #error ROM support not enabled, rerun configure.py with --rom-support #else /* DUK_USE_ROM_OBJECTS */ -/* native functions: 176 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = { +/* native functions: 177 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[177] = { NULL, duk_bi_array_constructor, duk_bi_array_constructor_is_array, @@ -10741,6 +10978,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = { duk_bi_nodejs_buffer_tojson, duk_bi_nodejs_buffer_tostring, duk_bi_nodejs_buffer_write, + duk_bi_number_check_shared, duk_bi_number_constructor, duk_bi_number_prototype_to_exponential, duk_bi_number_prototype_to_fixed, @@ -10827,556 +11065,577 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = { duk_bi_uint8array_plainof, }; #if defined(DUK_USE_DOUBLE_LE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = { -144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242, -252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33, +DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = { +144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243, +124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33, 167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228, 64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46, 142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240, 242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0, -1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, -33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17, -13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192, -0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188, -0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85, -217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225, -146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,0,0, -0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,172,19,120,71,10,25,196,136, -113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,2, -185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,130, -249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,138, -9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,190,15, -38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,53,64, -243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,124, -35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,116, -88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,240,70, -68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,51,132, -9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,105,27, -60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,117,204, -123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,65,112, -152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,39,199, -89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,58,205, -227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,133,18, -2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,39,31,23, -60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,18,84,141, -159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,194,197, -217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,32,130, -166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,151,21,0, -100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,214,111, -31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,10,62, -46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,52, -156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142, -214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173, -165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6, -143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62, -180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129, -54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0, -178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87, -129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104, -201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71, -132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232, -46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35, -193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194, -133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56, -9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14, -134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184, -64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6, -145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67, -77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113, -110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113, -110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2, -127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4, -33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207, -4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,255,255,255,255, -239,127,19,214,33,187,85,2,232,72,0,32,0,0,0,0,0,0,25,136,0,0,0,0,0,0,31, -15,228,122,247,73,19,69,73,180,134,149,13,68,241,0,0,0,0,0,0,3,193,252,143, -90,67,2,104,169,54,144,210,161,168,158,32,0,0,0,0,0,0,120,127,142,73,78,20, -0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68, -13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205, -222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90, -112,164,0,0,0,0,0,0,124,63,226,117,119,128,25,55,112,96,153,57,41,197,13, -53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16, -22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74, -113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104, -97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22, -190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196, -206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208, -76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49, -39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49, -39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112, -163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229, -100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117, -11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68, -157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149, -178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34, -9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62, -49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17, -34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60, -137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248, -199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200, -147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2, -54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56, -7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49, -89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0, -131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217, -231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232, -228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19, -235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1, -64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93, -168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20, -19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,0,0,0,0,93,105,160,91, -60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168, -110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115, -36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145, -139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166, -28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145, -92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41, -100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177, -69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99, -68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9, -49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20, -98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36, -249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242, -136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229, -16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39, -194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68, -89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,104,71,161,196,201,45,167,146,59, -68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,136,71,161,196,201,45,167,146, -59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,168,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,200,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,232,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,8,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,40,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,72,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,52,102,32,76,72,1,246,136,235, -103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91, -171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13, -158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1, -246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161, -37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79, -75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112, -39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186, -129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237, -17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134, -207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134, -207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38, -78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213, -146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39, -104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208, -146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16, -217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101, -162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201, -77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68, -117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104, -162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123, -102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160, -72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32, -52,171,138,69,133,95,130,160,4,234,219,163,161,0,89,86,214,238,197,172,9,0, -31,86,221,40,29,231,63,95,200,69,220,199,225,122,183,27,72,144,63,160,138, -217,81,197,125,207,195,117,110,54,142,129,32,7,114,147,10,189,229,237,159, -130,235,209,0,96,181,17,83,236,132,37,0,63,101,8,207,71,107,74,6,105,219, -251,52,245,7,49,248,94,202,17,158,148,12,211,183,246,105,234,15,99,242,159, -129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160, -192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152, -27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163, -32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72, -188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29, -13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205, -72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80, -81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128, -153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9, -128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203, -164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113, -120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17, -16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94, -100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14, -108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7, -10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227, -138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43, -80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178, -48,141,156,0,0,0,0,0,0,15,3,243,49,135,16,143,67,137,146,91,79,36,118,136, -178,48,141,156,0,0,0,0,0,0,15,3,245,20,5,173,194,227,214,4,55,0,0,21,196,7, -122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180, -69,145,132,108,224,0,0,0,0,0,0,120,31,153,140,72,132,122,28,76,146,218,121, -35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,80,132,122,28,76,146,218, -121,35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,88,132,122,28,76,146, -218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,96,132,122,28,76, -146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,104,132,122, -28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,112, -132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,16,32,16, -113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224, -104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131, -165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3, -154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232, -147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0, +1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, +33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198, +174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32, +248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215, +128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170, +154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130, +249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145, +136,67,134,19,49,0,0,0,0,0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1, +172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240, +149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68, +141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147, +132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42, +96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242, +243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53, +79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47, +147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139, +121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8, +151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147, +180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52, +78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52, +146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194, +70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31, +55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64, +96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36, +103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178, +1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17, +46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200, +217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140, +241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250, +96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81, +46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104, +194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8, +109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71, +240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173, +174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40, +104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32, +194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62, +16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150, +129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179, +224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255, +248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128, +124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34, +131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231, +192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107, +255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19, +245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161, +163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132, +5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13, +34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80, +211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39, +22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221, +197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2, +127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64, +132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46, +190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,129,255,255,255,255,255, +255,222,254,39,172,67,118,170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0, +62,31,200,245,238,146,38,138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131, +249,30,180,134,4,209,82,109,33,165,67,81,60,64,0,0,0,0,0,0,240,255,15,210, +62,72,91,155,0,0,0,0,0,0,2,192,240,135,88,11,237,72,5,38,210,27,50,24,145, +129,255,255,255,255,255,254,126,134,67,172,67,118,164,2,147,105,13,153,12, +72,192,255,255,255,255,255,255,63,195,16,240,70,68,226,27,51,199,138,120, +35,34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217, +144,196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196, +142,224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119, +224,3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64, +92,221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62, +210,98,177,252,3,107,173,88,3,146,211,141,32,0,0,0,0,0,3,225,255,19,175, +188,0,100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56, +161,166,188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7, +18,155,184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222, +8,77,133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152, +32,35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198, +57,179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96, +153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197, +144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150, +22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161, +166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100, +39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18, +32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72, +68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46, +16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117, +11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178, +36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173, +191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35, +43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4, +201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102, +123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162, +215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192, +131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201, +176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86, +127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0, +57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38, +191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128, +80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69, +220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150, +27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24, +186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64, +28,24,61,73,25,33,205,128,0,0,0,0,1,167,166,129,108,242,151,15,39,8,34,26, +87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140, +130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0, +80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145, +139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0, +0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240, +0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42, +130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137, +62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196, +159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79, +133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137, +62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16, +217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108, +244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192, +158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161, +196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,168,71, +161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,200, +71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51, +232,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,155,52, +8,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,155,52,40, +71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,52,72, +71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,52, +104,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155, +52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135, +52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44, +50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209, +214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15, +136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40, +161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75, +171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110, +4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129, +89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209, +29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134, +207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136, +235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29, +108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146, +155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54, +122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134, +218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79, +75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162, +137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209, +131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232, +73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68, +117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100, +226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1, +114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45, +162,137,147,111,2,8,4,16,7,8,96,120,72,13,42,226,145,97,87,224,168,1,58, +182,232,232,64,22,85,181,187,177,107,2,64,7,213,183,74,7,121,207,215,242, +17,119,49,248,94,173,198,210,36,15,232,34,182,84,113,95,115,240,221,91,141, +163,160,72,1,220,164,194,175,121,123,103,224,186,244,64,24,45,68,84,251,33, +9,64,15,217,66,51,209,218,210,129,154,118,254,205,61,65,204,126,23,178,132, +103,165,3,52,237,253,154,122,131,216,254,168,48,6,90,130,1,0,39,75,80,72,8, +9,33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,128, +65,17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,234,10, +8,41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,141, +168,40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,47,0, +216,134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,209, +234,10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,192, +115,3,117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,113,67, +76,130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,1,78, +192,56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,147, +182,140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,188,24, +49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,14,49, +39,199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,35, +100,128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,28, +217,114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,32, +225,64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,76, +156,113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5, +114,1,18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180, +69,145,132,108,224,0,0,0,0,0,0,120,31,153,172,56,132,122,28,76,146,218,121, +35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,168,160,45,110,23,30,176,33, +184,0,0,175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,180, +242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63,51,88,145,8,244,56,153,37, +180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,88,161,8,244,56,153,37, +180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,88,177,8,244,56,153,37, +180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,193,8,244,56,153, +37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,209,8,244,56, +153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,225,8,244, +56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,32,64,32,227,194,0, +97,57,162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73, +29,153,1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58, +112,28,211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73, +240,117,32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32, +148,25,174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173, +214,3,192, }; #elif defined(DUK_USE_DOUBLE_BE) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = { -144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242, -252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33, +DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = { +144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243, +124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33, 167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228, 64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46, 142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240, 242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0, -1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, -33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17, -13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192, -0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188, -0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85, -217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225, -146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,1,255, -224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,172,19,120,71,10,25,196, -136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58, -2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58, -130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180, -138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46, -190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207, -53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94, -124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37, -116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20, -240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153, -51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238, -105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129, -117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0, -65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49, -39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62, -58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129, -133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13, -39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95, -18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37, -194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151, -32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72, -151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113, -214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226, -10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84, -52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142, -214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173, -165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6, -143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62, -180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129, -54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0, -178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87, -129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104, -201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71, -132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232, -46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35, -193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194, -133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56, -9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14, -134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184, -64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6, -145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67, -77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113, -110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113, -110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2, -127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4, -33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207, -4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,127,239,255,255,255,255, -255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,0,0,0,57,136,15,255,0,0,0,0,0, -0,4,122,247,73,19,69,73,180,134,149,13,68,241,1,255,192,0,0,0,0,0,0,143,90, -67,2,104,169,54,144,210,161,168,158,32,127,248,0,0,0,0,0,0,14,73,78,20,0,0, -0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,13, -155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,222, -17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,112, -164,63,252,0,0,0,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,53,224, -65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,22,78, -12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,113,67, -77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,97,47, -128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,190, -96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,206, -185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,76, -150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,39, -195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,39, -198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,163, -18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,100,40, -15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,11,90, -36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,157,160, -3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,178,166, -74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,9,205, -28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,49,13, -164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,34,79, -135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,137,62, -12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,199,54, -103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,147,225, -104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,54,223, -224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,7,38, -193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,89, -252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,131, -64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,231, -197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,228, -74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,235,1, -64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,64, -174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,168, -167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,19, -177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,32,105,221,0,0,0,0,0,91,60, -149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,110, -20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,36,14, -100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,139, -163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,28,1, -204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,92, -203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,100, -73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,69, -49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,68, -152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,49, -39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,98, -79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,249, -68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,136, -108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,16, -217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,194, -173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,89,24, -70,206,1,255,128,0,0,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,68,89, -24,70,206,1,255,128,0,0,0,0,0,1,153,51,136,71,161,196,201,45,167,146,59,68, -89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,168,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,200,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,232,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,8,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,40,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,72,71,161,196,201,45,167,146,59, -68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,103, -177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37, -20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142, -183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136, -235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20, -138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161, -37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208, -146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89, -58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214, -207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207, -161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207, -98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78, -209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146, -155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104, -142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146, -155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217, -233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162, -137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77, -156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117, -179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162, -100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,102, -53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,72, -16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,32,2, -223,133,69,138,43,180,132,234,219,163,161,1,0,9,174,198,238,213,84,88,31, -86,221,40,7,252,197,200,95,223,71,61,225,122,183,27,72,144,15,253,197,81, -217,74,224,191,131,117,110,54,142,129,32,31,237,229,189,138,147,114,135,2, -235,209,1,0,36,135,237,81,16,180,96,63,101,8,207,71,107,74,1,255,53,4,243, -51,249,222,104,94,202,17,158,148,3,255,106,9,230,103,243,188,210,159,129, -228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,192,25, -106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,27,165, -171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,32,24, -157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,188,8, -134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,13,65, -74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,72,1, -98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,81, -129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,153, -78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,128,0, -10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,164,237, -35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,120,96, -196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,16,113, -137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,100,108, -144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,108,185, -36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,10,4,28, -200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,138,89, -18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,80,17,42, -4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,48,141,156, -3,255,0,0,0,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,178,48,141, -156,3,255,0,0,0,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,122,192,134, -241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,69,145,132, -108,224,31,248,0,0,0,0,0,0,25,140,72,132,122,28,76,146,218,121,35,180,69, -145,132,108,224,32,0,0,0,0,0,0,0,25,140,80,132,122,28,76,146,218,121,35, -180,69,145,132,108,224,32,0,0,0,0,0,0,0,25,140,88,132,122,28,76,146,218, -121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,96,132,122,28,76,146, -218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,104,132,122,28, -76,146,218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,112,132, -122,28,76,146,218,121,35,180,69,145,132,108,224,32,16,0,0,0,0,0,0,16,113, -225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,104, -82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,165, -1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,154, -102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,147, -161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0, +1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, +33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198, +174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32, +248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215, +128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170, +154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130, +249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145, +136,67,134,19,49,1,255,224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1, +172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240, +149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68, +141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147, +132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42, +96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242, +243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53, +79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47, +147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139, +121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8, +151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147, +180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52, +78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52, +146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194, +70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31, +55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64, +96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36, +103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178, +1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17, +46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200, +217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140, +241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250, +96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81, +46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104, +194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8, +109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71, +240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173, +174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40, +104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32, +194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62, +16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150, +129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179, +224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255, +248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128, +124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34, +131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231, +192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107, +255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19, +245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161, +163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132, +5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13, +34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80, +211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39, +22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221, +197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2, +127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64, +132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46, +190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,128,255,223,255,255,255, +255,255,254,39,172,67,118,170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0, +0,0,0,0,8,245,238,146,38,138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0, +1,30,180,134,4,209,82,109,33,165,67,81,60,64,255,240,0,0,0,0,0,0,15,210,62, +72,91,155,0,242,192,0,0,0,0,0,0,135,88,11,237,72,5,38,210,27,50,24,145,128, +134,127,255,255,255,255,255,254,67,172,67,118,164,2,147,105,13,153,12,72, +192,195,63,255,255,255,255,255,255,16,240,70,68,226,27,51,199,138,120,35, +34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217,144, +196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196,142, +224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119,224, +3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64,92, +221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62,210, +98,177,252,3,107,173,88,3,146,211,141,33,255,224,0,0,0,0,0,3,19,175,188,0, +100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56,161,166, +188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7,18,155, +184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222,8,77, +133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152,32, +35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198,57, +179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96, +153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197, +144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150, +22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161, +166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100, +39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18, +32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72, +68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46, +16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117, +11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178, +36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173, +191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35, +43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4, +201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102, +123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162, +215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192, +131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201, +176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86, +127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0, +57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38, +191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128, +80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69, +220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150, +27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24, +186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64, +28,24,61,73,25,33,205,128,129,167,166,0,0,0,0,1,108,242,151,15,39,8,34,26, +87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140, +130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0, +80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145, +139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0, +0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240, +0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42, +130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137, +62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196, +159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79, +133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137, +62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16, +217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108, +244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192, +158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161, +196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,168,71, +161,196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,200, +71,161,196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51, +232,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,155,52, +8,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,155,52,40, +71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,52,72, +71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,52, +104,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155, +52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,2,1,0,0,0,0,0,0,1,135, +52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44, +50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209, +214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15, +136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40, +161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75, +171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110, +4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129, +89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209, +29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134, +207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136, +235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29, +108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146, +155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54, +122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134, +218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79, +75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162, +137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209, +131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232, +73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68, +117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100, +226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1, +114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45, +162,137,147,111,2,8,4,16,7,8,96,120,72,8,0,183,225,81,98,138,237,33,58,182, +232,232,64,64,2,107,177,187,181,85,22,7,213,183,74,1,255,49,114,23,247,209, +207,120,94,173,198,210,36,3,255,113,84,118,82,184,47,224,221,91,141,163, +160,72,7,251,121,111,98,164,220,161,192,186,244,64,64,9,33,251,84,68,45,24, +15,217,66,51,209,218,210,128,127,205,65,60,204,254,119,154,23,178,132,103, +165,0,255,218,130,121,153,252,239,54,168,48,6,90,130,1,0,39,75,80,72,8,9, +33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,128,65, +17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,234,10,8, +41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,141,168, +40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,47,0,216, +134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,209,234, +10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,192,115,3, +117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,113,67,76, +130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,1,78,192, +56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,147,182, +140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,188,24,49, +39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,14,49,39, +199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,35,100, +128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,28,217, +114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,32,225, +64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,76,156, +113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5,114,1, +18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180,69,145, +132,108,224,31,248,0,0,0,0,0,0,25,172,56,132,122,28,76,146,218,121,35,180, +69,145,132,108,224,31,248,0,0,0,0,0,0,40,160,45,110,23,30,176,33,184,0,0, +175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,180,242,71, +104,139,35,8,217,192,63,240,0,0,0,0,0,0,51,88,145,8,244,56,153,37,180,242, +71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,88,161,8,244,56,153,37,180,242, +71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,88,177,8,244,56,153,37,180,242, +71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,193,8,244,56,153,37,180, +242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,209,8,244,56,153,37, +180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,225,8,244,56,153, +37,180,242,71,104,139,35,8,217,192,64,32,0,0,0,0,0,0,32,227,194,0,97,57, +162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73,29,153, +1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58,112,28, +211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73,240,117, +32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32,148,25, +174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173,214,3, +192, }; #elif defined(DUK_USE_DOUBLE_ME) -DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = { -144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242, -252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33, +DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = { +144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243, +124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33, 167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228, 64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46, 142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240, 242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0, -1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, -33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17, -13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192, -0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188, -0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85, -217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225, -146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,3, -225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,172,19,120,71,10,25,196, -136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58, -2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58, -130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180, -138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46, -190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207, -53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94, -124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37, -116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20, -240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153, -51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238, -105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129, -117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0, -65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49, -39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62, -58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129, -133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13, -39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95, -18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37, -194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151, -32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72, -151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113, -214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226, -10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84, -52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142, -214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173, -165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6, -143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62, -180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129, -54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0, -178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87, -129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104, -201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71, -132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232, -46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35, -193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194, -133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56, -9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14, -134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184, -64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6, -145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67, -77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113, -110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113, -110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2, -127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4, -33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207, -4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,239,127,255,255, -255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,32,0,0,25,136,0,0,31,15,224,0, -0,0,4,122,247,73,19,69,73,180,134,149,13,68,241,0,0,3,193,252,0,0,0,0,143, -90,67,2,104,169,54,144,210,161,168,158,32,0,0,120,127,128,0,0,0,14,73,78, -20,0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247, -68,13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205, -222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90, -112,164,0,0,124,63,128,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13, -53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16, -22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74, -113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104, -97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22, -190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196, -206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208, -76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49, -39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49, -39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112, -163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229, -100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117, -11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68, -157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149, -178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34, -9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62, -49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17, -34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60, -137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248, -199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200, -147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2, -54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56, -7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49, -89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0, -131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217, -231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232, -228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19, -235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1, -64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93, -168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20, -19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,93,105,160,0,0,0,0,91, -60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168, -110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115, -36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145, -139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166, -28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145, -92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41, -100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177, -69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99, -68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9, -49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20, -98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36, -249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242, -136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229, -16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39, -194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68, -89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59, -68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,136,71,161,196,201,45,167,146, -59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,168,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,200,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,232,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,8,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,40,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,72,71,161,196,201,45,167, -146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235, -103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91, -171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13, -158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1, -246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161, -37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79, -75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112, -39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186, -129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237, -17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134, -207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134, -207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38, -78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213, -146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39, -104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208, -146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16, -217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101, -162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201, -77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68, -117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104, -162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123, -102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160, -72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,5, -95,130,160,52,171,138,69,132,234,219,163,161,2,197,172,9,0,89,86,214,236, -31,86,221,40,8,69,220,199,253,231,63,95,193,122,183,27,72,144,17,197,125, -207,255,160,138,217,67,117,110,54,142,129,32,61,229,237,159,135,114,147,10, -130,235,209,3,236,132,37,0,96,181,17,80,63,101,8,207,71,107,74,4,245,7,49, -254,105,219,251,48,94,202,17,158,148,9,234,15,99,252,211,183,246,98,159, -129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160, -192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152, -27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163, -32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72, -188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29, -13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205, -72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80, -81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128, -153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9, -128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203, -164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113, -120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17, -16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94, -100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14, -108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7, -10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227, -138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43, -80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178, -48,141,156,0,0,15,3,240,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136, -178,48,141,156,0,0,15,3,240,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7, -122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180, -69,145,132,108,224,0,0,120,31,128,0,0,0,25,140,72,132,122,28,76,146,218, -121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,80,132,122,28,76,146, -218,121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,88,132,122,28,76, -146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,96,132,122, -28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,104, -132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25, -140,112,132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,16,32,0,0, -0,0,16,113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33, -18,224,104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80, -70,131,165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73, -7,78,3,154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154, -232,147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0, +1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, +33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198, +174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32, +248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215, +128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170, +154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130, +249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145, +136,67,134,19,49,0,0,3,225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1, +172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240, +149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68, +141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147, +132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42, +96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242, +243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53, +79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47, +147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139, +121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8, +151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147, +180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52, +78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52, +146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194, +70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31, +55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64, +96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36, +103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178, +1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17, +46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200, +217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140, +241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250, +96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81, +46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104, +194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8, +109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71, +240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173, +174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40, +104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32, +194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62, +16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150, +129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179, +224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255, +248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128, +124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34, +131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231, +192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107, +255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19, +245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161, +163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132, +5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13, +34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80, +211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39, +22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221, +197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2, +127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64, +132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46, +190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,129,255,255,222,255,255, +255,255,254,39,172,67,118,170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31, +192,0,0,0,8,245,238,146,38,138,147,105,13,42,26,137,226,0,0,7,131,248,0,0, +0,1,30,180,134,4,209,82,109,33,165,67,81,60,64,0,0,240,255,0,0,0,0,15,210, +62,72,91,155,0,0,2,192,240,0,0,0,0,135,88,11,237,72,5,38,210,27,50,24,145, +129,255,254,126,135,255,255,255,254,67,172,67,118,164,2,147,105,13,153,12, +72,192,255,255,63,195,255,255,255,255,16,240,70,68,226,27,51,199,138,120, +35,34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217, +144,196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196, +142,224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119, +224,3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64, +92,221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62, +210,98,177,252,3,107,173,88,3,146,211,141,32,0,3,225,252,0,0,0,3,19,175, +188,0,100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56, +161,166,188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7, +18,155,184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222, +8,77,133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152, +32,35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198, +57,179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96, +153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197, +144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150, +22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161, +166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100, +39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18, +32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72, +68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46, +16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117, +11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178, +36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173, +191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35, +43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4, +201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102, +123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162, +215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192, +131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201, +176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86, +127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0, +57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38, +191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128, +80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69, +220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150, +27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24, +186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64, +28,24,61,73,25,33,205,128,1,167,166,128,0,0,0,1,108,242,151,15,39,8,34,26, +87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140, +130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0, +80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145, +139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0, +0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240, +0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42, +130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137, +62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196, +159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79, +133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137, +62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16, +217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108, +244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192, +158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161, +196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,168,71, +161,196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,200, +71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51, +232,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,155,52, +8,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,155,52,40, +71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,52,72, +71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,52, +104,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155, +52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135, +52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44, +50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209, +214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15, +136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40, +161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75, +171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110, +4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129, +89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209, +29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134, +207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136, +235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29, +108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146, +155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54, +122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134, +218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79, +75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162, +137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209, +131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232, +73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68, +117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100, +226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1, +114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45, +162,137,147,111,2,8,4,16,7,8,96,120,72,1,87,224,168,13,42,226,145,97,58, +182,232,232,64,177,107,2,64,22,85,181,187,7,213,183,74,2,17,119,49,255,121, +207,215,240,94,173,198,210,36,4,113,95,115,255,232,34,182,80,221,91,141, +163,160,72,15,121,123,103,225,220,164,194,160,186,244,64,251,33,9,64,24,45, +68,84,15,217,66,51,209,218,210,129,61,65,204,127,154,118,254,204,23,178, +132,103,165,2,122,131,216,255,52,237,253,154,168,48,6,90,130,1,0,39,75,80, +72,8,9,33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20, +128,65,17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119, +234,10,8,41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91, +141,168,40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211, +47,0,216,134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168, +209,234,10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40, +192,115,3,117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202, +113,67,76,130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0, +1,78,192,56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86, +147,182,140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186, +188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68, +14,49,39,199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243, +35,100,128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146, +28,217,114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164, +32,225,64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28, +76,156,113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5, +114,1,18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180, +69,145,132,108,224,0,0,120,31,128,0,0,0,25,172,56,132,122,28,76,146,218, +121,35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,40,160,45,110,23,30,176, +33,184,0,0,175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37, +180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0,51,88,145,8,244,56,153, +37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,88,161,8,244,56,153, +37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,88,177,8,244,56,153, +37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,193,8,244,56, +153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,209,8,244, +56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,225,8, +244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,32,64,0,0,0,0,32,227,194, +0,97,57,162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73, +29,153,1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58, +112,28,211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73, +240,117,32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32, +148,25,174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173, +214,3,192, }; #else #error invalid endianness defines @@ -11501,10 +11760,18 @@ DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *ms DUK_UNREF(udata); DUK_UNREF(msg); + msg = msg ? msg : "NULL"; + #if defined(DUK_USE_FATAL_HANDLER) /* duk_config.h provided a custom default fatal handler. */ - DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg ? msg : "NULL")); + DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg)); DUK_USE_FATAL_HANDLER(udata, msg); +#elif defined(DUK_USE_CPP_EXCEPTIONS) + /* With C++ use a duk_fatal_exception which user code can catch in + * a natural way. + */ + DUK_D(DUK_DPRINT("built-in default C++ fatal error handler called: %s", msg)); + throw duk_fatal_exception(msg); #else /* Default behavior is to abort() on error. There's no printout * which makes this awkward, so it's always recommended to use an @@ -11521,7 +11788,7 @@ DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *ms * - http://duktape.org/api.html#taglist-protected * ==================================================================== */ - DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL")); + DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg)); DUK_ABORT(); #endif @@ -11677,7 +11944,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_u /* * Unicode codepoints above U+FFFF are encoded as surrogate * pairs here. This ensures that all CESU-8 codepoints are - * 16-bit values as expected in Ecmascript. The surrogate + * 16-bit values as expected in ECMAScript. The surrogate * pairs always get a 3-byte encoding (each) in CESU-8. * See: http://en.wikipedia.org/wiki/Surrogate_pair * @@ -11816,8 +12083,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, return cp; } DUK_ERROR_INTERNAL(thr); - DUK_UNREACHABLE(); - return 0; + DUK_WO_NORETURN(return 0;); } /* Compute (extended) utf-8 length without codepoint encoding validation, @@ -11966,7 +12232,7 @@ DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_si duk_bitdecoder_ctx bd_ctx; duk_codepoint_t prev_re; - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); + duk_memzero(&bd_ctx, sizeof(bd_ctx)); bd_ctx.data = (const duk_uint8_t *) unitab; bd_ctx.length = (duk_size_t) unilen; @@ -12518,7 +12784,7 @@ duk_codepoint_t duk__case_transform_helper(duk_hthread *thr, } /* 1:1 or special conversions, but not locale/context specific: script generated rules */ - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); + duk_memzero(&bd_ctx, sizeof(bd_ctx)); if (uppercase) { bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc; bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc); @@ -12718,7 +12984,7 @@ DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = { #endif /* DUK_USE_REGEXP_SUPPORT */ #line 1 "duk_util_misc.c" /* - * Misc util stuff + * Misc util stuff. */ /* #include duk_internal.h -> already included */ @@ -12880,45 +13146,6 @@ DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = { }; #endif /* DUK_USE_HEX_FASTPATH */ -/* - * Table for base-64 encoding - */ - -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = { - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */ - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */ - 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */ - 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */ -}; -#endif /* DUK_USE_BASE64_FASTPATH */ - -/* - * Table for base-64 decoding - */ - -#if defined(DUK_USE_BASE64_FASTPATH) -DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = { - /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */ - -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */ - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */ - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */ -}; -#endif /* DUK_USE_BASE64_FASTPATH */ - /* * Arbitrary byteswap for potentially unaligned values * @@ -12939,192 +13166,9 @@ DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) { } } #endif - -/* - * Miscellaneous coercion / clamping helpers. - */ - -/* Check whether a duk_double_t is a whole number in the 32-bit range (reject - * negative zero), and if so, return a duk_int32_t. - * For compiler use: don't allow negative zero as it will cause trouble with - * LDINT+LDINTX, positive zero is OK. - */ -DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) { - duk_int32_t t; - - t = (duk_int32_t) x; - if (!((duk_double_t) t == x)) { - return 0; - } - if (t == 0) { - duk_double_union du; - du.d = x; - if (DUK_DBLUNION_HAS_SIGNBIT(&du)) { - return 0; - } - } - *ival = t; - return 1; -} - -/* Check whether a duk_double_t is a whole number in the 32-bit range, and if - * so, return a duk_int32_t. - */ -DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) { - duk_int32_t t; - - t = (duk_int32_t) x; - if (!((duk_double_t) t == x)) { - return 0; - } - *ival = t; - return 1; -} - -/* - * IEEE double checks - */ - -DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) { - duk_double_union du; - du.d = x; - return DUK_DBLUNION_IS_ANYINF(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) { - duk_double_union du; - du.d = x; - return DUK_DBLUNION_IS_POSINF(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) { - duk_double_union du; - du.d = x; - return DUK_DBLUNION_IS_NEGINF(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) { - duk_double_union du; - du.d = x; - /* Assumes we're dealing with a Duktape internal NaN which is - * NaN normalized if duk_tval requires it. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - return DUK_DBLUNION_IS_NAN(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) { - duk_double_union du; - du.d = x; - /* Assumes we're dealing with a Duktape internal NaN which is - * NaN normalized if duk_tval requires it. - */ - DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); - return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du); -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) { - duk_double_union du; - du.d = x; - /* If exponent is 0x7FF the argument is either a NaN or an - * infinity. We don't need to check any other fields. - */ -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) - return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000); -#else - return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000); -#endif -#else - return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL; -#endif -} - -DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) { - duk_double_union du; -#if defined(DUK_USE_64BIT_OPS) - duk_uint64_t t; -#else - duk_uint32_t t; -#endif - du.d = x; -#if defined(DUK_USE_64BIT_OPS) -#if defined(DUK_USE_DOUBLE_ME) - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000); - if (t == DUK_U64_CONSTANT(0x0000000000000000)) { - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000); - return t == 0; - } - if (t == DUK_U64_CONSTANT(0x000000007ff00000)) { - return 1; - } -#else - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000); - if (t == DUK_U64_CONSTANT(0x0000000000000000)) { - t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000); - return t == 0; - } - if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) { - return 1; - } -#endif -#else - t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL; - if (t == 0x00000000UL) { - return DUK_DBLUNION_IS_ANYZERO(&du); - } - if (t == 0x7ff00000UL) { - return 1; - } -#endif - return 0; -} - -DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) { - duk_double_union du; - du.d = x; - return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du); -} - -DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) { - /* XXX: optimize */ - duk_small_uint_t s = duk_double_signbit(x); - x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */ - if (s) { - x = -x; - } - return x; -} - -DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) { - duk_double_union du1; - duk_double_union du2; - du1.d = x; - du2.d = y; - - return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0); -} - -DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) { - /* Doesn't replicate fmin() behavior exactly: for fmin() if one - * argument is a NaN, the other argument should be returned. - * Duktape doesn't rely on this behavior so the replacement can - * be simplified. - */ - return (x < y ? x : y); -} - -DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) { - /* Doesn't replicate fmax() behavior exactly: for fmax() if one - * argument is a NaN, the other argument should be returned. - * Duktape doesn't rely on this behavior so the replacement can - * be simplified. - */ - return (x > y ? x : y); -} #line 1 "duk_hobject_class.c" /* - * Hobject Ecmascript [[Class]]. + * Hobject ECMAScript [[Class]]. */ /* #include duk_internal.h -> already included */ @@ -13304,9 +13348,10 @@ DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + DUK_WO_NORETURN(return NULL;); } - /* maximum size check is handled by callee */ + /* Maximum size check is handled by callee. */ duk_hbuffer_resize(thr, h, new_size); return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); @@ -13324,6 +13369,7 @@ DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + DUK_WO_NORETURN(return NULL;); } /* Forget the previous allocation, setting size to 0 and alloc to @@ -13352,6 +13398,7 @@ DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, if (!DUK_HBUFFER_HAS_EXTERNAL(h)) { DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + DUK_WO_NORETURN(return;); } DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h)); @@ -13401,7 +13448,7 @@ DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, duk_uint8_t *p) { len = DUK_RAW_READ_U32_BE(p); buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); DUK_ASSERT(buf != NULL); - DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len); + duk_memcpy((void *) buf, (const void *) p, (size_t) len); p += len; return p; } @@ -13416,7 +13463,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) { DUK_ASSERT(len <= 0xffffffffUL); /* string limits */ tmp32 = (duk_uint32_t) len; DUK_RAW_WRITE_U32_BE(p, tmp32); - DUK_MEMCPY((void *) p, + duk_memcpy((void *) p, (const void *) DUK_HSTRING_GET_DATA(h), len); p += len; @@ -13435,9 +13482,10 @@ DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, d DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */ tmp32 = (duk_uint32_t) len; DUK_RAW_WRITE_U32_BE(p, tmp32); - DUK_MEMCPY((void *) p, - (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), - len); + /* When len == 0, buffer data pointer may be NULL. */ + duk_memcpy_unsafe((void *) p, + (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), + len); p += len; return p; } @@ -13649,7 +13697,7 @@ static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bu ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func); DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr); #if defined(DUK_USE_INTEGER_BE) - DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins)); + duk_memcpy_unsafe((void *) p, (const void *) ins, (size_t) (ins_end - ins)); p += (size_t) (ins_end - ins); #else while (ins != ins_end) { @@ -13671,7 +13719,7 @@ static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bu h_str = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h_str != NULL); DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p), + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p); *p++ = DUK__SER_STRING; p = duk__dump_hstring_raw(p, h_str); } else { @@ -13835,7 +13883,7 @@ static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t)); #if defined(DUK_USE_INTEGER_BE) q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; - DUK_MEMCPY((void *) q, + duk_memcpy((void *) q, (const void *) p, sizeof(duk_instr_t) * count_instr); p += sizeof(duk_instr_t) * count_instr; @@ -13900,15 +13948,12 @@ static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL); q = fun_data; - if (count_const > 0) { - /* Explicit zero size check to avoid NULL 'tv1'. */ - DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const); - for (n = count_const; n > 0; n--) { - DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */ - q += sizeof(duk_tval); - } - tv1 += count_const; + duk_memcpy_unsafe((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const); + for (n = count_const; n > 0; n--) { + DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */ + q += sizeof(duk_tval); } + tv1 += count_const; DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q); for (n = count_funcs; n > 0; n--) { @@ -14109,6 +14154,7 @@ DUK_EXTERNAL void duk_load_function(duk_hthread *thr) { format_error: DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE); + DUK_WO_NORETURN(return;); } #else /* DUK_USE_BYTECODE_DUMP_SUPPORT */ @@ -14116,11 +14162,13 @@ DUK_EXTERNAL void duk_load_function(duk_hthread *thr) { DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) { DUK_ASSERT_API_ENTRY(thr); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_load_function(duk_hthread *thr) { DUK_ASSERT_API_ENTRY(thr); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } #endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */ @@ -14188,7 +14236,7 @@ DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, du idx_func = duk_get_top(thr) - nargs - other; if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */ DUK_ERROR_TYPE_INVALID_ARGS(thr); - /* unreachable */ + DUK_WO_NORETURN(return 0;); } DUK_ASSERT(duk_is_valid_index(thr, idx_func)); return idx_func; @@ -14300,6 +14348,7 @@ DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t n obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */ if (DUK_UNLIKELY(nargs < 0)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return;); } duk__call_prop_prep_stack(thr, obj_idx, nargs); @@ -14336,7 +14385,7 @@ DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) { args.nargs = nargs; if (DUK_UNLIKELY(nargs < 0)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ + DUK_WO_NORETURN(return DUK_EXEC_ERROR;); } args.call_flags = 0; @@ -14371,7 +14420,7 @@ DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, args.nargs = nargs; if (DUK_UNLIKELY(nargs < 0)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ + DUK_WO_NORETURN(return DUK_EXEC_ERROR;); } args.call_flags = call_flags; @@ -14412,7 +14461,7 @@ DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_i args.nargs = nargs; if (DUK_UNLIKELY(nargs < 0)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ + DUK_WO_NORETURN(return DUK_EXEC_ERROR;); } args.call_flags = 0; @@ -14448,7 +14497,7 @@ DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function fu (long) (thr->valstack_top - thr->valstack), (long) nrets)); DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ + DUK_WO_NORETURN(return DUK_EXEC_ERROR;); } rc = duk_handle_safe_call(thr, /* thread */ @@ -14496,7 +14545,7 @@ DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) { if (DUK_UNLIKELY(nargs < 0)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); - return DUK_EXEC_ERROR; /* unreachable */ + DUK_WO_NORETURN(return DUK_EXEC_ERROR;); } rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); @@ -14523,6 +14572,7 @@ DUK_INTERNAL void duk_require_constructor_call(duk_hthread *thr) { if (!duk_is_constructor_call(thr)) { DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY); + DUK_WO_NORETURN(return;); } } @@ -14533,7 +14583,7 @@ DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) { * because all Duktape/C functions are considered strict, * and strict is also the default when nothing is running. * However, Duktape may call this function internally when - * the current activation is an Ecmascript function, so + * the current activation is an ECMAScript function, so * this cannot be replaced by a 'return 1' without fixing * the internal call sites. */ @@ -14600,7 +14650,7 @@ DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) { /* fall through */ type_error: DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) { @@ -14632,7 +14682,7 @@ DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) { h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) { - duk_push_tval(thr, &((duk_hboundfunc *) h)->target); + duk_push_tval(thr, &((duk_hboundfunc *) (void *) h)->target); duk_replace(thr, -2); #if 0 DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target); @@ -14663,6 +14713,10 @@ DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) { /* #include duk_internal.h -> already included */ +/* + * Misc helpers + */ + /* Shared handling for encode/decode argument. Fast path handling for * buffer and string values because they're the most common. In particular, * avoid creating a temporary string or buffer when possible. @@ -14684,250 +14738,425 @@ DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx return (const duk_uint8_t *) duk_to_lstring(thr, idx, out_len); } +/* + * Base64 + */ + +#if defined(DUK_USE_BASE64_SUPPORT) +/* Bytes emitted for number of padding characters in range [0,4]. */ +DUK_LOCAL const duk_int8_t duk__base64_decode_nequal_step[5] = { + 3, /* #### -> 24 bits, emit 3 bytes */ + 2, /* ###= -> 18 bits, emit 2 bytes */ + 1, /* ##== -> 12 bits, emit 1 byte */ + -1, /* #=== -> 6 bits, error */ + 0, /* ==== -> 0 bits, emit 0 bytes */ +}; + #if defined(DUK_USE_BASE64_FASTPATH) -DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { +DUK_LOCAL const duk_uint8_t duk__base64_enctab_fast[64] = { + 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U, /* A...P */ + 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, 0x59U, 0x5aU, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, /* Q...f */ + 0x67U, 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU, 0x6fU, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U, /* g...v */ + 0x77U, 0x78U, 0x79U, 0x7aU, 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x2bU, 0x2fU /* w.../ */ +}; +#endif /* DUK_USE_BASE64_FASTPATH */ + +#if defined(DUK_USE_BASE64_FASTPATH) +/* Decode table for one byte of input: + * -1 = allowed whitespace + * -2 = padding + * -3 = error + * 0...63 decoded bytes + */ +DUK_LOCAL const duk_int8_t duk__base64_dectab_fast[256] = { + -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3, /* 0x00...0x0f */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x10...0x1f */ + -1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 62, -3, -3, -3, 63, /* 0x20...0x2f */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -3, -3, -3, -2, -3, -3, /* 0x30...0x3f */ + -3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -3, -3, -3, -3, -3, /* 0x50...0x5f */ + -3, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */ + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -3, -3, -3, -3, -3, /* 0x70...0x7f */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x80...0x8f */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x90...0x9f */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xa0...0xaf */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xb0...0xbf */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xc0...0xcf */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xd0...0xdf */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xe0...0xef */ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3 /* 0xf0...0xff */ +}; +#endif /* DUK_USE_BASE64_FASTPATH */ + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_3(const duk_uint8_t *src, duk_uint8_t *dst) { duk_uint_t t; - duk_size_t n_full, n_full3, n_final; - const duk_uint8_t *src_end_fast; - n_full = srclen / 3; /* full 3-byte -> 4-char conversions */ - n_full3 = n_full * 3; - n_final = srclen - n_full3; - DUK_ASSERT_DISABLE(n_final >= 0); - DUK_ASSERT(n_final <= 2); + t = (duk_uint_t) src[0]; + t = (t << 8) + (duk_uint_t) src[1]; + t = (t << 8) + (duk_uint_t) src[2]; - src_end_fast = src + n_full3; - while (DUK_UNLIKELY(src != src_end_fast)) { - t = (duk_uint_t) (*src++); - t = (t << 8) + (duk_uint_t) (*src++); - t = (t << 8) + (duk_uint_t) (*src++); + dst[0] = duk__base64_enctab_fast[t >> 18]; + dst[1] = duk__base64_enctab_fast[(t >> 12) & 0x3fU]; + dst[2] = duk__base64_enctab_fast[(t >> 6) & 0x3fU]; + dst[3] = duk__base64_enctab_fast[t & 0x3fU]; - *dst++ = duk_base64_enctab[t >> 18]; - *dst++ = duk_base64_enctab[(t >> 12) & 0x3f]; - *dst++ = duk_base64_enctab[(t >> 6) & 0x3f]; - *dst++ = duk_base64_enctab[t & 0x3f]; - -#if 0 /* Tested: not faster on x64 */ - /* aaaaaabb bbbbcccc ccdddddd */ - dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f]; - dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)]; - dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)]; - dst[3] = duk_base64_enctab[src[2] & 0x3f]; - src += 3; dst += 4; +#if 0 + /* Tested: not faster on x64, most likely due to aliasing between + * output and input index computation. + */ + /* aaaaaabb bbbbcccc ccdddddd */ + dst[0] = duk__base64_enctab_fast[(src[0] >> 2) & 0x3fU]; + dst[1] = duk__base64_enctab_fast[((src[0] << 4) & 0x30U) | ((src[1] >> 4) & 0x0fU)]; + dst[2] = duk__base64_enctab_fast[((src[1] << 2) & 0x3fU) | ((src[2] >> 6) & 0x03U)]; + dst[3] = duk__base64_enctab_fast[src[2] & 0x3fU]; #endif +} + +DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_2(const duk_uint8_t *src, duk_uint8_t *dst) { + duk_uint_t t; + + t = (duk_uint_t) src[0]; + t = (t << 8) + (duk_uint_t) src[1]; + dst[0] = duk__base64_enctab_fast[t >> 10]; /* XXXXXX-- -------- */ + dst[1] = duk__base64_enctab_fast[(t >> 4) & 0x3fU]; /* ------XX XXXX---- */ + dst[2] = duk__base64_enctab_fast[(t << 2) & 0x3fU]; /* -------- ----XXXX */ + dst[3] = DUK_ASC_EQUALS; +} + +DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_1(const duk_uint8_t *src, duk_uint8_t *dst) { + duk_uint_t t; + + t = (duk_uint_t) src[0]; + dst[0] = duk__base64_enctab_fast[t >> 2]; /* XXXXXX-- */ + dst[1] = duk__base64_enctab_fast[(t << 4) & 0x3fU]; /* ------XX */ + dst[2] = DUK_ASC_EQUALS; + dst[3] = DUK_ASC_EQUALS; +} + +DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { + duk_size_t n; + const duk_uint8_t *p; + duk_uint8_t *q; + + n = srclen; + p = src; + q = dst; + + if (n >= 16U) { + /* Fast path, unrolled by 4, allows interleaving. Process + * 12-byte input chunks which encode to 16-char output chunks. + * Only enter when at least one block is emitted (avoids div+mul + * for short inputs too). + */ + const duk_uint8_t *p_end_fast; + + p_end_fast = p + ((n / 12U) * 12U); + DUK_ASSERT(p_end_fast >= p + 12); + do { + duk__base64_encode_fast_3(p, q); + duk__base64_encode_fast_3(p + 3, q + 4); + duk__base64_encode_fast_3(p + 6, q + 8); + duk__base64_encode_fast_3(p + 9, q + 12); + p += 12; + q += 16; + } while (DUK_LIKELY(p != p_end_fast)); + + DUK_ASSERT(src + srclen >= p); + n = (duk_size_t) (src + srclen - p); + DUK_ASSERT(n < 12U); } - switch (n_final) { - /* case 0: nop */ - case 1: { - /* XX== */ - t = (duk_uint_t) (*src++); - *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */ - *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */ - *dst++ = DUK_ASC_EQUALS; - *dst++ = DUK_ASC_EQUALS; - break; - } - case 2: { - /* XXX= */ - t = (duk_uint_t) (*src++); - t = (t << 8) + (duk_uint_t) (*src++); - *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */ - *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */ - *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */ - *dst++ = DUK_ASC_EQUALS; - break; + /* Remainder. */ + while (n >= 3U) { + duk__base64_encode_fast_3(p, q); + p += 3; + q += 4; + n -= 3U; } + DUK_ASSERT(n == 0U || n == 1U || n == 2U); + if (n == 1U) { + duk__base64_encode_fast_1(p, q); +#if 0 /* Unnecessary. */ + p += 1; + q += 4; + n -= 1U; +#endif + } else if (n == 2U) { + duk__base64_encode_fast_2(p, q); +#if 0 /* Unnecessary. */ + p += 2; + q += 4; + n -= 2U; +#endif + } else { + DUK_ASSERT(n == 0U); /* nothing to do */ + ; } } #else /* DUK_USE_BASE64_FASTPATH */ DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { - duk_small_uint_t i, snip; - duk_uint_t t; - duk_uint_fast8_t x, y; - const duk_uint8_t *src_end; + duk_small_uint_t i, npad; + duk_uint_t t, x, y; + const duk_uint8_t *p; + const duk_uint8_t *p_end; + duk_uint8_t *q; - src_end = src + srclen; + p = src; + p_end = src + srclen; + q = dst; + npad = 0U; - while (src < src_end) { - /* read 3 bytes into 't', padded by zero */ - snip = 4; + while (p < p_end) { + /* Read 3 bytes into 't', padded by zero. */ t = 0; for (i = 0; i < 3; i++) { t = t << 8; - if (src >= src_end) { - snip--; + if (p < p_end) { + t += (duk_uint_t) (*p++); } else { - t += (duk_uint_t) (*src++); + /* This only happens on the last loop and we're + * guaranteed to exit on the next loop. + */ + npad++; } } + DUK_ASSERT(npad <= 2U); - /* - * Missing bytes snip base64 example - * 0 4 XXXX - * 1 3 XXX= - * 2 2 XX== + /* Emit 4 encoded characters. If npad > 0, some of the + * chars will be incorrect (zero bits) but we fix up the + * padding after the loop. A straightforward 64-byte + * lookup would be faster and cleaner, but this is shorter. */ - - DUK_ASSERT(snip >= 2 && snip <= 4); - for (i = 0; i < 4; i++) { - x = (duk_uint_fast8_t) ((t >> 18) & 0x3f); + x = ((t >> 18) & 0x3fU); t = t << 6; - /* A straightforward 64-byte lookup would be faster - * and cleaner, but this is shorter. - */ - if (i >= snip) { - y = '='; - } else if (x <= 25) { - y = x + 'A'; - } else if (x <= 51) { - y = x - 26 + 'a'; - } else if (x <= 61) { - y = x - 52 + '0'; - } else if (x == 62) { - y = '+'; + if (x <= 51U) { + if (x <= 25) { + y = x + DUK_ASC_UC_A; + } else { + y = x - 26 + DUK_ASC_LC_A; + } } else { - y = '/'; + if (x <= 61U) { + y = x - 52 + DUK_ASC_0; + } else if (x == 62) { + y = DUK_ASC_PLUS; + } else { + DUK_ASSERT(x == 63); + y = DUK_ASC_SLASH; + } } - *dst++ = (duk_uint8_t) y; + *q++ = (duk_uint8_t) y; } } + + /* Handle padding by rewriting 0-2 bogus characters at the end. + * + * Missing bytes npad base64 example + * 0 0 #### + * 1 1 ###= + * 2 2 ##== + */ + DUK_ASSERT(npad <= 2U); + while (npad > 0U) { + *(q - npad) = DUK_ASC_EQUALS; + npad--; + } } #endif /* DUK_USE_BASE64_FASTPATH */ #if defined(DUK_USE_BASE64_FASTPATH) DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { duk_int_t x; - duk_int_t t; + duk_uint_t t; duk_small_uint_t n_equal; - duk_small_uint_t n_chars; - const duk_uint8_t *src_end; - const duk_uint8_t *src_end_safe; + duk_int8_t step; + const duk_uint8_t *p; + const duk_uint8_t *p_end; + const duk_uint8_t *p_end_safe; + duk_uint8_t *q; - src_end = src + srclen; - src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */ + p = src; + p_end = src + srclen; + p_end_safe = p_end - 8; /* If 'src <= src_end_safe', safe to read 8 bytes. */ + q = dst; - /* Innermost fast path processes 4 valid base-64 characters at a time - * but bails out on whitespace, padding chars ('=') and invalid chars. - * Once the slow path segment has been processed, we return to the - * inner fast path again. This handles e.g. base64 with newlines - * reasonably well because the majority of a line is in the fast path. + /* Alternate between a fast path which processes clean groups with no + * padding or whitespace, and a slow path which processes one arbitrary + * group and then re-enters the fast path. This handles e.g. base64 + * with newlines reasonably well because the majority of a line is in + * the fast path. */ for (;;) { - /* Fast path, handle units with just actual encoding characters. */ + /* Fast path, on each loop handle two 4-char input groups. + * If both are clean, emit 6 bytes and continue. If first + * is clean, emit 3 bytes and drop out; otherwise emit + * nothing and drop out. This approach could be extended to + * more groups per loop, but for inputs with e.g. periodic + * newlines (which are common) it might not be an improvement. + */ + while (DUK_LIKELY(p <= p_end_safe)) { + duk_int_t t1, t2; - while (src <= src_end_safe) { - /* The lookup byte is intentionally sign extended to (at least) - * 32 bits and then ORed. This ensures that is at least 1 byte - * is negative, the highest bit of 't' will be set at the end - * and we don't need to check every byte. + /* The lookup byte is intentionally sign extended to + * (at least) 32 bits and then ORed. This ensures + * that is at least 1 byte is negative, the highest + * bit of the accumulator will be set at the end and + * we don't need to check every byte. + * + * Read all input bytes first before writing output + * bytes to minimize aliasing. */ - DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p", - (const void *) src, (const void *) src_end_safe, (const void *) src_end)); + DUK_DDD(DUK_DDDPRINT("fast loop: p=%p, p_end_safe=%p, p_end=%p", + (const void *) p, (const void *) p_end_safe, (const void *) p_end)); - t = (duk_int_t) duk_base64_dectab[*src++]; - t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; - t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; - t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + t1 = (duk_int_t) duk__base64_dectab_fast[p[0]]; + t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[1]]; + t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[2]]; + t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[3]]; - if (DUK_UNLIKELY(t < 0)) { - DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit")); - src -= 4; + t2 = (duk_int_t) duk__base64_dectab_fast[p[4]]; + t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[5]]; + t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[6]]; + t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[7]]; + + q[0] = (duk_uint8_t) (((duk_uint_t) t1 >> 16) & 0xffU); + q[1] = (duk_uint8_t) (((duk_uint_t) t1 >> 8) & 0xffU); + q[2] = (duk_uint8_t) ((duk_uint_t) t1 & 0xffU); + + q[3] = (duk_uint8_t) (((duk_uint_t) t2 >> 16) & 0xffU); + q[4] = (duk_uint8_t) (((duk_uint_t) t2 >> 8) & 0xffU); + q[5] = (duk_uint8_t) ((duk_uint_t) t2 & 0xffU); + + /* Optimistic check using one branch. */ + if (DUK_LIKELY((t1 | t2) >= 0)) { + p += 8; + q += 6; + } else if (t1 >= 0) { + DUK_DDD(DUK_DDDPRINT("fast loop first group was clean, second was not, process one slow path group")); + DUK_ASSERT(t2 < 0); + p += 4; + q += 3; + break; + } else { + DUK_DDD(DUK_DDDPRINT("fast loop first group was not clean, second does not matter, process one slow path group")); + DUK_ASSERT(t1 < 0); break; } + } /* fast path */ - DUK_ASSERT(t <= 0xffffffL); - DUK_ASSERT((t >> 24) == 0); - *dst++ = (duk_uint8_t) (t >> 16); - *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - *dst++ = (duk_uint8_t) (t & 0xff); - } - - /* Handle one slow path unit (or finish if we're done). */ - - n_equal = 0; - n_chars = 0; - t = 0; - for (;;) { - DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld", - (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t)); - - if (DUK_UNLIKELY(src >= src_end)) { - goto done; /* two level break */ - } - - x = duk_base64_dectab[*src++]; - if (DUK_UNLIKELY(x < 0)) { - if (x == -2) { - continue; /* allowed ascii whitespace */ - } else if (x == -3) { - n_equal++; - t <<= 6; - } else { - DUK_ASSERT(x == -1); - goto decode_error; - } - } else { - DUK_ASSERT(x >= 0 && x <= 63); - if (n_equal > 0) { - /* Don't allow actual chars after equal sign. */ - goto decode_error; - } - t = (t << 6) + x; - } - - if (DUK_UNLIKELY(n_chars == 3)) { - /* Emit 3 bytes and backtrack if there was padding. There's - * always space for the whole 3 bytes so no check needed. - */ - DUK_ASSERT(t <= 0xffffffL); - DUK_ASSERT((t >> 24) == 0); - *dst++ = (duk_uint8_t) (t >> 16); - *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - *dst++ = (duk_uint8_t) (t & 0xff); - - if (DUK_UNLIKELY(n_equal > 0)) { - DUK_ASSERT(n_equal <= 4); - - /* There may be whitespace between the equal signs. */ - if (n_equal == 1) { - /* XXX= */ - dst -= 1; - } else if (n_equal == 2) { - /* XX== */ - dst -= 2; - } else { - goto decode_error; /* invalid padding */ - } - - /* Continue parsing after padding, allows concatenated, - * padded base64. - */ - } - break; /* back to fast loop */ - } else { - n_chars++; - } - } - } - done: - DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld", - (const void *) src, (const void *) src_end, (long) n_chars)); - - DUK_ASSERT(src == src_end); - - if (n_chars != 0) { - /* Here we'd have the option of decoding unpadded base64 - * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not - * accepted. + /* Slow path step 1: try to scan a 4-character encoded group, + * end-of-input, or start-of-padding. We exit with: + * 1. n_chars == 4: full group, no padding, no end-of-input. + * 2. n_chars < 4: partial group (may also be 0), encountered + * padding or end of input. + * + * The accumulator is initialized to 1; this allows us to detect + * a full group by comparing >= 0x1000000 without an extra + * counter variable. */ - goto decode_error; - } + t = 1UL; + for (;;) { + DUK_DDD(DUK_DDDPRINT("slow loop: p=%p, p_end=%p, t=%lu", + (const void *) p, (const void *) p_end, (unsigned long) t)); - *out_dst_final = dst; + if (DUK_LIKELY(p < p_end)) { + x = duk__base64_dectab_fast[*p++]; + if (DUK_LIKELY(x >= 0)) { + DUK_ASSERT(x >= 0 && x <= 63); + t = (t << 6) + (duk_uint_t) x; + if (t >= 0x1000000UL) { + break; + } + } else if (x == -1) { + continue; /* allowed ascii whitespace */ + } else if (x == -2) { + p--; + break; /* start of padding */ + } else { + DUK_ASSERT(x == -3); + goto decode_error; + } + } else { + break; /* end of input */ + } + } /* slow path step 1 */ + + /* Complete the padding by simulating pad characters, + * regardless of actual input padding chars. + */ + n_equal = 0; + while (t < 0x1000000UL) { + t = (t << 6) + 0U; + n_equal++; + } + + /* Slow path step 2: deal with full/partial group, padding, + * etc. Note that for num chars in [0,3] we intentionally emit + * 3 bytes but don't step forward that much, buffer space is + * guaranteed in setup. + * + * num chars: + * 0 #### no output (= step 0) + * 1 #=== reject, 6 bits of data + * 2 ##== 12 bits of data, output 1 byte (= step 1) + * 3 ###= 18 bits of data, output 2 bytes (= step 2) + * 4 #### 24 bits of data, output 3 bytes (= step 3) + */ + q[0] = (duk_uint8_t) ((t >> 16) & 0xffU); + q[1] = (duk_uint8_t) ((t >> 8) & 0xffU); + q[2] = (duk_uint8_t) (t & 0xffU); + + DUK_ASSERT(n_equal <= 4); + step = duk__base64_decode_nequal_step[n_equal]; + if (DUK_UNLIKELY(step < 0)) { + goto decode_error; + } + q += step; + + /* Slow path step 3: read and ignore padding and whitespace + * until (a) next non-padding and non-whitespace character + * after which we resume the fast path, or (b) end of input. + * This allows us to accept missing, partial, full, and extra + * padding cases uniformly. We also support concatenated + * base-64 documents because we resume scanning afterwards. + * + * Note that to support concatenated documents well, the '=' + * padding found inside the input must also allow for 'extra' + * padding. For example, 'Zm===' decodes to 'f' and has one + * extra padding char. So, 'Zm===Zm' should decode 'ff', even + * though the standard break-up would be 'Zm==' + '=Zm' which + * doesn't make sense. + * + * We also accept prepended padding like '==Zm9', because it + * is equivalent to an empty document with extra padding ('==') + * followed by a valid document. + */ + + for (;;) { + if (DUK_UNLIKELY(p >= p_end)) { + goto done; + } + x = duk__base64_dectab_fast[*p++]; + if (x == -1 || x == -2) { + ; /* padding or whitespace, keep eating */ + } else { + p--; + break; /* backtrack and go back to fast path, even for -1 */ + } + } /* slow path step 3 */ + } /* outer fast+slow path loop */ + + done: + DUK_DDD(DUK_DDDPRINT("done; p=%p, p_end=%p", + (const void *) p, (const void *) p_end)); + + DUK_ASSERT(p == p_end); + + *out_dst_final = q; return 1; decode_error: @@ -14935,94 +15164,138 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_ } #else /* DUK_USE_BASE64_FASTPATH */ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { - duk_uint_t t; - duk_uint_fast8_t x, y; - duk_small_uint_t group_idx; - duk_small_uint_t n_equal; - const duk_uint8_t *src_end; + duk_uint_t t, x; + duk_int_t y; + duk_int8_t step; + const duk_uint8_t *p; + const duk_uint8_t *p_end; + duk_uint8_t *q; + /* 0x09, 0x0a, or 0x0d */ + duk_uint32_t mask_white = (1U << 9) | (1U << 10) | (1U << 13); - src_end = src + srclen; - t = 0; - group_idx = 0; - n_equal = 0; + /* 't' tracks progress of the decoded group: + * + * t == 1 no valid chars yet + * t >= 0x40 1x6 = 6 bits shifted in + * t >= 0x1000 2x6 = 12 bits shifted in + * t >= 0x40000 3x6 = 18 bits shifted in + * t >= 0x1000000 4x6 = 24 bits shifted in + * + * By initializing t=1 there's no need for a separate counter for + * the number of characters found so far. + */ + p = src; + p_end = src + srclen; + q = dst; + t = 1UL; - while (src < src_end) { - x = *src++; + for (;;) { + duk_small_uint_t n_equal; - if (x >= 'A' && x <= 'Z') { - y = x - 'A' + 0; - } else if (x >= 'a' && x <= 'z') { - y = x - 'a' + 26; - } else if (x >= '0' && x <= '9') { - y = x - '0' + 52; - } else if (x == '+') { - y = 62; - } else if (x == '/') { - y = 63; - } else if (x == '=') { - /* We don't check the zero padding bytes here right now - * (that they're actually zero). This seems to be common - * behavior for base-64 decoders. + DUK_ASSERT(t >= 1U); + if (p >= p_end) { + /* End of input: if input exists, treat like + * start of padding, finish the block, then + * re-enter here to see we're done. */ - - n_equal++; - t <<= 6; /* shift in zeroes */ - goto skip_add; - } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) { - /* allow basic ASCII whitespace */ - continue; - } else { - goto decode_error; - } - - if (n_equal > 0) { - /* Don't allow mixed padding and actual chars. */ - goto decode_error; - } - t = (t << 6) + y; - skip_add: - - if (group_idx == 3) { - /* output 3 bytes from 't' */ - *dst++ = (duk_uint8_t) ((t >> 16) & 0xff); - *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - *dst++ = (duk_uint8_t) (t & 0xff); - - if (DUK_UNLIKELY(n_equal > 0)) { - /* Backtrack. */ - DUK_ASSERT(n_equal <= 4); - if (n_equal == 1) { - dst -= 1; - } else if (n_equal == 2) { - dst -= 2; - } else { - goto decode_error; /* invalid padding */ - } - - /* Here we can choose either to end parsing and ignore - * whatever follows, or to continue parsing in case - * multiple (possibly padded) base64 strings have been - * concatenated. Currently, keep on parsing. - */ - n_equal = 0; + if (t == 1U) { + break; + } else { + goto simulate_padding; } - - t = 0; - group_idx = 0; - } else { - group_idx++; } - } - if (group_idx != 0) { - /* Here we'd have the option of decoding unpadded base64 - * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not - * accepted. + x = *p++; + + if (x >= 0x41U) { + /* Valid: a-z and A-Z. */ + DUK_ASSERT(x >= 0x41U && x <= 0xffU); + if (x >= 0x61U && x <= 0x7aU) { + y = (duk_int_t) x - 0x61 + 26; + } else if (x <= 0x5aU) { + y = (duk_int_t) x - 0x41; + } else { + goto decode_error; + } + } else if (x >= 0x30U) { + /* Valid: 0-9 and =. */ + DUK_ASSERT(x >= 0x30U && x <= 0x40U); + if (x <= 0x39U) { + y = (duk_int_t) x - 0x30 + 52; + } else if (x == 0x3dU) { + /* Skip padding and whitespace unless we're in the + * middle of a block. Otherwise complete group by + * simulating shifting in the correct padding. + */ + if (t == 1U) { + continue; + } + goto simulate_padding; + } else { + goto decode_error; + } + } else if (x >= 0x20U) { + /* Valid: +, /, and 0x20 whitespace. */ + DUK_ASSERT(x >= 0x20U && x <= 0x2fU); + if (x == 0x2bU) { + y = 62; + } else if (x == 0x2fU) { + y = 63; + } else if (x == 0x20U) { + continue; + } else { + goto decode_error; + } + } else { + /* Valid: whitespace. */ + duk_uint32_t m; + DUK_ASSERT(x < 0x20U); /* 0x00 to 0x1f */ + m = (1U << x); + if (mask_white & m) { + /* Allow basic ASCII whitespace. */ + continue; + } else { + goto decode_error; + } + } + + DUK_ASSERT(y >= 0 && y <= 63); + t = (t << 6) + (duk_uint_t) y; + if (t < 0x1000000UL) { + continue; + } + /* fall through; no padding will be added */ + + simulate_padding: + n_equal = 0; + while (t < 0x1000000UL) { + t = (t << 6) + 0U; + n_equal++; + } + + /* Output 3 bytes from 't' and advance as needed. */ + q[0] = (duk_uint8_t) ((t >> 16) & 0xffU); + q[1] = (duk_uint8_t) ((t >> 8) & 0xffU); + q[2] = (duk_uint8_t) (t & 0xffU); + + DUK_ASSERT(n_equal <= 4U); + step = duk__base64_decode_nequal_step[n_equal]; + if (step < 0) { + goto decode_error; + } + q += step; + + /* Re-enter loop. The actual padding characters are skipped + * by the main loop. This handles cases like missing, partial, + * full, and extra padding, and allows parsing of concatenated + * documents (with extra padding) like: Zm===Zm. Also extra + * prepended padding is accepted: ===Zm9v. */ - goto decode_error; + t = 1U; } + DUK_ASSERT(t == 1UL); - *out_dst_final = dst; + *out_dst_final = q; return 1; decode_error: @@ -15039,15 +15312,12 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT_API_ENTRY(thr); - /* XXX: optimize for string inputs: no need to coerce to a buffer - * which makes a copy of the input. - */ - idx = duk_require_normalize_index(thr, idx); src = duk__prep_codec_arg(thr, idx, &srclen); /* Note: for srclen=0, src may be NULL */ - /* Computation must not wrap; this limit works for 32-bit size_t: + /* Compute exact output length. Computation must not wrap; this + * limit works for 32-bit size_t: * >>> srclen = 3221225469 * >>> '%x' % ((srclen + 2) / 3 * 4) * 'fffffffc' @@ -15055,7 +15325,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) { if (srclen > 3221225469UL) { goto type_error; } - dstlen = (srclen + 2) / 3 * 4; + dstlen = (srclen + 2U) / 3U * 4U; dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen); duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst); @@ -15066,7 +15336,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) { type_error: DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED); - return NULL; /* never here */ + DUK_WO_NORETURN(return NULL;); } DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) { @@ -15075,31 +15345,24 @@ DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) { duk_size_t dstlen; duk_uint8_t *dst; duk_uint8_t *dst_final; - duk_bool_t retval; DUK_ASSERT_API_ENTRY(thr); - /* XXX: optimize for buffer inputs: no need to coerce to a string - * which causes an unnecessary interning. - */ - idx = duk_require_normalize_index(thr, idx); src = duk__prep_codec_arg(thr, idx, &srclen); - /* Computation must not wrap, only srclen + 3 is at risk of - * wrapping because after that the number gets smaller. - * This limit works for 32-bit size_t: - * 0x100000000 - 3 - 1 = 4294967292 + /* Round up and add safety margin. Avoid addition before division to + * avoid possibility of wrapping. Margin includes +3 for rounding up, + * and +3 for one extra group: the decoder may emit and then backtrack + * a full group (3 bytes) from zero-sized input for technical reasons. + * Similarly, 'xx' may ecause 1+3 = bytes to be emitted and then + * backtracked. */ - if (srclen > 4294967292UL) { - goto type_error; - } - dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */ + dstlen = (srclen / 4) * 3 + 6; /* upper limit, assuming no whitespace etc */ dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen); /* Note: for dstlen=0, dst may be NULL */ - retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final); - if (!retval) { + if (!duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final)) { goto type_error; } @@ -15110,8 +15373,27 @@ DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) { type_error: DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED); + DUK_WO_NORETURN(return;); +} +#else /* DUK_USE_BASE64_SUPPORT */ +DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) { + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } +DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) { + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); +} +#endif /* DUK_USE_BASE64_SUPPORT */ + +/* + * Hex + */ + +#if defined(DUK_USE_HEX_SUPPORT) DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) { const duk_uint8_t *inp; duk_size_t len; @@ -15222,8 +15504,12 @@ DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) { } } for (; i < len; i += 2) { - t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | - ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + /* First cast to duk_int_t to sign extend, second cast to + * duk_uint_t to avoid signed left shift, and final cast to + * duk_int_t result type. + */ + t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) | + ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]])); if (DUK_UNLIKELY(t < 0)) { goto type_error; } @@ -15235,8 +15521,8 @@ DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) { * at least 16 bits. If either nybble is invalid, the * resulting 't' will be < 0. */ - t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | - ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) | + ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]])); if (DUK_UNLIKELY(t < 0)) { goto type_error; } @@ -15249,7 +15535,24 @@ DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) { type_error: DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED); + DUK_WO_NORETURN(return;); } +#else /* DUK_USE_HEX_SUPPORT */ +DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) { + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); +} +DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) { + DUK_UNREF(idx); + DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); +} +#endif /* DUK_USE_HEX_SUPPORT */ + +/* + * JSON + */ #if defined(DUK_USE_JSON_SUPPORT) DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) { @@ -15302,12 +15605,14 @@ DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT_API_ENTRY(thr); DUK_UNREF(idx); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return NULL;); } DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT_API_ENTRY(thr); DUK_UNREF(idx); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } #endif /* DUK_USE_JSON_SUPPORT */ #line 1 "duk_api_compile.c" @@ -15402,6 +15707,7 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) { if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */ (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */ DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE); + DUK_WO_NORETURN(return 0;); } DUK_ASSERT(h_sourcecode != NULL); comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode); @@ -15527,6 +15833,7 @@ DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) { DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) { DUK_ASSERT_API_ENTRY(thr); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } #endif /* DUK_USE_JSON_SUPPORT */ @@ -15638,7 +15945,7 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) top = duk_get_top(thr); if (top < nvalues) { DUK_ERROR_RANGE(thr, "not enough stack values for notify"); - return ret; /* unreachable */ + DUK_WO_NORETURN(return 0;); } if (duk_debug_is_attached(thr->heap)) { duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY); @@ -15705,11 +16012,13 @@ DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr, DUK_UNREF(detached_cb); DUK_UNREF(udata); DUK_ERROR_TYPE(thr, "no debugger support"); + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) { DUK_ASSERT_API_ENTRY(thr); DUK_ERROR_TYPE(thr, "no debugger support"); + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) { @@ -15726,7 +16035,7 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) top = duk_get_top(thr); if (top < nvalues) { DUK_ERROR_RANGE_INVALID_COUNT(thr); - return 0; /* unreachable */ + DUK_WO_NORETURN(return 0;); } /* No debugger support, just pop values. */ @@ -15849,7 +16158,7 @@ DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) { duk_push_tval(thr, &lj->value2); /* XXX: creating_error == 0 is asserted above, so no need to store. */ - DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate)); + duk_memcpy((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate)); snapshot->creating_error = heap->creating_error; snapshot->curr_thread = heap->curr_thread; snapshot->call_recursion_depth = heap->call_recursion_depth; @@ -15879,7 +16188,7 @@ DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) { heap = thr->heap; - DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate)); + duk_memcpy((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate)); heap->creating_error = snapshot->creating_error; heap->curr_thread = snapshot->curr_thread; heap->call_recursion_depth = snapshot->call_recursion_depth; @@ -16016,7 +16325,7 @@ DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT_API_ENTRY(thr); /* Assume two's complement and set everything to -1. */ - DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals)); + duk_memset((void *) &vals, (int) 0xff, sizeof(vals)); DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */ tv = duk_get_tval_or_unused(thr, idx); @@ -16032,12 +16341,12 @@ DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) { goto finish; } duk_push_pointer(thr, (void *) h); - duk_put_prop_string(thr, -2, "hptr"); + duk_put_prop_literal(thr, -2, "hptr"); #if 0 /* Covers a lot of information, e.g. buffer and string variants. */ duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h)); - duk_put_prop_string(thr, -2, "hflags"); + duk_put_prop_literal(thr, -2, "hflags"); #endif #if defined(DUK_USE_REFERENCE_COUNTING) @@ -16082,7 +16391,7 @@ DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) { } vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj); - vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj), + vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj); vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj); vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj); vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj); @@ -16285,7 +16594,7 @@ DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) { * Property handling * * The API exposes only the most common property handling functions. - * The caller can invoke Ecmascript built-ins for full control (e.g. + * The caller can invoke ECMAScript built-ins for full control (e.g. * defineProperty, getOwnPropertyDescriptor). */ @@ -16317,7 +16626,7 @@ DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, DUK_ASSERT(key != NULL); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_string(thr, key); + (void) duk_push_string(thr, key); return duk_get_prop(thr, obj_idx); } @@ -16326,10 +16635,22 @@ DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx DUK_ASSERT(key != NULL); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_lstring(thr, key, key_len); + (void) duk_push_lstring(thr, key, key_len); return duk_get_prop(thr, obj_idx); } +#if !defined(DUK_USE_PREFER_SIZE) +DUK_EXTERNAL duk_bool_t duk_get_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(key != NULL); + DUK_ASSERT(key[key_len] == (char) 0); + + obj_idx = duk_require_normalize_index(thr, obj_idx); + (void) duk_push_literal_raw(thr, key, key_len); + return duk_get_prop(thr, obj_idx); +} +#endif + DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { DUK_ASSERT_API_ENTRY(thr); @@ -16342,7 +16663,7 @@ DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx DUK_ASSERT_API_ENTRY(thr); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ + (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ return duk_get_prop(thr, obj_idx); } @@ -16351,7 +16672,7 @@ DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, DUK_ASSERT_STRIDX_VALID(stridx); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); + (void) duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); return duk_get_prop(thr, obj_idx); } @@ -16370,10 +16691,7 @@ DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t if (out_has_prop) { *out_has_prop = rc; } - rc = duk_to_boolean(thr, -1); - DUK_ASSERT(rc == 0 || rc == 1); - duk_pop(thr); - return rc; + return duk_to_boolean_top_pop(thr); } DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) { @@ -16433,6 +16751,18 @@ DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx return duk__put_prop_shared(thr, obj_idx, -1); } +#if !defined(DUK_USE_PREFER_SIZE) +DUK_EXTERNAL duk_bool_t duk_put_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(key != NULL); + DUK_ASSERT(key[key_len] == (char) 0); + + obj_idx = duk_normalize_index(thr, obj_idx); + (void) duk_push_literal_raw(thr, key, key_len); + return duk__put_prop_shared(thr, obj_idx, -1); +} +#endif + DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { DUK_ASSERT_API_ENTRY(thr); @@ -16445,7 +16775,7 @@ DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx DUK_ASSERT_API_ENTRY(thr); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ + (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ return duk__put_prop_shared(thr, obj_idx, -1); } @@ -16492,7 +16822,7 @@ DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, DUK_ASSERT(key != NULL); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_string(thr, key); + (void) duk_push_string(thr, key); return duk_del_prop(thr, obj_idx); } @@ -16501,10 +16831,22 @@ DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx DUK_ASSERT(key != NULL); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_lstring(thr, key, key_len); + (void) duk_push_lstring(thr, key, key_len); return duk_del_prop(thr, obj_idx); } +#if !defined(DUK_USE_PREFER_SIZE) +DUK_EXTERNAL duk_bool_t duk_del_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(key != NULL); + DUK_ASSERT(key[key_len] == (char) 0); + + obj_idx = duk_require_normalize_index(thr, obj_idx); + (void) duk_push_literal_raw(thr, key, key_len); + return duk_del_prop(thr, obj_idx); +} +#endif + DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { DUK_ASSERT_API_ENTRY(thr); @@ -16517,7 +16859,7 @@ DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx DUK_ASSERT_API_ENTRY(thr); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ + (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ return duk_del_prop(thr, obj_idx); } @@ -16563,7 +16905,7 @@ DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, DUK_ASSERT(key != NULL); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_string(thr, key); + (void) duk_push_string(thr, key); return duk_has_prop(thr, obj_idx); } @@ -16572,10 +16914,22 @@ DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx DUK_ASSERT(key != NULL); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_lstring(thr, key, key_len); + (void) duk_push_lstring(thr, key, key_len); return duk_has_prop(thr, obj_idx); } +#if !defined(DUK_USE_PREFER_SIZE) +DUK_EXTERNAL duk_bool_t duk_has_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(key != NULL); + DUK_ASSERT(key[key_len] == (char) 0); + + obj_idx = duk_require_normalize_index(thr, obj_idx); + (void) duk_push_literal_raw(thr, key, key_len); + return duk_has_prop(thr, obj_idx); +} +#endif + DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { DUK_ASSERT_API_ENTRY(thr); @@ -16588,7 +16942,7 @@ DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx DUK_ASSERT_API_ENTRY(thr); obj_idx = duk_require_normalize_index(thr, obj_idx); - duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ + (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ return duk_has_prop(thr, obj_idx); } @@ -16788,17 +17142,17 @@ DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t f fail_invalid_desc: DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR); - return; + DUK_WO_NORETURN(return;); fail_not_callable: DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); - return; + DUK_WO_NORETURN(return;); } /* * Object related * - * Note: seal() and freeze() are accessible through Ecmascript bindings, + * Note: seal() and freeze() are accessible through ECMAScript bindings, * and are not exposed through the API. */ @@ -16890,6 +17244,7 @@ DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_b fail_cannot_freeze: DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */ + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) { @@ -16973,6 +17328,38 @@ DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key return ret; } +#if !defined(DUK_USE_PREFER_SIZE) +DUK_EXTERNAL duk_bool_t duk_get_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) { + duk_bool_t ret; + + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + DUK_ASSERT(key[key_len] == (char) 0); + + /* XXX: direct implementation */ + + duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); + ret = duk_get_prop_literal_raw(thr, -1, key, key_len); + duk_remove_m2(thr); + return ret; +} +#endif + +DUK_EXTERNAL duk_bool_t duk_get_global_heapptr(duk_hthread *thr, void *ptr) { + duk_bool_t ret; + + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + + /* XXX: direct implementation */ + + duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); + ret = duk_get_prop_heapptr(thr, -1, ptr); + duk_remove_m2(thr); + return ret; +} + + DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) { duk_bool_t ret; @@ -17003,6 +17390,56 @@ DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key return ret; } +#if !defined(DUK_USE_PREFER_SIZE) +DUK_EXTERNAL duk_bool_t duk_put_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) { + duk_bool_t ret; + + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + DUK_ASSERT(key[key_len] == (char) 0); + + /* XXX: direct implementation */ + + duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); + duk_insert(thr, -2); + ret = duk_put_prop_literal_raw(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */ + duk_pop(thr); + return ret; +} +#endif + +DUK_EXTERNAL duk_bool_t duk_put_global_heapptr(duk_hthread *thr, void *ptr) { + duk_bool_t ret; + + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); + + /* XXX: direct implementation */ + + duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); + duk_insert(thr, -2); + ret = duk_put_prop_heapptr(thr, -2, ptr); /* [ ... global val ] -> [ ... global ] */ + duk_pop(thr); + return ret; +} + +/* + * ES2015 GetMethod() + */ + +DUK_INTERNAL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx) { + (void) duk_get_prop_stridx(thr, idx, stridx); + if (duk_is_null_or_undefined(thr, -1)) { + duk_pop_nodecref_unsafe(thr); + return 0; + } + if (!duk_is_callable(thr, -1)) { + DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); + DUK_WO_NORETURN(return 0;); + } + return 1; +} + /* * Object prototype */ @@ -17041,7 +17478,7 @@ DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) { #if defined(DUK_USE_ROM_OBJECTS) if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */ - return; + DUK_WO_NORETURN(return;); } #endif @@ -17098,14 +17535,26 @@ DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT_API_ENTRY(thr); DUK_UNREF(idx); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT_API_ENTRY(thr); DUK_UNREF(idx); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } #endif /* DUK_USE_FINALIZER_SUPPORT */ +#line 1 "duk_api_random.c" +/* + * Random numbers + */ + +/* #include duk_internal.h -> already included */ + +DUK_EXTERNAL duk_double_t duk_random(duk_hthread *thr) { + return (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr); +} #line 1 "duk_api_stack.c" /* * API calls related to general value stack manipulation: resizing the value @@ -17281,7 +17730,7 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int if (require) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); - /* not reachable */ + DUK_WO_NORETURN(return 0;); } return def_value; @@ -17332,7 +17781,7 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_u if (require) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); - /* not reachable */ + DUK_WO_NORETURN(return 0;); } return def_value; @@ -17407,7 +17856,7 @@ DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t i return (duk_idx_t) uidx; } DUK_ERROR_RANGE_INDEX(thr, idx); - return 0; /* unreachable */ + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) { @@ -17483,7 +17932,7 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) { return thr->valstack_bottom + uidx; } DUK_ERROR_RANGE_INDEX(thr, idx); - return NULL; + DUK_WO_NORETURN(return NULL;); } /* Non-critical. */ @@ -17501,7 +17950,7 @@ DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) { if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) { DUK_ERROR_RANGE_INDEX(thr, idx); - return; /* unreachable */ + DUK_WO_NORETURN(return;); } } @@ -17526,6 +17975,7 @@ DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_t ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); if (DUK_UNLIKELY(ret < min_top)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return 0;); } return ret; } @@ -17570,7 +18020,7 @@ DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) { #else if (DUK_UNLIKELY(uidx > vs_limit)) { DUK_ERROR_RANGE_INDEX(thr, idx); - return; /* unreachable */ + DUK_WO_NORETURN(return;); } #endif DUK_ASSERT(uidx <= vs_limit); @@ -17753,7 +18203,7 @@ DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) { ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; if (DUK_UNLIKELY(ret < 0)) { DUK_ERROR_RANGE_INDEX(thr, -1); - return 0; /* unreachable */ + DUK_WO_NORETURN(return 0;); } return ret; } @@ -17954,6 +18404,7 @@ DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, */ if (throw_on_error) { DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT); + DUK_WO_NORETURN(return 0;); } return 0; } @@ -17961,6 +18412,7 @@ DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, if (duk__resize_valstack(thr, new_size) == 0) { if (throw_on_error) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return 0;); } return 0; } @@ -18221,7 +18673,7 @@ DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) { if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) { DUK_ERROR_RANGE_INDEX(thr, -1); - return; /* unreachable */ + DUK_WO_NORETURN(return;); } tv_from = thr->valstack_top - 1; tv_to = thr->valstack_top++; @@ -18283,18 +18735,12 @@ DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) { DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu", (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes)); - /* No net refcount changes. */ - - if (nbytes > 0) { - DUK_TVAL_SET_TVAL(&tv_tmp, q); - DUK_ASSERT(nbytes > 0); - DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes); - DUK_TVAL_SET_TVAL(p, &tv_tmp); - } else { - /* nop: insert top to top */ - DUK_ASSERT(nbytes == 0); - DUK_ASSERT(p == q); - } + /* No net refcount changes. No need to special case nbytes == 0 + * (p == q). + */ + DUK_TVAL_SET_TVAL(&tv_tmp, q); + duk_memmove((void *) (p + 1), (const void *) p, (size_t) nbytes); + DUK_TVAL_SET_TVAL(p, &tv_tmp); } DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) { @@ -18386,7 +18832,7 @@ DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) { #endif nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ - DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */ + duk_memmove((void *) p, (const void *) (p + 1), (size_t) nbytes); DUK_TVAL_SET_UNDEFINED(q); thr->valstack_top--; @@ -18439,7 +18885,7 @@ DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) DUK_TVAL_DECREF_NORZ(thr, tv); } - DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, bytes); + duk_memmove((void *) tv_dst, (const void *) tv_src, bytes); tv_newtop = thr->valstack_top - count; for (tv = tv_newtop; tv < thr->valstack_top; tv++) { @@ -18478,14 +18924,14 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, if (DUK_UNLIKELY(to_thr == from_thr)) { DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT); - return; + DUK_WO_NORETURN(return;); } if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) { /* Maximum value check ensures 'nbytes' won't wrap below. * Also handles negative count. */ DUK_ERROR_RANGE_INVALID_COUNT(to_thr); - return; + DUK_WO_NORETURN(return;); } DUK_ASSERT(count >= 0); @@ -18496,17 +18942,19 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) { DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); + DUK_WO_NORETURN(return;); } src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) { DUK_ERROR_RANGE_INVALID_COUNT(to_thr); + DUK_WO_NORETURN(return;); } - /* copy values (no overlap even if to_thr == from_thr; that's not - * allowed now anyway) + /* Copy values (no overlap even if to_thr == from_thr; that's not + * allowed now anyway). */ DUK_ASSERT(nbytes > 0); - DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes); + duk_memcpy((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes); p = to_thr->valstack_top; to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes); @@ -18555,7 +19003,7 @@ DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes); copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src); thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes); - DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, copy_bytes); + duk_memmove((void *) tv_dst, (const void *) tv_src, copy_bytes); /* Values in the gap are left as garbage: caller must fill them in * and INCREF them before any side effects. @@ -18576,6 +19024,7 @@ DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT(tv != NULL); if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED); + DUK_WO_NORETURN(return;); } } @@ -18588,6 +19037,7 @@ DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT(tv != NULL); if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL); + DUK_WO_NORETURN(return;); } } @@ -18636,6 +19086,7 @@ DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) { return ret; } else { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN); + DUK_WO_NORETURN(return 0;); } } @@ -18697,6 +19148,7 @@ DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT(tv != NULL); if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER); + DUK_WO_NORETURN(return 0.0;); } ret.d = DUK_TVAL_GET_NUMBER(tv); @@ -18928,6 +19380,7 @@ DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT(tv != NULL); if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT); + DUK_WO_NORETURN(return;); } } @@ -18979,6 +19432,7 @@ DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT(tv != NULL); if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER); + DUK_WO_NORETURN(return NULL;); } p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ return p; @@ -19026,6 +19480,7 @@ DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size } else { if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); + DUK_WO_NORETURN(return NULL;); } len = def_size; ret = def_ptr; @@ -19129,6 +19584,7 @@ DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_ if (throw_flag) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); + DUK_WO_NORETURN(return NULL;); } return def_ptr; } @@ -19208,6 +19664,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) { h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING); + DUK_WO_NORETURN(return NULL;); } return h; } @@ -19220,6 +19677,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_id h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING); + DUK_WO_NORETURN(return NULL;); } return h; } @@ -19237,6 +19695,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) { h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT); + DUK_WO_NORETURN(return NULL;); } return h; } @@ -19254,6 +19713,7 @@ DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) { h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER); if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER); + DUK_WO_NORETURN(return NULL;); } return h; } @@ -19278,6 +19738,7 @@ DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) { h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD); + DUK_WO_NORETURN(return NULL;); } return (duk_hthread *) h; } @@ -19302,6 +19763,7 @@ DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t id h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC); + DUK_WO_NORETURN(return NULL;); } return (duk_hcompfunc *) h; } @@ -19326,6 +19788,7 @@ DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); + DUK_WO_NORETURN(return NULL;); } return (duk_hnatfunc *) h; } @@ -19384,6 +19847,7 @@ DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t i ret = duk_get_c_function(thr, idx); if (DUK_UNLIKELY(!ret)) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC); + DUK_WO_NORETURN(return ret;); } return ret; } @@ -19392,6 +19856,7 @@ DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT_API_ENTRY(thr); if (DUK_UNLIKELY(!duk_is_function(thr, idx))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION); + DUK_WO_NORETURN(return;); } } @@ -19403,6 +19868,7 @@ DUK_INTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) { h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC); if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE); + DUK_WO_NORETURN(return;); } /* Lightfuncs (h == NULL) are constructable. */ } @@ -19490,6 +19956,7 @@ DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT(tv != NULL); if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE); + DUK_WO_NORETURN(return NULL;); } ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); @@ -19523,6 +19990,7 @@ DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_i if (type_mask & DUK_TYPE_MASK_THROW) { DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT); + DUK_WO_NORETURN(return NULL;); } return NULL; } @@ -19583,6 +20051,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_i DUK_UNREF(h_class); DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE); + DUK_WO_NORETURN(return NULL;); } return h; } @@ -19775,49 +20244,43 @@ DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) { } /* E5 Section 9.1 */ -DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) { - /* inline initializer for coercers[] is not allowed by old compilers like BCC */ +DUK_LOCAL const char * const duk__toprim_hint_strings[3] = { + "default", "string", "number" +}; +DUK_LOCAL void duk__to_primitive_helper(duk_hthread *thr, duk_idx_t idx, duk_int_t hint, duk_bool_t check_symbol) { + /* Inline initializer for coercers[] is not allowed by old compilers like BCC. */ duk_small_uint_t coercers[2]; - duk_small_uint_t class_number; DUK_ASSERT_API_ENTRY(thr); DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING); idx = duk_require_normalize_index(thr, idx); + /* If already primitive, return as is. */ if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) { - /* Any other values stay as is. */ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */ return; } - class_number = duk_get_class_number(thr, idx); - - /* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive() - * algorithm which consults value[@@toPrimitive] and avoids calling - * .valueOf() and .toString(). Before that is implemented, special - * case Symbol objects to behave as if they had the default @@toPrimitive - * algorithm of E6 Section 19.4.3.4, i.e. return the plain symbol value - * with no further side effects. + /* @@toPrimitive lookup. Also do for plain buffers and lightfuncs + * which mimic objects. */ - - if (class_number == DUK_HOBJECT_CLASS_SYMBOL) { - duk_hobject *h_obj; - duk_hstring *h_str; - - /* XXX: pretty awkward, index based API for internal value access? */ - h_obj = duk_known_hobject(thr, idx); - h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj); - if (h_str) { - duk_push_hstring(thr, h_str); - duk_replace(thr, idx); - return; + if (check_symbol && duk_get_method_stridx(thr, idx, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)) { + DUK_ASSERT(hint >= 0 && (duk_size_t) hint < sizeof(duk__toprim_hint_strings) / sizeof(const char *)); + duk_dup(thr, idx); + duk_push_string(thr, duk__toprim_hint_strings[hint]); + duk_call_method(thr, 1); /* [ ... method value hint ] -> [ ... res] */ + if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | + DUK_TYPE_MASK_LIGHTFUNC | + DUK_TYPE_MASK_BUFFER)) { + goto fail; } + duk_replace(thr, idx); + return; } - /* Objects are coerced based on E5 specification. * Lightfuncs are coerced because they behave like * objects even if they're internally a primitive @@ -19825,17 +20288,29 @@ DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hi * like ArrayBuffer objects since Duktape 2.x. */ - coercers[0] = DUK_STRIDX_VALUE_OF; - coercers[1] = DUK_STRIDX_TO_STRING; - + /* Hint magic for Date is unnecessary in ES2015 because of + * Date.prototype[@@toPrimitive]. However, it is needed if + * symbol support is not enabled. + */ +#if defined(DUK_USE_SYMBOL_BUILTIN) if (hint == DUK_HINT_NONE) { + hint = DUK_HINT_NUMBER; + } +#else /* DUK_USE_SYMBOL_BUILTIN */ + if (hint == DUK_HINT_NONE) { + duk_small_uint_t class_number; + + class_number = duk_get_class_number(thr, idx); if (class_number == DUK_HOBJECT_CLASS_DATE) { hint = DUK_HINT_STRING; } else { hint = DUK_HINT_NUMBER; } } +#endif /* DUK_USE_SYMBOL_BUILTIN */ + coercers[0] = DUK_STRIDX_VALUE_OF; + coercers[1] = DUK_STRIDX_TO_STRING; if (hint == DUK_HINT_STRING) { coercers[0] = DUK_STRIDX_TO_STRING; coercers[1] = DUK_STRIDX_VALUE_OF; @@ -19851,9 +20326,21 @@ DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hi return; } + fail: DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED); + DUK_WO_NORETURN(return;); } +DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) { + duk__to_primitive_helper(thr, idx, hint, 1 /*check_symbol*/); +} + +#if defined(DUK_USE_SYMBOL_BUILTIN) +DUK_INTERNAL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) { + duk__to_primitive_helper(thr, idx, hint, 0 /*check_symbol*/); +} +#endif + /* E5 Section 9.2 */ DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) { duk_tval *tv; @@ -19874,6 +20361,22 @@ DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) { return val; } +DUK_INTERNAL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr) { + duk_tval *tv; + duk_bool_t val; + + DUK_ASSERT_API_ENTRY(thr); + + tv = duk_require_tval(thr, -1); + DUK_ASSERT(tv != NULL); + + val = duk_js_toboolean(tv); + DUK_ASSERT(val == 0 || val == 1); + + duk_pop_unsafe(thr); + return val; +} + DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) { duk_tval *tv; duk_double_t d; @@ -20153,68 +20656,67 @@ DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) { #endif /* Push Object.prototype.toString() output for 'tv'. */ -DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) { - duk_small_uint_t stridx; - duk_hstring *h_strclass; +#if 0 /* See XXX note why this variant doesn't work. */ +DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) { + duk_uint_t stridx_bidx = 0; /* (prototype_bidx << 16) + default_tag_stridx */ DUK_ASSERT_API_ENTRY(thr); + /* Conceptually for any non-undefined/null value we should do a + * ToObject() coercion and look up @@toStringTag (from the object + * prototype) to see if a custom tag should be used. Avoid the + * actual conversion by doing a prototype lookup without the object + * coercion. However, see problem below. + */ + + duk_push_literal(thr, "[object "); /* -> [ ... "[object" ] */ + switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */ case DUK_TAG_UNDEFINED: { - stridx = DUK_STRIDX_UC_UNDEFINED; - break; + stridx_bidx = DUK_STRIDX_UC_UNDEFINED; + goto use_stridx; } case DUK_TAG_NULL: { - stridx = DUK_STRIDX_UC_NULL; - break; + stridx_bidx = DUK_STRIDX_UC_NULL; + goto use_stridx; } case DUK_TAG_BOOLEAN: { - stridx = DUK_STRIDX_UC_BOOLEAN; - break; + stridx_bidx = (DUK_BIDX_BOOLEAN_PROTOTYPE << 16) + DUK_STRIDX_UC_BOOLEAN; + goto use_proto_bidx; } case DUK_TAG_POINTER: { - stridx = DUK_STRIDX_UC_POINTER; - break; + stridx_bidx = (DUK_BIDX_POINTER_PROTOTYPE << 16) + DUK_STRIDX_UC_POINTER; + goto use_proto_bidx; } case DUK_TAG_LIGHTFUNC: { - stridx = DUK_STRIDX_UC_FUNCTION; - break; + stridx_bidx = (DUK_BIDX_FUNCTION_PROTOTYPE << 16) + DUK_STRIDX_UC_FUNCTION; + goto use_proto_bidx; } case DUK_TAG_STRING: { duk_hstring *h; h = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h != NULL); if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { - stridx = DUK_STRIDX_UC_SYMBOL; + /* Even without DUK_USE_SYMBOL_BUILTIN the Symbol + * prototype exists so we can lookup @@toStringTag + * and provide [object Symbol] for symbol values + * created from C code. + */ + stridx_bidx = (DUK_BIDX_SYMBOL_PROTOTYPE << 16) + DUK_STRIDX_UC_SYMBOL; } else { - stridx = DUK_STRIDX_UC_STRING; + stridx_bidx = (DUK_BIDX_STRING_PROTOTYPE << 16) + DUK_STRIDX_UC_STRING; } - break; + goto use_proto_bidx; } case DUK_TAG_OBJECT: { - duk_hobject *h; - duk_small_uint_t classnum; - - h = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(h != NULL); - classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h); - stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum); - - /* XXX: This is not entirely correct anymore; in ES2015 the - * default lookup should use @@toStringTag to come up with - * e.g. [object Symbol], [object Uint8Array], etc. See - * ES2015 Section 19.1.3.6. The downside of implementing that - * directly is that the @@toStringTag lookup may have side - * effects, so all call sites must be checked for that. - * Some may need a side-effect free lookup, e.g. avoiding - * getters which are not typical. - */ - break; + duk_push_tval(thr, tv); + stridx_bidx = 0xffffffffUL; /* Marker value. */ + goto use_pushed_object; } case DUK_TAG_BUFFER: { - stridx = DUK_STRIDX_UINT8_ARRAY; - break; + stridx_bidx = (DUK_BIDX_UINT8ARRAY_PROTOTYPE << 16) + DUK_STRIDX_UINT8_ARRAY; + goto use_proto_bidx; } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: @@ -20222,14 +20724,142 @@ DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) { #endif default: { DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* number (maybe fastint) */ - stridx = DUK_STRIDX_UC_NUMBER; - break; + stridx_bidx = (DUK_BIDX_NUMBER_PROTOTYPE << 16) + DUK_STRIDX_UC_NUMBER; + goto use_proto_bidx; } } - h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx); - DUK_ASSERT(h_strclass != NULL); + DUK_ASSERT(0); /* Never here. */ - duk_push_sprintf(thr, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass)); + use_proto_bidx: + DUK_ASSERT_BIDX_VALID((stridx_bidx >> 16) & 0xffffUL); + duk_push_hobject(thr, thr->builtins[(stridx_bidx >> 16) & 0xffffUL]); + /* Fall through. */ + + use_pushed_object: + /* [ ... "[object" obj ] */ + +#if defined(DUK_USE_SYMBOL_BUILTIN) + /* XXX: better handling with avoid_side_effects == 1; lookup tval + * without Proxy or getter side effects, and use it in sanitized + * form if it's a string. + */ + if (!avoid_side_effects) { + /* XXX: The problem with using the prototype object as the + * lookup base is that if @@toStringTag is a getter, its + * 'this' binding must be the ToObject() coerced input value, + * not the prototype object of the type. + */ + (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG); + if (duk_is_string_notsymbol(thr, -1)) { + duk_remove_m2(thr); + goto finish; + } + duk_pop_unsafe(thr); + } +#endif + + if (stridx_bidx == 0xffffffffUL) { + duk_hobject *h_obj; + duk_small_uint_t classnum; + + h_obj = duk_known_hobject(thr, -1); + DUK_ASSERT(h_obj != NULL); + classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj); + stridx_bidx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum); + } else { + /* stridx_bidx already has the desired fallback stridx. */ + ; + } + duk_pop_unsafe(thr); + /* Fall through. */ + + use_stridx: + /* [ ... "[object" ] */ + duk_push_hstring_stridx(thr, stridx_bidx & 0xffffUL); + + finish: + /* [ ... "[object" tag ] */ + duk_push_literal(thr, "]"); + duk_concat(thr, 3); /* [ ... "[object" tag "]" ] -> [ ... res ] */ +} +#endif /* 0 */ + +DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) { + duk_hobject *h_obj; + duk_small_uint_t classnum; + duk_small_uint_t stridx; + duk_tval tv_tmp; + + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(tv != NULL); + + /* Stabilize 'tv', duk_push_literal() may trigger side effects. */ + DUK_TVAL_SET_TVAL(&tv_tmp, tv); + tv = &tv_tmp; + + /* Conceptually for any non-undefined/null value we should do a + * ToObject() coercion and look up @@toStringTag (from the object + * prototype) to see if a custom result should be used. We'd like to + * avoid the actual conversion, but even for primitive types the + * prototype may have @@toStringTag. What's worse, the @@toStringTag + * property may be a getter that must get the object coerced value + * (not the prototype) as its 'this' binding. + * + * For now, do an actual object coercion. This could be avoided by + * doing a side effect free lookup to see if a getter would be invoked. + * If not, the value can be read directly and the object coercion could + * be avoided. This may not be worth it in practice, because + * Object.prototype.toString() is usually not performance critical. + */ + + duk_push_literal(thr, "[object "); /* -> [ ... "[object" ] */ + + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */ + case DUK_TAG_UNDEFINED: { + duk_push_hstring_stridx(thr, DUK_STRIDX_UC_UNDEFINED); + goto finish; + } + case DUK_TAG_NULL: { + duk_push_hstring_stridx(thr, DUK_STRIDX_UC_NULL); + goto finish; + } + } + + duk_push_tval(thr, tv); + tv = NULL; /* Invalidated by ToObject(). */ + duk_to_object(thr, -1); + + /* [ ... "[object" obj ] */ + +#if defined(DUK_USE_SYMBOL_BUILTIN) + /* XXX: better handling with avoid_side_effects == 1; lookup tval + * without Proxy or getter side effects, and use it in sanitized + * form if it's a string. + */ + if (!avoid_side_effects) { + (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG); + if (duk_is_string_notsymbol(thr, -1)) { + duk_remove_m2(thr); + goto finish; + } + duk_pop_unsafe(thr); + } +#else + DUK_UNREF(avoid_side_effects); +#endif + + h_obj = duk_known_hobject(thr, -1); + DUK_ASSERT(h_obj != NULL); + classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj); + stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum); + duk_pop_unsafe(thr); + duk_push_hstring_stridx(thr, stridx); + + finish: + /* [ ... "[object" tag ] */ + duk_push_literal(thr, "]"); + duk_concat(thr, 3); /* [ ... "[object" tag "]" ] -> [ ... res ] */ } /* XXX: other variants like uint, u32 etc */ @@ -20289,6 +20919,7 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, d /* coerced value is updated to value stack even when RangeError thrown */ if (clamped) { DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE); + DUK_WO_NORETURN(return 0;); } } @@ -20346,12 +20977,14 @@ DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) { DUK_ASSERT(h != NULL); if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); + DUK_WO_NORETURN(goto skip_replace;); } else { goto skip_replace; } #else goto skip_replace; #endif + break; } case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */ case DUK_TAG_OBJECT: { @@ -20502,14 +21135,9 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t } dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/); - if (DUK_LIKELY(src_size > 0)) { - /* When src_size == 0, src_data may be NULL (if source - * buffer is dynamic), and dst_data may be NULL (if - * target buffer is dynamic). Avoid zero-size memcpy() - * with an invalid pointer. - */ - DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size); - } + /* dst_data may be NULL if size is zero. */ + duk_memcpy_unsafe((void *) dst_data, (const void *) src_data, (size_t) src_size); + duk_replace(thr, idx); skip_copy: @@ -20625,6 +21253,7 @@ DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) { case DUK_TAG_UNDEFINED: case DUK_TAG_NULL: { DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); + DUK_WO_NORETURN(return;); break; } case DUK_TAG_BOOLEAN: { @@ -20932,7 +21561,7 @@ DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk } if (mask & DUK_TYPE_MASK_THROW) { DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return 0;); } return 0; } @@ -21405,21 +22034,22 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk DUK_ASSERT_API_ENTRY(thr); - /* check stack before interning (avoid hanging temp) */ + /* Check stack before interning (avoid hanging temp). */ DUK__CHECK_SPACE(); /* NULL with zero length represents an empty string; NULL with higher - * length is also now trated like an empty string although it is + * length is also now treated like an empty string although it is * a bit dubious. This is unlike duk_push_string() which pushes a * 'null' if the input string is a NULL. */ - if (!str) { - len = 0; + if (DUK_UNLIKELY(str == NULL)) { + len = 0U; } - /* Check for maximum string length */ + /* Check for maximum string length. */ if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); + DUK_WO_NORETURN(return NULL;); } h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); @@ -21443,6 +22073,42 @@ DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) { } } +#if !defined(DUK_USE_PREFER_SIZE) +#if defined(DUK_USE_LITCACHE_SIZE) +DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) { + duk_hstring *h; + duk_tval *tv_slot; + + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(str != NULL); + DUK_ASSERT(str[len] == (char) 0); + + /* Check for maximum string length. */ + if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { + DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); + DUK_WO_NORETURN(return NULL;); + } + + h = duk_heap_strtable_intern_literal_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); + DUK_ASSERT(h != NULL); + + tv_slot = thr->valstack_top++; + DUK_TVAL_SET_STRING(tv_slot, h); + DUK_HSTRING_INCREF(thr, h); /* no side effects */ + + return (const char *) DUK_HSTRING_GET_DATA(h); +} +#else /* DUK_USE_LITCACHE_SIZE */ +DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) { + DUK_ASSERT_API_ENTRY(thr); + DUK_ASSERT(str != NULL); + DUK_ASSERT(str[len] == (char) 0); + + return duk_push_lstring(thr, str, len); +} +#endif /* DUK_USE_LITCACHE_SIZE */ +#endif /* !DUK_USE_PREFER_SIZE */ + DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) { duk_tval *tv_slot; @@ -21496,6 +22162,7 @@ DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_ob type_error: DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_push_this(duk_hthread *thr) { @@ -21539,6 +22206,46 @@ DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) { return thr->valstack_bottom - 1; } +DUK_EXTERNAL void duk_push_new_target(duk_hthread *thr) { + duk_activation *act; + + DUK_ASSERT_API_ENTRY(thr); + + /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation + * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget + * + * No newTarget support now, so as a first approximation + * use the resolved (non-bound) target function. + * + * Check CONSTRUCT flag from current function, or if running + * direct eval, from a non-direct-eval parent (with possibly + * more than one nested direct eval). An alternative to this + * would be to store [[NewTarget]] as a hidden symbol of the + * lexical scope, and then just look up that variable. + * + * Calls from the application will either be for an empty + * call stack, or a Duktape/C function as the top activation. + */ + + act = thr->callstack_curr; + for (;;) { + if (act == NULL) { + break; + } + + if (act->flags & DUK_ACT_FLAG_CONSTRUCT) { + duk_push_tval(thr, &act->tv_func); + return; + } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { + act = act->parent; + } else { + break; + } + } + + duk_push_undefined(thr); +} + DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) { duk_activation *act; @@ -21599,7 +22306,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_th DUK_ASSERT_API_ENTRY(thr); if (DUK_UNLIKELY(target_thr == NULL)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); - return; /* not reached */ + DUK_WO_NORETURN(return;); } duk_push_hobject(thr, (duk_hobject *) target_thr); duk__push_stash(thr); @@ -21675,6 +22382,7 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va sz = sz * 2; if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) { DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); + DUK_WO_NORETURN(return NULL;); } } @@ -21863,6 +22571,7 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) { /* important to do this *after* pushing, to make the thread reachable for gc */ if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return 0;); } /* initialize built-ins - either by copying or creating new ones */ @@ -21904,6 +22613,7 @@ DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) { DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); if (DUK_UNLIKELY(obj == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return NULL;); } DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags)); @@ -21935,6 +22645,7 @@ DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) { DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); if (!obj) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return NULL;); } tv_slot = thr->valstack_top++; @@ -21991,7 +22702,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function fu api_error: DUK_ERROR_TYPE_INVALID_ARGS(thr); - return 0; /* not reached */ + DUK_WO_NORETURN(return 0;); } DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) { @@ -22083,7 +22794,7 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function fun api_error: DUK_ERROR_TYPE_INVALID_ARGS(thr); - return 0; /* not reached */ + DUK_WO_NORETURN(return 0;); } #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) @@ -22235,11 +22946,11 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, range_error: DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); - return; /* not reached */ + DUK_WO_NORETURN(return;); arg_error: DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS); - return; /* not reached */ + DUK_WO_NORETURN(return;); } #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { @@ -22249,6 +22960,7 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, DUK_UNREF(byte_length); DUK_UNREF(flags); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return;); } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ @@ -22286,7 +22998,7 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcod duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); } else { /* If no explicit message given, put error code into message field - * (as a number). This is not fully in keeping with the Ecmascript + * (as a number). This is not fully in keeping with the ECMAScript * error model because messages are supposed to be strings (Error * constructors use ToString() on their argument). However, it's * probably more useful than having a separate 'code' property. @@ -22348,11 +23060,13 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_sm /* Check for maximum buffer length. */ if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) { DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); + DUK_WO_NORETURN(return NULL;); } h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); if (DUK_UNLIKELY(h == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return NULL;); } tv_slot = thr->valstack_top; @@ -22374,11 +23088,12 @@ DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) DUK_ASSERT_API_ENTRY(thr); ptr = duk_push_buffer_raw(thr, len, 0); + DUK_ASSERT(ptr != NULL); #if !defined(DUK_USE_ZERO_BUFFER_DATA) /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA * is not set. */ - DUK_MEMZERO((void *) ptr, (size_t) len); + duk_memzero((void *) ptr, (size_t) len); #endif return ptr; } @@ -22475,12 +23190,14 @@ DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) fail_args: DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return 0;); } #else /* DUK_USE_ES6_PROXY */ DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) { DUK_ASSERT_API_ENTRY(thr); DUK_UNREF(proxy_flags); DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return 0;); } #endif /* DUK_USE_ES6_PROXY */ @@ -22778,7 +23495,7 @@ DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) { if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); - return; + DUK_WO_NORETURN(return;); } DUK_ASSERT(count >= 0); @@ -22866,6 +23583,7 @@ DUK_EXTERNAL void duk_pop(duk_hthread *thr) { DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); + DUK_WO_NORETURN(return;); } duk__pop_unsafe_raw(thr); @@ -22954,6 +23672,7 @@ DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) { DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) { DUK_ERROR_RANGE_INVALID_COUNT(thr); + DUK_WO_NORETURN(return;); } duk__pop_2_unsafe_raw(thr); @@ -23011,7 +23730,7 @@ DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) { if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) { /* Also handles negative count. */ DUK_ERROR_RANGE_INVALID_COUNT(thr); - return; + DUK_WO_NORETURN(return;); } DUK_ASSERT(count >= 0); @@ -23028,9 +23747,8 @@ DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) { /* Copy value stack values directly to the array part without * any refcount updates: net refcount changes are zero. */ - tv_src = thr->valstack_top - count - 1; - DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval)); + duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval)); /* Overwrite result array to final value stack location and wipe * the rest; no refcount operations needed. @@ -23148,11 +23866,11 @@ DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) { } DUK_ERROR_TYPE_INVALID_ARGS(thr); - return 0; + DUK_WO_NORETURN(return 0;); fail_over_2g: DUK_ERROR_RANGE_INVALID_LENGTH(thr); - return 0; + DUK_WO_NORETURN(return 0;); } /* @@ -23169,6 +23887,7 @@ DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) { if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return;); } /* Errors are augmented when they are created, not when they are @@ -23232,6 +23951,7 @@ DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, con duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); (void) duk_throw(thr); + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { @@ -23243,6 +23963,7 @@ DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); va_end(ap); (void) duk_throw(thr); + DUK_WO_NORETURN(return;); } #if !defined(DUK_USE_VARIADIC_MACROS) @@ -23261,6 +23982,7 @@ DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_c duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); (void) duk_throw(thr); + DUK_WO_NORETURN(return;); } #define DUK__ERROR_STASH_SHARED(code) do { \ @@ -23268,7 +23990,7 @@ DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_c va_start(ap, fmt); \ duk__throw_error_from_stash(thr, (code), fmt, ap); \ va_end(ap); \ - /* Never reached; if return 0 here, gcc/clang will complain. */ \ + DUK_WO_NORETURN(return 0;); \ } while (0) DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) { @@ -23398,7 +24120,7 @@ DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function f DUK_ASSERT_API_ENTRY(thr); - duk_push_sprintf(thr, "light_"); + duk_push_literal(thr, "light_"); duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func)); duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags); duk_concat(thr, 3); @@ -23423,9 +24145,9 @@ DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) { DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */ - duk_push_string(thr, "function "); + duk_push_literal(thr, "function "); duk_push_lightfunc_name_raw(thr, func, lf_flags); - duk_push_string(thr, "() { [lightfunc code] }"); + duk_push_literal(thr, "() { [lightfunc code] }"); duk_concat(thr, 3); } @@ -23537,7 +24259,7 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval /* 'tv' may be NULL */ if (tv == NULL) { - duk_push_string(thr, "none"); + duk_push_literal(thr, "none"); } else { switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_STRING: { @@ -23546,11 +24268,11 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval /* XXX: string summary produces question marks * so this is not very ideal. */ - duk_push_string(thr, "[Symbol "); + duk_push_literal(thr, "[Symbol "); duk_push_string(thr, duk__get_symbol_type_string(h)); - duk_push_string(thr, " "); + duk_push_literal(thr, " "); duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS); - duk_push_string(thr, "]"); + duk_push_literal(thr, "]"); duk_concat(thr, 5); break; } @@ -23580,7 +24302,7 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval break; } } - duk_push_class_string_tval(thr, tv); + duk_push_class_string_tval(thr, tv, 1 /*avoid_side_effects*/); break; } case DUK_TAG_BUFFER: { @@ -23635,7 +24357,7 @@ DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstri DUK_ASSERT_API_ENTRY(thr); /* .toString() */ - duk_push_string(thr, "Symbol("); + duk_push_literal(thr, "Symbol("); p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); p_end = p + DUK_HSTRING_GET_BYTELEN(h); DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80); @@ -23651,7 +24373,7 @@ DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstri } } duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p)); - duk_push_string(thr, ")"); + duk_push_literal(thr, ")"); duk_concat(thr, 3); } @@ -23687,7 +24409,8 @@ DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_ DUK_ASSERT_API_ENTRY(thr); DUK_UNREF(thr); DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */ - DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval)); + + duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval)); tv = tv_dst; while (count-- > 0) { @@ -23724,7 +24447,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, if (DUK_UNLIKELY(count_in <= 0)) { if (count_in < 0) { DUK_ERROR_RANGE_INVALID_COUNT(thr); - return; + DUK_WO_NORETURN(return;); } DUK_ASSERT(count_in == 0); duk_push_hstring_empty(thr); @@ -23780,11 +24503,11 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, for (i = count; i >= 1; i--) { if (is_join && i != count) { h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */ - DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); idx += DUK_HSTRING_GET_BYTELEN(h); } h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */ - DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); + duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); idx += DUK_HSTRING_GET_BYTELEN(h); } @@ -23811,6 +24534,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, error_overflow: DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); + DUK_WO_NORETURN(return;); } DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) { @@ -23848,8 +24572,8 @@ DUK_INTERNAL void duk_concat_2(duk_hthread *thr) { buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len); DUK_ASSERT(buf != NULL); - DUK_MEMCPY((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1); - DUK_MEMCPY((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2); + duk_memcpy((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1); + duk_memcpy((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2); (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */ /* [ ... str1 str2 buf ] */ @@ -23860,6 +24584,7 @@ DUK_INTERNAL void duk_concat_2(duk_hthread *thr) { error_overflow: DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); + DUK_WO_NORETURN(return;); } #endif /* DUK_USE_PREFER_SIZE */ @@ -24089,7 +24814,7 @@ DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, d /* #include duk_internal.h -> already included */ DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) { - /* Ecmascript time, with millisecond fractions. Exposed via + /* ECMAScript time, with millisecond fractions. Exposed via * duk_get_now() for example. */ DUK_UNREF(thr); @@ -24097,7 +24822,7 @@ DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) { } DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) { - /* Ecmascript time without millisecond fractions. Exposed via + /* ECMAScript time without millisecond fractions. Exposed via * the Date built-in which doesn't allow fractions. */ DUK_UNREF(thr); @@ -24140,7 +24865,7 @@ DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, DUK_UNREF(thr); /* Convert as one-based, but change month to zero-based to match the - * Ecmascript Date built-in behavior 1:1. + * ECMAScript Date built-in behavior 1:1. */ flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO; @@ -24196,9 +24921,9 @@ DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_comp /* * Array built-ins * - * Most Array built-ins are intentionally generic in Ecmascript, and are + * Most Array built-ins are intentionally generic in ECMAScript, and are * intended to work even when the 'this' binding is not an Array instance. - * This Ecmascript feature is also used by much real world code. For this + * This ECMAScript feature is also used by much real world code. For this * reason the implementations here don't assume exotic Array behavior or * e.g. presence of a .length property. However, some algorithms have a * fast path for duk_harray backed actual Array instances, enabled when @@ -24272,6 +24997,7 @@ DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) { duk_uint32_t ret = duk__push_this_obj_len_u32(thr); if (DUK_UNLIKELY(ret >= 0x80000000UL)) { DUK_ERROR_RANGE_INVALID_LENGTH(thr); + DUK_WO_NORETURN(return 0U;); } return ret; } @@ -24424,11 +25150,17 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) { DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) { duk_idx_t i, n; - duk_uarridx_t idx, idx_last; - duk_uarridx_t j, len; + duk_uint32_t j, idx, len; duk_hobject *h; + duk_size_t tmp_len; - /* XXX: the insert here is a bit expensive if there are a lot of items. + /* XXX: In ES2015 Array .length can be up to 2^53-1. The current + * implementation is limited to 2^32-1. + */ + + /* XXX: Fast path for array 'this' and array element. */ + + /* XXX: The insert here is a bit expensive if there are a lot of items. * It could also be special cased in the outermost for loop quite easily * (as the element is dup()'d anyway). */ @@ -24446,59 +25178,97 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) { */ idx = 0; - idx_last = 0; for (i = 0; i < n; i++) { + duk_bool_t spreadable; + duk_bool_t need_has_check; + DUK_ASSERT_TOP(thr, n + 1); /* [ ToObject(this) item1 ... itemN arr ] */ - duk_dup(thr, i); - h = duk_get_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_ARRAY); - if (!h) { - duk_xdef_prop_index_wec(thr, -2, idx++); - idx_last = idx; + h = duk_get_hobject(thr, i); + + if (h == NULL) { + spreadable = 0; + } else { +#if defined(DUK_USE_SYMBOL_BUILTIN) + duk_get_prop_stridx(thr, i, DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE); + if (duk_is_undefined(thr, -1)) { + spreadable = (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY); + } else { + spreadable = duk_to_boolean(thr, -1); + } + duk_pop_nodecref_unsafe(thr); +#else + spreadable = (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY); +#endif + } + + if (!spreadable) { + duk_dup(thr, i); + duk_xdef_prop_index_wec(thr, -2, idx); + idx++; + if (DUK_UNLIKELY(idx == 0U)) { + /* Index after update is 0, and index written + * was 0xffffffffUL which is no longer a valid + * array index. + */ + goto fail_wrap; + } continue; } - /* [ ToObject(this) item1 ... itemN arr item(i) ] */ + DUK_ASSERT(duk_is_object(thr, i)); + need_has_check = (DUK_HOBJECT_IS_PROXY(h) != 0); /* Always 0 w/o Proxy support. */ - /* XXX: an array can have length higher than 32 bits; this is not handled - * correctly now. - */ - len = (duk_uarridx_t) duk_get_length(thr, -1); - for (j = 0; j < len; j++) { - if (duk_get_prop_index(thr, -1, j)) { - /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */ - duk_xdef_prop_index_wec(thr, -3, idx++); - idx_last = idx; - } else { - idx++; - duk_pop_undefined(thr); -#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER) - /* According to E5.1 Section 15.4.4.4 nonexistent trailing - * elements do not affect 'length' of the result. Test262 - * and other engines disagree, so update idx_last here too. - */ - idx_last = idx; -#else - /* Strict standard behavior, ignore trailing elements for - * result 'length'. - */ -#endif - } + /* [ ToObject(this) item1 ... itemN arr ] */ + + tmp_len = duk_get_length(thr, i); + len = (duk_uint32_t) tmp_len; + if (DUK_UNLIKELY(tmp_len != (duk_size_t) len)) { + goto fail_wrap; + } + if (DUK_UNLIKELY(idx + len < idx)) { + /* Result length must be at most 0xffffffffUL to be + * a valid 32-bit array index. + */ + goto fail_wrap; + } + for (j = 0; j < len; j++) { + /* For a Proxy element, an explicit 'has' check is + * needed to allow the Proxy to present gaps. + */ + if (need_has_check) { + if (duk_has_prop_index(thr, i, j)) { + duk_get_prop_index(thr, i, j); + duk_xdef_prop_index_wec(thr, -2, idx); + } + } else { + if (duk_get_prop_index(thr, i, j)) { + duk_xdef_prop_index_wec(thr, -2, idx); + } else { + duk_pop_undefined(thr); + } + } + idx++; + DUK_ASSERT(idx != 0U); /* Wrap check above. */ } - duk_pop_unsafe(thr); } - /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly - * in the end, but because we're operating with an internal value which - * is known to be an array, this should be equivalent. + /* ES5.1 has a specification "bug" in that nonexistent trailing + * elements don't affect the result .length. Test262 and other + * engines disagree, and the specification bug was fixed in ES2015 + * (see NOTE 1 in https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat). */ - duk_push_uarridx(thr, idx_last); + duk_push_uarridx(thr, idx); duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); DUK_ASSERT_TOP(thr, n + 1); return 1; + + fail_wrap: + DUK_ERROR_RANGE_INVALID_LENGTH(thr); + DUK_WO_NORETURN(return 0;); } /* @@ -25620,20 +26390,12 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) { DUK_ASSERT_TOP(thr, 5); if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) { -#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER) - /* Real world behavior for map(): trailing non-existent - * elements don't invoke the user callback, but are still - * counted towards result 'length'. + /* For 'map' trailing missing elements don't invoke the + * callback but count towards the result length. */ if (iter_type == DUK__ITER_MAP) { res_length = i + 1; } -#else - /* Standard behavior for map(): trailing non-existent - * elements don't invoke the user callback and are not - * counted towards result 'length'. - */ -#endif duk_pop_undefined(thr); continue; } @@ -26060,6 +26822,7 @@ DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_u if (flags & DUK__BUFOBJ_FLAG_THROW) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); + DUK_WO_NORETURN(return NULL;); } return NULL; } @@ -26101,7 +26864,7 @@ DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx } DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); - return NULL; /* not reachable */ + DUK_WO_NORETURN(return NULL;); } DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) { @@ -26176,6 +26939,7 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr, fail_range: DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); + DUK_WO_NORETURN(return;); } /* Shared lenient buffer length clamping helper. No negative indices, no @@ -26326,7 +27090,8 @@ DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_h DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { duk_double_union du; - DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size); + DUK_ASSERT(elem_size > 0); + duk_memcpy((void *) du.uc, (const void *) p, (size_t) elem_size); switch (h_bufobj->elem_type) { case DUK_HBUFOBJ_ELEM_UINT8: @@ -26394,7 +27159,11 @@ DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_b du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1); break; case DUK_HBUFOBJ_ELEM_FLOAT32: - du.f[0] = (duk_float_t) duk_to_number_m1(thr); + /* A double-to-float cast is undefined behavior in C99 if + * the cast is out-of-range, so use a helper. Example: + * runtime error: value -1e+100 is outside the range of representable values of type 'float' + */ + du.f[0] = duk_double_to_float_t(duk_to_number_m1(thr)); break; case DUK_HBUFOBJ_ELEM_FLOAT64: du.d = (duk_double_t) duk_to_number_m1(thr); @@ -26403,7 +27172,8 @@ DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_b DUK_UNREACHABLE(); } - DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size); + DUK_ASSERT(elem_size > 0); + duk_memcpy((void *) p, (const void *) du.uc, (size_t) elem_size); } /* Helper to create a fixed buffer from argument value at index 0. @@ -26439,12 +27209,14 @@ DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) { h_bufobj = (duk_hbufobj *) h; if (DUK_UNLIKELY(h_bufobj->buf == NULL)) { DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return NULL;); } if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) { /* No support for ArrayBuffers with slice * offset/length. */ DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return NULL;); } duk_push_hbuffer(thr, h_bufobj->buf); return h_bufobj->buf; @@ -26460,6 +27232,7 @@ DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) { } default: DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return NULL;); } done: @@ -26501,7 +27274,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) { duk_push_buffer_object(thr, -1, 0, - DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf), + DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) (void *) h_buf), DUK_BUFOBJ_UINT8ARRAY); duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); duk_set_prototype(thr, -2); @@ -26829,7 +27602,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) { DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld", (void *) p_src, (void *) p_dst, (long) byte_length)); - DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length); + duk_memcpy_unsafe((void *) p_dst, (const void *) p_src, (size_t) byte_length); break; } case 1: { @@ -27065,7 +27838,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) { h_this = duk__get_bufobj_this(thr); if (h_this == NULL) { /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */ - duk_push_string(thr, "[object Object]"); + duk_push_literal(thr, "[object Object]"); return 1; } DUK_ASSERT_HBUFOBJ_VALID(h_this); @@ -27096,9 +27869,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) { */ DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)); - DUK_MEMCPY((void *) buf_slice, - (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), - (size_t) slice_length); + duk_memcpy_unsafe((void *) buf_slice, + (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), + (size_t) slice_length); /* Use the equivalent of: new TextEncoder().encode(this) to convert the * string. Result will be valid UTF-8; non-CESU-8 inputs are currently @@ -27260,7 +28033,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) { /* Handle single character fills as memset() even when * the fill data comes from a one-char argument. */ - DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length); + duk_memset_unsafe((void *) p, (int) fill_str_ptr[0], (size_t) fill_length); } else if (fill_str_len > 1) { duk_size_t i, n, t; @@ -27311,9 +28084,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) { if (DUK_HBUFOBJ_VALID_SLICE(h_this)) { /* Cannot overlap. */ - DUK_MEMCPY((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset), - (const void *) str_data, - (size_t) length); + duk_memcpy_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset), + (const void *) str_data, + (size_t) length); } else { DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore")); } @@ -27409,9 +28182,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) { /* Must use memmove() because copy area may overlap (source and target * buffer may be the same, or from different slices. */ - DUK_MEMMOVE((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart), - (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart), - (size_t) copy_size); + duk_memmove_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart), + (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart), + (size_t) copy_size); } else { DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring")); } @@ -27597,7 +28370,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) { DUK_ASSERT(src_length == dst_length); DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible")); - DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length); + duk_memmove_unsafe((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length); return 0; } DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item")); @@ -27640,7 +28413,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) { DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source")); p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length); DUK_ASSERT(p_src_copy != NULL); - DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length); + duk_memcpy_unsafe((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length); p_src_base = p_src_copy; /* use p_src_base from now on */ } @@ -27767,9 +28540,9 @@ DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val DUK_ASSERT(p_copy != NULL); copy_length = slice_length; - DUK_MEMCPY((void *) p_copy, - (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset), - copy_length); + duk_memcpy_unsafe((void *) p_copy, + (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset), + copy_length); } #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ @@ -27891,9 +28664,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) { * is left as zero. */ copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length); - DUK_MEMCPY((void *) p_copy, - (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), - copy_length); + duk_memcpy_unsafe((void *) p_copy, + (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), + copy_length); h_val = duk_known_hbuffer(thr, -1); @@ -28085,9 +28858,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) { if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { - DUK_MEMCPY((void *) p, - (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj), - copy_size); + duk_memcpy_unsafe((void *) p, + (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj), + copy_size); } else { /* Just skip, leaving zeroes in the result. */ ; @@ -28237,7 +29010,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) { if (offset + 2U > check_length) { goto fail_bounds; } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2); + duk_memcpy((void *) du.uc, (const void *) (buf + offset), 2); tmp = du.us[0]; if (endswap) { tmp = DUK_BSWAP16(tmp); @@ -28254,7 +29027,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) { if (offset + 4U > check_length) { goto fail_bounds; } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4); + duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4); tmp = du.ui[0]; if (endswap) { tmp = DUK_BSWAP32(tmp); @@ -28271,7 +29044,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) { if (offset + 4U > check_length) { goto fail_bounds; } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4); + duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4); if (endswap) { tmp = du.ui[0]; tmp = DUK_BSWAP32(tmp); @@ -28284,7 +29057,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) { if (offset + 8U > check_length) { goto fail_bounds; } - DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8); + duk_memcpy((void *) du.uc, (const void *) (buf + offset), 8); if (endswap) { DUK_DBLUNION_BSWAP64(&du); } @@ -28341,9 +29114,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) { } while (i != i_end); if (magic_signed) { - /* Shift to sign extend. */ + /* Shift to sign extend. Left shift must be unsigned + * to avoid undefined behavior; right shift must be + * signed to sign extend properly. + */ shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U); - tmp = (tmp << shift_tmp) >> shift_tmp; + tmp = (duk_int64_t) ((duk_uint64_t) tmp << shift_tmp) >> shift_tmp; } duk_push_i64(thr, tmp); @@ -28519,7 +29295,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) { } du.us[0] = tmp; /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2); + duk_memcpy((void *) (buf + offset), (const void *) du.uc, 2); break; } case DUK__FLD_32BIT: { @@ -28533,7 +29309,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) { } du.ui[0] = tmp; /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4); + duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4); break; } case DUK__FLD_FLOAT: { @@ -28548,7 +29324,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) { du.ui[0] = tmp; } /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4); + duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4); break; } case DUK__FLD_DOUBLE: { @@ -28560,7 +29336,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) { DUK_DBLUNION_BSWAP64(&du); } /* sign doesn't matter when writing */ - DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8); + duk_memcpy((void *) (buf + offset), (const void *) du.uc, 8); break; } case DUK__FLD_VARINT: { @@ -29007,7 +29783,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const ch duk_small_uint_t i; /* During parsing, month and day are one-based; set defaults here. */ - DUK_MEMZERO(parts, sizeof(parts)); + duk_memzero(parts, sizeof(parts)); DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */ parts[DUK_DATE_IDX_MONTH] = 1; parts[DUK_DATE_IDX_DAY] = 1; @@ -29234,13 +30010,13 @@ DUK_LOCAL duk_uint8_t duk__days_in_month[12] = { }; /* Maximum iteration count for computing UTC-to-local time offset when - * creating an Ecmascript time value from local parts. + * creating an ECMAScript time value from local parts. */ #define DUK__LOCAL_TZOFFSET_MAXITER 4 /* Because 'day since epoch' can be negative and is used to compute weekday * using a modulo operation, add this multiple of 7 to avoid negative values - * when year is below 1970 epoch. Ecmascript time values are restricted to + * when year is below 1970 epoch. ECMAScript time values are restricted to * +/- 100 million days from epoch, so this adder fits nicely into 32 bits. * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin. */ @@ -29431,10 +30207,10 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, d = DUK_FLOOR(d); /* remove fractions if present */ DUK_ASSERT(DUK_FLOOR(d) == d); - /* The timevalue must be in valid Ecmascript range, but since a local + /* The timevalue must be in valid ECMAScript range, but since a local * time offset can be applied, we need to allow a +/- 24h leeway to * the value. In other words, although the UTC time is within the - * Ecmascript range, the local part values can be just outside of it. + * ECMAScript range, the local part values can be just outside of it. */ DUK_UNREF(duk_bi_date_timeval_in_leeway_range); DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d)); @@ -29477,7 +30253,7 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, (long) parts[DUK_DATE_IDX_MILLISECOND])); /* This assert depends on the input parts representing time inside - * the Ecmascript range. + * the ECMAScript range. */ DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0); parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */ @@ -29597,7 +30373,7 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dpar * computation happens with intermediate results coerced to * double values (instead of using something more accurate). * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754 - * rules (= Ecmascript '+' and '*' operators). + * rules (= ECMAScript '+' and '*' operators). * * Without 'volatile' even this approach fails on some platform * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu @@ -29704,6 +30480,7 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */ if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) { DUK_ERROR_TYPE(thr, "expected Date"); + DUK_WO_NORETURN(return 0.0;); } duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); @@ -29716,6 +30493,7 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk } if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) { DUK_ERROR_RANGE(thr, "Invalid Date"); + DUK_WO_NORETURN(return 0.0;); } } /* if no NaN handling flag, may still be NaN here, but not Inf */ @@ -30332,7 +31110,7 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) { * Notes: * * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are - * required to be the same Ecmascript function object (!), so it is + * required to be the same ECMAScript function object (!), so it is * omitted from here. * * - Date.prototype.toUTCString(): E5.1 specification does not require a @@ -30528,6 +31306,41 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) { return 1; } +/* + * Misc. + */ + +#if defined(DUK_USE_SYMBOL_BUILTIN) +DUK_INTERNAL duk_ret_t duk_bi_date_prototype_toprimitive(duk_hthread *thr) { + duk_size_t hintlen; + const char *hintstr; + duk_int_t hint; + + /* Invokes OrdinaryToPrimitive() with suitable hint. Note that the + * method is generic, and works on non-Date arguments too. + * + * https://www.ecma-international.org/ecma-262/6.0/#sec-date.prototype-@@toprimitive + */ + + duk_push_this(thr); + duk_require_object(thr, -1); + DUK_ASSERT_TOP(thr, 2); + + hintstr = duk_require_lstring(thr, 0, &hintlen); + if ((hintlen == 6 && DUK_STRCMP(hintstr, "string") == 0) || + (hintlen == 7 && DUK_STRCMP(hintstr, "default") == 0)) { + hint = DUK_HINT_STRING; + } else if (hintlen == 6 && DUK_STRCMP(hintstr, "number") == 0) { + hint = DUK_HINT_NUMBER; + } else { + DUK_DCERROR_TYPE_INVALID_ARGS(thr); + } + + duk_to_primitive_ordinary(thr, -1, hint); + return 1; +} +#endif /* DUK_USE_SYMBOL_BUILTIN */ + #endif /* DUK_USE_DATE_BUILTIN */ /* automatic undefs */ @@ -30596,7 +31409,7 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) { #define DUK__STRFTIME_BUF_SIZE 64 #if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) -/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */ +/* Get current ECMAScript time (= UNIX/Posix time, but in milliseconds). */ DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) { struct timeval tv; duk_double_t d; @@ -30644,7 +31457,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { return 0; } - /* If not within Ecmascript range, some integer time calculations + /* If not within ECMAScript range, some integer time calculations * won't work correctly (and some asserts will fail), so bail out * if so. This fixes test-bug-date-insane-setyear.js. There is * a +/- 24h leeway in this range check to avoid a test262 corner @@ -30695,10 +31508,10 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { * Since we rely on the platform APIs for conversions between local * time and UTC, we can't guarantee the above. Rather, if the platform * has historical DST rules they will be applied. This seems to be the - * general preferred direction in Ecmascript standardization (or at least + * general preferred direction in ECMAScript standardization (or at least * implementations) anyway, and even the equivalent year mapping should * be disabled if the platform is known to handle DST properly for the - * full Ecmascript range. + * full ECMAScript range. * * The following has useful discussion and links: * @@ -30713,7 +31526,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { t = (time_t) (d / 1000.0); DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t)); - DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2); + duk_memzero((void *) tms, sizeof(struct tm) * 2); #if defined(DUK_USE_DATE_TZO_GMTIME_R) (void) gmtime_r(&t, &tms[0]); @@ -30723,9 +31536,9 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { (void) localtime_s(&t, &tms[1]); #elif defined(DUK_USE_DATE_TZO_GMTIME) tm_ptr = gmtime(&t); - DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm)); + duk_memcpy((void *) &tms[0], tm_ptr, sizeof(struct tm)); tm_ptr = localtime(&t); - DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm)); + duk_memcpy((void *) &tms[1], tm_ptr, sizeof(struct tm)); #else #error internal error #endif @@ -30786,13 +31599,13 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, cons /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */ DUK_ASSERT(str != NULL); - DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */ + duk_memzero(buf, sizeof(buf)); /* valgrind whine without this */ DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str); buf[sizeof(buf) - 1] = (char) 0; DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf)); - DUK_MEMZERO(&tm, sizeof(tm)); + duk_memzero(&tm, sizeof(tm)); if (strptime((const char *) buf, "%c", &tm) != NULL) { DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld," "wday:%ld,yday:%ld,isdst:%ld}", @@ -30823,7 +31636,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const * convenient for an embeddable interpreter. */ - DUK_MEMZERO(&tm, sizeof(struct tm)); + duk_memzero(&tm, sizeof(struct tm)); rc = (duk_small_int_t) getdate_r(str, &tm); DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc)); @@ -30848,16 +31661,16 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_ DUK_UNREF(tzoffset); - /* If the platform doesn't support the entire Ecmascript range, we need + /* If the platform doesn't support the entire ECMAScript range, we need * to return 0 so that the caller can fall back to the default formatter. * - * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript + * For now, assume that if time_t is 8 bytes or more, the whole ECMAScript * range is supported. For smaller time_t values (4 bytes in practice), * assumes that the signed 32-bit range is supported. * * XXX: detect this more correctly per platform. The size of time_t is * probably not an accurate guarantee of strftime() supporting or not - * supporting a large time range (the full Ecmascript range). + * supporting a large time range (the full ECMAScript range). */ if (sizeof(time_t) < 8 && (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) { @@ -30865,7 +31678,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_ return 0; } - DUK_MEMZERO(&tm, sizeof(tm)); + duk_memzero(&tm, sizeof(tm)); tm.tm_sec = parts[DUK_DATE_IDX_SECOND]; tm.tm_min = parts[DUK_DATE_IDX_MINUTE]; tm.tm_hour = parts[DUK_DATE_IDX_HOUR]; @@ -30875,7 +31688,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_ tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY]; tm.tm_isdst = 0; - DUK_MEMZERO(buf, sizeof(buf)); + duk_memzero(buf, sizeof(buf)); if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) { fmt = "%c"; } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) { @@ -30934,13 +31747,15 @@ DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEG } } +#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) { res->LowPart = ft->dwLowDateTime; res->HighPart = ft->dwHighDateTime; } +#endif /* DUK_USE_DATE_NOW_WINDOWS_SUBMS */ DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) { - DUK_MEMZERO((void *) st, sizeof(*st)); + duk_memzero((void *) st, sizeof(*st)); st->wYear = 1970; st->wMonth = 1; st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */ @@ -31005,10 +31820,11 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) { ULARGE_INTEGER tmp2; ULARGE_INTEGER tmp3; FILETIME ft1; + BOOL ret; /* XXX: handling of timestamps outside Windows supported range. * How does Windows deal with dates before 1600? Does windows - * support all Ecmascript years (like -200000 and +200000)? + * support all ECMAScript years (like -200000 and +200000)? * Should equivalent year mapping be used here too? If so, use * a shared helper (currently integrated into timeval-to-parts). */ @@ -31024,7 +31840,11 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) { ft1.dwLowDateTime = tmp2.LowPart; ft1.dwHighDateTime = tmp2.HighPart; - FileTimeToSystemTime((const FILETIME *) &ft1, &st2); + ret = FileTimeToSystemTime((const FILETIME *) &ft1, &st2); + if (!ret) { + DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0")); + return 0; + } if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) { DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0")); return 0; @@ -31044,6 +31864,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_ FILETIME ft2; ULARGE_INTEGER tmp1; ULARGE_INTEGER tmp2; + BOOL ret; /* Do a similar computation to duk_bi_date_get_local_tzoffset_windows * but without accounting for daylight savings time. Use this on @@ -31059,9 +31880,17 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_ ft1.dwLowDateTime = tmp1.LowPart; ft1.dwHighDateTime = tmp1.HighPart; - FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2); + ret = FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2); + if (!ret) { + DUK_D(DUK_DPRINT("FileTimeToLocalFileTime() failed, return tzoffset 0")); + return 0; + } - FileTimeToSystemTime((const FILETIME *) &ft2, &st2); + ret = FileTimeToSystemTime((const FILETIME *) &ft2, &st2); + if (!ret) { + DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0")); + return 0; + } duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */ @@ -31098,7 +31927,7 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) { * * Size optimization note: it might seem that vararg multipurpose functions * like fin(), enc(), and dec() are not very size optimal, but using a single - * user-visible Ecmascript function saves a lot of run-time footprint; each + * user-visible ECMAScript function saves a lot of run-time footprint; each * Function instance takes >100 bytes. Using a shared native helper and a * 'magic' value won't save much if there are multiple Function instances * anyway. @@ -31493,7 +32322,7 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *de DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER | DUK_TYPE_MASK_OBJECT); - if (duk_get_prop_string(thr, 1, "stream")) { + if (duk_get_prop_literal(thr, 1, "stream")) { stream = duk_to_boolean(thr, -1); } } @@ -31508,6 +32337,7 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *de */ if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) { DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG); + DUK_WO_NORETURN(return 0;); } output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */ @@ -31585,7 +32415,7 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *de fail_type: DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED); - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return 0;); } /* @@ -31603,7 +32433,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) { } DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) { - duk_push_string(thr, "utf-8"); + duk_push_literal(thr, "utf-8"); return 1; } @@ -31625,6 +32455,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) { len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input); if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) { DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG); + DUK_WO_NORETURN(return 0;); } } @@ -31644,14 +32475,14 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) { DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */ /* XXX: duk_decode_string() is used to process the input - * string. For standard Ecmascript strings, represented + * string. For standard ECMAScript strings, represented * internally as CESU-8, this is fine. However, behavior * beyond CESU-8 is not very strict: codepoints using an * extended form of UTF-8 are also accepted, and invalid * codepoint sequences (which are allowed in Duktape strings) * are not handled as well as they could (e.g. invalid * continuation bytes may mask following codepoints). - * This is how Ecmascript code would also see such strings. + * This is how ECMAScript code would also see such strings. * Maybe replace duk_decode_string() with an explicit strict * CESU-8 decoder here? */ @@ -31679,7 +32510,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) { /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will * be backed by a dynamic buffer which differs from e.g. Uint8Arrays - * created as 'new Uint8Array(N)'. Ecmascript code won't see the + * created as 'new Uint8Array(N)'. ECMAScript code won't see the * difference but C code will. When bufferobjects are not supported, * returns a plain dynamic buffer. */ @@ -31701,10 +32532,10 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) { duk_to_string(thr, 0); } if (!duk_is_null_or_undefined(thr, 1)) { - if (duk_get_prop_string(thr, 1, "fatal")) { + if (duk_get_prop_literal(thr, 1, "fatal")) { fatal = duk_to_boolean(thr, -1); } - if (duk_get_prop_string(thr, 1, "ignoreBOM")) { + if (duk_get_prop_literal(thr, 1, "ignoreBOM")) { ignore_bom = duk_to_boolean(thr, -1); } } @@ -31719,7 +32550,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) { dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom; duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */ - duk_put_prop_string(thr, -2, DUK_INTERNAL_SYMBOL("Context")); + duk_put_prop_literal(thr, -2, DUK_INTERNAL_SYMBOL("Context")); return 0; } @@ -31727,7 +32558,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) { DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) { duk__decode_context *dec_ctx; duk_push_this(thr); - duk_get_prop_string(thr, -1, DUK_INTERNAL_SYMBOL("Context")); + duk_get_prop_literal(thr, -1, DUK_INTERNAL_SYMBOL("Context")); dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL); DUK_ASSERT(dec_ctx != NULL); return dec_ctx; @@ -31744,7 +32575,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *t /* Encoding is now fixed, so _Context lookup is only needed to * validate the 'this' binding (TypeError if not TextDecoder-like). */ - duk_push_string(thr, "utf-8"); + duk_push_literal(thr, "utf-8"); break; case 1: duk_push_boolean(thr, dec_ctx->fatal); @@ -31845,7 +32676,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) { duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME); if (duk_is_undefined(thr, -1)) { duk_pop(thr); - duk_push_string(thr, "Error"); + duk_push_literal(thr, "Error"); } else { duk_to_string(thr, -1); } @@ -31875,7 +32706,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) { duk_pop(thr); return 1; } - duk_push_string(thr, ": "); + duk_push_literal(thr, ": "); duk_insert(thr, -2); /* ... name ': ' message */ duk_concat(thr, 3); @@ -31944,13 +32775,13 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t o duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i); duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1)); d = duk_to_number_m1(thr); - pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32); - flags = (duk_uint_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32); + pc = duk_double_to_int_t(DUK_FMOD(d, DUK_DOUBLE_2TO32)); + flags = duk_double_to_uint_t(DUK_FLOOR(d / DUK_DOUBLE_2TO32)); t = (duk_small_int_t) duk_get_type(thr, -2); if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) { /* - * Ecmascript/native function call or lightfunc call + * ECMAScript/native function call or lightfunc call */ count_func++; @@ -32220,7 +33051,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) { duk_push_hstring_empty(thr); } else { duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */ - duk_push_string(thr, ","); + duk_push_literal(thr, ","); duk_insert(thr, 1); duk_join(thr, nargs - 1); } @@ -32232,11 +33063,11 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) { /* XXX: this placeholder is not always correct, but use for now. * It will fail in corner cases; see test-dev-func-cons-args.js. */ - duk_push_string(thr, "function("); + duk_push_literal(thr, "function("); duk_dup_1(thr); - duk_push_string(thr, "){"); + duk_push_literal(thr, "){"); duk_dup_0(thr); - duk_push_string(thr, "}"); + duk_push_literal(thr, "\n}"); /* Newline is important to handle trailing // comment. */ duk_concat(thr, 5); /* [ body formals source ] */ @@ -32254,7 +33085,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) { comp_flags); /* Force .name to 'anonymous' (ES2015). */ - duk_push_string(thr, "anonymous"); + duk_push_literal(thr, "anonymous"); duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); func = (duk_hcompfunc *) duk_known_hobject(thr, -1); @@ -32466,7 +33297,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) { if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) { duk_hboundfunc *h_boundtarget; - h_boundtarget = (duk_hboundfunc *) h_target; + h_boundtarget = (duk_hboundfunc *) (void *) h_target; /* The final function should always be non-bound, unless * there's a bug in the internals. Assert for it. @@ -32500,7 +33331,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) { DUK_DCERROR_RANGE_INVALID_COUNT(thr); } tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval)); - DUK_ASSERT(tv_res != NULL); + DUK_ASSERT(tv_res != NULL || bound_nargs == 0); DUK_ASSERT(h_bound->args == NULL); DUK_ASSERT(h_bound->nargs == 0); h_bound->args = tv_res; @@ -32540,7 +33371,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) { duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS); /* Function name and fileName (non-standard). */ - duk_push_string(thr, "bound "); /* ES2015 19.2.3.2. */ + duk_push_literal(thr, "bound "); /* ES2015 19.2.3.2. */ duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME); if (!duk_is_string_notsymbol(thr, -1)) { /* ES2015 has requirement to check that .name of target is a string @@ -32624,6 +33455,17 @@ DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) { fail_type: DUK_DCERROR_TYPE_INVALID_ARGS(thr); } + +#if defined(DUK_USE_SYMBOL_BUILTIN) +DUK_INTERNAL duk_ret_t duk_bi_function_prototype_hasinstance(duk_hthread *thr) { + /* This binding: RHS, stack index 0: LHS. */ + duk_bool_t ret; + + ret = duk_js_instanceof_ordinary(thr, DUK_GET_TVAL_POSIDX(thr, 0), DUK_GET_THIS_TVAL_PTR(thr)); + duk_push_boolean(thr, ret); + return 1; +} +#endif /* DUK_USE_SYMBOL_BUILTIN */ #line 1 "duk_bi_global.c" /* * Global object built-ins @@ -32827,6 +33669,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct uri_error: DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { @@ -32965,6 +33808,7 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct uri_error: DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); + DUK_WO_NORETURN(return;); } #if defined(DUK_USE_SECTION_B) @@ -33005,6 +33849,7 @@ DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, c esc_error: DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { @@ -33037,7 +33882,7 @@ DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, * Eval needs to handle both a "direct eval" and an "indirect eval". * Direct eval handling needs access to the caller's activation so that its * lexical environment can be accessed. A direct eval is only possible from - * Ecmascript code; an indirect eval call is possible also from C code. + * ECMAScript code; an indirect eval call is possible also from C code. * When an indirect eval call is made from C code, there may not be a * calling activation at all which needs careful handling. */ @@ -33076,7 +33921,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) { #if defined(DUK_USE_DEBUGGER_SUPPORT) /* NOTE: level is used only by the debugger and should never be present - * for an Ecmascript eval(). + * for an ECMAScript eval(). */ DUK_ASSERT(level == -2); /* by default, use caller's environment */ if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) { @@ -33570,6 +34415,7 @@ DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) { */ DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON, (long) (js_ctx->p - js_ctx->p_start)); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) { @@ -33985,7 +34831,7 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) { src_len = (duk_size_t) (p - js_ctx->p); buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len); DUK_ASSERT(buf != NULL); - DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len); + duk_memcpy((void *) buf, (const void *) js_ctx->p, src_len); duk_hex_decode(thr, -1); js_ctx->p = p + 1; /* skip '|' */ @@ -34076,6 +34922,7 @@ DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) { DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT); + DUK_WO_NORETURN(return;); } js_ctx->recursion_depth++; } @@ -34652,9 +35499,9 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly * and go forward one byte. This is of course very lossy, but allows some kind * of output to be produced even for internal strings which don't conform to - * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior - * does not violate the Ecmascript specification. The behavior is applied to - * all modes, including Ecmascript standard JSON. Because the current XUTF-8 + * XUTF-8. All standard ECMAScript strings are always CESU-8, so this behavior + * does not violate the ECMAScript specification. The behavior is applied to + * all modes, including ECMAScript standard JSON. Because the current XUTF-8 * decoding is not very strict, this behavior only really affects initial bytes * and truncated codepoints. * @@ -34791,7 +35638,7 @@ DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2. * For platforms where unaligned accesses are not allowed, shift 'dst' - * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result + * ahead by 1 byte to get alignment and then duk_memmove() the result * in place. The faster encoding loop makes up the difference. * There's always space for one extra byte because a terminator always * follows the hex data and that's been accounted for by the caller. @@ -34824,7 +35671,7 @@ DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size #if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) if (shift_dst) { q--; - DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe); + duk_memmove((void *) dst, (const void *) (dst + 1), 2 * len_safe); DUK_ASSERT(dst + 2 * len_safe == q); } #endif @@ -34900,7 +35747,7 @@ DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_d #if defined(DUK_USE_JC) { DUK_ASSERT(js_ctx->flag_ext_compatible); - DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */ + duk_memcpy((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */ q += 9; q = duk__enc_buffer_data_hex(buf_data, buf_len, q); *q++ = DUK_ASC_DOUBLEQUOTE; @@ -34973,7 +35820,7 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); - DUK_MEMZERO(buf, sizeof(buf)); + duk_memzero(buf, sizeof(buf)); /* The #if defined() clutter here needs to handle the three * cases: (1) JX+JC, (2) JX only, (3) JC only. @@ -35063,21 +35910,21 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t dept p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes); p_start = p; - DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len); + duk_memcpy((void *) p, (const void *) gap_data, (size_t) gap_len); p += gap_len; avail_bytes = gap_len; DUK_ASSERT(need_bytes >= gap_len); need_bytes -= gap_len; while (need_bytes >= avail_bytes) { - DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes); + duk_memcpy((void *) p, (const void *) p_start, (size_t) avail_bytes); p += avail_bytes; need_bytes -= avail_bytes; avail_bytes <<= 1; } DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */ - DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes); + duk_memcpy((void *) p, (const void *) p_start, (size_t) need_bytes); p += need_bytes; /*avail_bytes += need_bytes*/ @@ -35109,6 +35956,7 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_ if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) { DUK_DD(DUK_DDPRINT("slow path loop detect")); DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT); + DUK_WO_NORETURN(return;); } } if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { @@ -35118,6 +35966,7 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_ duk_dup_top(thr); /* -> [ ... voidp voidp ] */ if (duk_has_prop(thr, js_ctx->idx_loop)) { DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT); + DUK_WO_NORETURN(return;); } duk_push_true(thr); /* -> [ ... voidp true ] */ duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */ @@ -35129,6 +35978,7 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_ DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT); + DUK_WO_NORETURN(return;); } js_ctx->recursion_depth++; @@ -35726,12 +36576,14 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { DUK_DD(DUK_DDPRINT("fast path recursion limit")); DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT); + DUK_WO_NORETURN(return 0;); } for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) { if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) { DUK_DD(DUK_DDPRINT("fast path loop detect")); DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT); + DUK_WO_NORETURN(return 0;); } } @@ -36112,7 +36964,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du /* Error message doesn't matter: the error is ignored anyway. */ DUK_DD(DUK_DDPRINT("aborting fast path")); DUK_ERROR_INTERNAL(js_ctx->thr); - return 0; /* unreachable */ + DUK_WO_NORETURN(return 0;); } DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) { @@ -36161,7 +37013,7 @@ void duk_bi_json_parse_helper(duk_hthread *thr, (unsigned long) flags, (long) duk_get_top(thr))); - DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); + duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc)); js_ctx->thr = thr; #if defined(DUK_USE_EXPLICIT_NULL_INIT) /* nothing now */ @@ -36271,7 +37123,7 @@ void duk_bi_json_stringify_helper(duk_hthread *thr, * Context init */ - DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc)); + duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc)); js_ctx->thr = thr; #if defined(DUK_USE_EXPLICIT_NULL_INIT) js_ctx->h_replacer = NULL; @@ -36670,7 +37522,7 @@ DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk DUK_LOCAL double duk__fmin_fixed(double x, double y) { /* fmin() with args -0 and +0 is not guaranteed to return - * -0 as Ecmascript requires. + * -0 as ECMAScript requires. */ if (x == 0 && y == 0) { duk_double_union du1, du2; @@ -36697,7 +37549,7 @@ DUK_LOCAL double duk__fmin_fixed(double x, double y) { DUK_LOCAL double duk__fmax_fixed(double x, double y) { /* fmax() with args -0 and +0 is not guaranteed to return - * +0 as Ecmascript requires. + * +0 as ECMAScript requires. */ if (x == 0 && y == 0) { if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) { @@ -37161,6 +38013,7 @@ DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) { (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) { DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1))); DUK_ERROR_TYPE(thr, "number expected"); + DUK_WO_NORETURN(return 0.0;); } duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); DUK_ASSERT(duk_is_number(thr, -1)); @@ -37267,8 +38120,11 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) { duk_small_int_t c; duk_small_uint_t n2s_flags; - frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20); + /* In ES5.1 frac_digits is coerced first; in ES2015 the 'this number + * value' check is done first. + */ d = duk__push_this_number_plain(thr); + frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20); c = (duk_small_int_t) DUK_FPCLASSIFY(d); if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { @@ -37375,6 +38231,42 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) { return 1; } +/* + * ES2015 isFinite() etc + */ + +#if defined(DUK_USE_ES6) +DUK_INTERNAL duk_ret_t duk_bi_number_check_shared(duk_hthread *thr) { + duk_int_t magic; + duk_bool_t ret = 0; + + if (duk_is_number(thr, 0)) { + duk_double_t d; + + magic = duk_get_current_magic(thr); + d = duk_get_number(thr, 0); + + switch (magic) { + case 0: /* isFinite() */ + ret = duk_double_is_finite(d); + break; + case 1: /* isInteger() */ + ret = duk_double_is_integer(d); + break; + case 2: /* isNaN() */ + ret = duk_double_is_nan(d); + break; + default: /* isSafeInteger() */ + DUK_ASSERT(magic == 3); + ret = duk_double_is_safe_integer(d); + } + } + + duk_push_boolean(thr, ret); + return 1; +} +#endif /* DUK_USE_ES6 */ + #endif /* DUK_USE_NUMBER_BUILTIN */ #line 1 "duk_bi_object.c" /* @@ -37386,12 +38278,9 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) { /* Needed even when Object built-in disabled. */ DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) { duk_tval *tv; + tv = DUK_HTHREAD_THIS_PTR(thr); - /* XXX: This is not entirely correct anymore; in ES2015 the - * default lookup should use @@toStringTag to come up with - * e.g. [object Symbol]. - */ - duk_push_class_string_tval(thr, tv); + duk_push_class_string_tval(thr, tv, 0 /*avoid_side_effects*/); return 1; } @@ -37896,7 +38785,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *th DUK_ASSERT(duk_get_hobject(thr, 2) != NULL); /* - * Validate and convert argument property descriptor (an Ecmascript + * Validate and convert argument property descriptor (an ECMAScript * object) into a set of defprop_flags and possibly property value, * getter, and/or setter values on the value stack. * @@ -38174,6 +39063,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); + DUK_WO_NORETURN(return 0;); } duk_get_prototype(thr, -1); @@ -38301,37 +39191,37 @@ DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) { DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) { DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) { DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) { DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) { DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) { DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) { DUK_ERROR_TYPE(thr, "unimplemented"); - return 0; + DUK_WO_NORETURN(return 0;); } #endif /* DUK_USE_PROMISE_BUILTIN */ @@ -38366,6 +39256,7 @@ DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h h = duk_get_hstring(thr, -1); if (h == NULL) { DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr); + DUK_WO_NORETURN(return;); } if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) { @@ -38474,6 +39365,7 @@ DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) { if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) { /* XXX: [[Get]] receiver currently unsupported */ DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return 0;); } /* [ target key receiver? ...? ] */ @@ -38517,6 +39409,7 @@ DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) { if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) { /* XXX: [[Set]] receiver currently unsupported */ DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return 0;); } /* [ target key value receiver? ...? ] */ @@ -38651,7 +39544,7 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) { /* This must be generic in ES2015 and later. */ DUK_ASSERT_TOP(thr, 0); duk_push_this(thr); - duk_push_string(thr, "/"); + duk_push_literal(thr, "/"); duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE); duk_dup_m2(thr); /* another "/" */ duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS); @@ -38715,7 +39608,7 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) { if (magic != 16 /* .source */) { return 0; } - duk_push_string(thr, "(?:)"); /* .source handled by switch-case */ + duk_push_literal(thr, "(?:)"); /* .source handled by switch-case */ re_flags = 0; } else { DUK_DCERROR_TYPE_INVALID_ARGS(thr); @@ -38787,6 +39680,7 @@ DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t i if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) { DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return NULL;); } h = duk_to_hstring(thr, idx); DUK_ASSERT(h != NULL); @@ -38833,14 +39727,14 @@ DUK_LOCAL duk_int_t duk__str_search_shared(duk_hthread *thr, duk_hstring *h_this while (p <= p_end && p >= p_start) { t = *p; - /* For Ecmascript strings, this check can only match for + /* For ECMAScript strings, this check can only match for * initial UTF-8 bytes (not continuation bytes). For other * strings all bets are off. */ if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { - DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { + DUK_ASSERT(q_blen > 0); + if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { return cpos; } } @@ -39022,13 +39916,37 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) { */ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) { + duk_hstring *h; duk_int_t pos; /* XXX: faster implementation */ - (void) duk_push_this_coercible_to_string(thr); + h = duk_push_this_coercible_to_string(thr); + DUK_ASSERT(h != NULL); + pos = duk_to_int(thr, 0); - duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) (pos + 1)); + + if (sizeof(duk_size_t) >= sizeof(duk_uint_t)) { + /* Cast to duk_size_t works in this case: + * - If pos < 0, (duk_size_t) pos will always be + * >= max_charlen, and result will be the empty string + * (see duk_substring()). + * - If pos >= 0, pos + 1 cannot wrap. + */ + DUK_ASSERT((duk_size_t) DUK_INT_MIN >= DUK_HSTRING_MAX_BYTELEN); + DUK_ASSERT((duk_size_t) DUK_INT_MAX + 1U > (duk_size_t) DUK_INT_MAX); + duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U); + } else { + /* If size_t is smaller than int, explicit bounds checks + * are needed because an int may wrap multiple times. + */ + if (DUK_UNLIKELY(pos < 0 || (duk_uint_t) pos >= (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h))) { + duk_push_hstring_empty(thr); + } else { + duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U); + } + } + return 1; } @@ -39418,7 +40336,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) { while (p <= p_end) { DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { + if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { duk_dup_0(thr); h_match = duk_known_hstring(thr, -1); #if defined(DUK_USE_REGEXP_SUPPORT) @@ -39799,7 +40717,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) { while (p <= p_end) { DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */ - if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { + if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { /* never an empty match, so step 13.c.iii can't be triggered */ goto found; } @@ -40112,12 +41030,14 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) { /* Temporary fixed buffer, later converted to string. */ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len); + DUK_ASSERT(buf != NULL); src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + DUK_ASSERT(src != NULL); #if defined(DUK_USE_PREFER_SIZE) p = buf; while (count-- > 0) { - DUK_MEMCPY((void *) p, (const void *) src, input_blen); /* copy size may be zero */ + duk_memcpy((void *) p, (const void *) src, input_blen); /* copy size may be zero, but pointers are valid */ p += input_blen; } #else /* DUK_USE_PREFER_SIZE */ @@ -40134,12 +41054,12 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) { (long) result_len)); if (remain <= copy_size) { /* If result_len is zero, this case is taken and does - * a zero size copy. + * a zero size copy (with valid pointers). */ - DUK_MEMCPY((void *) p, (const void *) src, remain); + duk_memcpy((void *) p, (const void *) src, remain); break; } else { - DUK_MEMCPY((void *) p, (const void *) src, copy_size); + duk_memcpy((void *) p, (const void *) src, copy_size); p += copy_size; } @@ -40194,8 +41114,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr) h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2); prefix_len = (h1_len <= h2_len ? h1_len : h2_len); - /* Zero size compare not an issue with DUK_MEMCMP. */ - rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1), + rc = (duk_small_int_t) duk_memcmp((const void *) DUK_HSTRING_GET_DATA(h1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) prefix_len); @@ -40245,7 +41164,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread * if (duk_is_undefined(thr, 1)) { if (magic) { - p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search; + p_cmp_start = p_cmp_start + DUK_HSTRING_GET_BYTELEN(h) - blen_search; } else { /* p_cmp_start already OK */ } @@ -40276,7 +41195,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread * result = 0; if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) && (duk_size_t) (p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) { - if (DUK_MEMCMP((const void *) p_cmp_start, + if (duk_memcmp((const void *) p_cmp_start, (const void *) DUK_HSTRING_GET_DATA(h_search), (size_t) blen_search) == 0) { result = 1; @@ -40351,9 +41270,10 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) { * +1 0xff after unique suffix for symbols with undefined description */ buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1); + DUK_ASSERT(buf != NULL); p = buf + 1; DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */ - DUK_MEMCPY((void *) p, (const void *) desc, len); + duk_memcpy_unsafe((void *) p, (const void *) desc, len); p += len; if (magic == 0) { /* Symbol(): create unique symbol. Use two 32-bit values @@ -40525,7 +41445,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) { * * The thread must be in resumable state, either (a) new thread which hasn't * yet started, or (b) a thread which has previously yielded. This method - * must be called from an Ecmascript function. + * must be called from an ECMAScript function. * * Args: * - thread @@ -40551,8 +41471,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) { DUK_ASSERT(thr->heap->curr_thread == thr); thr_resume = duk_require_hthread(thr, 0); - is_error = (duk_small_uint_t) duk_to_boolean(thr, 2); - duk_set_top(thr, 2); + DUK_ASSERT(duk_get_top(thr) == 3); + is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr); + DUK_ASSERT(duk_get_top(thr) == 2); /* [ thread value ] */ @@ -40572,7 +41493,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) { caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { - DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code")); + DUK_DD(DUK_DDPRINT("resume state invalid: caller must be ECMAScript code")); goto state_error; } @@ -40600,7 +41521,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) { DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE); - /* The initial function must be an Ecmascript function (but + /* The initial function must be an ECMAScript function (but * can be bound). We must make sure of that before we longjmp * because an error in the RESUME handler call processing will * not be handled very cleanly. @@ -40679,7 +41600,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) { * The thread must be in yieldable state: it must have a resumer, and there * must not be any yield-preventing calls (native calls and constructor calls, * currently) in the thread's call stack (otherwise a resume would not be - * possible later). This method must be called from an Ecmascript function. + * possible later). This method must be called from an ECMAScript function. * * Args: * - value @@ -40700,8 +41621,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) { DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->heap->curr_thread == thr); - is_error = (duk_small_uint_t) duk_to_boolean(thr, 1); - duk_set_top(thr, 1); + DUK_ASSERT(duk_get_top(thr) == 2); + is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr); + DUK_ASSERT(duk_get_top(thr) == 1); /* [ value ] */ @@ -40727,7 +41649,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) { caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent); if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { - DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code")); + DUK_DD(DUK_DDPRINT("yield state invalid: caller must be ECMAScript code")); goto state_error; } @@ -40826,7 +41748,7 @@ DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffe } else { copylen = length; } - DUK_MEMCPY(fb->buffer + fb->offset, buffer, copylen); + duk_memcpy_unsafe(fb->buffer + fb->offset, buffer, copylen); fb->offset += copylen; } @@ -40913,7 +41835,7 @@ DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) { * (excluding the null terminator). If retval == buffer size, * output was truncated (except for corner cases). * - * * Output format is intentionally different from Ecmascript + * * Output format is intentionally different from ECMAScript * formatting requirements, as formatting here serves debugging * of internals. * @@ -41699,7 +42621,7 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha const char *p_end = p + DUK_STRLEN(format); duk_int_t retval; - DUK_MEMZERO(&fb, sizeof(fb)); + duk_memzero(&fb, sizeof(fb)); fb.buffer = (duk_uint8_t *) str; fb.length = size; fb.offset = 0; @@ -41724,7 +42646,7 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha * understand. See man 3 printf. */ - DUK_MEMZERO(&st, sizeof(st)); + duk_memzero(&st, sizeof(st)); st.fb = &fb; st.depth = 0; st.depth_limit = 1; @@ -41791,8 +42713,8 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha /* format is too large, abort */ goto format_error; } - DUK_MEMZERO(fmtbuf, sizeof(fmtbuf)); - DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen); + duk_memzero(fmtbuf, sizeof(fmtbuf)); + duk_memcpy(fmtbuf, p_begfmt, fmtlen); /* assume exactly 1 arg, which is why '*' is forbidden; arg size still * depends on type though. @@ -41897,7 +42819,8 @@ DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_u duk_uint8_t *p = (duk_uint8_t *) buf; duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1); - DUK_MEMZERO(buf, buf_size); + DUK_ASSERT(buf != NULL); + duk_memzero(buf, buf_size); for (i = 0; i < fptr_size; i++) { duk_int_t left = (duk_int_t) (p_end - p); @@ -42236,6 +43159,7 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_ DUK_ASSERT(thr != NULL); heap = thr->heap; DUK_ASSERT(heap != NULL); + DUK_ASSERT(data != NULL); if (heap->dbg_read_cb == NULL) { DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length)); @@ -42273,7 +43197,7 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_ return; fail: - DUK_MEMZERO((void *) data, (size_t) length); + duk_memzero((void *) data, (size_t) length); } DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) { @@ -42886,7 +43810,7 @@ DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) { (unsigned int) du2.uc[4], (unsigned int) du2.uc[5], (unsigned int) du2.uc[6], (unsigned int) du2.uc[7])); - if (DUK_MEMCMP((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) { + if (duk_memcmp((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) { duk_debug_write_int(thr, i32); } else { DUK_DBLUNION_DOUBLE_HTON(&du1); @@ -42995,9 +43919,9 @@ DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) { duk_debug_write_int(thr, 0); } else { duk_push_tval(thr, &act->tv_func); - duk_get_prop_string(thr, -1, "fileName"); + duk_get_prop_literal(thr, -1, "fileName"); duk__debug_write_hstring_safe_top(thr); - duk_get_prop_string(thr, -2, "name"); + duk_get_prop_literal(thr, -2, "name"); duk__debug_write_hstring_safe_top(thr); duk_pop_3(thr); /* Report next pc/line to be executed. */ @@ -43042,7 +43966,7 @@ DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) { act = thr->callstack_curr; if (act != NULL) { duk_push_tval(thr, &act->tv_func); - duk_get_prop_string(thr, -1, "fileName"); + duk_get_prop_literal(thr, -1, "fileName"); duk__debug_write_hstring_safe_top(thr); pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act); duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc)); @@ -43519,7 +44443,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) { fun = DUK_ACT_GET_FUNC(act); if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) { /* Direct eval requires that there's a current - * activation and it is an Ecmascript function. + * activation and it is an ECMAScript function. * When Eval is executed from e.g. cooperate API * call we'll need to do an indirect eval instead. */ @@ -44185,7 +45109,7 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) { duk_hboundfunc *h_bfun; - h_bfun = (duk_hboundfunc *) h_obj; + h_bfun = (duk_hboundfunc *) (void *) h_obj; duk__debug_getinfo_flags_key(thr, "target"); duk_debug_write_tval(thr, &h_bfun->target); @@ -44662,7 +45586,7 @@ DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is - * guaranteed to be a non-NULL Ecmascript function. + * guaranteed to be a non-NULL ECMAScript function. */ DUK_ASSERT(act->curr_pc == NULL || (fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun))); @@ -44758,11 +45682,10 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_ DUK_ASSERT(h != NULL); move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1); - if (move_size > 0) { - DUK_MEMMOVE((void *) b, - (const void *) (b + 1), - (size_t) move_size); - } + duk_memmove((void *) b, + (const void *) (b + 1), + (size_t) move_size); + heap->dbg_breakpoint_count--; heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; @@ -44849,7 +45772,7 @@ DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) { * * Error augmentation may throw an internal error (e.g. alloc error). * - * Ecmascript allows throwing any values, so all values cannot be + * ECMAScript allows throwing any values, so all values cannot be * augmented. Currently, the built-in augmentation at error creation * only augments error values which are Error instances (= have the * built-in Error.prototype in their prototype chain) and are also @@ -45189,7 +46112,6 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c DUK_UNREF(pc); DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ - act = NULL; /* invalidated by pushes, so get out of the way */ duk_push_hobject(thr, func); @@ -45405,12 +46327,15 @@ DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) { /* #include duk_internal.h -> already included */ #if defined(DUK_USE_PREFER_SIZE) +DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_minimal(duk_hthread *thr)); DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) { (void) duk_fatal(thr, "uncaught error"); + DUK_WO_NORETURN(return;); } #endif #if 0 +DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_readable(duk_hthread *thr)); DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) { const char *summary; char buf[DUK_USE_FATAL_MAXLEN]; @@ -45419,10 +46344,12 @@ DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) { DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary); buf[sizeof(buf) - 1] = (char) 0; (void) duk_fatal(thr, (const char *) buf); + DUK_WO_NORETURN(return;); } #endif #if !defined(DUK_USE_PREFER_SIZE) +DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_error_aware(duk_hthread *thr)); DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) { const char *summary; char buf[DUK_USE_FATAL_MAXLEN]; @@ -45432,6 +46359,7 @@ DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) { DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary); buf[sizeof(buf) - 1] = (char) 0; (void) duk_fatal(thr, (const char *) buf); + DUK_WO_NORETURN(return;); } #endif @@ -45469,14 +46397,9 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) { DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld", (long) thr->heap->pf_prevent_count)); -#if !defined(DUK_USE_CPP_EXCEPTIONS) /* If we don't have a jmpbuf_ptr, there is little we can do except * cause a fatal error. The caller's expectation is that we never * return. - * - * With C++ exceptions we now just propagate an uncaught error - * instead of invoking the fatal error handler. Because there's - * a dummy jmpbuf for C++ exceptions now, this could be changed. */ if (!thr->heap->lj.jmpbuf_ptr) { DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T", @@ -45490,16 +46413,12 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) { #endif DUK_UNREACHABLE(); } -#endif /* DUK_USE_CPP_EXCEPTIONS */ #if defined(DUK_USE_CPP_EXCEPTIONS) - { - duk_internal_exception exc; /* dummy */ - throw exc; - } -#else /* DUK_USE_CPP_EXCEPTIONS */ + throw duk_internal_exception(); /* dummy */ +#else DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb); -#endif /* DUK_USE_CPP_EXCEPTIONS */ +#endif DUK_UNREACHABLE(); } @@ -45680,10 +46599,10 @@ DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_t } #line 1 "duk_error_throw.c" /* - * Create and throw an Ecmascript error object based on a code and a message. + * Create and throw an ECMAScript error object based on a code and a message. * - * Used when we throw errors internally. Ecmascript generated error objects - * are created by Ecmascript code, and the throwing is handled by the bytecode + * Used when we throw errors internally. ECMAScript generated error objects + * are created by ECMAScript code, and the throwing is handled by the bytecode * executor. */ @@ -45839,7 +46758,7 @@ DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t r */ duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc); - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return;); } #line 1 "duk_hbuffer_alloc.c" /* @@ -45891,10 +46810,10 @@ DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk /* zero everything unless requested not to do so */ #if defined(DUK_USE_ZERO_BUFFER_DATA) - DUK_MEMZERO((void *) res, + duk_memzero((void *) res, (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size); #else - DUK_MEMZERO((void *) res, header_size); + duk_memzero((void *) res, header_size); #endif if (flags & DUK_BUF_FLAG_EXTERNAL) { @@ -45941,7 +46860,7 @@ DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL); } } else { - *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1); + *out_bufdata = (void *) ((duk_hbuffer_fixed *) (void *) res + 1); } DUK_HBUFFER_SET_SIZE(res, size); @@ -46001,6 +46920,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, if (new_size > DUK_HBUFFER_MAX_BYTELEN) { DUK_ERROR_RANGE(thr, "buffer too long"); + DUK_WO_NORETURN(return;); } /* @@ -46029,7 +46949,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, if (new_size > prev_size) { DUK_ASSERT(new_size - prev_size > 0); #if defined(DUK_USE_ZERO_BUFFER_DATA) - DUK_MEMZERO((void *) ((char *) res + prev_size), + duk_memzero((void *) ((char *) res + prev_size), (duk_size_t) (new_size - prev_size)); #endif } @@ -46038,6 +46958,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res); } else { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return;); } DUK_ASSERT(res != NULL || new_size == 0); @@ -46141,7 +47062,7 @@ DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) { * functions in the callstack. */ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { - duk_hboundfunc *f = (duk_hboundfunc *) h; + duk_hboundfunc *f = (duk_hboundfunc *) (void *) h; DUK_FREE(heap, f->args); } @@ -46539,7 +47460,7 @@ DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) { duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ duk_small_uint_t i; - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); + duk_memzero(&bd_ctx, sizeof(bd_ctx)); bd->data = (const duk_uint8_t *) duk_strings_data; bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH; @@ -46760,7 +47681,8 @@ DUK_LOCAL void duk__dump_type_sizes(void) { DUK__DUMPSZ(duk_heap); DUK__DUMPSZ(duk_activation); DUK__DUMPSZ(duk_catcher); - DUK__DUMPSZ(duk_strcache); + DUK__DUMPSZ(duk_strcache_entry); + DUK__DUMPSZ(duk_litcache_entry); DUK__DUMPSZ(duk_ljstate); DUK__DUMPSZ(duk_fixedbuffer); DUK__DUMPSZ(duk_bitdecoder_ctx); @@ -46969,7 +47891,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, * Zero the struct, and start initializing roughly in order */ - DUK_MEMZERO(res, sizeof(*res)); + duk_memzero(res, sizeof(*res)); #if defined(DUK_USE_ASSERTIONS) res->heap_initializing = 1; #endif @@ -47054,7 +47976,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, /* XXX: use the pointer as a seed for now: mix in time at least */ - /* The casts through duk_intptr_t is to avoid the following GCC warning: + /* The casts through duk_uintptr_t is to avoid the following GCC warning: * * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] * @@ -47065,7 +47987,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED)); res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED; #else /* DUK_USE_ROM_STRINGS */ - res->hash_seed = (duk_uint32_t) (duk_intptr_t) res; + res->hash_seed = (duk_uint32_t) (duk_uintptr_t) res; #if !defined(DUK_USE_STRHASH_DENSE) res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */ #endif @@ -47105,17 +48027,17 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, #if defined(DUK_USE_STRTAB_PTRCOMP) /* zero assumption */ - DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize); + duk_memzero(res->strtable16, sizeof(duk_uint16_t) * st_initsize); #else #if defined(DUK_USE_EXPLICIT_NULL_INIT) { - duk_small_uint_t i; + duk_uint32_t i; for (i = 0; i < st_initsize; i++) { res->strtable[i] = NULL; } } #else - DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize); + duk_memzero(res->strtable, sizeof(duk_hstring *) * st_initsize); #endif /* DUK_USE_EXPLICIT_NULL_INIT */ #endif /* DUK_USE_STRTAB_PTRCOMP */ @@ -47125,13 +48047,30 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, #if defined(DUK_USE_EXPLICIT_NULL_INIT) { - duk_small_uint_t i; + duk_uint_t i; for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { res->strcache[i].h = NULL; } } #endif + /* + * Init litcache + */ +#if defined(DUK_USE_LITCACHE_SIZE) + DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0); + DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE)); +#if defined(DUK_USE_EXPLICIT_NULL_INIT) + { + duk_uint_t i; + for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) { + res->litcache[i].addr = NULL; + res->litcache[i].h = NULL; + } + } +#endif +#endif /* DUK_USE_LITCACHE_SIZE */ + /* XXX: error handling is incomplete. It would be cleanest if * there was a setjmp catchpoint, so that all init code could * freely throw errors. If that were the case, the return code @@ -47203,7 +48142,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, { duk_uint64_t tmp_u64; tmp_u64 = 0; - DUK_MEMCPY((void *) &tmp_u64, + duk_memcpy((void *) &tmp_u64, (const void *) &res, (size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *))); res->rnd_state[1] ^= tmp_u64; @@ -47961,7 +48900,7 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) { duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop); #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { - duk_hboundfunc *f = (duk_hboundfunc *) h; + duk_hboundfunc *f = (duk_hboundfunc *) (void *) h; DUK_ASSERT_HBOUNDFUNC_VALID(f); duk__mark_tval(heap, &f->target); duk__mark_tval(heap, &f->this_binding); @@ -48435,7 +49374,8 @@ DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep duk_hstring *next; next = h->hdr.h_next; - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { + if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) + { DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); count_keep++; prev = h; @@ -48444,13 +49384,26 @@ DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep count_free++; #endif + /* For pinned strings the refcount has been + * bumped. We could unbump it here before + * freeing, but that's actually not necessary + * except for assertions. + */ +#if 0 + if (DUK_HSTRING_HAS_PINNED_LITERAL(h)) { + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) > 0U); + DUK_HSTRING_DECREF_NORZ(heap->heap_thread, h); + DUK_HSTRING_CLEAR_PINNED_LITERAL(h); + } +#endif #if defined(DUK_USE_REFERENCE_COUNTING) /* Non-zero refcounts should not happen for unreachable strings, * because we refcount finalize all unreachable objects which * should have decreased unreachable string refcounts to zero - * (even for cycles). + * (even for cycles). However, pinned strings have a +1 bump. */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); + DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == + DUK_HSTRING_HAS_PINNED_LITERAL(h) ? 1U : 0U); #endif /* Deal with weak references first. */ @@ -48653,6 +49606,26 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_ *out_count_keep = count_keep; } +/* + * Litcache helpers. + */ + +#if defined(DUK_USE_LITCACHE_SIZE) +DUK_LOCAL void duk__wipe_litcache(duk_heap *heap) { + duk_uint_t i; + duk_litcache_entry *e; + + e = heap->litcache; + for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) { + e->addr = NULL; + /* e->h does not need to be invalidated: when e->addr is + * NULL, e->h is considered garbage. + */ + e++; + } +} +#endif /* DUK_USE_LITCACHE_SIZE */ + /* * Object compaction. * @@ -48837,6 +49810,7 @@ DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) { DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { duk_bool_t count_ok; + duk_size_t expect_refc; /* The refcount check only makes sense for reachable objects on * heap_allocated or string table, after the sweep phase. Prior to @@ -48853,7 +49827,11 @@ DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { */ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); - count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount); + expect_refc = hdr->h_assert_refcount; + if (DUK_HEAPHDR_IS_STRING(hdr) && DUK_HSTRING_HAS_PINNED_LITERAL((duk_hstring *) hdr)) { + expect_refc++; + } + count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == expect_refc); if (!count_ok) { DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO", (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr), @@ -48890,6 +49868,22 @@ DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) { } } #endif /* DUK_USE_REFERENCE_COUNTING */ + +#if defined(DUK_USE_LITCACHE_SIZE) +DUK_LOCAL void duk__assert_litcache_nulls(duk_heap *heap) { + duk_uint_t i; + duk_litcache_entry *e; + + e = heap->litcache; + for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) { + /* Entry addresses were NULLed before mark-and-sweep, check + * that they're still NULL afterwards to ensure no pointers + * were recorded through any side effects. + */ + DUK_ASSERT(e->addr == NULL); + } +} +#endif /* DUK_USE_LITCACHE_SIZE */ #endif /* DUK_USE_ASSERTIONS */ /* @@ -48910,10 +49904,13 @@ DUK_LOCAL void duk__dump_stats(duk_heap *heap) { DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld", (long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count, (long) heap->stats_ms_emergency_count)); - DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, resize_check=%ld, resize_grow=%ld, resize_shrink=%ld", + DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, " + "resize_check=%ld, resize_grow=%ld, resize_shrink=%ld, " + "litcache_hit=%ld, litcache_miss=%ld, litcache_pin=%ld", (long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss, (long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow, - (long) heap->stats_strtab_resize_shrink)); + (long) heap->stats_strtab_resize_shrink, (long) heap->stats_strtab_litcache_hit, + (long) heap->stats_strtab_litcache_miss, (long) heap->stats_strtab_litcache_pin)); DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld", (long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array)); DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld", @@ -49053,6 +50050,9 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) duk__clear_assert_refcounts(heap); +#endif +#if defined(DUK_USE_LITCACHE_SIZE) + duk__wipe_litcache(heap); #endif duk__mark_roots_heap(heap); /* Mark main reachability roots. */ #if defined(DUK_USE_REFERENCE_COUNTING) @@ -49159,6 +50159,9 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags */ duk__assert_valid_refcounts(heap); #endif /* DUK_USE_REFERENCE_COUNTING */ +#if defined(DUK_USE_LITCACHE_SIZE) + duk__assert_litcache_nulls(heap); +#endif /* DUK_USE_LITCACHE_SIZE */ #endif /* DUK_USE_ASSERTIONS */ /* @@ -49349,8 +50352,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) { res = DUK_ALLOC(heap, size); if (DUK_LIKELY(res != NULL)) { - /* assume memset with zero size is OK */ - DUK_MEMZERO(res, size); + duk_memzero(res, size); } return res; } @@ -49364,7 +50366,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) return res; } DUK_ERROR_ALLOC_FAILED(thr); - return NULL; + DUK_WO_NORETURN(return NULL;); } DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) { @@ -49376,7 +50378,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_ return res; } DUK_ERROR_ALLOC_FAILED(thr); - return NULL; + DUK_WO_NORETURN(return NULL;); } /* @@ -49941,7 +50943,7 @@ DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop); #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { - duk_hboundfunc *f = (duk_hboundfunc *) h; + duk_hboundfunc *f = (duk_hboundfunc *) (void *) h; DUK_ASSERT_HBOUNDFUNC_VALID(f); DUK_TVAL_DECREF_NORZ(thr, &f->target); DUK_TVAL_DECREF_NORZ(thr, &f->this_binding); @@ -50632,9 +51634,9 @@ DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) { */ DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) { - duk_small_int_t i; + duk_uint_t i; for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; + duk_strcache_entry *c = heap->strcache + i; if (c->h == h) { DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p", (void *) h, (void *) heap)); @@ -50706,9 +51708,9 @@ DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) { duk_heap *heap; - duk_strcache *sce; + duk_strcache_entry *sce; duk_uint_fast32_t byte_offset; - duk_small_int_t i; + duk_uint_t i; duk_bool_t use_cache; duk_uint_fast32_t dist_start, dist_end, dist_sce; duk_uint_fast32_t char_length; @@ -50759,14 +51761,14 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):")); for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; + duk_strcache_entry *c = heap->strcache + i; DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld", (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx)); } #endif for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; + duk_strcache_entry *c = heap->strcache + i; if (c->h == h) { sce = c; @@ -50895,10 +51897,10 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t * C <- sce ==> B * D D */ - duk_strcache tmp; + duk_strcache_entry tmp; tmp = *sce; - DUK_MEMMOVE((void *) (&heap->strcache[1]), + duk_memmove((void *) (&heap->strcache[1]), (const void *) (&heap->strcache[0]), (size_t) (((char *) sce) - ((char *) &heap->strcache[0]))); heap->strcache[0] = tmp; @@ -50908,7 +51910,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):")); for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { - duk_strcache *c = heap->strcache + i; + duk_strcache_entry *c = heap->strcache + i; DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld", (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx)); } @@ -50919,7 +51921,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t scan_error: DUK_ERROR_INTERNAL(thr); - return 0; + DUK_WO_NORETURN(return 0;); } #line 1 "duk_heap_stringtable.c" /* @@ -50978,7 +51980,7 @@ DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) { return; } - DUK_MEMZERO((void *) count_len, sizeof(count_len)); + duk_memzero((void *) count_len, sizeof(count_len)); for (i = 0; i < heap->st_size; i++) { h = DUK__HEAPPTR_DEC16(heap, strtable[i]); count_chain = 0; @@ -51090,7 +52092,7 @@ DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } - DUK_MEMZERO(res, sizeof(duk_hstring_external)); + duk_memzero(res, sizeof(duk_hstring_external)); #if defined(DUK_USE_EXPLICIT_NULL_INIT) DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); #endif @@ -51110,14 +52112,14 @@ DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, if (DUK_UNLIKELY(res == NULL)) { goto alloc_error; } - DUK_MEMZERO(res, sizeof(duk_hstring)); + duk_memzero(res, sizeof(duk_hstring)); #if defined(DUK_USE_EXPLICIT_NULL_INIT) DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); data_tmp = (duk_uint8_t *) (res + 1); - DUK_MEMCPY(data_tmp, str, blen); + duk_memcpy(data_tmp, str, blen); data_tmp[blen] = (duk_uint8_t) 0; data = (const duk_uint8_t *) data_tmp; } @@ -51610,11 +52612,12 @@ DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_ui } lookup_hash &= 0xff; - curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); + curr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); while (curr != NULL) { + /* Unsafe memcmp() because for zero blen, str may be NULL. */ if (strhash == DUK_HSTRING_GET_HASH(curr) && blen == DUK_HSTRING_GET_BYTELEN(curr) && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { + duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx", curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr))); return curr; @@ -51634,6 +52637,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin /* Preliminaries. */ + /* XXX: maybe just require 'str != NULL' even for zero size? */ DUK_ASSERT(heap != NULL); DUK_ASSERT(blen == 0 || str != NULL); DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */ @@ -51652,7 +52656,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin while (h != NULL) { if (DUK_HSTRING_GET_HASH(h) == strhash && DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { + duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { /* Found existing entry. */ DUK_STATS_INC(heap, stats_strtab_intern_hit); return h; @@ -51725,10 +52729,67 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, con res = duk_heap_strtable_intern(thr->heap, str, blen); if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return NULL;); } return res; } +#if defined(DUK_USE_LITCACHE_SIZE) +DUK_LOCAL duk_uint_t duk__strtable_litcache_key(const duk_uint8_t *str, duk_uint32_t blen) { + duk_uintptr_t key; + + DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0); + DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE)); + + key = (duk_uintptr_t) blen ^ (duk_uintptr_t) str; + key &= (duk_uintptr_t) (DUK_USE_LITCACHE_SIZE - 1); /* Assumes size is power of 2. */ + /* Due to masking, cast is in 32-bit range. */ + DUK_ASSERT(key <= DUK_UINT_MAX); + return (duk_uint_t) key; +} + +DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { + duk_uint_t key; + duk_litcache_entry *ent; + duk_hstring *h; + + /* Fast path check: literal exists in literal cache. */ + key = duk__strtable_litcache_key(str, blen); + ent = thr->heap->litcache + key; + if (ent->addr == str) { + DUK_DD(DUK_DDPRINT("intern check for cached, pinned literal: str=%p, blen=%ld -> duk_hstring %!O", + (const void *) str, (long) blen, (duk_heaphdr *) ent->h)); + DUK_ASSERT(ent->h != NULL); + DUK_ASSERT(DUK_HSTRING_HAS_PINNED_LITERAL(ent->h)); + DUK_STATS_INC(thr->heap, stats_strtab_litcache_hit); + return ent->h; + } + + /* Intern and update (overwrite) cache entry. */ + h = duk_heap_strtable_intern_checked(thr, str, blen); + ent->addr = str; + ent->h = h; + DUK_STATS_INC(thr->heap, stats_strtab_litcache_miss); + + /* Pin the duk_hstring until the next mark-and-sweep. This means + * litcache entries don't need to be invalidated until the next + * mark-and-sweep as their target duk_hstring is not freed before + * the mark-and-sweep happens. The pin remains even if the literal + * cache entry is overwritten, and is still useful to avoid string + * table traffic. + */ + if (!DUK_HSTRING_HAS_PINNED_LITERAL(h)) { + DUK_DD(DUK_DDPRINT("pin duk_hstring because it is a literal: %!O", (duk_heaphdr *) h)); + DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); + DUK_HSTRING_INCREF(thr, h); + DUK_HSTRING_SET_PINNED_LITERAL(h); + DUK_STATS_INC(thr->heap, stats_strtab_litcache_pin); + } + + return h; +} +#endif /* DUK_USE_LITCACHE_SIZE */ + DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { duk_hstring *res; @@ -51738,6 +52799,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, res = duk_heap_strtable_intern_u32(thr->heap, val); if (DUK_UNLIKELY(res == NULL)) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return NULL;); } return res; } @@ -52044,7 +53106,7 @@ DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hob if (!res) { return NULL; } - DUK_MEMZERO(res, sizeof(duk_hboundfunc)); + duk_memzero(res, sizeof(duk_hboundfunc)); duk__init_object_parts(heap, hobject_flags, &res->obj); @@ -52086,7 +53148,7 @@ DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t if (DUK_UNLIKELY(res == NULL)) { return NULL; } - DUK_MEMZERO(res, sizeof(duk_hthread)); + duk_memzero(res, sizeof(duk_hthread)); duk__init_object_parts(heap, hobject_flags, &res->obj); @@ -52128,6 +53190,7 @@ DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags); if (res == NULL) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return NULL;); } return res; } @@ -52344,7 +53407,7 @@ DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk * are very often in order already. */ if (idx != idx_insert) { - DUK_MEMMOVE((void *) (keys + idx_insert + 1), + duk_memmove((void *) (keys + idx_insert + 1), (const void *) (keys + idx_insert), ((size_t) (idx - idx_insert) * sizeof(duk_hstring *))); keys[idx_insert] = h_curr; @@ -52828,7 +53891,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t } /* - * Get enumerated keys in an Ecmascript array. Matches Object.keys() behavior + * Get enumerated keys in an ECMAScript array. Matches Object.keys() behavior * described in E5 Section 15.2.3.14. */ @@ -52915,6 +53978,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, d break; } else { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); + DUK_WO_NORETURN(return 0;); } } h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); @@ -52999,7 +54063,7 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr (long) hdr[hdr_index + 1])); #endif - DUK_MEMZERO(be_ctx, sizeof(*be_ctx)); + duk_memzero(be_ctx, sizeof(*be_ctx)); be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset; be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH; @@ -53110,7 +54174,7 @@ DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk * Iterate the bitstream (line diffs) until PC is reached */ - DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx)); + duk_memzero(bd_ctx, sizeof(*bd_ctx)); bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset; bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset); @@ -53170,7 +54234,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_i */ duk_get_prop_stridx(thr, idx_func, DUK_STRIDX_INT_PC2LINE); - pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(thr, -1); + pc2line = (duk_hbuffer_fixed *) (void *) duk_get_hbuffer(thr, -1); if (pc2line != NULL) { DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line)); line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc); @@ -53239,7 +54303,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_i #define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED /* Valstack space that suffices for all local calls, excluding any recursion - * into Ecmascript or Duktape/C calls (Proxy, getters, etc). + * into ECMAScript or Duktape/C calls (Proxy, getters, etc). */ #define DUK__VALSTACK_SPACE 10 @@ -53789,6 +54853,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr, if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) { DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return;); } /* @@ -53992,18 +55057,14 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr, } else { array_copy_size = sizeof(duk_tval) * new_a_size; } - if (array_copy_size > 0) { - /* Avoid zero copy with an invalid pointer. If obj->p is NULL, - * the 'new_a' pointer will be invalid which is not allowed even - * when copy size is zero. - */ - DUK_ASSERT(new_a != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); - DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0); - DUK_MEMCPY((void *) new_a, - (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), - array_copy_size); - } + + DUK_ASSERT(new_a != NULL || array_copy_size == 0U); + DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || array_copy_size == 0U); + DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0 || array_copy_size == 0U); + duk_memcpy_unsafe((void *) new_a, + (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), + array_copy_size); + for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { duk_tval *tv = &new_a[i]; DUK_TVAL_SET_UNUSED(tv); @@ -54028,7 +55089,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr, /* fill new_h with u32 0xff = UNUSED */ DUK_ASSERT(new_h_size > 0); - DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); + duk_memset(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */ @@ -54138,6 +55199,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr, #endif DUK_ERROR_ALLOC_FAILED(thr); + DUK_WO_NORETURN(return;); } /* @@ -54615,7 +55677,7 @@ DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, /* This is not strictly necessary, but avoids compiler warnings; e.g. * gcc won't reliably detect that no uninitialized data is read below. */ - DUK_MEMZERO((void *) &tv, sizeof(duk_tval)); + duk_memzero((void *) &tv, sizeof(duk_tval)); if (duk_hobject_get_internal_value(heap, obj, &tv)) { duk_hstring *h; @@ -54803,7 +55865,7 @@ DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject } /* - * Ecmascript compliant [[GetOwnProperty]](P), for internal use only. + * ECMAScript compliant [[GetOwnProperty]](P), for internal use only. * * If property is found: * - Fills descriptor fields to 'out_desc' @@ -55178,7 +56240,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobje } /* - * Ecmascript compliant [[GetProperty]](P), for internal use only. + * ECMAScript compliant [[GetProperty]](P), for internal use only. * * If property is found: * - Fills descriptor fields to 'out_desc' @@ -55235,6 +56297,7 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h break; } else { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); + DUK_WO_NORETURN(return 0;); } } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); @@ -55516,7 +56579,7 @@ DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ /* - * GETPROP: Ecmascript property read. + * GETPROP: ECMAScript property read. */ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) { @@ -55570,7 +56633,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s", duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); #endif - return 0; + DUK_WO_NORETURN(return 0;); + break; } case DUK_TAG_BOOLEAN: { @@ -55726,6 +56790,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, !DUK_TVAL_IS_UNDEFINED(tv_hook); if (datadesc_reject || accdesc_reject) { DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); + DUK_WO_NORETURN(return 0;); } duk_pop_2_unsafe(thr); @@ -55917,6 +56982,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, */ if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); + DUK_WO_NORETURN(return 0;); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); } while (curr != NULL); @@ -55987,6 +57053,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, DUK_HOBJECT_HAS_STRICT(h)) { /* XXX: sufficient to check 'strict', assert for 'is function' */ DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ); + DUK_WO_NORETURN(return 0;); } } } @@ -55999,7 +57066,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, } /* - * HASPROP: Ecmascript property existence check ("in" operator). + * HASPROP: ECMAScript property existence check ("in" operator). * * Interestingly, the 'in' operator does not do any coercion of * the target object. @@ -56065,6 +57132,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, /* Note: unconditional throw */ DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject")); DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); + DUK_WO_NORETURN(return 0;); } /* XXX: fast path for arrays? */ @@ -56089,7 +57157,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_push_hobject(thr, h_target); /* target */ duk_push_tval(thr, tv_key); /* P */ duk_call_method(thr, 2 /*nargs*/); - tmp_bool = duk_to_boolean(thr, -1); + tmp_bool = duk_to_boolean_top_pop(thr); if (!tmp_bool) { /* Target object must be checked for a conflicting * non-configurable property. @@ -56108,11 +57176,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */ DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */ DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); + DUK_WO_NORETURN(return 0;); } } } - duk_pop_2_unsafe(thr); /* [ key trap_result ] -> [] */ + duk_pop_unsafe(thr); /* [ key ] -> [] */ return tmp_bool; } @@ -56204,7 +57273,7 @@ DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tv /* Refuse to update an Array's 'length' to a value outside the * 32-bit range. Negative zero is accepted as zero. */ - res = (duk_uint32_t) d; + res = duk_double_to_uint32_t(d); if ((duk_double_t) res != d) { goto fail_range; } @@ -56213,7 +57282,7 @@ DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tv fail_range: DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH); - return 0; /* unreachable */ + DUK_WO_NORETURN(return 0;); } /* Delete elements required by a smaller length, taking into account @@ -56482,9 +57551,9 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject } /* - * PUTPROP: Ecmascript property write. + * PUTPROP: ECMAScript property write. * - * Unlike Ecmascript primitive which returns nothing, returns 1 to indicate + * Unlike ECMAScript primitive which returns nothing, returns 1 to indicate * success and 0 to indicate failure (assuming throw is not set). * * This is an extremely tricky function. Some examples: @@ -56571,7 +57640,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s", duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); #endif - return 0; + DUK_WO_NORETURN(return 0;); + break; } case DUK_TAG_BOOLEAN: { @@ -56675,8 +57745,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_push_tval(thr, tv_val); /* V */ duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */ duk_call_method(thr, 4 /*nargs*/); - tmp_bool = duk_to_boolean(thr, -1); - duk_pop_nodecref_unsafe(thr); + tmp_bool = duk_to_boolean_top_pop(thr); if (!tmp_bool) { goto fail_proxy_rejected; } @@ -56708,6 +57777,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, (desc.set == NULL); if (datadesc_reject || accdesc_reject) { DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); + DUK_WO_NORETURN(return 0;); } duk_pop_2_unsafe(thr); @@ -57007,6 +58077,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, */ if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); + DUK_WO_NORETURN(return 0;); } curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); } while (curr != NULL); @@ -57356,6 +58427,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects")); if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); + DUK_WO_NORETURN(return 0;); } /* Note: no key on stack */ return 0; @@ -57370,6 +58442,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s", duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); #endif + DUK_WO_NORETURN(return 0;); } duk_pop_unsafe(thr); /* remove key */ return 0; @@ -57378,6 +58451,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_DDD(DUK_DDDPRINT("result: error, not extensible")); if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE); + DUK_WO_NORETURN(return 0;); } duk_pop_unsafe(thr); /* remove key */ return 0; @@ -57386,6 +58460,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_DDD(DUK_DDDPRINT("result: error, not writable")); if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE); + DUK_WO_NORETURN(return 0;); } duk_pop_unsafe(thr); /* remove key */ return 0; @@ -57395,6 +58470,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_DDD(DUK_DDDPRINT("result: error, not writable")); if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE); + DUK_WO_NORETURN(return 0;); } return 0; #endif @@ -57403,6 +58479,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful")); if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); + DUK_WO_NORETURN(return 0;); } duk_pop_unsafe(thr); /* remove key */ return 0; @@ -57411,6 +58488,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter")); if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED); + DUK_WO_NORETURN(return 0;); } duk_pop_unsafe(thr); /* remove key */ return 0; @@ -57419,13 +58497,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_DDD(DUK_DDDPRINT("result: error, internal")); if (throw_flag) { DUK_ERROR_INTERNAL(thr); + DUK_WO_NORETURN(return 0;); } duk_pop_unsafe(thr); /* remove key */ return 0; } /* - * Ecmascript compliant [[Delete]](P, Throw). + * ECMAScript compliant [[Delete]](P, Throw). */ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) { @@ -57579,12 +58658,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); + DUK_WO_NORETURN(return 0;); } return 0; } /* - * DELPROP: Ecmascript property deletion. + * DELPROP: ECMAScript property deletion. */ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) { @@ -57639,8 +58719,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_push_hobject(thr, h_target); /* target */ duk_dup_m4(thr); /* P */ duk_call_method(thr, 2 /*nargs*/); - tmp_bool = duk_to_boolean(thr, -1); - duk_pop_nodecref_unsafe(thr); + tmp_bool = duk_to_boolean_top_pop(thr); if (!tmp_bool) { goto fail_proxy_rejected; /* retval indicates delete failed */ } @@ -57665,6 +58744,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, if (desc_reject) { /* unconditional */ DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); + DUK_WO_NORETURN(return 0;); } } rc = 1; /* success */ @@ -57748,12 +58828,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s", duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); #endif - return 0; + DUK_WO_NORETURN(return 0;); #if defined(DUK_USE_ES6_PROXY) fail_proxy_rejected: if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); + DUK_WO_NORETURN(return 0;); } duk_set_top_unsafe(thr, entry_top); return 0; @@ -57762,6 +58843,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, fail_not_configurable: if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); + DUK_WO_NORETURN(return 0;); } duk_set_top_unsafe(thr, entry_top); return 0; @@ -57901,7 +58983,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob error_virtual: /* share error message */ error_internal: DUK_ERROR_INTERNAL(thr); - return; + DUK_WO_NORETURN(return;); } /* @@ -57981,7 +59063,7 @@ DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *ob val = duk_to_number_m1(thr); duk_pop_3_unsafe(thr); - /* This isn't part of Ecmascript semantics; return a value within + /* This isn't part of ECMAScript semantics; return a value within * duk_size_t range, or 0 otherwise. */ if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) { @@ -58092,7 +59174,7 @@ DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *th * NormalizePropertyDescriptor() related helper. * * Internal helper which validates and normalizes a property descriptor - * represented as an Ecmascript object (e.g. argument to defineProperty()). + * represented as an ECMAScript object (e.g. argument to defineProperty()). * The output of this conversion is a set of defprop_flags and possibly * some values pushed on the value stack to (1) ensure borrowed pointers * remain valid, and (2) avoid unnecessary pops for footprint reasons. @@ -58142,7 +59224,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr, if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) { is_data_desc = 1; - if (duk_to_boolean(thr, -1)) { + if (duk_to_boolean_top_pop(thr)) { defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE; } else { defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE; @@ -58194,7 +59276,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr, } if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) { - if (duk_to_boolean(thr, -1)) { + if (duk_to_boolean_top_pop(thr)) { defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE; } else { defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE; @@ -58202,7 +59284,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr, } if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) { - if (duk_to_boolean(thr, -1)) { + if (duk_to_boolean_top_pop(thr)) { defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE; } else { defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE; @@ -58223,6 +59305,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr, type_error: DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR); + DUK_WO_NORETURN(return;); } /* @@ -58231,7 +59314,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr, * * Inlines all [[DefineOwnProperty]] exotic behaviors. * - * Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not + * Note: ECMAScript compliant [[DefineOwnProperty]](P, Desc, Throw) is not * implemented directly, but Object.defineProperty() serves its purpose. * We don't need the [[DefineOwnProperty]] internally and we don't have a * property descriptor with 'missing values' so it's easier to avoid it @@ -59104,6 +60187,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr, fail_not_extensible: if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE); + DUK_WO_NORETURN(return 0;); } return 0; @@ -59111,6 +60195,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr, fail_not_configurable: if (throw_flag) { DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); + DUK_WO_NORETURN(return 0;); } return 0; } @@ -59166,6 +60251,7 @@ DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_ho if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject")); DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); + DUK_WO_NORETURN(return;); } #endif @@ -59314,7 +60400,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk (const void *) p_start, (const void *) p_end, (const void *) p)); - /* For invalid UTF-8 (never happens for standard Ecmascript strings) + /* For invalid UTF-8 (never happens for standard ECMAScript strings) * return U+FFFD replacement character. */ if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) { @@ -59470,7 +60556,7 @@ DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const c if (len != DUK_HSTRING_GET_BYTELEN(h)) { return 0; } - if (DUK_MEMCMP((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) { + if (duk_memcmp((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) { return 1; } return 0; @@ -59508,7 +60594,7 @@ DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr if (!thr->valstack) { goto fail; } - DUK_MEMZERO(thr->valstack, alloc_size); + duk_memzero(thr->valstack, alloc_size); thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM; thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE; thr->valstack_bottom = thr->valstack; @@ -59613,7 +60699,7 @@ DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { props = DUK_ALLOC_CHECKED(thr, alloc_size); DUK_ASSERT(props != NULL); DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL); - DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); + duk_memcpy((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); /* XXX: keep property attributes or tweak them here? * Properties will now be non-configurable even when they're @@ -59740,7 +60826,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS)); - DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); + duk_memzero(&bd_ctx, sizeof(bd_ctx)); bd->data = (const duk_uint8_t *) duk_builtins_data; bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH; @@ -59982,11 +61068,9 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { * signaled using a single flag bit in the bitstream. */ - if (duk_bd_decode_flag(bd)) { - defprop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS); - } else { - defprop_flags = DUK_PROPDESC_FLAGS_WC; - } + defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd, + DUK__PROP_FLAGS_BITS, + (duk_uint32_t) DUK_PROPDESC_FLAGS_WC); defprop_flags |= DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | @@ -60091,6 +61175,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { #if defined(DUK_USE_LIGHTFUNC_BUILTINS) duk_small_int_t lightfunc_eligible; #endif + duk_small_uint_t defprop_flags; duk__push_stridx_or_string(thr, bd); h_key = duk_known_hstring(thr, -1); @@ -60210,10 +61295,19 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { lightfunc_skip: #endif - /* XXX: So far all ES builtins are 'wc' but e.g. - * performance.now() should be 'wec'. - */ - duk_xdef_prop(thr, (duk_idx_t) i, DUK_PROPDESC_FLAGS_WC); + defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd, + DUK__PROP_FLAGS_BITS, + (duk_uint32_t) DUK_PROPDESC_FLAGS_WC); + defprop_flags |= DUK_DEFPROP_FORCE | + DUK_DEFPROP_HAVE_VALUE | + DUK_DEFPROP_HAVE_WRITABLE | + DUK_DEFPROP_HAVE_ENUMERABLE | + DUK_DEFPROP_HAVE_CONFIGURABLE; + DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE); + DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE); + DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE); + + duk_def_prop(thr, (duk_idx_t) i, defprop_flags); /* [ (builtin objects) ] */ } @@ -60286,7 +61380,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { "f" #endif " " - /* Low memory options */ + /* Low memory/performance options */ #if defined(DUK_USE_STRTAB_PTRCOMP) "s" #endif @@ -60326,6 +61420,9 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { * are in ROM. */ "Z" +#endif +#if defined(DUK_USE_LITCACHE_SIZE) + "l" #endif " " /* Object property allocation layout */ @@ -60903,8 +62000,8 @@ DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { /* Use DUK_ALLOC_RAW() to avoid side effects. */ new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size); if (new_ptr != NULL) { - DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size); - DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size); + duk_memcpy((void *) new_ptr, (const void *) thr->valstack, alloc_size); + duk_memset((void *) thr->valstack, 0x55, alloc_size); DUK_FREE_CHECKED(thr, (void *) thr->valstack); thr->valstack = new_ptr; thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off); @@ -60923,7 +62020,7 @@ DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { /* #include duk_internal.h -> already included */ -/* Ecmascript modulus ('%') does not match IEEE 754 "remainder" operation +/* ECMAScript modulus ('%') does not match IEEE 754 "remainder" operation * (implemented by remainder() in C99) but does seem to match ANSI C fmod(). * Compare E5 Section 11.5.3 and "man fmod". */ @@ -60977,9 +62074,9 @@ DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) { /* Shared helper for Math.pow() and exponentiation operator. */ DUK_INTERNAL double duk_js_arith_pow(double x, double y) { - /* The ANSI C pow() semantics differ from Ecmascript. + /* The ANSI C pow() semantics differ from ECMAScript. * - * E.g. when x==1 and y is +/- infinite, the Ecmascript required + * E.g. when x==1 and y is +/- infinite, the ECMAScript required * result is NaN, while at least Linux pow() returns 1. */ @@ -61060,7 +62157,7 @@ DUK_INTERNAL double duk_js_arith_pow(double x, double y) { * * duk_handle_call_unprotected(): * - * - Unprotected call to Ecmascript or Duktape/C function, from native + * - Unprotected call to ECMAScript or Duktape/C function, from native * code or bytecode executor. * * - Also handles Ecma-to-Ecma calls which reuses a currently running @@ -61114,6 +62211,7 @@ DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthre DUK_D(DUK_DPRINT("call prevented because C recursion limit reached")); DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT); + DUK_WO_NORETURN(return;); } DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) { @@ -61149,6 +62247,7 @@ DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread */ DUK_D(DUK_DPRINT("call prevented because call stack limit reached")); DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT); + DUK_WO_NORETURN(return;); } DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) { @@ -61562,6 +62661,7 @@ DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uin if (DUK_UNLIKELY(proxy_invariant != 0U)) { /* Proxy 'construct' return value invariant violated. */ DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr); + DUK_WO_NORETURN(return;); } /* XXX: direct value stack access */ duk_pop(thr); @@ -61622,7 +62722,7 @@ DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr, duk_tval *tv_args; duk_tval *tv_gap; - h_bound = (duk_hboundfunc *) func; + h_bound = (duk_hboundfunc *) (void *) func; tv_args = h_bound->args; len = h_bound->nargs; DUK_ASSERT(len == 0 || tv_args != NULL); @@ -61662,6 +62762,7 @@ DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr, } else { /* Shouldn't happen, so ugly error is enough. */ DUK_ERROR_INTERNAL(thr); + DUK_WO_NORETURN(return;); } DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); @@ -61837,11 +62938,13 @@ DUK_LOCAL duk_bool_t duk__handle_specialfuncs_for_call(duk_hthread *thr, duk_idx if (top < idx_func + 3) { /* argArray is a mandatory argument for Reflect.construct(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); + DUK_WO_NORETURN(return 0;); } if (top > idx_func + 3) { if (!duk_strict_equals(thr, idx_func, idx_func + 3)) { /* XXX: [[Construct]] newTarget currently unsupported */ DUK_ERROR_UNSUPPORTED(thr); + DUK_WO_NORETURN(return 0;); } duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */ } @@ -62378,6 +63481,7 @@ DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *th if (duk_hobject_find_existing_entry_tval_ptr(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_HTHREAD_STRING_INT_TARGET(thr)) != NULL) { duk_push_tval(thr, tv_func); (void) duk_throw(thr); + DUK_WO_NORETURN(return NULL;); } } #endif @@ -62391,8 +63495,7 @@ DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *th #else DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); #endif - DUK_UNREACHABLE(); - return NULL; /* never executed */ + DUK_WO_NORETURN(return NULL;); not_constructable: /* For now GETPROPC delayed error not needed for constructor calls. */ @@ -62405,8 +63508,7 @@ DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *th #else DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE); #endif - DUK_UNREACHABLE(); - return NULL; /* never executed */ + DUK_WO_NORETURN(return NULL;); } /* @@ -62430,6 +63532,7 @@ DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_re idx_rcbase = duk_get_top(thr) - num_actual_rets; /* base of known return values */ if (DUK_UNLIKELY(idx_rcbase < 0)) { DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC); + DUK_WO_NORETURN(return;); } DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: " @@ -62564,9 +63667,10 @@ DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr * - Disable StepOut processing for the activation unwind because * we reuse the activation, see: * https://github.com/svaarala/duktape/issues/1684. - * - Disable line change pause flag permanently (if set) because - * it would no longer be relevant, see: - * https://github.com/svaarala/duktape/issues/1726. + * - Disable line change pause flag permanently if act == dbg_pause_act + * (if set) because it would no longer be relevant, see: + * https://github.com/svaarala/duktape/issues/1726, + * https://github.com/svaarala/duktape/issues/1786. * - Check for function entry (e.g. StepInto) pause flag here, because * the executor pause check won't trigger due to shared activation, see: * https://github.com/svaarala/duktape/issues/1726. @@ -62587,9 +63691,12 @@ DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr DUK_ASSERT(thr->callstack_top > 0); DUK_ASSERT(thr->callstack_curr != NULL); #if defined(DUK_USE_DEBUGGER_SUPPORT) + if (act == thr->heap->dbg_pause_act) { + thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE; + } + prev_pause_act = thr->heap->dbg_pause_act; thr->heap->dbg_pause_act = NULL; - thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE; if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) { DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)")); duk_debug_set_paused(thr->heap); @@ -62729,10 +63836,10 @@ DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr, * Update return value stack index of current activation (if any). * * Although it might seem this is not necessary (bytecode executor - * does this for Ecmascript-to-Ecmascript calls; other calls are + * does this for ECMAScript-to-ECMAScript calls; other calls are * handled here), this turns out to be necessary for handling yield - * and resume. For them, an Ecmascript-to-native call happens, and - * the Ecmascript call's retval_byteoff must be set for things to work. + * and resume. For them, an ECMAScript-to-native call happens, and + * the ECMAScript call's retval_byteoff must be set for things to work. */ act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval); @@ -62939,16 +64046,16 @@ DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) { thread_state_error: DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)", (long) thr->state); - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return;); } /* * Main unprotected call handler, handles: * - * - All combinations of native/Ecmascript caller and native/Ecmascript + * - All combinations of native/ECMAScript caller and native/ECMAScript * target. * - * - Optimized Ecmascript-to-Ecmascript call where call handling only + * - Optimized ECMAScript-to-ECMAScript call where call handling only * sets up a new duk_activation but reuses an existing bytecode executor * (the caller) without native recursion. * @@ -62997,7 +64104,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, DUK_STATS_INC(thr->heap, stats_call_all); /* If a tail call: - * - an Ecmascript activation must be on top of the callstack + * - an ECMAScript activation must be on top of the callstack * - there cannot be any catch stack entries that would catch * a return */ @@ -63102,6 +64209,12 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, * Because 'act' is not zeroed, all fields must be filled in. */ + /* Should not be necessary, but initialize to silence warnings. */ + act = NULL; + nargs = 0; + nregs = 0; + vs_min_bytes = 0; + #if defined(DUK_USE_TAILCALL) use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL); if (use_tailcall) { @@ -63149,7 +64262,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, * compiler; the compiled function's parent env will contain * the (immutable) binding already. * - * This handling is now identical for C and Ecmascript functions. + * This handling is now identical for C and ECMAScript functions. * C functions always have the 'NEWENV' flag set, so their * environment record initialization is delayed (which is good). * @@ -63196,7 +64309,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { /* - * Ecmascript call. + * ECMAScript call. */ DUK_ASSERT(func != NULL); @@ -63290,9 +64403,10 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, ; } else if (rc < 0) { duk_error_throw_from_negative_rc(thr, rc); - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return 0;); } else { DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC); + DUK_WO_NORETURN(return 0;); } } DUK_ASSERT(thr->ptr_curr_pc == NULL); @@ -63380,7 +64494,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see * GH-303. Only needed for success path, error path always causes a * breakpoint recheck in the executor. It would be enough to set this - * only when returning to an Ecmascript activation, but setting the flag + * only when returning to an ECMAScript activation, but setting the flag * on every return should have no ill effect. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) @@ -63492,6 +64606,7 @@ DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr, if (DUK_UNLIKELY(rc < 0)) { duk_error_throw_from_negative_rc(thr, rc); + DUK_WO_NORETURN(return;); } DUK_ASSERT(rc >= 0); @@ -63769,7 +64884,10 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr, retval = DUK_EXEC_ERROR; } #if defined(DUK_USE_CPP_EXCEPTIONS) - catch (std::exception &exc) { + catch (duk_fatal_exception &exc) { + DUK_D(DUK_DPRINT("rethrow duk_fatal_exception")); + throw; + } catch (std::exception &exc) { const char *what = exc.what(); DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); DUK_STATS_INC(thr->heap, stats_safecall_throw); @@ -63779,6 +64897,7 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr, DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)")); try { DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what); + DUK_WO_NORETURN(return 0;); } catch (duk_internal_exception exc) { DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception")); DUK_UNREF(exc); @@ -63801,6 +64920,7 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr, DUK_STATS_INC(thr->heap, stats_safecall_throw); try { DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)"); + DUK_WO_NORETURN(return 0;); } catch (duk_internal_exception exc) { DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception")); DUK_UNREF(exc); @@ -63860,7 +64980,7 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr, /* * Property-based call (foo.noSuch()) error setup: replace target function * on stack top with a specially tagged (hidden Symbol) error which gets - * thrown in call handling at the proper spot to follow Ecmascript semantics. + * thrown in call handling at the proper spot to follow ECMAScript semantics. */ #if defined(DUK_USE_VERBOSE_ERRORS) @@ -63919,7 +65039,7 @@ DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthrea #undef DUK__AUGMENT_CALL_RELAX_COUNT #line 1 "duk_js_compiler.c" /* - * Ecmascript compiler. + * ECMAScript compiler. * * Parses an input string and generates a function template result. * Compilation may happen in multiple contexts (global code, eval @@ -64155,9 +65275,9 @@ DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue * DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem); DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id); -DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof); +DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof, duk_bool_t regexp_after); -DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token); +DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_bool_t regexp_after, duk_small_int_t expect_token); DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx); DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags); DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags); @@ -64329,6 +65449,7 @@ DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) { DUK_ASSERT(comp_ctx->recursion_depth >= 0); if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) { DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT); + DUK_WO_NORETURN(return;); } comp_ctx->recursion_depth++; } @@ -64383,15 +65504,20 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e comp_ctx->curr_func.reject_regexp_in_adv = 0; regexp = 0; } + if (comp_ctx->curr_func.allow_regexp_in_adv) { + comp_ctx->curr_func.allow_regexp_in_adv = 0; + regexp = 1; + } if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) { DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld", (long) expect, (long) comp_ctx->curr_token.t)); DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); + DUK_WO_NORETURN(return;); } /* make current token the previous; need to fiddle with valstack "backing store" */ - DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token)); + duk_memcpy(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token)); duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx); duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx); @@ -64439,7 +65565,7 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) { entry_top = duk_get_top(thr); - DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */ + duk_memzero(func, sizeof(*func)); /* intentional overlap with earlier memzero */ #if defined(DUK_USE_EXPLICIT_NULL_INIT) func->h_name = NULL; func->h_consts = NULL; @@ -64686,7 +65812,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) { (long) code_size, (long) data_size)); duk_push_fixed_buffer_nozero(thr, data_size); - h_data = (duk_hbuffer_fixed *) duk_known_hbuffer(thr, -1); + h_data = (duk_hbuffer_fixed *) (void *) duk_known_hbuffer(thr, -1); DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data); DUK_HEAPHDR_INCREF(thr, h_data); @@ -64891,7 +66017,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) { */ #if 0 - duk_push_string(thr, "XXX"); + duk_push_literal(thr, "XXX"); duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE); #endif } @@ -65090,6 +66216,7 @@ DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) { fail_bc_limit: DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT); + DUK_WO_NORETURN(return;); } /* Update function min/max line from current token. Needed to improve @@ -65374,6 +66501,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f error_outofregs: DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); + DUK_WO_NORETURN(return;); } /* For many of the helpers below it'd be technically correct to add @@ -65472,6 +66600,7 @@ DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_fl error_outofregs: DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) { @@ -65506,6 +66635,7 @@ DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, du error_outofregs: DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val, duk_small_uint_t op_flags) { @@ -65603,6 +66733,7 @@ DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump fail_bc_limit: DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT); + DUK_WO_NORETURN(return;); } /* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional @@ -65658,6 +66789,7 @@ DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)", (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname)); DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); + DUK_WO_NORETURN(return;); } instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname); } else { @@ -65849,6 +66981,7 @@ DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_i if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */ DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT); + DUK_WO_NORETURN(return 0;); } /* maintain highest 'used' temporary, needed to figure out nregs of function */ @@ -65908,6 +67041,7 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) { if (n > DUK__MAX_CONSTS) { DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT); + DUK_WO_NORETURN(return 0;); } DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld", @@ -66081,6 +67215,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx, } } } /* end switch */ + goto fail_internal; /* never here */ } case DUK_ISPEC_REGCONST: { if (forced_reg >= 0) { @@ -66113,12 +67248,13 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx, return x->regconst; } default: { - break; + break; /* never here */ } } + fail_internal: DUK_ERROR_INTERNAL(thr); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) { @@ -66191,7 +67327,10 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x break; } case DUK_OP_DIV: { - d3 = d1 / d2; + /* Division-by-zero is undefined + * behavior, so rely on a helper. + */ + d3 = duk_double_div(d1, d2); break; } case DUK_OP_EXP: { @@ -66218,7 +67357,7 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x } } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) { /* Inline string concatenation. No need to check for - * symbols, as all inputs are valid Ecmascript strings. + * symbols, as all inputs are valid ECMAScript strings. */ duk_dup(thr, x->x1.valstack_idx); duk_dup(thr, x->x2.valstack_idx); @@ -66316,7 +67455,7 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x } DUK_ERROR_INTERNAL(thr); - return; + DUK_WO_NORETURN(return;); } /* evaluate to plain value, no forced register (temp/bound reg both ok) */ @@ -66548,6 +67687,7 @@ DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) { DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL); + DUK_WO_NORETURN(return;); } } @@ -66677,6 +67817,7 @@ DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring */ if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) { DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL); + DUK_WO_NORETURN(return;); } else { DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not " "allow a continue -> continue lookup deeper in label stack")); @@ -66686,6 +67827,7 @@ DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring /* XXX: match flag is awkward, rework */ if (!match) { DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL); + DUK_WO_NORETURN(return;); } DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld", @@ -66875,6 +68017,7 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL); + DUK_WO_NORETURN(return;); } typedef struct { @@ -67151,13 +68294,14 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r #endif DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY); - duk__advance(comp_ctx); + duk__advance(comp_ctx); /* No RegExp after object literal. */ duk__ivalue_regconst(res, st.reg_obj); return; syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL); + DUK_WO_NORETURN(return;); } /* Parse argument list. Arguments are written to temps starting from @@ -67201,7 +68345,7 @@ DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue } /* eat the right paren */ - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* RegExp mode does not matter. */ DUK_DDD(DUK_DDDPRINT("end parsing arguments")); @@ -67334,7 +68478,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */ - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* No RegExp after parenthesized expression. */ comp_ctx->curr_func.allow_in = prev_allow_in; comp_ctx->curr_func.paren_level--; return; @@ -67469,6 +68613,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { if (comp_ctx->curr_func.is_strict) { DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER); + DUK_WO_NORETURN(return;); } DUK__SETTEMP(comp_ctx, temp_at_entry); @@ -67633,7 +68778,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { } /* end switch */ DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); - return; + DUK_WO_NORETURN(return;); unary: { @@ -67737,10 +68882,12 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { #if defined(DUK_USE_ES6) syntax_error_newtarget: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_NEWTARGET); + DUK_WO_NORETURN(return;); #endif syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION); + DUK_WO_NORETURN(return;); } /* XXX: add flag to indicate whether caller cares about return value; this @@ -67795,6 +68942,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i /* NB: must accept reserved words as property name */ if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) { DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER); + DUK_WO_NORETURN(return;); } res->t = DUK_IVAL_PROP; @@ -68224,7 +69372,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok)); DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); - return; + DUK_WO_NORETURN(return;); #if 0 /* XXX: shared handling for 'duk__expr_lhs'? */ @@ -68454,7 +69602,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i * one instruction, so use explicit PC computation. */ DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based =")); - DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (duk_size_t) (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr)); + DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * (duk_int_t) sizeof(duk_compiler_instr)); reg_src = reg_varbind; } else { DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS")); @@ -68714,11 +69862,11 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION); - return; + DUK_WO_NORETURN(return;); syntax_error_lvalue: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE); - return; + DUK_WO_NORETURN(return;); } DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) { @@ -68783,7 +69931,7 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_ (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level)); - DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc)); + duk_memzero(&tmp_alloc, sizeof(tmp_alloc)); tmp->x1.valstack_idx = duk_get_top(thr); tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1; duk_push_undefined(thr); @@ -68803,6 +69951,7 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_ DUK_DDD(DUK_DDDPRINT("empty expression")); if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) { DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED); + DUK_WO_NORETURN(return;); } duk_push_undefined(thr); duk__ivalue_plain_fromstack(comp_ctx, res); @@ -68841,6 +69990,7 @@ DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_sma if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) { DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED); + DUK_WO_NORETURN(return;); } } @@ -69033,6 +70183,7 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) { @@ -69264,7 +70415,8 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, } DUK__SETTEMP(comp_ctx, temp_reset); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + comp_ctx->curr_func.allow_regexp_in_adv = 1; + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ pc_l3 = duk__get_current_pc(comp_ctx); duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); @@ -69355,7 +70507,8 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); DUK__SETTEMP(comp_ctx, temp_reset); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + comp_ctx->curr_func.allow_regexp_in_adv = 1; + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ pc_l3 = duk__get_current_pc(comp_ctx); duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); @@ -69404,6 +70557,7 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { @@ -69445,7 +70599,7 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re duk__advance(comp_ctx); duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* RegExp mode does not matter. */ duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch)); @@ -69570,7 +70724,8 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re } DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY); - duk__advance(comp_ctx); + comp_ctx->curr_func.allow_regexp_in_adv = 1; + duk__advance(comp_ctx); /* Allow RegExp as part of next stmt. */ /* default case control flow patchup; note that if pc_prevcase < 0 * (i.e. no case clauses), control enters default case automatically. @@ -69603,6 +70758,7 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { @@ -69622,7 +70778,8 @@ DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */ DUK__SETTEMP(comp_ctx, temp_reset); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + comp_ctx->curr_func.allow_regexp_in_adv = 1; + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); @@ -69658,7 +70815,7 @@ DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, d DUK_DDD(DUK_DDDPRINT("begin parsing do statement")); - duk__advance(comp_ctx); /* eat 'do' */ + duk__advance(comp_ctx); /* Eat 'do'; allow RegExp as part of next stmt. */ pc_start = duk__get_current_pc(comp_ctx); duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); @@ -69672,6 +70829,7 @@ DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, d duk__emit_jump(comp_ctx, pc_start); /* no need to reset temps, as we're finished emitting code */ + comp_ctx->curr_func.allow_regexp_in_adv = 1; /* Allow RegExp as part of next stmt. */ duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */ @@ -69701,7 +70859,8 @@ DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res pc_jump_false = duk__emit_jump_empty(comp_ctx); DUK__SETTEMP(comp_ctx, temp_reset); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + comp_ctx->curr_func.allow_regexp_in_adv = 1; + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); duk__emit_jump(comp_ctx, pc_start); @@ -69737,6 +70896,7 @@ DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk duk__advance(comp_ctx); } else { DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL); + DUK_WO_NORETURN(return;); } /* Use a fast break/continue when possible. A fast break/continue is @@ -69778,6 +70938,7 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re */ if (!comp_ctx->curr_func.is_function) { DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN); + DUK_WO_NORETURN(return;); } if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */ @@ -69879,6 +71040,7 @@ DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res if (comp_ctx->curr_token.lineterm) { DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW); + DUK_WO_NORETURN(return;); } reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); @@ -69935,10 +71097,9 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) /* try part */ duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); + duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ - duk__emit_op_only(comp_ctx, - DUK_OP_ENDTRY); + duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY); if (comp_ctx->curr_token.t == DUK_TOK_CATCH) { /* @@ -70034,7 +71195,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT", (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx))); - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); + duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ if (varmap_value == -2) { @@ -70076,7 +71237,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) duk__advance(comp_ctx); duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); + duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ duk__emit_abc(comp_ctx, DUK_OP_ENDFIN, @@ -70119,6 +71280,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) syntax_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { @@ -70129,6 +71291,7 @@ DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) if (comp_ctx->curr_func.is_strict) { DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE); + DUK_WO_NORETURN(return;); } comp_ctx->curr_func.catch_depth++; @@ -70139,7 +71302,8 @@ DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch); - duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); + comp_ctx->curr_func.allow_regexp_in_adv = 1; + duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ pc_trycatch = duk__get_current_pc(comp_ctx); trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING; @@ -70151,8 +71315,7 @@ DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) duk__emit_invalid(comp_ctx); /* finished jump */ duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); - duk__emit_op_only(comp_ctx, - DUK_OP_ENDTRY); + duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY); pc_finished = duk__get_current_pc(comp_ctx); @@ -70319,13 +71482,14 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_ break; } else { DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED); + DUK_WO_NORETURN(return;); } break; } case DUK_TOK_LCURLY: { DUK_DDD(DUK_DDDPRINT("block statement")); duk__advance(comp_ctx); - duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/); + duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ if (label_id >= 0) { duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */ @@ -70579,7 +71743,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_ */ if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 && - DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict", 10) == 0) { + DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict") == 0) { #if defined(DUK_USE_STRICT_DECL) DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld", (long) comp_ctx->curr_func.is_strict, (long) 1)); @@ -70588,7 +71752,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_ DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring")); #endif } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 && - DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail", 14) == 0) { + DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail") == 0) { DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld", (long) comp_ctx->curr_func.is_notail, (long) 1)); comp_ctx->curr_func.is_notail = 1; @@ -70656,6 +71820,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_ "even though no lineterm present before next token)")); } else { DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT); + DUK_WO_NORETURN(return;); } } } else { @@ -70704,7 +71869,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_ * (EOF or closing brace). */ -DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) { +DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof, duk_bool_t regexp_after) { duk_hthread *thr = comp_ctx->thr; duk_ivalue res_alloc; duk_ivalue *res = &res_alloc; @@ -70718,7 +71883,7 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou * for nested functions (which may occur inside expressions). */ - DUK_MEMZERO(&res_alloc, sizeof(res_alloc)); + duk_memzero(&res_alloc, sizeof(res_alloc)); res->t = DUK_IVAL_PLAIN; res->x1.t = DUK_ISPEC_VALUE; res->x1.valstack_idx = duk_get_top(thr); @@ -70752,6 +71917,15 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou duk__parse_stmt(comp_ctx, res, allow_source_elem); } + /* RegExp is allowed / not allowed depending on context. For function + * declarations RegExp is allowed because it follows a function + * declaration statement and may appear as part of the next statement. + * For function expressions RegExp is not allowed, and it's possible + * to do something like '(function () {} / 123)'. + */ + if (regexp_after) { + comp_ctx->curr_func.allow_regexp_in_adv = 1; + } duk__advance(comp_ctx); /* Tear down state. */ @@ -71075,13 +72249,11 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct error_outofregs: DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT); - DUK_UNREACHABLE(); - return; + DUK_WO_NORETURN(return;); error_argname: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME); - DUK_UNREACHABLE(); - return; + DUK_WO_NORETURN(return;); } /* @@ -71118,7 +72290,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct * token (EOF or closing brace). */ -DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token) { +DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_bool_t regexp_after, duk_small_int_t expect_token) { duk_compiler_func *func; duk_hthread *thr; duk_regconst_t reg_stmt_value = -1; @@ -71190,7 +72362,9 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec func->max_line = 0; #endif - /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */ + /* duk__parse_stmts() expects curr_tok to be set; parse in "allow + * regexp literal" mode with current strictness. + */ if (expect_token >= 0) { /* Eating a left curly; regexp mode is allowed by left curly * based on duk__token_lbp[] automatically. @@ -71209,7 +72383,8 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec DUK_DDD(DUK_DDDPRINT("begin 1st pass")); duk__parse_stmts(comp_ctx, 1, /* allow source elements */ - expect_eof); /* expect EOF instead of } */ + expect_eof, /* expect EOF instead of } */ + regexp_after); /* regexp after */ DUK_DDD(DUK_DDDPRINT("end 1st pass")); /* @@ -71316,7 +72491,8 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec DUK_DDD(DUK_DDDPRINT("begin 2nd pass")); duk__parse_stmts(comp_ctx, 1, /* allow source elements */ - expect_eof); /* expect EOF instead of } */ + expect_eof, /* expect EOF instead of } */ + regexp_after); /* regexp after */ DUK_DDD(DUK_DDDPRINT("end 2nd pass")); duk__update_lineinfo_currtoken(comp_ctx); @@ -71329,6 +72505,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec /* Should never happen but avoid infinite loop just in case. */ DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen")); DUK_ERROR_INTERNAL(thr); + DUK_WO_NORETURN(return;); } DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round)); } @@ -71372,6 +72549,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec error_funcname: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME); + DUK_WO_NORETURN(return;); } /* @@ -71420,6 +72598,7 @@ DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) { if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) { DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER); + DUK_WO_NORETURN(return;); } DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER); DUK_ASSERT(comp_ctx->curr_token.str1 != NULL); @@ -71485,6 +72664,7 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_ui duk_to_string(thr, -1); } else { DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME); + DUK_WO_NORETURN(return;); } comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */ } else { @@ -71502,6 +72682,7 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_ui no_advance = 1; if (flags & DUK__FUNC_FLAG_DECL) { DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED); + DUK_WO_NORETURN(return;); } } } @@ -71535,6 +72716,7 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_ui duk__parse_func_body(comp_ctx, 0, /* expect_eof */ 0, /* implicit_return_value */ + flags & DUK__FUNC_FLAG_DECL, /* regexp_after */ DUK_TOK_LCURLY); /* expect_token */ /* @@ -71587,6 +72769,14 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */ comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */ duk__advance(comp_ctx); + + /* RegExp is not allowed after a function expression, e.g. in + * (function () {} / 123). A RegExp *is* allowed after a + * function declaration! + */ + if (flags & DUK__FUNC_FLAG_DECL) { + comp_ctx->curr_func.allow_regexp_in_adv = 1; + } duk__advance_expect(comp_ctx, DUK_TOK_RCURLY); return fnum; @@ -71601,9 +72791,9 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld", (long) entry_top, (long) comp_ctx->curr_token.start_offset)); - DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func)); + duk_memcpy(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func)); - DUK_MEMZERO(&comp_ctx->curr_func, sizeof(duk_compiler_func)); + duk_memzero(&comp_ctx->curr_func, sizeof(duk_compiler_func)); duk__init_func_valstack_slots(comp_ctx); DUK_ASSERT(comp_ctx->curr_func.num_formals == 0); @@ -71645,6 +72835,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm if (fnum > DUK__MAX_FUNCS) { DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT); + DUK_WO_NORETURN(return 0;); } /* array writes autoincrement length */ @@ -71669,7 +72860,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm } else { duk_set_top(thr, entry_top); } - DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func)); + duk_memcpy((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func)); return fnum; } @@ -71678,7 +72869,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm * Compile input string into an executable function template without * arguments. * - * The string is parsed as the "Program" production of Ecmascript E5. + * The string is parsed as the "Program" production of ECMAScript E5. * Compilation context can be either global code or eval code (see E5 * Sections 14 and 15.1.2.1). * @@ -71819,6 +73010,7 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_hthread *thr, void *udata) { duk__parse_func_body(comp_ctx, 1, /* expect_eof */ 1, /* implicit_return_value */ + 1, /* regexp_after (does not matter) */ -1); /* expect_token */ } @@ -71846,7 +73038,7 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer DUK_ASSERT(src_buffer != NULL); /* preinitialize lexer state partially */ - DUK_MEMZERO(&comp_stk, sizeof(comp_stk)); + duk_memzero(&comp_stk, sizeof(comp_stk)); comp_stk.flags = flags; DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex); comp_stk.comp_ctx_alloc.lex.input = src_buffer; @@ -71863,6 +73055,7 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer if (safe_rc != DUK_EXEC_SUCCESS) { DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(thr, -1))); (void) duk_throw(thr); + DUK_WO_NORETURN(return;); } /* [ ... template ] */ @@ -71954,7 +73147,7 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer #undef DUK__TOKEN_LBP_GET_BP #line 1 "duk_js_executor.c" /* - * Ecmascript bytecode executor. + * ECMAScript bytecode executor. */ /* #include duk_internal.h -> already included */ @@ -72005,7 +73198,7 @@ DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, d tv_dst = thr->valstack_top; copy_size = sizeof(duk_tval) * count; - DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, copy_size); + duk_memcpy((void *) tv_dst, (const void *) tv_src, copy_size); for (i = 0; i < count; i++) { DUK_TVAL_INCREF(thr, tv_dst); tv_dst++; @@ -72269,7 +73462,10 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tv break; } case DUK_OP_DIV >> 2: { - du.d = d1 / d2; + /* Division-by-zero is undefined behavior, so + * rely on a helper. + */ + du.d = duk_double_div(d1, d2); break; } case DUK_OP_MOD >> 2: { @@ -72726,7 +73922,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr, * top are combined into one pass. */ -/* Reconfigure value stack for return to an Ecmascript function at +/* Reconfigure value stack for return to an ECMAScript function at * callstack top (caller unwinds). */ DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) { @@ -72742,7 +73938,7 @@ DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) { /* Clamp so that values at 'clamp_top' and above are wiped and won't * retain reachable garbage. Then extend to 'nregs' because we're - * returning to an Ecmascript function. + * returning to an ECMAScript function. */ h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); @@ -72758,7 +73954,7 @@ DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) { /* XXX: a best effort shrink check would be OK here */ } -/* Reconfigure value stack for an Ecmascript catcher. Use topmost catcher +/* Reconfigure value stack for an ECMAScript catcher. Use topmost catcher * in 'act'. */ DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_activation *act) { @@ -72994,7 +74190,7 @@ DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_tva act_resumer = resumer->callstack_curr; DUK_ASSERT(act_resumer != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(act_resumer) != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer))); /* resume caller must be an ecmascript func */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer))); /* resume caller must be an ECMAScript func */ tv1 = (duk_tval *) (void *) ((duk_uint8_t *) resumer->valstack + act_resumer->retval_byteoff); /* return value from Duktape.Thread.resume() */ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ /* XXX: avoid side effects */ @@ -73050,7 +74246,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */ - DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ + DUK_ASSERT(thr->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ DUK_ASSERT(thr->callstack_curr != NULL); DUK_ASSERT(thr->callstack_curr->parent != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && @@ -73068,7 +74264,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE || resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || - resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */ + resumee->callstack_top >= 2); /* YIELDED: ECMAScript activation + Duktape.Thread.yield() activation */ DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL && DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) && @@ -73106,8 +74302,8 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation goto check_longjmp; } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) { /* Unwind previous Duktape.Thread.yield() call. The - * activation remaining must always be an Ecmascript - * call now (yield() accepts calls from Ecmascript + * activation remaining must always be an ECMAScript + * call now (yield() accepts calls from ECMAScript * only). */ duk_activation *act_resumee; @@ -73115,7 +74311,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation DUK_ASSERT(resumee->callstack_top >= 2); act_resumee = resumee->callstack_curr; /* Duktape.Thread.yield() */ DUK_ASSERT(act_resumee != NULL); - act_resumee = act_resumee->parent; /* Ecmascript call site for yield() */ + act_resumee = act_resumee->parent; /* ECMAScript call site for yield() */ DUK_ASSERT(act_resumee != NULL); tv = (duk_tval *) (void *) ((duk_uint8_t *) resumee->valstack + act_resumee->retval_byteoff); /* return value from Duktape.Thread.yield() */ @@ -73163,6 +74359,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation * executor which can be quite misleading. */ DUK_ERROR_INTERNAL(thr); + DUK_WO_NORETURN(return 0;); } DUK_ASSERT(resumee->resumer == NULL); @@ -73185,7 +74382,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation case DUK_LJ_TYPE_YIELD: { /* * Currently only allowed only if yielding thread has only - * Ecmascript activations (except for the Duktape.Thread.yield() + * ECMAScript activations (except for the Duktape.Thread.yield() * call at the callstack top) and none of them constructor * calls. * @@ -73201,27 +74398,27 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */ #endif DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */ - DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */ + DUK_ASSERT(thr->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.yield() activation */ DUK_ASSERT(thr->callstack_curr != NULL); DUK_ASSERT(thr->callstack_curr->parent != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield); DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* an Ecmascript function */ + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* an ECMAScript function */ resumer = thr->resumer; DUK_ASSERT(resumer != NULL); DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */ - DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ + DUK_ASSERT(resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ DUK_ASSERT(resumer->callstack_curr != NULL); DUK_ASSERT(resumer->callstack_curr->parent != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL && DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) && ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume); DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent))); /* an Ecmascript function */ + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent))); /* an ECMAScript function */ if (thr->heap->lj.iserror) { thr->state = DUK_HTHREAD_STATE_YIELDED; @@ -73275,7 +74472,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation * resumer in this case.) * * Note: until we hit the entry level, there can only be - * Ecmascript activations. + * ECMAScript activations. */ duk_activation *act; @@ -73342,11 +74539,11 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation */ DUK_ASSERT(thr->resumer != NULL); - DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ + DUK_ASSERT(thr->resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ DUK_ASSERT(thr->resumer->callstack_curr != NULL); DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */ + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an ECMAScript function */ resumer = thr->resumer; @@ -73399,8 +74596,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation * infinite loop in this catchpoint. */ DUK_ERROR_INTERNAL(thr); - DUK_UNREACHABLE(); - return retval; + DUK_WO_NORETURN(return 0;); } /* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE @@ -73464,7 +74660,7 @@ DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_break_or_continue(duk_hthread *thr /* Should never happen, but be robust. */ DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error")); DUK_ERROR_INTERNAL(thr); - return; + DUK_WO_NORETURN(return;); } /* Handle a RETURN opcode. Avoid using longjmp() for return handling because @@ -73499,7 +74695,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation * * 2. The return happens at the entry level of the bytecode * executor, so return from the executor (in C stack). * - * 3. There is a calling (Ecmascript) activation in the call + * 3. There is a calling (ECMAScript) activation in the call * stack => return to it, in the same executor instance. * * 4. There is no calling activation, and the thread is @@ -73544,16 +74740,16 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation * } if (thr->callstack_top >= 2) { - /* There is a caller; it MUST be an Ecmascript caller (otherwise it would + /* There is a caller; it MUST be an ECMAScript caller (otherwise it would * match entry_act check). */ - DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, retval_byteoff=%ld, lj_value1=%!T", + DUK_DDD(DUK_DDDPRINT("return to ECMAScript caller, retval_byteoff=%ld, lj_value1=%!T", (long) (thr->callstack_curr->parent->retval_byteoff), (duk_tval *) &thr->heap->lj.value1)); DUK_ASSERT(thr->callstack_curr != NULL); DUK_ASSERT(thr->callstack_curr->parent != NULL); - DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* must be ecmascript */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* must be ECMAScript */ #if defined(DUK_USE_ES6_PROXY) if (thr->callstack_curr->flags & (DUK_ACT_FLAG_CONSTRUCT | DUK_ACT_FLAG_CONSTRUCT_PROXY)) { @@ -73583,31 +74779,51 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation * DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)")); DUK_ASSERT(thr->resumer != NULL); - DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */ + DUK_ASSERT(thr->resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ DUK_ASSERT(thr->resumer->callstack_curr != NULL); DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL); DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL && - DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */ + DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an ECMAScript function */ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); resumer = thr->resumer; - /* Share yield longjmp handler. */ + /* Share yield longjmp handler. + * + * This sequence of steps is a bit fragile (see GH-1845): + * - We need the return value from 'thr' (resumed thread) value stack. + * The termination unwinds its value stack, losing the value. + * - We need a refcounted reference for 'thr', which may only exist + * in the caller value stack. We can't unwind or reconfigure the + * caller's value stack without potentially freeing 'thr'. + * + * Current approach is to capture the 'thr' return value and store + * a reference to 'thr' in the caller value stack temporarily. This + * keeps 'thr' reachable until final yield/return handling which + * removes the references atomatically. + */ + DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); - duk_hthread_activation_unwind_norz(resumer); - duk__handle_yield(thr, resumer, thr->valstack_top - 1); - - duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */ - DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); + duk_hthread_activation_unwind_norz(resumer); /* May remove last reference to 'thr', but is NORZ. */ + duk_push_tval(resumer, thr->valstack_top - 1); /* Capture return value, side effect free. */ + duk_push_hthread(resumer, thr); /* Make 'thr' reachable again, before side effects. */ + duk_hthread_terminate(thr); /* Updates thread state, minimizes its allocations. */ thr->resumer = NULL; DUK_HTHREAD_DECREF(thr, resumer); + DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); + resumer->state = DUK_HTHREAD_STATE_RUNNING; DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); + + DUK_ASSERT(resumer->valstack_top - 2 >= resumer->valstack_bottom); + duk__handle_yield(thr, resumer, resumer->valstack_top - 2); + thr = NULL; /* 'thr' invalidated by call */ + #if 0 thr = resumer; /* not needed */ #endif @@ -73617,7 +74833,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation * #else /* Without coroutine support this case should never happen. */ DUK_ERROR_INTERNAL(thr); - return DUK__RETHAND_FINISHED; /* not executed */ + DUK_WO_NORETURN(return 0;); #endif } @@ -73767,7 +74983,7 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_ if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) { /* Monotonic time should not experience time jumps, * but the provider may be missing and we're actually - * using Ecmascript time. So, tolerate negative values + * using ECMAScript time. So, tolerate negative values * so that a time jump works reasonably. * * Same interval is now used for status sending and @@ -73916,6 +75132,7 @@ DUK_LOCAL DUK__NOINLINE_PERF DUK_COLD duk_small_uint_t duk__executor_interrupt(d thr->interrupt_counter = 0; DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap); DUK_ERROR_RANGE(thr, "execution timeout"); + DUK_WO_NORETURN(return 0;); } #endif /* DUK_USE_EXEC_TIMEOUT_CHECK */ @@ -74601,7 +75818,7 @@ DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, } /* - * Ecmascript bytecode executor. + * ECMAScript bytecode executor. * * Resume execution for the current thread from its current activation. * Returns when execution would return from the entry level activation, @@ -74610,7 +75827,7 @@ DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level * setjmp() jmpbuf. * - * Ecmascript function calls and coroutine resumptions are handled + * ECMAScript function calls and coroutine resumptions are handled * internally (by the outer executor function) without recursive C calls. * Other function calls are handled using duk_handle_call(), increasing * C recursion depth. @@ -74703,6 +75920,7 @@ DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, #if defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS) #define DUK__INTERNAL_ERROR(msg) do { \ DUK_ERROR_ERROR(thr, (msg)); \ + DUK_WO_NORETURN(return;); \ } while (0) #else #define DUK__INTERNAL_ERROR(msg) do { \ @@ -74867,7 +76085,10 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) { entry_jmpbuf_ptr); } #if defined(DUK_USE_CPP_EXCEPTIONS) - catch (std::exception &exc) { + catch (duk_fatal_exception &exc) { + DUK_D(DUK_DPRINT("rethrow duk_fatal_exception")); + throw; + } catch (std::exception &exc) { const char *what = exc.what(); if (!what) { what = "unknown"; @@ -74877,6 +76098,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) { try { DUK_ASSERT(heap->curr_thread != NULL); DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what); + DUK_WO_NORETURN(return;); } catch (duk_internal_exception exc) { DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception")); DUK_UNREF(exc); @@ -74891,6 +76113,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) { try { DUK_ASSERT(heap->curr_thread != NULL); DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)"); + DUK_WO_NORETURN(return;); } catch (duk_internal_exception exc) { DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception")); DUK_UNREF(exc); @@ -74903,7 +76126,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) { #endif } - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return;); } /* Inner executor, performance critical. */ @@ -75272,7 +76495,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread * /* XXX: fast double-to-int conversion, we know number is integer in [-0x80000000,0xffffffff]. */ val = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv1); #endif - val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */ + val = (duk_int32_t) ((duk_uint32_t) val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */ DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */ break; } @@ -76927,7 +78150,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread * case DUK_OP_INVLHS: { DUK_ERROR_REFERENCE(thr, DUK_STR_INVALID_LVALUE); - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return;); break; } @@ -76962,45 +78185,13 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread * case DUK_OP_INVALID: { DUK_ERROR_FMT1(thr, DUK_ERR_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_ABC(ins)); + DUK_WO_NORETURN(return;); break; } #if defined(DUK_USE_ES6) case DUK_OP_NEWTARGET: { - /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation - * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget - * - * No newTarget support now, so as a first approximation - * use the resolved (non-bound) target function. - */ - /* XXX: C API: push_new_target()? */ - duk_activation *act; - - act = thr->callstack_curr; - DUK_ASSERT(act != NULL); - - /* Check CONSTRUCT flag from current function, or if running - * direct eval, from a non-direct-eval parent (with possibly - * more than one nested direct eval). An alternative to this - * would be to store [[NewTarget]] as a hidden symbol of the - * lexical scope, and then just look up that variable. - */ - for (;;) { - if (act == NULL) { - duk_push_undefined(thr); - break; - } - if (act->flags & DUK_ACT_FLAG_CONSTRUCT) { - duk_push_tval(thr, &act->tv_func); - break; - } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { - act = act->parent; - } else { - duk_push_undefined(thr); - break; - } - } - + duk_push_new_target(thr); DUK__REPLACE_TOP_BC_BREAK(); } #endif /* DUK_USE_ES6 */ @@ -77102,11 +78293,12 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread * continue; #endif } - DUK_UNREACHABLE(); + DUK_WO_NORETURN(return;); #if !defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS) internal_error: DUK_ERROR_INTERNAL(thr); + DUK_WO_NORETURN(return;); #endif } @@ -77176,9 +78368,9 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread * #undef DUK__TVAL_SHIFT #line 1 "duk_js_ops.c" /* - * Ecmascript specification algorithm and conversion helpers. + * ECMAScript specification algorithm and conversion helpers. * - * These helpers encapsulate the primitive Ecmascript operation semantics, + * These helpers encapsulate the primitive ECMAScript operation semantics, * and are used by the bytecode executor and the API (among other places). * Some primitives are only implemented as part of the API and have no * "internal" helper. This is the case when an internal helper would not @@ -77394,6 +78586,7 @@ DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) { duk_hstring *h = DUK_TVAL_GET_STRING(tv); if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL); + DUK_WO_NORETURN(return 0.0;); } duk_push_hstring(thr, h); return duk__tonumber_string_raw(thr); @@ -77609,7 +78802,7 @@ DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) { return 0; #else /* DUK_USE_PARANOID_MATH */ /* Better equivalent algorithm. If the compiler is compliant, C and - * Ecmascript semantics are identical for this particular comparison. + * ECMAScript semantics are identical for this particular comparison. * In particular, NaNs must never compare equal and zeroes must compare * equal regardless of sign. Could also use a macro, but this inlines * already nicely (no difference on gcc, for instance). @@ -77902,12 +79095,12 @@ DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const prefix_len = (len1 <= len2 ? len1 : len2); - /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length - * inputs so no zero length check is needed. + /* duk_memcmp() is guaranteed to return zero (equal) for zero length + * inputs. */ - rc = DUK_MEMCMP((const void *) buf1, - (const void *) buf2, - (size_t) prefix_len); + rc = duk_memcmp_unsafe((const void *) buf1, + (const void *) buf2, + (size_t) prefix_len); if (rc < 0) { return -1; @@ -78174,22 +79367,19 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, */ /* - * E5 Section 11.8.6 describes the main algorithm, which uses - * [[HasInstance]]. [[HasInstance]] is defined for only - * function objects: + * ES2015 Section 7.3.19 describes the OrdinaryHasInstance() algorithm + * which covers both bound and non-bound functions; in effect the algorithm + * includes E5 Sections 11.8.6, 15.3.5.3, and 15.3.4.5.3. * - * - Normal functions: - * E5 Section 15.3.5.3 - * - Functions established with Function.prototype.bind(): - * E5 Section 15.3.4.5.3 - * - * For other objects, a TypeError is thrown. + * ES2015 Section 12.9.4 describes the instanceof operator which first + * checks @@hasInstance well-known symbol and falls back to + * OrdinaryHasInstance(). * * Limited Proxy support: don't support 'getPrototypeOf' trap but * continue lookup in Proxy target if the value is a Proxy. */ -DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { +DUK_LOCAL duk_bool_t duk__js_instanceof_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_bool_t skip_sym_check) { duk_hobject *func; duk_hobject *val; duk_hobject *proto; @@ -78212,6 +79402,23 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_ func = duk_require_hobject(thr, -1); DUK_ASSERT(func != NULL); +#if defined(DUK_USE_SYMBOL_BUILTIN) + /* + * @@hasInstance check, ES2015 Section 12.9.4, Steps 2-4. + */ + if (!skip_sym_check) { + if (duk_get_method_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)) { + /* [ ... lhs rhs func ] */ + duk_insert(thr, -3); /* -> [ ... func lhs rhs ] */ + duk_swap_top(thr, -2); /* -> [ ... func rhs(this) lhs ] */ + duk_call_method(thr, 1); + return duk_to_boolean_top_pop(thr); + } + } +#else + DUK_UNREF(skip_sym_check); +#endif + /* * For bound objects, [[HasInstance]] just calls the target function * [[HasInstance]]. If that is again a bound object, repeat until @@ -78223,7 +79430,7 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_ if (!DUK_HOBJECT_IS_CALLABLE(func)) { /* - * Note: of native Ecmascript objects, only Function instances + * Note: of native ECMAScript objects, only Function instances * have a [[HasInstance]] internal property. Custom objects might * also have it, but not in current implementation. * @@ -78233,7 +79440,7 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_ } if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) { - duk_push_tval(thr, &((duk_hboundfunc *) func)->target); + duk_push_tval(thr, &((duk_hboundfunc *) (void *) func)->target); duk_replace(thr, -2); func = duk_require_hobject(thr, -1); /* lightfunc throws */ @@ -78338,6 +79545,7 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_ if (DUK_UNLIKELY(sanity == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); + DUK_WO_NORETURN(return 0;); } DUK_UNREACHABLE(); @@ -78355,15 +79563,25 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_ error_invalid_rval: DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL); - return 0; + DUK_WO_NORETURN(return 0;); #if defined(DUK_USE_VERBOSE_ERRORS) error_invalid_rval_noproto: DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO); - return 0; + DUK_WO_NORETURN(return 0;); #endif } +#if defined(DUK_USE_SYMBOL_BUILTIN) +DUK_INTERNAL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { + return duk__js_instanceof_helper(thr, tv_x, tv_y, 1 /*skip_sym_check*/); +} +#endif + +DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { + return duk__js_instanceof_helper(thr, tv_x, tv_y, 0 /*skip_sym_check*/); +} + /* * in */ @@ -78615,7 +79833,7 @@ DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) { * be used for most identifier accesses. Consequently, these slow path * primitives should be optimized for maximum compactness. * - * Ecmascript environment records (declarative and object) are represented + * ECMAScript environment records (declarative and object) are represented * as internal objects with control keys. Environment records have a * parent record ("outer environment reference") which is represented by * the implicit prototype for technical reasons (in other words, it is a @@ -78657,7 +79875,7 @@ typedef struct { * Create a new function object based on a "template function" which contains * compiled bytecode, constants, etc, but lacks a lexical environment. * - * Ecmascript requires that each created closure is a separate object, with + * ECMAScript requires that each created closure is a separate object, with * its own set of editable properties. However, structured property values * (such as the formal arguments list and the variable map) are shared. * Also the bytecode, constants, and inner functions are shared. @@ -79666,6 +80884,7 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr, if (DUK_UNLIKELY(sanity-- == 0)) { DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); + DUK_WO_NORETURN(return 0;); } env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); } @@ -79805,6 +81024,7 @@ duk_bool_t duk__getvar_helper(duk_hthread *thr, DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR, "identifier '%s' undefined", (const char *) DUK_HSTRING_GET_DATA(name)); + DUK_WO_NORETURN(return 0;); } return 0; @@ -79929,6 +81149,7 @@ void duk__putvar_helper(duk_hthread *thr, DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR, "identifier '%s' undefined", (const char *) DUK_HSTRING_GET_DATA(name)); + DUK_WO_NORETURN(return;); } DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global")); @@ -80319,7 +81540,7 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr, fail_existing_attributes: fail_not_extensible: DUK_ERROR_TYPE(thr, "declaration failed"); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_INTERNAL @@ -80365,7 +81586,7 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr, * Lexer for source files, ToNumber() string conversions, RegExp expressions, * and JSON. * - * Provides a stream of Ecmascript tokens from an UTF-8/CESU-8 buffer. The + * Provides a stream of ECMAScript tokens from an UTF-8/CESU-8 buffer. The * caller can also rewind the token stream into a certain position which is * needed by the compiler part for multi-pass scanning. Tokens are * represented as duk_token structures, and contain line number information. @@ -80388,14 +81609,14 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr, * * Token parsing supports the full range of Unicode characters as described * in the E5 specification. Parsing has been optimized for ASCII characters - * because ordinary Ecmascript code consists almost entirely of ASCII + * because ordinary ECMAScript code consists almost entirely of ASCII * characters. Matching of complex Unicode codepoint sets (such as in the * IdentifierStart and IdentifierPart productions) is optimized for size, * and is done using a linear scan of a bit-packed list of ranges. This is * very slow, but should never be entered unless the source code actually * contains Unicode characters. * - * Ecmascript tokenization is partially context sensitive. First, + * ECMAScript tokenization is partially context sensitive. First, * additional future reserved words are recognized in strict mode (see E5 * Section 7.6.1.2). Second, a forward slash character ('/') can be * recognized either as starting a RegExp literal or as a division operator, @@ -80492,7 +81713,7 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr, * * * In particular, surrogate pairs are allowed and not combined, which * allows source files to represent all SourceCharacters with CESU-8. - * Broken surrogate pairs are allowed, as Ecmascript does not mandate + * Broken surrogate pairs are allowed, as ECMAScript does not mandate * their validation. * * * Allow non-shortest UTF-8 encodings. @@ -80500,20 +81721,20 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr, * Leniency here causes few security concerns because all character data is * decoded into Unicode codepoints before lexer processing, and is then * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with - * a compiler option. However, Ecmascript source characters include -all- + * a compiler option. However, ECMAScript source characters include -all- * 16-bit unsigned integer codepoints, so leniency seems to be appropriate. * * Note that codepoints above the BMP are not strictly SourceCharacters, * but the lexer still accepts them as such. Before ending up in a string * or an identifier name, codepoints above BMP are converted into surrogate * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as - * expected by Ecmascript. + * expected by ECMAScript. * * An alternative approach to dealing with invalid or partial sequences * would be to skip them and replace them with e.g. the Unicode replacement * character U+FFFD. This has limited utility because a replacement character * will most likely cause a parse error, unless it occurs inside a string. - * Further, Ecmascript source is typically pure ASCII. + * Further, ECMAScript source is typically pure ASCII. * * See: * @@ -80676,6 +81897,7 @@ DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t s lex_ctx->input_line = input_line; DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED); + DUK_WO_NORETURN(return;); } DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) { @@ -80698,7 +81920,7 @@ DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count /* Not enough data to provide a full window, so "scroll" window to * start of buffer and fill up the rest. */ - DUK_MEMMOVE((void *) lex_ctx->buffer, + duk_memmove((void *) lex_ctx->buffer, (const void *) lex_ctx->window, (size_t) avail_bytes); lex_ctx->window = lex_ctx->buffer; @@ -80836,7 +82058,7 @@ DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) { error_clipped: /* clipped codepoint */ error_encoding: /* invalid codepoint encoding or codepoint */ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED); - return 0; + DUK_WO_NORETURN(return 0;); } DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) { @@ -80849,7 +82071,7 @@ DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count /* Zero 'count' is also allowed to make call sites easier. */ keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes; - DUK_MEMMOVE((void *) lex_ctx->window, + duk_memmove((void *) lex_ctx->window, (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes), (size_t) keep_bytes); @@ -80938,7 +82160,7 @@ DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valst DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) { DUK_ASSERT(lex_ctx != NULL); - DUK_MEMZERO(lex_ctx, sizeof(*lex_ctx)); + duk_memzero(lex_ctx, sizeof(*lex_ctx)); #if defined(DUK_USE_EXPLICIT_NULL_INIT) #if defined(DUK_USE_LEXER_SLIDING_WINDOW) lex_ctx->window = NULL; @@ -81103,6 +82325,7 @@ DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bo fail_escape: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); + DUK_WO_NORETURN(return 0;); } /* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum @@ -81299,11 +82522,11 @@ DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token fail_escape: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); - return; + DUK_WO_NORETURN(return;); fail_unterminated: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_STRING); - return; + DUK_WO_NORETURN(return;); } /* Skip to end-of-line (or end-of-file), used for single line comments. */ @@ -81320,7 +82543,7 @@ DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { } /* - * Parse Ecmascript source InputElementDiv or InputElementRegExp + * Parse ECMAScript source InputElementDiv or InputElementRegExp * (E5 Section 7), skipping whitespace, comments, and line terminators. * * Possible results are: @@ -81347,13 +82570,13 @@ DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { * lookup window to quickly determine which production is the -longest- * matching one, and then parse that. The top-level if-else clauses * match the first character, and the code blocks for each clause - * handle -all- alternatives for that first character. Ecmascript + * handle -all- alternatives for that first character. ECMAScript * specification uses the "longest match wins" semantics, so the order * of the if-clauses matters. * * Misc notes: * - * * Ecmascript numeric literals do not accept a sign character. + * * ECMAScript numeric literals do not accept a sign character. * Consequently e.g. "-1.0" is parsed as two tokens: a negative * sign and a positive numeric literal. The compiler performs * the negation during compilation, so this has no adverse impact. @@ -81863,7 +83086,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not * used now). The compiler needs to work around this. * - * Strictly speaking, following Ecmascript longest match + * Strictly speaking, following ECMAScript longest match * specification, an invalid escape for the first character * should cause a syntax error. However, an invalid escape * for IdentifierParts should just terminate the identifier @@ -82147,32 +83370,32 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, fail_token_limit: DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT); - return; + DUK_WO_NORETURN(return;); fail_token: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_TOKEN); - return; + DUK_WO_NORETURN(return;); fail_number_literal: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_NUMBER_LITERAL); - return; + DUK_WO_NORETURN(return;); fail_escape: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); - return; + DUK_WO_NORETURN(return;); fail_unterm_regexp: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_REGEXP); - return; + DUK_WO_NORETURN(return;); fail_unterm_comment: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_COMMENT); - return; + DUK_WO_NORETURN(return;); #if !defined(DUK_USE_REGEXP_SUPPORT) fail_regexp_support: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_REGEXP_SUPPORT_DISABLED); - return; + DUK_WO_NORETURN(return;); #endif } @@ -82195,7 +83418,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token goto fail_token_limit; } - DUK_MEMZERO(out_token, sizeof(*out_token)); + duk_memzero(out_token, sizeof(*out_token)); x = DUK__L0(); y = DUK__L1(); @@ -82520,24 +83743,24 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token fail_token_limit: DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT); - return; + DUK_WO_NORETURN(return;); fail_escape: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); - return; + DUK_WO_NORETURN(return;); fail_group: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP); - return; + DUK_WO_NORETURN(return;); #if !defined(DUK_USE_ES6_REGEXP_SYNTAX) fail_invalid_char: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER); - return; + DUK_WO_NORETURN(return;); fail_quantifier: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_QUANTIFIER); - return; + DUK_WO_NORETURN(return;); #endif } @@ -82786,15 +84009,15 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range fail_escape: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); - return; + DUK_WO_NORETURN(return;); fail_range: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_RANGE); - return; + DUK_WO_NORETURN(return;); fail_unterm_charclass: DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_CHARCLASS); - return; + DUK_WO_NORETURN(return;); } #endif /* DUK_USE_REGEXP_SUPPORT */ @@ -82956,10 +84179,8 @@ DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) { n = y->n; x->n = n; - if (n == 0) { - return; - } - DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * (size_t) n)); + /* No need to special case n == 0. */ + duk_memcpy((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * (size_t) n)); } DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) { @@ -83235,7 +84456,7 @@ DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) { return; } - DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx)); + duk_memzero((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx)); x->n = nx; nz = z->n; @@ -83385,7 +84606,7 @@ DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) { n = (y / 32) + 1; DUK_ASSERT(n > 0); r = y % 32; - DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * (size_t) n); + duk_memzero((void *) x->v, sizeof(duk_uint32_t) * (size_t) n); x->n = n; x->v[n - 1] = (((duk_uint32_t) 1) << r); } @@ -83499,6 +84720,7 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x duk_small_int_t dig; duk_uint32_t t; + DUK_ASSERT(buf != NULL); DUK_ASSERT(radix >= 2 && radix <= 36); /* A 32-bit unsigned integer formats to at most 32 digits (the @@ -83521,7 +84743,7 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x } len = (duk_size_t) ((buf + 32) - p); - DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len); + duk_memmove((void *) buf, (const void *) p, (size_t) len); return len; } @@ -83924,7 +85146,7 @@ DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) { { duk_uint8_t buf[2048]; duk_small_int_t i, t; - DUK_MEMZERO(buf, sizeof(buf)); + duk_memzero(buf, sizeof(buf)); for (i = 0; i < nc_ctx->count; i++) { t = nc_ctx->digits[i]; if (t < 0 || t > 36) { @@ -83989,7 +85211,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify *p = 0; if (p == &nc_ctx->digits[0]) { DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling")); - DUK_MEMMOVE((void *) (&nc_ctx->digits[1]), + duk_memmove((void *) (&nc_ctx->digits[1]), (const void *) (&nc_ctx->digits[0]), (size_t) (sizeof(char) * (size_t) nc_ctx->count)); nc_ctx->digits[0] = 1; /* don't increase 'count' */ @@ -84033,7 +85255,7 @@ DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx, duk_uint8_t *buf; /* - * The string conversion here incorporates all the necessary Ecmascript + * The string conversion here incorporates all the necessary ECMAScript * semantics without attempting to be generic. nc_ctx->digits contains * nc_ctx->count digits (>= 1), with the topmost digit's 'position' * indicated by nc_ctx->k as follows: @@ -84044,11 +85266,11 @@ DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx, * digits="123" count=3 k=-1 --> 0.0123 * * Note that the identifier names used for format selection are different - * in Burger-Dybvig paper and Ecmascript specification (quite confusingly + * in Burger-Dybvig paper and ECMAScript specification (quite confusingly * so, because e.g. 'k' has a totally different meaning in each). See * documentation for discussion. * - * Ecmascript doesn't specify any specific behavior for format selection + * ECMAScript doesn't specify any specific behavior for format selection * (e.g. when to use exponent notation) for non-base-10 numbers. * * The bigint space in the context is reused for string output, as there @@ -84132,7 +85354,7 @@ DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx, /* Exponent */ if (expt != DUK__NO_EXP) { /* - * Exponent notation for non-base-10 numbers isn't specified in Ecmascript + * Exponent notation for non-base-10 numbers isn't specified in ECMAScript * specification, as it never explicitly turns up: non-decimal numbers can * only be formatted with Number.prototype.toString([radix]) and for that, * behavior is not explicitly specified. @@ -84234,7 +85456,7 @@ DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, du * (perhaps because the low part is set (seemingly) conditionally in a * loop), so this is here to avoid the bogus warning. */ - DUK_MEMZERO((void *) &u, sizeof(u)); + duk_memzero((void *) &u, sizeof(u)); /* * Figure out how generated digits match up with the mantissa, @@ -84417,7 +85639,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, * sprintf "%lu" for the fast path and for exponent formatting. */ - uval = (unsigned int) x; + uval = duk_double_to_uint32_t(x); if (((double) uval) == x && /* integer number in range */ flags == 0) { /* no special formatting */ /* use bigint area as a temp */ @@ -84449,7 +85671,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, * is 1-2 kilobytes and nothing should rely on it being zeroed. */ #if 0 - DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */ + duk_memzero((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */ #endif nc_ctx->is_s2n = 0; @@ -84489,7 +85711,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, } DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count)); DUK_ASSERT(count >= 1); - DUK_MEMZERO((void *) nc_ctx->digits, (size_t) count); + duk_memzero((void *) nc_ctx->digits, (size_t) count); nc_ctx->count = count; nc_ctx->k = 1; /* 0.000... */ neg = 0; @@ -84569,8 +85791,8 @@ DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc; duk_double_t res; duk_hstring *h_str; - duk_small_int_t expt; - duk_small_int_t expt_neg; + duk_int_t expt; + duk_bool_t expt_neg; duk_small_int_t expt_adj; duk_small_int_t neg; duk_small_int_t dig; @@ -84706,7 +85928,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk * accuracy, so that Dragon4 will generate enough binary output digits. * For decimal numbers, this means generating a 20-digit significand, * which should yield enough practical accuracy to parse IEEE doubles. - * In fact, the Ecmascript specification explicitly allows an + * In fact, the ECMAScript specification explicitly allows an * implementation to treat digits beyond 20 as zeroes (and even * to round the 20th digit upwards). For non-decimal numbers, the * appropriate number of digits has been precomputed for comparable @@ -84877,9 +86099,10 @@ DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk } else { /* exponent digit */ + DUK_ASSERT(radix == 10); expt = expt * radix + dig; if (expt > DUK_S2N_MAX_EXPONENT) { - /* impose a reasonable exponent limit, so that exp + /* Impose a reasonable exponent limit, so that exp * doesn't need to get tracked using a bigint. */ DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large")); @@ -85082,7 +86305,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk parse_explimit_error: DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value")); DUK_ERROR_RANGE(thr, "exponent too large"); - return; + DUK_WO_NORETURN(return;); } /* automatic undefs */ @@ -85624,6 +86847,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex if (re_ctx->recursion_depth >= re_ctx->recursion_limit) { DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT); + DUK_WO_NORETURN(return;); } re_ctx->recursion_depth++; @@ -85697,9 +86921,11 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex case DUK_RETOK_QUANTIFIER: { if (atom_start_offset < 0) { DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM); + DUK_WO_NORETURN(return;); } if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) { DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES); + DUK_WO_NORETURN(return;); } if (atom_char_length >= 0) { /* @@ -85768,6 +86994,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex re_ctx->curr_token.qmin : re_ctx->curr_token.qmax; if (atom_copies > DUK_RE_MAX_ATOM_COPIES) { DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES); + DUK_WO_NORETURN(return;); } /* wipe the capture range made by the atom (if any) */ @@ -86031,17 +87258,20 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex case DUK_RETOK_ATOM_END_GROUP: { if (expect_eof) { DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN); + DUK_WO_NORETURN(return;); } goto done; } case DUK_RETOK_EOF: { if (!expect_eof) { DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN); + DUK_WO_NORETURN(return;); } goto done; } default: { DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN); + DUK_WO_NORETURN(return;); } } @@ -86136,7 +87366,7 @@ DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) flags_error: DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS); - return 0; /* never here */ + DUK_WO_NORETURN(return 0U;); } /* @@ -86173,7 +87403,7 @@ DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) { n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); if (n == 0) { - duk_push_string(thr, "(?:)"); + duk_push_literal(thr, "(?:)"); return; } @@ -86253,7 +87483,7 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) { /* [ ... pattern flags escaped_source buffer ] */ - DUK_MEMZERO(&re_ctx, sizeof(re_ctx)); + duk_memzero(&re_ctx, sizeof(re_ctx)); DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */ re_ctx.thr = thr; re_ctx.lex.thr = thr; @@ -86300,6 +87530,7 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) { if (re_ctx.highest_backref > re_ctx.captures) { DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS); + DUK_WO_NORETURN(return;); } /* @@ -86384,7 +87615,7 @@ DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) { /* * Regexp executor. * - * Safety: the Ecmascript executor should prevent user from reading and + * Safety: the ECMAScript executor should prevent user from reading and * replacing regexp bytecode. Even so, the executor must validate all * memory accesses etc. When an invalid access is detected (e.g. a 'save' * opcode to invalid, unallocated index) it should fail with an internal @@ -86451,7 +87682,7 @@ DUK_LOCAL const duk_uint8_t *duk__utf8_backtrack(duk_hthread *thr, const duk_uin fail: DUK_ERROR_INTERNAL(thr); - return NULL; /* never here */ + DUK_WO_NORETURN(return NULL;); } DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) { @@ -86482,7 +87713,7 @@ DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8 fail: DUK_ERROR_INTERNAL(thr); - return NULL; /* never here */ + DUK_WO_NORETURN(return NULL;); } /* @@ -86531,6 +87762,7 @@ DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) { if (re_ctx->recursion_depth >= re_ctx->recursion_limit) { DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT); + DUK_WO_NORETURN(return NULL;); } re_ctx->recursion_depth++; @@ -86539,6 +87771,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const if (re_ctx->steps_count >= re_ctx->steps_limit) { DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT); + DUK_WO_NORETURN(return NULL;); } re_ctx->steps_count++; @@ -86884,14 +88117,14 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr, sizeof(duk_uint8_t *) * idx_count); DUK_ASSERT(range_save != NULL); - DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count); + duk_memcpy(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count); #if defined(DUK_USE_EXPLICIT_NULL_INIT) idx_end = idx_start + idx_count; for (idx = idx_start; idx < idx_end; idx++) { re_ctx->saved[idx] = NULL; } #else - DUK_MEMZERO((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count); + duk_memzero((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count); #endif sub_sp = duk__match_regexp(re_ctx, pc, sp); @@ -86909,7 +88142,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])", (long) idx_start, (long) (idx_start + idx_count - 1), (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2))); - DUK_MEMCPY((void *) (re_ctx->saved + idx_start), + duk_memcpy((void *) (re_ctx->saved + idx_start), (const void *) range_save, sizeof(duk_uint8_t *) * idx_count); duk_pop_unsafe(re_ctx->thr); @@ -86941,7 +88174,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr, sizeof(duk_uint8_t *) * re_ctx->nsaved); DUK_ASSERT(full_save != NULL); - DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved); + duk_memcpy(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved); skip = duk__bc_get_i32(re_ctx, &pc); sub_sp = duk__match_regexp(re_ctx, pc, sp); @@ -86966,7 +88199,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const lookahead_fail: /* fail: restore saves */ - DUK_MEMCPY((void *) re_ctx->saved, + duk_memcpy((void *) re_ctx->saved, (const void *) full_save, sizeof(duk_uint8_t *) * re_ctx->nsaved); duk_pop_unsafe(re_ctx->thr); @@ -87048,7 +88281,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const internal_error: DUK_ERROR_INTERNAL(re_ctx->thr); - return NULL; /* never here */ + DUK_WO_NORETURN(return NULL;); } /* @@ -87114,7 +88347,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_ /* [ ... re_obj input bc ] */ - DUK_MEMZERO(&re_ctx, sizeof(re_ctx)); + duk_memzero(&re_ctx, sizeof(re_ctx)); re_ctx.thr = thr; re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); @@ -87151,7 +88384,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_ #elif defined(DUK_USE_ZERO_BUFFER_DATA) /* buffer is automatically zeroed */ #else - DUK_MEMZERO((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved); + duk_memzero((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved); #endif DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld", @@ -87236,7 +88469,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_ * internal/limit error occurs (which causes a longjmp()) * * - If we supported anchored matches, we would break out here - * unconditionally; however, Ecmascript regexps don't have anchored + * unconditionally; however, ECMAScript regexps don't have anchored * matches. It might make sense to implement a fast bail-out if * the regexp begins with '^' and sp is not 0: currently we'll just * run through the entire input string, trivially failing the match @@ -87431,13 +88664,13 @@ typedef union { } while (0) #define DUK__DBLUNION_CMP_TRUE(a,b) do { \ - if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \ + if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \ DUK__FAILED("double union compares false (expected true)"); \ } \ } while (0) #define DUK__DBLUNION_CMP_FALSE(a,b) do { \ - if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \ + if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \ DUK__FAILED("double union compares true (expected false)"); \ } \ } while (0) @@ -87746,7 +88979,7 @@ DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) { */ DUK__DOUBLE_INIT(&a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - DUK_MEMSET((void *) &c, 0, sizeof(c)); + duk_memset((void *) &c, 0, sizeof(c)); c.d = a.d + b.d; if (!DUK__DOUBLE_COMPARE(&c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)) { DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x", @@ -87766,7 +88999,7 @@ DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) { */ DUK__DOUBLE_INIT(&a, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01); DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - DUK_MEMSET((void *) &c, 0, sizeof(c)); + duk_memset((void *) &c, 0, sizeof(c)); c.d = a.d + b.d; if (!DUK__DOUBLE_COMPARE(&c, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02)) { DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x", @@ -88205,7 +89438,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint * packed format. These tables are used to match non-ASCII * characters of complex productions by resorting to a linear * range-by-range comparison. This is very slow, but is expected - * to be very rare in practical Ecmascript source code, and thus + * to be very rare in practical ECMAScript source code, and thus * compactness is most important. * * The tables are matched using uni_range_match() and the format @@ -88219,54 +89452,55 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint * Automatically generated by extract_chars.py, do not edit! */ -const duk_uint8_t duk_unicode_ids_noa[1036] = { +const duk_uint8_t duk_unicode_ids_noa[1063] = { 249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34, 2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191, 21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240, -101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19, -240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47, -2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18, -47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12, -38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6, -41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98, -34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2, -85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35, -63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227, -240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5, -15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40, -240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27, -43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47, -15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68, -112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52, -29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12, -146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255, -224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63, -253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34, -35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31, -240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32, -240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7, -95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245, -207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10, -207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37,255, -223,13,79,33,242,31,16,240,47,11,111,22,191,14,63,20,87,36,241,207,142,240, -79,20,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241,194,20, -3,240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135,31,50,15, -1,50,34,240,191,30,240,212,240,223,21,114,240,207,13,242,107,240,107,240, -62,240,47,96,243,159,41,242,62,242,63,254,32,79,37,243,223,29,241,47,9,240, -207,20,241,191,19,64,223,32,240,3,240,112,32,241,95,2,47,9,244,102,32,35, -46,41,143,31,241,135,49,63,6,38,33,36,64,240,64,212,249,15,37,240,67,242, -127,32,240,97,32,250,175,31,241,179,241,111,32,240,96,242,223,27,244,127, -10,255,224,122,243,15,17,15,254,11,79,41,255,152,47,21,240,48,242,63,14, -255,226,100,255,226,140,245,143,95,240,63,180,255,233,176,255,227,33,255, -238,197,255,225,57,255,240,1,10,223,254,18,184,240,255,99,240,239,4,242,15, -2,63,17,240,86,240,63,254,38,79,53,192,243,76,243,32,241,31,255,0,6,223, -240,95,254,30,95,255,0,20,1,31,254,175,47,91,108,72,137,255,240,0,101,175, -69,47,55,33,48,49,51,43,32,38,47,49,35,55,38,47,12,35,36,32,70,47,254,4,99, -240,146,240,146,240,242,240,146,240,242,240,146,240,242,240,146,240,242, -240,146,127,254,242,143,181,242,223,52,255,227,176,50,240,178,18,3,2,146, -50,2,7,5,2,2,2,34,18,3,2,2,2,2,2,18,3,50,98,50,50,2,146,240,22,34,66,240, -31,255,0,0,56,255,240,9,92,159,27,255,239,39,207,206,63,255,0,5,116,255, -240,1,133,47,254,17,0, +101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115, +19,240,98,98,4,52,15,2,14,18,47,0,27,9,85,19,240,98,98,18,18,31,17,50,15,5, +47,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16, +18,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15, +12,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2, +6,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50, +98,34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15, +2,85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25, +35,63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21, +227,240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79, +21,5,15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240, +175,40,240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241, +79,27,43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32, +32,47,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57, +32,68,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247, +87,52,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15, +254,12,146,240,184,132,52,95,70,114,47,74,35,111,26,63,78,240,63,11,242, +127,0,255,224,244,255,240,0,138,143,60,255,240,4,13,223,7,255,227,127,243, +95,30,63,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39, +243,26,34,35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13, +143,31,240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52, +48,32,240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150, +223,7,95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18, +18,245,207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10, +127,10,207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37, +255,223,13,79,33,242,31,16,239,14,111,22,191,14,63,20,87,36,241,207,142, +240,79,20,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241, +194,20,3,240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135, +31,50,15,1,50,34,240,191,30,240,212,240,223,21,114,240,207,13,242,107,240, +107,240,62,240,47,96,243,159,41,242,62,242,63,254,32,79,37,243,223,29,241, +47,9,240,207,20,241,191,19,64,223,32,240,3,240,112,32,241,95,2,47,9,244, +102,32,35,46,41,143,31,241,135,49,63,6,38,33,36,64,240,64,212,249,15,37, +240,67,242,127,32,240,97,32,250,175,31,241,179,241,111,32,240,96,242,223, +27,244,127,10,255,224,122,243,15,17,15,242,11,241,136,15,7,12,241,131,63, +40,242,159,249,130,241,95,3,15,35,240,239,98,98,18,241,111,7,15,254,26,223, +254,40,207,88,245,255,3,251,79,254,155,15,254,50,31,254,236,95,254,19,159, +255,0,16,173,255,225,43,143,15,246,63,14,240,79,32,240,35,241,31,5,111,3, +255,226,100,243,92,15,52,207,50,31,16,255,240,0,109,255,5,255,225,229,255, +240,1,64,31,254,1,31,67,255,224,126,255,231,248,245,182,196,136,159,255,0, +6,90,244,82,243,114,19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4, +98,255,224,70,63,9,47,9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255, +239,40,251,95,45,243,79,254,59,3,47,11,33,32,48,41,35,32,32,112,80,32,32, +34,33,32,48,32,32,32,32,33,32,51,38,35,35,32,41,47,1,98,36,47,1,255,240,0, +3,143,255,0,149,201,241,191,254,242,124,252,227,255,240,0,87,79,0,255,240, +0,194,63,254,177,63,254,17,0, }; #else /* IdentifierStart production with ASCII and non-BMP excluded */ @@ -88275,35 +89509,35 @@ const duk_uint8_t duk_unicode_ids_noa[1036] = { * Automatically generated by extract_chars.py, do not edit! */ -const duk_uint8_t duk_unicode_ids_noabmp[625] = { +const duk_uint8_t duk_unicode_ids_noabmp[626] = { 249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34, 2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191, 21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240, -101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19, -240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47, -2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18, -47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12, -38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6, -41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98, -34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2, -85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35, -63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227, -240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5, -15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40, -240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27, -43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47, -15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68, -112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52, -29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12, -146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255, -224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63, -253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34, -35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31, -240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32, -240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7, -95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245, -207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10, -207,73,69,53,53,50,0, +101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115, +19,240,98,98,4,52,15,2,14,18,47,0,27,9,85,19,240,98,98,18,18,31,17,50,15,5, +47,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16, +18,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15, +12,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2, +6,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50, +98,34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15, +2,85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25, +35,63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21, +227,240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79, +21,5,15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240, +175,40,240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241, +79,27,43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32, +32,47,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57, +32,68,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247, +87,52,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15, +254,12,146,240,184,132,52,95,70,114,47,74,35,111,26,63,78,240,63,11,242, +127,0,255,224,244,255,240,0,138,143,60,255,240,4,13,223,7,255,227,127,243, +95,30,63,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39, +243,26,34,35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13, +143,31,240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52, +48,32,240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150, +223,7,95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18, +18,245,207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10, +127,10,207,73,69,53,53,50,0, }; #endif @@ -88338,32 +89572,33 @@ const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = { * Automatically generated by extract_chars.py, do not edit! */ -const duk_uint8_t duk_unicode_idp_m_ids_noa[530] = { +const duk_uint8_t duk_unicode_idp_m_ids_noa[549] = { 255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112, 245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34, 36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50, 160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240, -97,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9, -240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50, -242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41, -244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245, -111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241, -241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242, -244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57, -241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31, -35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31, -255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242, -79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29, -208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, +97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9, +240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,35, +242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215, +41,244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160, +245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240, +241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41, +242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12, +57,241,237,242,47,4,153,121,246,130,47,5,80,82,50,251,143,42,36,255,225,0, +31,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91, +31,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161, +242,79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242, +29,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, 225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,15,254,27,16,253,64, 248,116,255,224,25,159,254,68,178,33,99,241,162,80,249,113,255,228,13,47, 39,239,17,159,1,63,31,175,39,151,47,22,210,159,37,13,47,34,218,36,159,68, 183,15,146,182,151,63,42,2,99,19,42,11,19,100,79,178,240,42,159,72,240,77, 159,199,99,143,13,31,68,240,31,1,159,67,201,159,69,229,159,254,9,169,255, -226,57,114,127,2,159,42,240,98,223,255,0,60,157,159,120,79,45,111,11,159, -254,46,191,30,240,35,255,240,3,191,225,255,240,0,59,164,69,151,54,241,3, -248,98,255,228,125,242,47,254,15,79,39,95,34,144,240,0,240,132,46,255,228, -68,98,240,19,98,18,79,254,121,150,245,246,105,255,240,192,105,175,224,0, +224,11,159,26,98,57,10,175,32,240,15,254,8,151,39,240,41,242,175,6,45,246, +197,64,33,38,32,153,255,240,3,191,169,247,132,242,214,240,185,255,226,235, +241,239,2,63,255,0,59,254,31,255,0,3,186,68,89,115,111,16,63,134,47,254,71, +223,34,255,224,244,242,117,242,41,15,0,15,8,66,239,254,68,70,47,1,54,33,36, +255,231,153,111,95,102,159,255,12,6,154,254,0, }; #else /* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */ @@ -88372,23 +89607,23 @@ const duk_uint8_t duk_unicode_idp_m_ids_noa[530] = { * Automatically generated by extract_chars.py, do not edit! */ -const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357] = { +const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358] = { 255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112, 245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34, 36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50, 160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240, -97,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9, -240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50, -242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41, -244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245, -111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241, -241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242, -244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57, -241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31, -35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31, -255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242, -79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29, -208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, +97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9, +240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,35, +242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215, +41,244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160, +245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240, +241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41, +242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12, +57,241,237,242,47,4,153,121,246,130,47,5,80,82,50,251,143,42,36,255,225,0, +31,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91, +31,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161, +242,79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242, +29,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, 225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,0, }; #endif @@ -94576,6 +95811,10 @@ DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) { /* #include duk_internal.h -> already included */ +/* XXX: Avoid duk_{memcmp,memmove}_unsafe() by imposing a minimum length of + * >0 for the underlying dynamic buffer. + */ + /* * Macro support functions (use only macros in calling code) */ @@ -94587,6 +95826,9 @@ DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, DUK_ASSERT(bw_ctx != NULL); DUK_UNREF(thr); + /* 'p' might be NULL when the underlying buffer is zero size. If so, + * the resulting pointers are not used unsafely. + */ p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf); DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0)); bw_ctx->p = p + curr_offset; @@ -94595,7 +95837,6 @@ DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, } DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) { - DUK_ASSERT(thr != NULL); DUK_ASSERT(bw_ctx != NULL); DUK_ASSERT(h_buf != NULL); @@ -94610,6 +95851,7 @@ DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ct (void) duk_push_dynamic_buffer(thr, buf_size); bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1); + DUK_ASSERT(bw_ctx->buf != NULL); duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size); } @@ -94634,7 +95876,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ if (DUK_UNLIKELY(new_sz < curr_off)) { /* overflow */ DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); - return NULL; /* not reachable */ + DUK_WO_NORETURN(return NULL;); } #if 0 /* for manual torture testing: tight allocation, useful with valgrind */ new_sz = curr_off + sz; @@ -94677,9 +95919,9 @@ DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw DUK_UNREF(thr); p_base = bw->p_base; - DUK_MEMCPY((void *) bw->p, - (const void *) (p_base + src_off), - (size_t) len); + duk_memcpy_unsafe((void *) bw->p, + (const void *) (p_base + src_off), + (size_t) len); bw->p += len; } @@ -94709,12 +95951,12 @@ DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *b move_sz = buf_sz - dst_off; DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ - DUK_MEMMOVE((void *) (p_base + dst_off + len), - (const void *) (p_base + dst_off), - (size_t) move_sz); - DUK_MEMCPY((void *) (p_base + dst_off), - (const void *) buf, - (size_t) len); + duk_memmove_unsafe((void *) (p_base + dst_off + len), + (const void *) (p_base + dst_off), + (size_t) move_sz); + duk_memcpy_unsafe((void *) (p_base + dst_off), + (const void *) buf, + (size_t) len); bw->p += len; } @@ -94756,12 +95998,12 @@ DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b move_sz = buf_sz - dst_off; DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ - DUK_MEMMOVE((void *) (p_base + dst_off + len), - (const void *) (p_base + dst_off), - (size_t) move_sz); - DUK_MEMCPY((void *) (p_base + dst_off), - (const void *) (p_base + src_off), - (size_t) len); + duk_memmove_unsafe((void *) (p_base + dst_off + len), + (const void *) (p_base + dst_off), + (size_t) move_sz); + duk_memcpy_unsafe((void *) (p_base + dst_off), + (const void *) (p_base + src_off), + (size_t) len); bw->p += len; } @@ -94794,7 +96036,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter move_sz = buf_sz - off; p_dst = p_base + off + len; p_src = p_base + off; - DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz); + duk_memmove_unsafe((void *) p_dst, (const void *) p_src, (size_t) move_sz); return p_src; /* point to start of 'reserved area' */ } @@ -94825,9 +96067,9 @@ DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b p_dst = p_base + off; p_src = p_dst + len; move_sz = (duk_size_t) (bw->p - p_src); - DUK_MEMMOVE((void *) p_dst, - (const void *) p_src, - (size_t) move_sz); + duk_memmove_unsafe((void *) p_dst, + (const void *) p_src, + (size_t) move_sz); bw->p -= len; } @@ -94848,7 +96090,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) duk_uint16_t x; } u; - DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2); + duk_memcpy((void *) u.b, (const void *) (*p), (size_t) 2); u.x = DUK_NTOH16(u.x); *p += 2; return u.x; @@ -94860,7 +96102,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) duk_uint32_t x; } u; - DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4); + duk_memcpy((void *) u.b, (const void *) (*p), (size_t) 4); u.x = DUK_NTOH32(u.x); *p += 4; return u.x; @@ -94873,10 +96115,10 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t * duk_uint32_t x; } u; - DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4); + duk_memcpy((void *) u.b, (const void *) (*p), (size_t) 4); u.x = DUK_NTOH32(u.x); du.ui[DUK_DBL_IDX_UI0] = u.x; - DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4); + duk_memcpy((void *) u.b, (const void *) (*p + 4), (size_t) 4); u.x = DUK_NTOH32(u.x); du.ui[DUK_DBL_IDX_UI1] = u.x; *p += 8; @@ -94891,7 +96133,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_ui } u; u.x = DUK_HTON16(val); - DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2); + duk_memcpy((void *) (*p), (const void *) u.b, (size_t) 2); *p += 2; } @@ -94902,7 +96144,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_ui } u; u.x = DUK_HTON32(val); - DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4); + duk_memcpy((void *) (*p), (const void *) u.b, (size_t) 4); *p += 4; } @@ -94916,12 +96158,416 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk du.d = val; u.x = du.ui[DUK_DBL_IDX_UI0]; u.x = DUK_HTON32(u.x); - DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4); + duk_memcpy((void *) (*p), (const void *) u.b, (size_t) 4); u.x = du.ui[DUK_DBL_IDX_UI1]; u.x = DUK_HTON32(u.x); - DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4); + duk_memcpy((void *) (*p + 4), (const void *) u.b, (size_t) 4); *p += 8; } +#line 1 "duk_util_cast.c" +/* + * Cast helpers. + * + * C99+ coercion is challenging portability-wise because out-of-range casts + * may invoke implementation defined or even undefined behavior. See e.g. + * http://blog.frama-c.com/index.php?post/2013/10/09/Overflow-float-integer. + * + * Provide explicit cast helpers which try to avoid implementation defined + * or undefined behavior. These helpers can then be simplified in the vast + * majority of cases where the implementation defined or undefined behavior + * is not problematic. + */ + +/* #include duk_internal.h -> already included */ + +/* Portable double-to-integer cast which avoids undefined behavior and avoids + * relying on fmin(), fmax(), or other intrinsics. Out-of-range results are + * not assumed by caller, but here value is clamped, NaN converts to minval. + */ +#define DUK__DOUBLE_INT_CAST1(tname,minval,maxval) do { \ + if (DUK_LIKELY(x >= (duk_double_t) (minval))) { \ + DUK_ASSERT(!DUK_ISNAN(x)); \ + if (DUK_LIKELY(x <= (duk_double_t) (maxval))) { \ + return (tname) x; \ + } else { \ + return (tname) (maxval); \ + } \ + } else { \ + /* NaN or below minval. Since we don't care about the result \ + * for out-of-range values, just return the minimum value for \ + * both. \ + */ \ + return (tname) (minval); \ + } \ + } while (0) + +/* Rely on specific NaN behavior for duk_double_{fmin,fmax}(): if either + * argument is a NaN, return the second argument. This avoids a + * NaN-to-integer cast which is undefined behavior. + */ +#define DUK__DOUBLE_INT_CAST2(tname,minval,maxval) do { \ + return (tname) duk_double_fmin(duk_double_fmax(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \ + } while (0) + +/* Another solution which doesn't need C99+ behavior for fmin() and fmax(). */ +#define DUK__DOUBLE_INT_CAST3(tname,minval,maxval) do { \ + if (DUK_ISNAN(x)) { \ + /* 0 or any other value is fine. */ \ + return (tname) 0; \ + } else \ + return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \ + } \ + } while (0) + +/* C99+ solution: relies on specific fmin() and fmax() behavior in C99: if + * one argument is NaN but the other isn't, the non-NaN argument is returned. + * Because the limits are non-NaN values, explicit NaN check is not needed. + * This may not work on all legacy platforms, and also doesn't seem to inline + * the fmin() and fmax() calls (unless one uses -ffast-math which we don't + * support). + */ +#define DUK__DOUBLE_INT_CAST4(tname,minval,maxval) do { \ + return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \ + } while (0) + +DUK_INTERNAL duk_int_t duk_double_to_int_t(duk_double_t x) { +#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) + /* Real world solution: almost any practical platform will provide + * an integer value without any guarantees what it is (which is fine). + */ + return (duk_int_t) x; +#else + DUK__DOUBLE_INT_CAST1(duk_int_t, DUK_INT_MIN, DUK_INT_MAX); +#endif +} + +DUK_INTERNAL duk_uint_t duk_double_to_uint_t(duk_double_t x) { +#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) + return (duk_uint_t) x; +#else + DUK__DOUBLE_INT_CAST1(duk_uint_t, DUK_UINT_MIN, DUK_UINT_MAX); +#endif +} + +DUK_INTERNAL duk_int32_t duk_double_to_int32_t(duk_double_t x) { +#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) + return (duk_int32_t) x; +#else + DUK__DOUBLE_INT_CAST1(duk_int32_t, DUK_INT32_MIN, DUK_INT32_MAX); +#endif +} + +DUK_INTERNAL duk_uint32_t duk_double_to_uint32_t(duk_double_t x) { +#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) + return (duk_uint32_t) x; +#else + DUK__DOUBLE_INT_CAST1(duk_uint32_t, DUK_UINT32_MIN, DUK_UINT32_MAX); +#endif +} + +/* Largest IEEE double that doesn't round to infinity in the default rounding + * mode. The exact midpoint between (1 - 2^(-24)) * 2^128 and 2^128 rounds to + * infinity, at least on x64. This number is one double unit below that + * midpoint. See misc/float_cast.c. + */ +#define DUK__FLOAT_ROUND_LIMIT 340282356779733623858607532500980858880.0 + +/* Maximum IEEE float. Double-to-float conversion above this would be out of + * range and thus technically undefined behavior. + */ +#define DUK__FLOAT_MAX 340282346638528859811704183484516925440.0 + +DUK_INTERNAL duk_float_t duk_double_to_float_t(duk_double_t x) { + /* Even a double-to-float cast is technically undefined behavior if + * the double is out-of-range. C99 Section 6.3.1.5: + * + * If the value being converted is in the range of values that can + * be represented but cannot be represented exactly, the result is + * either the nearest higher or nearest lower representable value, + * chosen in an implementation-defined manner. If the value being + * converted is outside the range of values that can be represented, + * the behavior is undefined. + */ +#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) + return (duk_float_t) x; +#else + duk_double_t t; + + t = DUK_FABS(x); + DUK_ASSERT((DUK_ISNAN(x) && DUK_ISNAN(t)) || + (!DUK_ISNAN(x) && !DUK_ISNAN(t))); + + if (DUK_LIKELY(t <= DUK__FLOAT_MAX)) { + /* Standard in-range case, try to get here with a minimum + * number of checks and branches. + */ + DUK_ASSERT(!DUK_ISNAN(x)); + return (duk_float_t) x; + } else if (t <= DUK__FLOAT_ROUND_LIMIT) { + /* Out-of-range, but rounds to min/max float. */ + DUK_ASSERT(!DUK_ISNAN(x)); + if (x < 0.0) { + return (duk_float_t) -DUK__FLOAT_MAX; + } else { + return (duk_float_t) DUK__FLOAT_MAX; + } + } else if (DUK_ISNAN(x)) { + /* Assumes double NaN -> float NaN considered "in range". */ + DUK_ASSERT(DUK_ISNAN(x)); + return (duk_float_t) x; + } else { + /* Out-of-range, rounds to +/- Infinity. */ + if (x < 0.0) { + return (duk_float_t) -DUK_DOUBLE_INFINITY; + } else { + return (duk_float_t) DUK_DOUBLE_INFINITY; + } + } +#endif +} + +/* automatic undefs */ +#undef DUK__DOUBLE_INT_CAST1 +#undef DUK__DOUBLE_INT_CAST2 +#undef DUK__DOUBLE_INT_CAST3 +#undef DUK__DOUBLE_INT_CAST4 +#undef DUK__FLOAT_MAX +#undef DUK__FLOAT_ROUND_LIMIT +#line 1 "duk_util_double.c" +/* + * IEEE double helpers. + */ + +/* #include duk_internal.h -> already included */ + +DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) { + duk_double_union du; + du.d = x; + return DUK_DBLUNION_IS_ANYINF(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) { + duk_double_union du; + du.d = x; + return DUK_DBLUNION_IS_POSINF(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) { + duk_double_union du; + du.d = x; + return DUK_DBLUNION_IS_NEGINF(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) { + duk_double_union du; + du.d = x; + /* Assumes we're dealing with a Duktape internal NaN which is + * NaN normalized if duk_tval requires it. + */ + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); + return DUK_DBLUNION_IS_NAN(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) { + duk_double_union du; + du.d = x; + /* Assumes we're dealing with a Duktape internal NaN which is + * NaN normalized if duk_tval requires it. + */ + DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); + return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du); +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) { + duk_double_union du; + du.d = x; + /* If exponent is 0x7FF the argument is either a NaN or an + * infinity. We don't need to check any other fields. + */ +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) + return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000); +#else + return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000); +#endif +#else + return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL; +#endif +} + +DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) { + duk_double_union du; +#if defined(DUK_USE_64BIT_OPS) + duk_uint64_t t; +#else + duk_uint32_t t; +#endif + du.d = x; +#if defined(DUK_USE_64BIT_OPS) +#if defined(DUK_USE_DOUBLE_ME) + t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000); + if (t == DUK_U64_CONSTANT(0x0000000000000000)) { + t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000); + return t == 0; + } + if (t == DUK_U64_CONSTANT(0x000000007ff00000)) { + return 1; + } +#else + t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000); + if (t == DUK_U64_CONSTANT(0x0000000000000000)) { + t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000); + return t == 0; + } + if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) { + return 1; + } +#endif +#else + t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL; + if (t == 0x00000000UL) { + return DUK_DBLUNION_IS_ANYZERO(&du); + } + if (t == 0x7ff00000UL) { + return 1; + } +#endif + return 0; +} + +DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) { + duk_double_union du; + du.d = x; + return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du); +} + +DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) { + /* XXX: optimize */ + duk_small_uint_t s = duk_double_signbit(x); + x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */ + if (s) { + x = -x; + } + return x; +} + +DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) { + duk_double_union du1; + duk_double_union du2; + du1.d = x; + du2.d = y; + + return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0); +} + +DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) { + /* Doesn't replicate fmin() behavior exactly: for fmin() if one + * argument is a NaN, the other argument should be returned. + * Duktape doesn't rely on this behavior so the replacement can + * be simplified. + */ + return (x < y ? x : y); +} + +DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) { + /* Doesn't replicate fmax() behavior exactly: for fmax() if one + * argument is a NaN, the other argument should be returned. + * Duktape doesn't rely on this behavior so the replacement can + * be simplified. + */ + return (x > y ? x : y); +} + +DUK_INTERNAL duk_bool_t duk_double_is_finite(duk_double_t x) { + return !duk_double_is_nan_or_inf(x); +} + +DUK_INTERNAL duk_bool_t duk_double_is_integer(duk_double_t x) { + if (duk_double_is_nan_or_inf(x)) { + return 0; + } else { + return duk_js_tointeger_number(x) == x; + } +} + +DUK_INTERNAL duk_bool_t duk_double_is_safe_integer(duk_double_t x) { + /* >>> 2**53-1 + * 9007199254740991 + */ + return duk_double_is_integer(x) && DUK_FABS(x) <= 9007199254740991.0; +} + +/* Check whether a duk_double_t is a whole number in the 32-bit range (reject + * negative zero), and if so, return a duk_int32_t. + * For compiler use: don't allow negative zero as it will cause trouble with + * LDINT+LDINTX, positive zero is OK. + */ +DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) { + duk_int32_t t; + + t = duk_double_to_int32_t(x); + if (!((duk_double_t) t == x)) { + return 0; + } + if (t == 0) { + duk_double_union du; + du.d = x; + if (DUK_DBLUNION_HAS_SIGNBIT(&du)) { + return 0; + } + } + *ival = t; + return 1; +} + +/* Check whether a duk_double_t is a whole number in the 32-bit range, and if + * so, return a duk_int32_t. + */ +DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) { + duk_int32_t t; + + t = duk_double_to_int32_t(x); + if (!((duk_double_t) t == x)) { + return 0; + } + *ival = t; + return 1; +} + +/* Division: division by zero is undefined behavior (and may in fact trap) + * so it needs special handling for portability. + */ + +DUK_INTERNAL DUK_INLINE duk_double_t duk_double_div(duk_double_t x, duk_double_t y) { +#if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) + if (DUK_UNLIKELY(y == 0.0)) { + /* In C99+ division by zero is undefined behavior so + * avoid it entirely. Hopefully the compiler is + * smart enough to avoid emitting any actual code + * because almost all practical platforms behave as + * expected. + */ + if (x > 0.0) { + if (DUK_SIGNBIT(y)) { + return -DUK_DOUBLE_INFINITY; + } else { + return DUK_DOUBLE_INFINITY; + } + } else if (x < 0.0) { + if (DUK_SIGNBIT(y)) { + return DUK_DOUBLE_INFINITY; + } else { + return -DUK_DOUBLE_INFINITY; + } + } else { + /* +/- 0, NaN */ + return DUK_DOUBLE_NAN; + } + } +#endif + + return x / y; +} #line 1 "duk_util_hashbytes.c" /* * Hash function duk_util_hashbytes(). @@ -94984,6 +96630,43 @@ DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t /* automatic undefs */ #undef DUK__MAGIC_M #undef DUK__MAGIC_R +#line 1 "duk_util_memory.c" +/* + * Memory utils. + */ + +/* #include duk_internal.h -> already included */ + +#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) +DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) { + DUK_ASSERT(s1 != NULL || len == 0U); + DUK_ASSERT(s2 != NULL || len == 0U); + return DUK_MEMCMP(s1, s2, (size_t) len); +} + +DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) { + DUK_ASSERT(s1 != NULL); + DUK_ASSERT(s2 != NULL); + return DUK_MEMCMP(s1, s2, (size_t) len); +} +#else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ +DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) { + DUK_ASSERT(s1 != NULL || len == 0U); + DUK_ASSERT(s2 != NULL || len == 0U); + if (DUK_UNLIKELY(len == 0U)) { + return 0; + } + DUK_ASSERT(s1 != NULL); + DUK_ASSERT(s2 != NULL); + return duk_memcmp(s1, s2, len); +} + +DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) { + DUK_ASSERT(s1 != NULL); + DUK_ASSERT(s2 != NULL); + return DUK_MEMCMP(s1, s2, (size_t) len); +} +#endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ #line 1 "duk_util_tinyrandom.c" /* * A tiny random number generator used for Math.random() and other internals. diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go index 83a7a80872..91f1b9327b 100644 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go @@ -199,7 +199,7 @@ func (e *Error) Error() string { return fmt.Sprintf("%s: %s", e.Type, e.Message) } -type Type int +type Type uint func (t Type) IsNone() bool { return t == TypeNone } func (t Type) IsUndefined() bool { return t == TypeUndefined } diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.h b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.h index 595cd77ec7..36f8060fd4 100755 --- a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.h +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.h @@ -1,12 +1,12 @@ /* - * Duktape public API for Duktape 2.2.0. + * Duktape public API for Duktape 2.3.0. * * See the API reference for documentation on call semantics. The exposed, * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API" * comments. Other parts of the header are Duktape internal and related to * e.g. platform/compiler/feature detection. * - * Git commit a459cf3c9bd1779fc01b435d69302b742675a08f (v2.2.0). + * Git commit d7fdb67f18561a50e06bafd196c6b423af9ad6fe (v2.3.0). * Git branch master. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and @@ -18,21 +18,21 @@ * =============== * Duktape license * =============== - * + * * (http://opensource.org/licenses/MIT) - * - * Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst) - * + * + * Copyright (c) 2013-2018 by Duktape authors (see AUTHORS.rst) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -47,24 +47,24 @@ * =============== * Duktape authors * =============== - * + * * Copyright * ========= - * + * * Duktape copyrights are held by its authors. Each author has a copyright * to their contribution, and agrees to irrevocably license the contribution * under the Duktape ``LICENSE.txt``. - * + * * Authors * ======= - * + * * Please include an e-mail address, a link to your GitHub profile, or something * similar to allow your contribution to be identified accurately. - * + * * The following people have contributed code, website contents, or Wiki contents, * and agreed to irrevocably license their contributions under the Duktape * ``LICENSE.txt`` (in order of appearance): - * + * * * Sami Vaarala * * Niki Dobrev * * Andreas \u00d6man @@ -92,13 +92,21 @@ * * Steven Don (https://github.com/shdon) * * Simon Stone (https://github.com/sstone1) * * \J. McC. (https://github.com/jmhmccr) - * + * * Jakub Nowakowski (https://github.com/jimvonmoon) + * * Tommy Nguyen (https://github.com/tn0502) + * * Fabrice Fontaine (https://github.com/ffontaine) + * * Christopher Hiller (https://github.com/boneskull) + * * Gonzalo Diethelm (https://github.com/gonzus) + * * Michal Kasperek (https://github.com/michalkas) + * * Andrew Janke (https://github.com/apjanke) + * * Steve Fan (https://github.com/stevefan1999) + * * Other contributions * =================== - * + * * The following people have contributed something other than code (e.g. reported * bugs, provided ideas, etc; roughly in order of appearance): - * + * * * Greg Burns * * Anthony Rabine * * Carlos Costa @@ -130,7 +138,9 @@ * * https://github.com/chris-y * * Laurent Zubiaur (https://github.com/lzubiaur) * * Neil Kolban (https://github.com/nkolban) - * + * * Wilhelm Wanecek (https://github.com/wanecek) + * * Andrew Janke (https://github.com/apjanke) + * * If you are accidentally missing from this list, send me an e-mail * (``sami.vaarala@iki.fi``) and I'll fix the omission. */ @@ -150,19 +160,19 @@ /* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value - * is also available to Ecmascript code in Duktape.version. Unofficial + * is also available to ECMAScript code in Duktape.version. Unofficial * development snapshots have 99 for patch level (e.g. 0.10.99 would be a * development version after 0.10.0 but before the next official release). */ -#define DUK_VERSION 20200L +#define DUK_VERSION 20300L /* Git commit, describe, and branch for Duktape build. Useful for * non-official snapshot builds so that application code can easily log - * which Duktape snapshot was used. Not available in the Ecmascript + * which Duktape snapshot was used. Not available in the ECMAScript * environment. */ -#define DUK_GIT_COMMIT "a459cf3c9bd1779fc01b435d69302b742675a08f" -#define DUK_GIT_DESCRIBE "v2.2.0" +#define DUK_GIT_COMMIT "d7fdb67f18561a50e06bafd196c6b423af9ad6fe" +#define DUK_GIT_DESCRIBE "v2.3.0" #define DUK_GIT_BRANCH "master" /* External duk_config.h provides platform/compiler/OS dependent @@ -258,7 +268,7 @@ struct duk_number_list_entry { }; struct duk_time_components { - duk_double_t year; /* year, e.g. 2016, Ecmascript year range */ + duk_double_t year; /* year, e.g. 2016, ECMAScript year range */ duk_double_t month; /* month: 1-12 */ duk_double_t day; /* day: 1-31 */ duk_double_t hours; /* hour: 0-59 */ @@ -294,12 +304,12 @@ struct duk_time_components { /* Value types, used by e.g. duk_get_type() */ #define DUK_TYPE_MIN 0U #define DUK_TYPE_NONE 0U /* no value, e.g. invalid index */ -#define DUK_TYPE_UNDEFINED 1U /* Ecmascript undefined */ -#define DUK_TYPE_NULL 2U /* Ecmascript null */ -#define DUK_TYPE_BOOLEAN 3U /* Ecmascript boolean: 0 or 1 */ -#define DUK_TYPE_NUMBER 4U /* Ecmascript number: double */ -#define DUK_TYPE_STRING 5U /* Ecmascript string: CESU-8 / extended UTF-8 encoded */ -#define DUK_TYPE_OBJECT 6U /* Ecmascript object: includes objects, arrays, functions, threads */ +#define DUK_TYPE_UNDEFINED 1U /* ECMAScript undefined */ +#define DUK_TYPE_NULL 2U /* ECMAScript null */ +#define DUK_TYPE_BOOLEAN 3U /* ECMAScript boolean: 0 or 1 */ +#define DUK_TYPE_NUMBER 4U /* ECMAScript number: double */ +#define DUK_TYPE_STRING 5U /* ECMAScript string: CESU-8 / extended UTF-8 encoded */ +#define DUK_TYPE_OBJECT 6U /* ECMAScript object: includes objects, arrays, functions, threads */ #define DUK_TYPE_BUFFER 7U /* fixed or dynamic, garbage collected byte buffer */ #define DUK_TYPE_POINTER 8U /* raw void pointer */ #define DUK_TYPE_LIGHTFUNC 9U /* lightweight function pointer */ @@ -668,7 +678,21 @@ DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p); DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...); DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap); +/* duk_push_literal() may evaluate its argument (a C string literal) more than + * once on purpose. When speed is preferred, sizeof() avoids an unnecessary + * strlen() at runtime. Sizeof("foo") == 4, so subtract 1. The argument + * must be non-NULL and should not contain internal NUL characters as the + * behavior will then depend on config options. + */ +#if defined(DUK_USE_PREFER_SIZE) +#define duk_push_literal(ctx,cstring) duk_push_string((ctx), (cstring)) +#else +DUK_EXTERNAL_DECL const char *duk_push_literal_raw(duk_context *ctx, const char *str, duk_size_t len); +#define duk_push_literal(ctx,cstring) duk_push_literal_raw((ctx), (cstring), sizeof((cstring)) - 1U) +#endif + DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx); +DUK_EXTERNAL_DECL void duk_push_new_target(duk_context *ctx); DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx); DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx); DUK_EXTERNAL_DECL void duk_push_global_object(duk_context *ctx); @@ -1000,29 +1024,55 @@ DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void * /* * Property access * - * The basic function assumes key is on stack. The _string variant takes - * a C string as a property name, while the _index variant takes an array - * index as a property name (e.g. 123 is equivalent to the key "123"). + * The basic function assumes key is on stack. The _(l)string variant takes + * a C string as a property name; the _literal variant takes a C literal. + * The _index variant takes an array index as a property name (e.g. 123 is + * equivalent to the key "123"). The _heapptr variant takes a raw, borrowed + * heap pointer. */ DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx); DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#if defined(DUK_USE_PREFER_SIZE) +#define duk_get_prop_literal(ctx,obj_idx,key) duk_get_prop_string((ctx), (obj_idx), (key)) +#else +DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_literal_raw(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#define duk_get_prop_literal(ctx,obj_idx,key) duk_get_prop_literal_raw((ctx), (obj_idx), (key), sizeof((key)) - 1U) +#endif DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx); DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#if defined(DUK_USE_PREFER_SIZE) +#define duk_put_prop_literal(ctx,obj_idx,key) duk_put_prop_string((ctx), (obj_idx), (key)) +#else +DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_literal_raw(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#define duk_put_prop_literal(ctx,obj_idx,key) duk_put_prop_literal_raw((ctx), (obj_idx), (key), sizeof((key)) - 1U) +#endif DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx); DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#if defined(DUK_USE_PREFER_SIZE) +#define duk_del_prop_literal(ctx,obj_idx,key) duk_del_prop_string((ctx), (obj_idx), (key)) +#else +DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_literal_raw(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#define duk_del_prop_literal(ctx,obj_idx,key) duk_del_prop_literal_raw((ctx), (obj_idx), (key), sizeof((key)) - 1U) +#endif DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx); DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key); DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#if defined(DUK_USE_PREFER_SIZE) +#define duk_has_prop_literal(ctx,obj_idx,key) duk_has_prop_string((ctx), (obj_idx), (key)) +#else +DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_literal_raw(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len); +#define duk_has_prop_literal(ctx,obj_idx,key) duk_has_prop_literal_raw((ctx), (obj_idx), (key), sizeof((key)) - 1U) +#endif DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx); DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr); @@ -1031,8 +1081,22 @@ DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uin DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key); DUK_EXTERNAL_DECL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); +#if defined(DUK_USE_PREFER_SIZE) +#define duk_get_global_literal(ctx,key) duk_get_global_string((ctx), (key)) +#else +DUK_EXTERNAL_DECL duk_bool_t duk_get_global_literal_raw(duk_context *ctx, const char *key, duk_size_t key_len); +#define duk_get_global_literal(ctx,key) duk_get_global_literal_raw((ctx), (key), sizeof((key)) - 1U) +#endif +DUK_EXTERNAL_DECL duk_bool_t duk_get_global_heapptr(duk_context *ctx, void *ptr); DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key); DUK_EXTERNAL_DECL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len); +#if defined(DUK_USE_PREFER_SIZE) +#define duk_put_global_literal(ctx,key) duk_put_global_string((ctx), (key)) +#else +DUK_EXTERNAL_DECL duk_bool_t duk_put_global_literal_raw(duk_context *ctx, const char *key, duk_size_t key_len); +#define duk_put_global_literal(ctx,key) duk_put_global_literal_raw((ctx), (key), sizeof((key)) - 1U) +#endif +DUK_EXTERNAL_DECL duk_bool_t duk_put_global_heapptr(duk_context *ctx, void *ptr); /* * Inspection @@ -1099,7 +1163,7 @@ DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t idx); DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset); /* - * Ecmascript operators + * ECMAScript operators */ DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); @@ -1107,6 +1171,12 @@ DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2); +/* + * Random + */ + +DUK_EXTERNAL_DECL duk_double_t duk_random(duk_context *ctx); + /* * Function (method) calls */ @@ -1257,7 +1327,7 @@ DUK_EXTERNAL_DECL duk_double_t duk_components_to_time(duk_context *ctx, duk_time #define DUK_DATE_MSEC_HOUR (60L * 60L * 1000L) #define DUK_DATE_MSEC_DAY (24L * 60L * 60L * 1000L) -/* Ecmascript date range is 100 million days from Epoch: +/* ECMAScript date range is 100 million days from Epoch: * > 100e6 * 24 * 60 * 60 * 1000 // 100M days in millisecs * 8640000000000000 * (= 8.64e15) @@ -1265,7 +1335,7 @@ DUK_EXTERNAL_DECL duk_double_t duk_components_to_time(duk_context *ctx, duk_time #define DUK_DATE_MSEC_100M_DAYS (8.64e15) #define DUK_DATE_MSEC_100M_DAYS_LEEWAY (8.64e15 + 24 * 3600e3) -/* Ecmascript year range: +/* ECMAScript year range: * > new Date(100e6 * 24 * 3600e3).toISOString() * '+275760-09-13T00:00:00.000Z' * > new Date(-100e6 * 24 * 3600e3).toISOString() @@ -1275,7 +1345,7 @@ DUK_EXTERNAL_DECL duk_double_t duk_components_to_time(duk_context *ctx, duk_time #define DUK_DATE_MAX_ECMA_YEAR 275760L /* Part indices for internal breakdowns. Part order from DUK_DATE_IDX_YEAR - * to DUK_DATE_IDX_MILLISECOND matches argument ordering of Ecmascript API + * to DUK_DATE_IDX_MILLISECOND matches argument ordering of ECMAScript API * calls (like Date constructor call). Some functions in duk_bi_date.c * depend on the specific ordering, so change with care. 16 bits are not * enough for all parts (year, specifically). diff --git a/vendor/vendor.json b/vendor/vendor.json index 406c1c4c7a..b3e1118007 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -941,10 +941,10 @@ "revisionTime": "2016-06-21T03:49:01Z" }, { - "checksumSHA1": "vndxs5Tv09/8S+Dr2PBAiM557lI=", + "checksumSHA1": "h+m6mYCZIKnMQI24faKak5o19es=", "path": "gopkg.in/olebedev/go-duktape.v3", - "revision": "abf0ba0be5d5d36b1f9266463cc320b9a5ab224e", - "revisionTime": "2018-03-02T12:15:09Z" + "revision": "ec84240a7772c7a122b1c58a13398210659f7c40", + "revisionTime": "2019-02-13T23:42:57Z" }, { "checksumSHA1": "4BwmmgQUhWtizsR2soXND0nqZ1I=", From 75a860880cfc88cc515ef91301aea0f7df4c17bc Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Fri, 3 May 2019 17:17:45 +0200 Subject: [PATCH 14/47] accounts/scwallet: display PUK retry count, validate PIN/PUK length --- accounts/scwallet/wallet.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 71b2c68af1..c480282819 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -27,6 +27,7 @@ import ( "errors" "fmt" "math/big" + "regexp" "sort" "strings" "sync" @@ -310,8 +311,10 @@ func (w *Wallet) Status() (string, error) { return fmt.Sprintf("Failed: %v", err), err } switch { + case !w.session.verified && status.PinRetryCount == 0 && status.PukRetryCount == 0: + return fmt.Sprintf("Bricked, waiting for full wipe"), nil case !w.session.verified && status.PinRetryCount == 0: - return fmt.Sprintf("Blocked, waiting for PUK and new PIN"), nil + return fmt.Sprintf("Blocked, waiting for PUK (%d attempts left) and new PIN", status.PukRetryCount), nil case !w.session.verified: return fmt.Sprintf("Locked, waiting for PIN (%d attempts left)", status.PinRetryCount), nil case !status.Initialized: @@ -377,10 +380,18 @@ func (w *Wallet) Open(passphrase string) error { case passphrase == "": return ErrPINUnblockNeeded case status.PinRetryCount > 0: + if !regexp.MustCompile(`^[0-9]{6,}$`).MatchString(passphrase) { + w.log.Error("PIN needs to be at least 6 digits") + return ErrPINNeeded + } if err := w.session.verifyPin([]byte(passphrase)); err != nil { return err } default: + if !regexp.MustCompile(`^[0-9]{12,}$`).MatchString(passphrase) { + w.log.Error("PUK needs to be at least 12 digits") + return ErrPINUnblockNeeded + } if err := w.session.unblockPin([]byte(passphrase)); err != nil { return err } From 7bc1cb3677ba18b83fa094799de4a4e8589a4eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 27 May 2019 17:27:18 +0300 Subject: [PATCH 15/47] accounts/scwallet: fix public key confirmation regression --- accounts/scwallet/wallet.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index c480282819..57b5977062 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -982,12 +982,10 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error) copy(sig[32-len(rbytes):32], rbytes) copy(sig[64-len(sbytes):64], sbytes) - pubkey, err := determinePublicKey(sig, sigdata.PublicKey) - if err != nil { + if err := confirmPublicKey(sig, sigdata.PublicKey); err != nil { return accounts.Account{}, err } - - pub, err := crypto.UnmarshalPubkey(pubkey) + pub, err := crypto.UnmarshalPubkey(sigdata.PublicKey) if err != nil { return accounts.Account{}, err } @@ -1057,10 +1055,10 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error return sig, nil } -// determinePublicKey uses a signature and the X component of a public key to -// recover the entire public key. -func determinePublicKey(sig, pubkeyX []byte) ([]byte, error) { - return makeRecoverableSignature(DerivationSignatureHash[:], sig, pubkeyX) +// confirmPublicKey confirms that the given signature belongs to the specified key. +func confirmPublicKey(sig, pubkey []byte) error { + _, err := makeRecoverableSignature(DerivationSignatureHash[:], sig, pubkey) + return err } // makeRecoverableSignature uses a signature and an expected public key to From f0bced30bb44a3185bf3bb15c22dfa7f07dd668b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 27 May 2019 18:41:47 +0300 Subject: [PATCH 16/47] internal/build: fix Travis and AppVeyor commit string injection --- internal/build/env.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/build/env.go b/internal/build/env.go index b7aa0f1228..95f00035dc 100644 --- a/internal/build/env.go +++ b/internal/build/env.go @@ -57,7 +57,7 @@ func Env() Environment { case os.Getenv("CI") == "true" && os.Getenv("TRAVIS") == "true": commit := os.Getenv("TRAVIS_PULL_REQUEST_SHA") if commit == "" { - os.Getenv("TRAVIS_COMMIT") + commit = os.Getenv("TRAVIS_COMMIT") } return Environment{ Name: "travis", @@ -73,7 +73,7 @@ func Env() Environment { case os.Getenv("CI") == "True" && os.Getenv("APPVEYOR") == "True": commit := os.Getenv("APPVEYOR_PULL_REQUEST_HEAD_COMMIT") if commit == "" { - os.Getenv("APPVEYOR_REPO_COMMIT") + commit = os.Getenv("APPVEYOR_REPO_COMMIT") } return Environment{ Name: "appveyor", From 5429dc75bd15e5436221cc08891b6ef3c9d2378e Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Mon, 27 May 2019 21:28:17 +0300 Subject: [PATCH 17/47] cmd/abigen: allow using `abigen --pkg` flag with standard input (#19207) --- cmd/abigen/main.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index b6ec04ce16..461c294681 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -81,7 +81,7 @@ func main() { bins []string types []string ) - if *solFlag != "" || *vyFlag != "" || (*abiFlag == "-" && *pkgFlag == "") { + if *solFlag != "" || *vyFlag != "" || *abiFlag == "-" { // Generate the list of types to exclude from binding exclude := make(map[string]bool) for _, kind := range strings.Split(*excFlag, ",") { @@ -129,13 +129,8 @@ func main() { } } else { // Otherwise load up the ABI, optional bytecode and type name from the parameters - var abi []byte - var err error - if *abiFlag == "-" { - abi, err = ioutil.ReadAll(os.Stdin) - } else { - abi, err = ioutil.ReadFile(*abiFlag) - } + abi, err := ioutil.ReadFile(*abiFlag) + if err != nil { fmt.Printf("Failed to read input ABI: %v\n", err) os.Exit(-1) From 2388e425f236d16daaa1d206a35e0ca8be2f89bc Mon Sep 17 00:00:00 2001 From: Antoine Rondelet Date: Tue, 28 May 2019 07:13:30 +0100 Subject: [PATCH 18/47] crypto/bn256/cloudflare: fix comments to describe the updated curve parameters (#19577) * Removed comment section referring to Cloudflare's bn curve parameters * Added comment to clarify the nature of the parameters * Changed value of xi to i+9 --- crypto/bn256/cloudflare/constants.go | 5 ++++- crypto/bn256/cloudflare/gfp6.go | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/crypto/bn256/cloudflare/constants.go b/crypto/bn256/cloudflare/constants.go index 5122aae64f..f7d2c7c001 100644 --- a/crypto/bn256/cloudflare/constants.go +++ b/crypto/bn256/cloudflare/constants.go @@ -13,10 +13,13 @@ func bigFromBase10(s string) *big.Int { return n } -// u is the BN parameter that determines the prime: 1868033³. +// u is the BN parameter. var u = bigFromBase10("4965661367192848881") // Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. +// Needs to be highly 2-adic for efficient SNARK key and proof generation. +// Order - 1 = 2^28 * 3^2 * 13 * 29 * 983 * 11003 * 237073 * 405928799 * 1670836401704629 * 13818364434197438864469338081. +// Refer to https://eprint.iacr.org/2013/879.pdf and https://eprint.iacr.org/2013/507.pdf for more information on these parameters. var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617") // P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1. diff --git a/crypto/bn256/cloudflare/gfp6.go b/crypto/bn256/cloudflare/gfp6.go index 83d61b781f..a42734911c 100644 --- a/crypto/bn256/cloudflare/gfp6.go +++ b/crypto/bn256/cloudflare/gfp6.go @@ -5,7 +5,7 @@ package bn256 // http://eprint.iacr.org/2006/471.pdf. // gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ -// and ξ=i+3. +// and ξ=i+9. type gfP6 struct { x, y, z gfP2 // value is xτ² + yτ + z } From 048df258dc45721021824727eeeff856027e4f25 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Tue, 28 May 2019 18:47:53 +0200 Subject: [PATCH 19/47] accounts/scwallet: change sc url scheme to keycard (#19632) --- accounts/scwallet/README.md | 20 ++++++++++---------- accounts/scwallet/hub.go | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/accounts/scwallet/README.md b/accounts/scwallet/README.md index 20519e092d..cfca916b3a 100644 --- a/accounts/scwallet/README.md +++ b/accounts/scwallet/README.md @@ -25,13 +25,13 @@ Start `geth` with the `console` command. You will notice the following warning: ``` - WARN [04-09|16:58:38.898] Failed to open wallet url=pcsc://044def09 err="smartcard: pairing password needed" + WARN [04-09|16:58:38.898] Failed to open wallet url=keycard://044def09 err="smartcard: pairing password needed" ``` - Write down the URL (`pcsc://044def09` in this example). Then ask `geth` to open the wallet: + Write down the URL (`keycard://044def09` in this example). Then ask `geth` to open the wallet: ``` - > personal.openWallet("pcsc://044def09") + > personal.openWallet("keycard://044def09") Please enter the pairing password: ``` @@ -42,12 +42,12 @@ ``` > personal - WARN [04-09|17:02:07.330] Smartcard wallet account derivation failed url=pcsc://044def09 err="Unexpected response status Cla=0x80, Ins=0xd1, Sw=0x6985" + WARN [04-09|17:02:07.330] Smartcard wallet account derivation failed url=keycard://044def09 err="Unexpected response status Cla=0x80, Ins=0xd1, Sw=0x6985" { listAccounts: [], listWallets: [{ status: "Empty, waiting for initialization", - url: "pcsc://044def09" + url: "keycard://044def09" }], ... } @@ -56,7 +56,7 @@ So the communication with the card is working, but there is no key associated with this wallet. Let's create it: ``` - > personal.initializeWallet("pcsc://044def09") + > personal.initializeWallet("keycard://044def09") "tilt ... impact" ``` @@ -67,10 +67,10 @@ [{ accounts: [{ address: "0x678b7cd55c61917defb23546a41803c5bfefbc7a", - url: "pcsc://044d/m/44'/60'/0'/0/0" + url: "keycard://044d/m/44'/60'/0'/0/0" }], status: "Online", - url: "pcsc://044def09" + url: "keycard://044def09" }] ``` @@ -84,14 +84,14 @@ ``` listWallets: [{ status: "Online, can derive public keys", - url: "pcsc://a4d73015" + url: "keycard://a4d73015" }] ``` 3. Open the wallet, you will be prompted for your pairing password, then PIN: ``` -personal.openWallet("pcsc://a4d73015") +personal.openWallet("keycard://a4d73015") ``` 4. Check that creation was successful by typing e.g. `personal`. Then use it like a regular wallet. diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index c259f711f0..d1440cb96d 100644 --- a/accounts/scwallet/hub.go +++ b/accounts/scwallet/hub.go @@ -49,7 +49,7 @@ import ( ) // Scheme is the URI prefix for smartcard wallets. -const Scheme = "pcsc" +const Scheme = "keycard" // refreshCycle is the maximum time between wallet refreshes (if USB hotplug // notifications don't work). From cf38a3dc654adacf23e6b3bc4f74d629d19bd19f Mon Sep 17 00:00:00 2001 From: Rafael Matias Date: Wed, 29 May 2019 00:14:24 +0200 Subject: [PATCH 20/47] swarm/api: update mission statement (#19612) --- swarm/api/http/server_test.go | 2 +- swarm/api/http/templates.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go index 1de41d18d3..9df820ce4b 100644 --- a/swarm/api/http/server_test.go +++ b/swarm/api/http/server_test.go @@ -1043,7 +1043,7 @@ func TestGet(t *testing.T) { method: "GET", headers: map[string]string{"Accept": "text/html"}, expectedStatusCode: http.StatusOK, - assertResponseBody: "Swarm: Serverless Hosting Incentivised Peer-To-Peer Storage And Content Distribution", + assertResponseBody: "Swarm provides censorship resistant storage and communication infrastructure for a sovereign digital society", verbose: false, }, { diff --git a/swarm/api/http/templates.go b/swarm/api/http/templates.go index 986f5f8873..19c4040ca5 100644 --- a/swarm/api/http/templates.go +++ b/swarm/api/http/templates.go @@ -122,7 +122,7 @@ const errorResponse = `{{ define "content" }} {{ end }}` @@ -155,10 +155,10 @@ function goToPage() { - + {{ end }}` const baseTemplate = ` @@ -177,7 +177,7 @@ const baseTemplate = ` ` -const css = `{{ define "css" }} +const css = `{{ define "css" }} html { font-size: 18px; font-size: 1.13rem; @@ -299,7 +299,7 @@ input[type=text]:focus { } {{ end }}` -const logo = `{{ define "logo" }} +const logo = `{{ define "logo" }} {{ end }}` From 008d250e3c57e1b8a350c8049fe4af71cf26a7e9 Mon Sep 17 00:00:00 2001 From: Elad Date: Wed, 29 May 2019 00:16:09 +0200 Subject: [PATCH 21/47] swarm/api/http: fix bzz-hash to return ens resolved hash directly (#19594) --- swarm/api/http/server.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index a336bd82ff..88f2e4db9c 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -669,7 +669,6 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *http.Request) { // if path is set, interpret as a manifest and return the // raw entry at the given path - etag := common.Bytes2Hex(addr) noneMatchEtag := r.Header.Get("If-None-Match") w.Header().Set("ETag", fmt.Sprintf("%q", etag)) // set etag to manifest key or raw entry key. @@ -680,18 +679,18 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *http.Request) { } } - // check the root chunk exists by retrieving the file's size - reader, isEncrypted := s.api.Retrieve(r.Context(), addr) - if _, err := reader.Size(r.Context(), nil); err != nil { - getFail.Inc(1) - respondError(w, r, fmt.Sprintf("root chunk not found %s: %s", addr, err), http.StatusNotFound) - return - } - - w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted)) - switch { case uri.Raw(): + // check the root chunk exists by retrieving the file's size + reader, isEncrypted := s.api.Retrieve(r.Context(), addr) + if _, err := reader.Size(r.Context(), nil); err != nil { + getFail.Inc(1) + respondError(w, r, fmt.Sprintf("root chunk not found %s: %s", addr, err), http.StatusNotFound) + return + } + + w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted)) + // allow the request to overwrite the content type using a query // parameter if typ := r.URL.Query().Get("content_type"); typ != "" { @@ -703,6 +702,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprint(w, addr) } + } // HandleGetList handles a GET request to bzz-list:// and returns From 3d58268bba92c6c8f7f035bafcd1608bc22cee51 Mon Sep 17 00:00:00 2001 From: Adam Schmideg Date: Thu, 30 May 2019 14:34:44 +0200 Subject: [PATCH 22/47] github: update code owners (#19638) * Update codeowners * Add karalabe to clique * remove codeowner for consensus/clique --- .github/CODEOWNERS | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ed59c98cc3..6286617d05 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,15 +4,20 @@ accounts/usbwallet @karalabe accounts/scwallet @gballet accounts/abi @gballet +cmd/clef @holiman +cmd/puppeth @karalabe consensus @karalabe -core/ @karalabe @holiman -eth/ @karalabe +core/ @karalabe @holiman @rjl493456442 +dashboard/ @kurkomisi +eth/ @karalabe @holiman @rjl493456442 graphql/ @gballet -les/ @zsfelfoldi -light/ @zsfelfoldi -mobile/ @karalabe +les/ @zsfelfoldi @rjl493456442 +light/ @zsfelfoldi @rjl493456442 +mobile/ @karalabe @ligi p2p/ @fjl @zsfelfoldi +rpc/ @fjl @holiman p2p/simulations @zelig @nonsense @janos @justelad p2p/protocols @zelig @nonsense @janos @justelad p2p/testing @zelig @nonsense @janos @justelad +signer/ @holiman whisper/ @gballet @gluk256 From 58497f46bd0bdd105828c30500e863e826e598cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 30 May 2019 20:51:13 +0200 Subject: [PATCH 23/47] les, les/flowcontrol: implement LES/3 (#19329) les, les/flowcontrol: implement LES/3 --- cmd/utils/flags.go | 8 +- core/blockchain.go | 12 +- core/blockchain_test.go | 22 +- les/api.go | 32 +- les/costtracker.go | 188 ++++++--- les/csvlogger/csvlogger.go | 227 +++++++++++ les/distributor.go | 33 +- les/execqueue.go | 9 +- les/flowcontrol/control.go | 111 +++++- les/flowcontrol/manager.go | 195 ++++++---- les/flowcontrol/manager_test.go | 12 +- les/freeclient.go | 57 ++- les/freeclient_test.go | 4 +- les/handler.go | 659 +++++++++++++++++--------------- les/handler_test.go | 51 ++- les/helper_test.go | 29 +- les/peer.go | 110 +++++- les/peer_test.go | 4 +- les/protocol.go | 10 +- les/retrieve.go | 70 +++- les/server.go | 91 ++++- les/servingqueue.go | 219 ++++++++--- 22 files changed, 1539 insertions(+), 614 deletions(-) create mode 100644 les/csvlogger/csvlogger.go diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ddeb44f346..93d162370a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -205,13 +205,13 @@ var ( } LightBandwidthInFlag = cli.IntFlag{ Name: "lightbwin", - Usage: "Incoming bandwidth limit for light server (1000 bytes/sec, 0 = unlimited)", - Value: 1000, + Usage: "Incoming bandwidth limit for light server (kilobytes/sec, 0 = unlimited)", + Value: 0, } LightBandwidthOutFlag = cli.IntFlag{ Name: "lightbwout", - Usage: "Outgoing bandwidth limit for light server (1000 bytes/sec, 0 = unlimited)", - Value: 5000, + Usage: "Outgoing bandwidth limit for light server (kilobytes/sec, 0 = unlimited)", + Value: 0, } LightPeersFlag = cli.IntFlag{ Name: "lightpeers", diff --git a/core/blockchain.go b/core/blockchain.go index 7119596928..2355f0ea31 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -74,7 +74,7 @@ const ( maxFutureBlocks = 256 maxTimeFutureBlocks = 30 badBlockLimit = 10 - triesInMemory = 128 + TriesInMemory = 128 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // @@ -799,7 +799,7 @@ func (bc *BlockChain) Stop() { if !bc.cacheConfig.TrieDirtyDisabled { triedb := bc.stateCache.TrieDB() - for _, offset := range []uint64{0, 1, triesInMemory - 1} { + for _, offset := range []uint64{0, 1, TriesInMemory - 1} { if number := bc.CurrentBlock().NumberU64(); number > offset { recent := bc.GetBlockByNumber(number - offset) @@ -1224,7 +1224,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive bc.triegc.Push(root, -int64(block.NumberU64())) - if current := block.NumberU64(); current > triesInMemory { + if current := block.NumberU64(); current > TriesInMemory { // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( nodes, imgs = triedb.Size() @@ -1234,7 +1234,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. triedb.Cap(limit - ethdb.IdealBatchSize) } // Find the next state trie we need to commit - chosen := current - triesInMemory + chosen := current - TriesInMemory // If we exceeded out time allowance, flush an entire trie to disk if bc.gcproc > bc.cacheConfig.TrieTimeLimit { @@ -1246,8 +1246,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } else { // If we're exceeding limits but haven't reached a large enough memory gap, // warn the user that the system is becoming unstable. - if chosen < lastWrite+triesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { - log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory) + if chosen < lastWrite+TriesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { + log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/TriesInMemory) } // Flush an entire trie and restart the counters triedb.Commit(header.Root, true) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 8dfcda6d45..27115af52d 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1534,7 +1534,7 @@ func TestTrieForkGC(t *testing.T) { db := rawdb.NewMemoryDatabase() genesis := new(Genesis).MustCommit(db) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain forks := make([]*types.Block, len(blocks)) @@ -1563,7 +1563,7 @@ func TestTrieForkGC(t *testing.T) { } } // Dereference all the recent tries and ensure no past trie is left in - for i := 0; i < triesInMemory; i++ { + for i := 0; i < TriesInMemory; i++ { chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } @@ -1582,8 +1582,8 @@ func TestLargeReorgTrieGC(t *testing.T) { genesis := new(Genesis).MustCommit(db) shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) - competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) + original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one diskdb := rawdb.NewMemoryDatabase() @@ -1618,7 +1618,7 @@ func TestLargeReorgTrieGC(t *testing.T) { if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } - for i, block := range competitor[:len(competitor)-triesInMemory] { + for i, block := range competitor[:len(competitor)-TriesInMemory] { if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { t.Fatalf("competitor %d: competing chain state missing", i) } @@ -1753,7 +1753,7 @@ func TestLowDiffLongChain(t *testing.T) { // We must use a pretty long chain to ensure that the fork doesn't overtake us // until after at least 128 blocks post tip - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*triesInMemory, func(i int, b *BlockGen) { + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) }) @@ -1771,7 +1771,7 @@ func TestLowDiffLongChain(t *testing.T) { } // Generate fork chain, starting from an early block parent := blocks[10] - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*triesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -1806,7 +1806,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon genesis := new(Genesis).MustCommit(db) // Generate and import the canonical chain - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, nil) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) diskdb := rawdb.NewMemoryDatabase() new(Genesis).MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) @@ -1817,9 +1817,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - lastPrunedIndex := len(blocks) - triesInMemory - 1 + lastPrunedIndex := len(blocks) - TriesInMemory - 1 lastPrunedBlock := blocks[lastPrunedIndex] - firstNonPrunedBlock := blocks[len(blocks)-triesInMemory] + firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { @@ -1836,7 +1836,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate fork chain, make it longer than canon parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parent := blocks[parentIndex] - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) // Prepend the parent(s) diff --git a/les/api.go b/les/api.go index a933cbd068..3a8d49ca5e 100644 --- a/les/api.go +++ b/les/api.go @@ -19,11 +19,13 @@ package les import ( "context" "errors" + "fmt" "sync" "time" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/les/csvlogger" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" ) @@ -99,7 +101,7 @@ func (s tcSubs) send(tc uint64, underrun bool) { // MinimumCapacity queries minimum assignable capacity for a single client func (api *PrivateLightServerAPI) MinimumCapacity() hexutil.Uint64 { - return hexutil.Uint64(minCapacity) + return hexutil.Uint64(api.server.minCapacity) } // FreeClientCapacity queries the capacity provided for free clients @@ -115,7 +117,7 @@ func (api *PrivateLightServerAPI) FreeClientCapacity() hexutil.Uint64 { // Note: assigned capacity can be changed while the client is connected with // immediate effect. func (api *PrivateLightServerAPI) SetClientCapacity(id enode.ID, cap uint64) error { - if cap != 0 && cap < minCapacity { + if cap != 0 && cap < api.server.minCapacity { return ErrMinCap } return api.server.priorityClientPool.setClientCapacity(id, cap) @@ -144,6 +146,8 @@ type priorityClientPool struct { totalCap, totalCapAnnounced uint64 totalConnectedCap, freeClientCap uint64 maxPeers, priorityCount int + logger *csvlogger.Logger + logTotalPriConn *csvlogger.Channel subs tcSubs updateSchedule []scheduledUpdate @@ -164,12 +168,14 @@ type priorityClientInfo struct { } // newPriorityClientPool creates a new priority client pool -func newPriorityClientPool(freeClientCap uint64, ps *peerSet, child clientPool) *priorityClientPool { +func newPriorityClientPool(freeClientCap uint64, ps *peerSet, child clientPool, metricsLogger, eventLogger *csvlogger.Logger) *priorityClientPool { return &priorityClientPool{ - clients: make(map[enode.ID]priorityClientInfo), - freeClientCap: freeClientCap, - ps: ps, - child: child, + clients: make(map[enode.ID]priorityClientInfo), + freeClientCap: freeClientCap, + ps: ps, + child: child, + logger: eventLogger, + logTotalPriConn: metricsLogger.NewChannel("totalPriConn", 0), } } @@ -185,6 +191,7 @@ func (v *priorityClientPool) registerPeer(p *peer) { id := p.ID() c := v.clients[id] + v.logger.Event(fmt.Sprintf("priorityClientPool: registerPeer cap=%d connected=%v, %x", c.cap, c.connected, id.Bytes())) if c.connected { return } @@ -192,6 +199,7 @@ func (v *priorityClientPool) registerPeer(p *peer) { v.child.registerPeer(p) } if c.cap != 0 && v.totalConnectedCap+c.cap > v.totalCap { + v.logger.Event(fmt.Sprintf("priorityClientPool: rejected, %x", id.Bytes())) go v.ps.Unregister(p.id) return } @@ -202,6 +210,8 @@ func (v *priorityClientPool) registerPeer(p *peer) { if c.cap != 0 { v.priorityCount++ v.totalConnectedCap += c.cap + v.logger.Event(fmt.Sprintf("priorityClientPool: accepted with %d capacity, %x", c.cap, id.Bytes())) + v.logTotalPriConn.Update(float64(v.totalConnectedCap)) if v.child != nil { v.child.setLimits(v.maxPeers-v.priorityCount, v.totalCap-v.totalConnectedCap) } @@ -217,6 +227,7 @@ func (v *priorityClientPool) unregisterPeer(p *peer) { id := p.ID() c := v.clients[id] + v.logger.Event(fmt.Sprintf("priorityClientPool: unregisterPeer cap=%d connected=%v, %x", c.cap, c.connected, id.Bytes())) if !c.connected { return } @@ -225,6 +236,7 @@ func (v *priorityClientPool) unregisterPeer(p *peer) { v.clients[id] = c v.priorityCount-- v.totalConnectedCap -= c.cap + v.logTotalPriConn.Update(float64(v.totalConnectedCap)) if v.child != nil { v.child.setLimits(v.maxPeers-v.priorityCount, v.totalCap-v.totalConnectedCap) } @@ -299,8 +311,10 @@ func (v *priorityClientPool) setLimitsNow(count int, totalCap uint64) { if v.priorityCount > count || v.totalConnectedCap > totalCap { for id, c := range v.clients { if c.connected { + v.logger.Event(fmt.Sprintf("priorityClientPool: setLimitsNow kicked out, %x", id.Bytes())) c.connected = false v.totalConnectedCap -= c.cap + v.logTotalPriConn.Update(float64(v.totalConnectedCap)) v.priorityCount-- v.clients[id] = c go v.ps.Unregister(c.peer.id) @@ -356,6 +370,7 @@ func (v *priorityClientPool) setClientCapacity(id enode.ID, cap uint64) error { v.priorityCount-- } v.totalConnectedCap += cap - c.cap + v.logTotalPriConn.Update(float64(v.totalConnectedCap)) if v.child != nil { v.child.setLimits(v.maxPeers-v.priorityCount, v.totalCap-v.totalConnectedCap) } @@ -374,6 +389,9 @@ func (v *priorityClientPool) setClientCapacity(id enode.ID, cap uint64) error { } else { delete(v.clients, id) } + if c.connected { + v.logger.Event(fmt.Sprintf("priorityClientPool: changed capacity to %d, %x", cap, id.Bytes())) + } return nil } diff --git a/les/costtracker.go b/les/costtracker.go index 332d733431..e463c9f8b0 100644 --- a/les/costtracker.go +++ b/les/costtracker.go @@ -18,6 +18,7 @@ package les import ( "encoding/binary" + "fmt" "math" "sync" "sync/atomic" @@ -26,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/les/csvlogger" "github.com/ethereum/go-ethereum/les/flowcontrol" "github.com/ethereum/go-ethereum/log" ) @@ -52,7 +54,7 @@ var ( GetCodeMsg: {0, 80}, GetProofsV2Msg: {0, 80}, GetHelperTrieProofsMsg: {0, 20}, - SendTxV2Msg: {0, 66000}, + SendTxV2Msg: {0, 16500}, GetTxStatusMsg: {0, 50}, } // maximum outgoing message size estimates @@ -66,17 +68,27 @@ var ( SendTxV2Msg: {0, 100}, GetTxStatusMsg: {0, 100}, } - minBufLimit = uint64(50000000 * maxCostFactor) // minimum buffer limit allowed for a client - minCapacity = (minBufLimit-1)/bufLimitRatio + 1 // minimum capacity allowed for a client + // request amounts that have to fit into the minimum buffer size minBufferMultiplier times + minBufferReqAmount = map[uint64]uint64{ + GetBlockHeadersMsg: 192, + GetBlockBodiesMsg: 1, + GetReceiptsMsg: 1, + GetCodeMsg: 1, + GetProofsV2Msg: 1, + GetHelperTrieProofsMsg: 16, + SendTxV2Msg: 8, + GetTxStatusMsg: 64, + } + minBufferMultiplier = 3 ) const ( maxCostFactor = 2 // ratio of maximum and average cost estimates - gfInitWeight = time.Second * 10 - gfMaxWeight = time.Hour gfUsageThreshold = 0.5 gfUsageTC = time.Second - gfDbKey = "_globalCostFactor" + gfRaiseTC = time.Second * 200 + gfDropTC = time.Second * 50 + gfDbKey = "_globalCostFactorV3" ) // costTracker is responsible for calculating costs and cost estimates on the @@ -94,21 +106,30 @@ type costTracker struct { inSizeFactor, outSizeFactor float64 gf, utilTarget float64 + minBufLimit uint64 gfUpdateCh chan gfUpdate gfLock sync.RWMutex totalRechargeCh chan uint64 - stats map[uint64][]uint64 + stats map[uint64][]uint64 + logger *csvlogger.Logger + logRecentTime, logRecentAvg, logTotalRecharge, logRelCost *csvlogger.Channel } -// newCostTracker creates a cost tracker and loads the cost factor statistics from the database -func newCostTracker(db ethdb.Database, config *eth.Config) *costTracker { +// newCostTracker creates a cost tracker and loads the cost factor statistics from the database. +// It also returns the minimum capacity that can be assigned to any peer. +func newCostTracker(db ethdb.Database, config *eth.Config, logger *csvlogger.Logger) (*costTracker, uint64) { utilTarget := float64(config.LightServ) * flowcontrol.FixedPointMultiplier / 100 ct := &costTracker{ - db: db, - stopCh: make(chan chan struct{}), - utilTarget: utilTarget, + db: db, + stopCh: make(chan chan struct{}), + utilTarget: utilTarget, + logger: logger, + logRelCost: logger.NewMinMaxChannel("relativeCost", true), + logRecentTime: logger.NewMinMaxChannel("recentTime", true), + logRecentAvg: logger.NewMinMaxChannel("recentAvg", true), + logTotalRecharge: logger.NewChannel("totalRecharge", 0.01), } if config.LightBandwidthIn > 0 { ct.inSizeFactor = utilTarget / float64(config.LightBandwidthIn) @@ -123,7 +144,16 @@ func newCostTracker(db ethdb.Database, config *eth.Config) *costTracker { } } ct.gfLoop() - return ct + costList := ct.makeCostList(ct.globalFactor() * 1.25) + for _, c := range costList { + amount := minBufferReqAmount[c.MsgCode] + cost := c.BaseCost + amount*c.ReqCost + if cost > ct.minBufLimit { + ct.minBufLimit = cost + } + } + ct.minBufLimit *= uint64(minBufferMultiplier) + return ct, (ct.minBufLimit-1)/bufLimitRatio + 1 } // stop stops the cost tracker and saves the cost factor statistics to the database @@ -138,16 +168,14 @@ func (ct *costTracker) stop() { // makeCostList returns upper cost estimates based on the hardcoded cost estimate // tables and the optionally specified incoming/outgoing bandwidth limits -func (ct *costTracker) makeCostList() RequestCostList { - maxCost := func(avgTime, inSize, outSize uint64) uint64 { - globalFactor := ct.globalFactor() - - cost := avgTime * maxCostFactor - inSizeCost := uint64(float64(inSize) * ct.inSizeFactor * globalFactor * maxCostFactor) +func (ct *costTracker) makeCostList(globalFactor float64) RequestCostList { + maxCost := func(avgTimeCost, inSize, outSize uint64) uint64 { + cost := avgTimeCost * maxCostFactor + inSizeCost := uint64(float64(inSize) * ct.inSizeFactor * globalFactor) if inSizeCost > cost { cost = inSizeCost } - outSizeCost := uint64(float64(outSize) * ct.outSizeFactor * globalFactor * maxCostFactor) + outSizeCost := uint64(float64(outSize) * ct.outSizeFactor * globalFactor) if outSizeCost > cost { cost = outSizeCost } @@ -155,17 +183,29 @@ func (ct *costTracker) makeCostList() RequestCostList { } var list RequestCostList for code, data := range reqAvgTimeCost { + baseCost := maxCost(data.baseCost, reqMaxInSize[code].baseCost, reqMaxOutSize[code].baseCost) + reqCost := maxCost(data.reqCost, reqMaxInSize[code].reqCost, reqMaxOutSize[code].reqCost) + if ct.minBufLimit != 0 { + // if minBufLimit is set then always enforce maximum request cost <= minBufLimit + maxCost := baseCost + reqCost*minBufferReqAmount[code] + if maxCost > ct.minBufLimit { + mul := 0.999 * float64(ct.minBufLimit) / float64(maxCost) + baseCost = uint64(float64(baseCost) * mul) + reqCost = uint64(float64(reqCost) * mul) + } + } + list = append(list, requestCostListItem{ MsgCode: code, - BaseCost: maxCost(data.baseCost, reqMaxInSize[code].baseCost, reqMaxOutSize[code].baseCost), - ReqCost: maxCost(data.reqCost, reqMaxInSize[code].reqCost, reqMaxOutSize[code].reqCost), + BaseCost: baseCost, + ReqCost: reqCost, }) } return list } type gfUpdate struct { - avgTime, servingTime float64 + avgTimeCost, servingTime float64 } // gfLoop starts an event loop which updates the global cost factor which is @@ -178,45 +218,74 @@ type gfUpdate struct { // total allowed serving time per second but nominated in cost units, should // also be scaled with the cost factor and is also updated by this loop. func (ct *costTracker) gfLoop() { - var gfUsage, gfSum, gfWeight float64 + var gfLog, recentTime, recentAvg float64 lastUpdate := mclock.Now() expUpdate := lastUpdate data, _ := ct.db.Get([]byte(gfDbKey)) - if len(data) == 16 { - gfSum = math.Float64frombits(binary.BigEndian.Uint64(data[0:8])) - gfWeight = math.Float64frombits(binary.BigEndian.Uint64(data[8:16])) + if len(data) == 8 { + gfLog = math.Float64frombits(binary.BigEndian.Uint64(data[:])) } - if gfWeight < float64(gfInitWeight) { - gfSum = float64(gfInitWeight) - gfWeight = float64(gfInitWeight) - } - gf := gfSum / gfWeight + gf := math.Exp(gfLog) ct.gf = gf + totalRecharge := ct.utilTarget * gf ct.gfUpdateCh = make(chan gfUpdate, 100) + threshold := gfUsageThreshold * float64(gfUsageTC) * ct.utilTarget / 1000000 go func() { + saveCostFactor := func() { + var data [8]byte + binary.BigEndian.PutUint64(data[:], math.Float64bits(gfLog)) + ct.db.Put([]byte(gfDbKey), data[:]) + log.Debug("global cost factor saved", "value", gf) + } + saveTicker := time.NewTicker(time.Minute * 10) + for { select { case r := <-ct.gfUpdateCh: now := mclock.Now() - max := r.servingTime * gf - if r.avgTime > max { - max = r.avgTime + if ct.logRelCost != nil && r.avgTimeCost > 1e-20 { + ct.logRelCost.Update(r.servingTime * gf / r.avgTimeCost) + } + if r.servingTime > 1000000000 { + ct.logger.Event(fmt.Sprintf("Very long servingTime = %f avgTimeCost = %f costFactor = %f", r.servingTime, r.avgTimeCost, gf)) } dt := float64(now - expUpdate) expUpdate = now - gfUsage = gfUsage*math.Exp(-dt/float64(gfUsageTC)) + max*1000000/float64(gfUsageTC) + exp := math.Exp(-dt / float64(gfUsageTC)) + // calculate gf correction until now, based on previous values + var gfCorr float64 + max := recentTime + if recentAvg > max { + max = recentAvg + } + // we apply continuous correction when MAX(recentTime, recentAvg) > threshold + if max > threshold { + // calculate correction time between last expUpdate and now + if max*exp >= threshold { + gfCorr = dt + } else { + gfCorr = math.Log(max/threshold) * float64(gfUsageTC) + } + // calculate log(gf) correction with the right direction and time constant + if recentTime > recentAvg { + // drop gf if actual serving times are larger than average estimates + gfCorr /= -float64(gfDropTC) + } else { + // raise gf if actual serving times are smaller than average estimates + gfCorr /= float64(gfRaiseTC) + } + } + // update recent cost values with current request + recentTime = recentTime*exp + r.servingTime + recentAvg = recentAvg*exp + r.avgTimeCost/gf - if gfUsage >= gfUsageThreshold*ct.utilTarget*gf { - gfSum += r.avgTime - gfWeight += r.servingTime + if gfCorr != 0 { + gfLog += gfCorr + gf = math.Exp(gfLog) if time.Duration(now-lastUpdate) > time.Second { - gf = gfSum / gfWeight - if gfWeight >= float64(gfMaxWeight) { - gfSum = gf * float64(gfMaxWeight) - gfWeight = float64(gfMaxWeight) - } + totalRecharge = ct.utilTarget * gf lastUpdate = now ct.gfLock.Lock() ct.gf = gf @@ -224,19 +293,22 @@ func (ct *costTracker) gfLoop() { ct.gfLock.Unlock() if ch != nil { select { - case ct.totalRechargeCh <- uint64(ct.utilTarget * gf): + case ct.totalRechargeCh <- uint64(totalRecharge): default: } } - log.Debug("global cost factor updated", "gf", gf, "weight", time.Duration(gfWeight)) + log.Debug("global cost factor updated", "gf", gf) } } + ct.logRecentTime.Update(recentTime) + ct.logRecentAvg.Update(recentAvg) + ct.logTotalRecharge.Update(totalRecharge) + + case <-saveTicker.C: + saveCostFactor() + case stopCh := <-ct.stopCh: - var data [16]byte - binary.BigEndian.PutUint64(data[0:8], math.Float64bits(gfSum)) - binary.BigEndian.PutUint64(data[8:16], math.Float64bits(gfWeight)) - ct.db.Put([]byte(gfDbKey), data[:]) - log.Debug("global cost factor saved", "sum", time.Duration(gfSum), "weight", time.Duration(gfWeight)) + saveCostFactor() close(stopCh) return } @@ -275,15 +347,15 @@ func (ct *costTracker) subscribeTotalRecharge(ch chan uint64) uint64 { // average estimate statistics func (ct *costTracker) updateStats(code, amount, servingTime, realCost uint64) { avg := reqAvgTimeCost[code] - avgTime := avg.baseCost + amount*avg.reqCost + avgTimeCost := avg.baseCost + amount*avg.reqCost select { - case ct.gfUpdateCh <- gfUpdate{float64(avgTime), float64(servingTime)}: + case ct.gfUpdateCh <- gfUpdate{float64(avgTimeCost), float64(servingTime)}: default: } if makeCostStats { realCost <<= 4 l := 0 - for l < 9 && realCost > avgTime { + for l < 9 && realCost > avgTimeCost { l++ realCost >>= 1 } @@ -339,8 +411,8 @@ type ( } ) -// getCost calculates the estimated cost for a given request type and amount -func (table requestCostTable) getCost(code, amount uint64) uint64 { +// getMaxCost calculates the estimated cost for a given request type and amount +func (table requestCostTable) getMaxCost(code, amount uint64) uint64 { costs := table[code] return costs.baseCost + amount*costs.reqCost } @@ -360,7 +432,7 @@ func (list RequestCostList) decode(protocolLength uint64) requestCostTable { } // testCostList returns a dummy request cost list used by tests -func testCostList() RequestCostList { +func testCostList(testCost uint64) RequestCostList { cl := make(RequestCostList, len(reqAvgTimeCost)) var max uint64 for code := range reqAvgTimeCost { @@ -372,7 +444,7 @@ func testCostList() RequestCostList { for code := uint64(0); code <= max; code++ { if _, ok := reqAvgTimeCost[code]; ok { cl[i].MsgCode = code - cl[i].BaseCost = 0 + cl[i].BaseCost = testCost cl[i].ReqCost = 0 i++ } diff --git a/les/csvlogger/csvlogger.go b/les/csvlogger/csvlogger.go new file mode 100644 index 0000000000..9a4093cb9a --- /dev/null +++ b/les/csvlogger/csvlogger.go @@ -0,0 +1,227 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package csvlogger + +import ( + "fmt" + "os" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/log" +) + +// Logger is a metrics/events logger that writes logged values and events into a comma separated file +type Logger struct { + file *os.File + started mclock.AbsTime + channels []*Channel + period time.Duration + stopCh, stopped chan struct{} + storeCh chan string + eventHeader string +} + +// NewLogger creates a new Logger +func NewLogger(fileName string, updatePeriod time.Duration, eventHeader string) *Logger { + if fileName == "" { + return nil + } + f, err := os.Create(fileName) + if err != nil { + log.Error("Error creating log file", "name", fileName, "error", err) + return nil + } + return &Logger{ + file: f, + period: updatePeriod, + stopCh: make(chan struct{}), + storeCh: make(chan string, 1), + eventHeader: eventHeader, + } +} + +// NewChannel creates a new value logger channel that writes values in a single +// column. If the relative change of the value is bigger than the given threshold +// then a new line is added immediately (threshold can also be 0). +func (l *Logger) NewChannel(name string, threshold float64) *Channel { + if l == nil { + return nil + } + c := &Channel{ + logger: l, + name: name, + threshold: threshold, + } + l.channels = append(l.channels, c) + return c +} + +// NewMinMaxChannel creates a new value logger channel that writes the minimum and +// maximum of the tracked value in two columns. It never triggers adding a new line. +// If zeroDefault is true then 0 is written to both min and max columns if no update +// was given during the last period. If it is false then the last update will appear +// in both columns. +func (l *Logger) NewMinMaxChannel(name string, zeroDefault bool) *Channel { + if l == nil { + return nil + } + c := &Channel{ + logger: l, + name: name, + minmax: true, + mmZeroDefault: zeroDefault, + } + l.channels = append(l.channels, c) + return c +} + +func (l *Logger) store(event string) { + s := fmt.Sprintf("%g", float64(mclock.Now()-l.started)/1000000000) + for _, ch := range l.channels { + s += ", " + ch.store() + } + if event != "" { + s += ", " + event + } + l.file.WriteString(s + "\n") +} + +// Start writes the header line and starts the logger +func (l *Logger) Start() { + if l == nil { + return + } + l.started = mclock.Now() + s := "Time" + for _, ch := range l.channels { + s += ", " + ch.header() + } + if l.eventHeader != "" { + s += ", " + l.eventHeader + } + l.file.WriteString(s + "\n") + go func() { + timer := time.NewTimer(l.period) + for { + select { + case <-timer.C: + l.store("") + timer.Reset(l.period) + case event := <-l.storeCh: + l.store(event) + if !timer.Stop() { + <-timer.C + } + timer.Reset(l.period) + case <-l.stopCh: + close(l.stopped) + return + } + } + }() +} + +// Stop stops the logger and closes the file +func (l *Logger) Stop() { + if l == nil { + return + } + l.stopped = make(chan struct{}) + close(l.stopCh) + <-l.stopped + l.file.Close() +} + +// Event immediately adds a new line and adds the given event string in the last column +func (l *Logger) Event(event string) { + if l == nil { + return + } + select { + case l.storeCh <- event: + case <-l.stopCh: + } +} + +// Channel represents a logger channel tracking a single value +type Channel struct { + logger *Logger + lock sync.Mutex + name string + threshold, storeMin, storeMax, lastValue, min, max float64 + minmax, mmSet, mmZeroDefault bool +} + +// Update updates the tracked value +func (lc *Channel) Update(value float64) { + if lc == nil { + return + } + lc.lock.Lock() + defer lc.lock.Unlock() + + lc.lastValue = value + if lc.minmax { + if value > lc.max || !lc.mmSet { + lc.max = value + } + if value < lc.min || !lc.mmSet { + lc.min = value + } + lc.mmSet = true + } else { + if value < lc.storeMin || value > lc.storeMax { + select { + case lc.logger.storeCh <- "": + default: + } + } + } +} + +func (lc *Channel) store() (s string) { + lc.lock.Lock() + defer lc.lock.Unlock() + + if lc.minmax { + s = fmt.Sprintf("%g, %g", lc.min, lc.max) + lc.mmSet = false + if lc.mmZeroDefault { + lc.min = 0 + } else { + lc.min = lc.lastValue + } + lc.max = lc.min + } else { + s = fmt.Sprintf("%g", lc.lastValue) + lc.storeMin = lc.lastValue * (1 - lc.threshold) + lc.storeMax = lc.lastValue * (1 + lc.threshold) + if lc.lastValue < 0 { + lc.storeMin, lc.storeMax = lc.storeMax, lc.storeMin + } + } + return +} + +func (lc *Channel) header() string { + if lc.minmax { + return lc.name + " (min), " + lc.name + " (max)" + } + return lc.name +} diff --git a/les/distributor.go b/les/distributor.go index 1de267f27f..9235adc03f 100644 --- a/les/distributor.go +++ b/les/distributor.go @@ -62,9 +62,10 @@ type distReq struct { canSend func(distPeer) bool request func(distPeer) func() - reqOrder uint64 - sentChn chan distPeer - element *list.Element + reqOrder uint64 + sentChn chan distPeer + element *list.Element + waitForPeers mclock.AbsTime } // newRequestDistributor creates a new request distributor @@ -106,7 +107,11 @@ func (d *requestDistributor) registerTestPeer(p distPeer) { // distMaxWait is the maximum waiting time after which further necessary waiting // times are recalculated based on new feedback from the servers -const distMaxWait = time.Millisecond * 10 +const distMaxWait = time.Millisecond * 50 + +// waitForPeers is the time window in which a request does not fail even if it +// has no suitable peers to send to at the moment +const waitForPeers = time.Second * 3 // main event loop func (d *requestDistributor) loop() { @@ -179,8 +184,6 @@ func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) { checkedPeers := make(map[distPeer]struct{}) elem := d.reqQueue.Front() var ( - bestPeer distPeer - bestReq *distReq bestWait time.Duration sel *weightedRandomSelect ) @@ -188,9 +191,18 @@ func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) { d.peerLock.RLock() defer d.peerLock.RUnlock() - for (len(d.peers) > 0 || elem == d.reqQueue.Front()) && elem != nil { + peerCount := len(d.peers) + for (len(checkedPeers) < peerCount || elem == d.reqQueue.Front()) && elem != nil { req := elem.Value.(*distReq) canSend := false + now := d.clock.Now() + if req.waitForPeers > now { + canSend = true + wait := time.Duration(req.waitForPeers - now) + if bestWait == 0 || wait < bestWait { + bestWait = wait + } + } for peer := range d.peers { if _, ok := checkedPeers[peer]; !ok && peer.canQueue() && req.canSend(peer) { canSend = true @@ -202,9 +214,7 @@ func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) { } sel.update(selectPeerItem{peer: peer, req: req, weight: int64(bufRemain*1000000) + 1}) } else { - if bestReq == nil || wait < bestWait { - bestPeer = peer - bestReq = req + if bestWait == 0 || wait < bestWait { bestWait = wait } } @@ -223,7 +233,7 @@ func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) { c := sel.choose().(selectPeerItem) return c.peer, c.req, 0 } - return bestPeer, bestReq, bestWait + return nil, nil, bestWait } // queue adds a request to the distribution queue, returns a channel where the @@ -237,6 +247,7 @@ func (d *requestDistributor) queue(r *distReq) chan distPeer { if r.reqOrder == 0 { d.lastReqOrder++ r.reqOrder = d.lastReqOrder + r.waitForPeers = d.clock.Now() + mclock.AbsTime(waitForPeers) } back := d.reqQueue.Back() diff --git a/les/execqueue.go b/les/execqueue.go index 614721bf0d..e0c88a990f 100644 --- a/les/execqueue.go +++ b/les/execqueue.go @@ -44,7 +44,7 @@ func (q *execQueue) loop() { func (q *execQueue) waitNext(drop bool) (f func()) { q.mu.Lock() - if drop { + if drop && len(q.funcs) > 0 { // Remove the function that just executed. We do this here instead of when // dequeuing so len(q.funcs) includes the function that is running. q.funcs = append(q.funcs[:0], q.funcs[1:]...) @@ -84,6 +84,13 @@ func (q *execQueue) queue(f func()) bool { return ok } +// clear drops all queued functions +func (q *execQueue) clear() { + q.mu.Lock() + q.funcs = q.funcs[:0] + q.mu.Unlock() +} + // quit stops the exec queue. // quit waits for the current execution to finish before returning. func (q *execQueue) quit() { diff --git a/les/flowcontrol/control.go b/les/flowcontrol/control.go index c03f673b28..490013677c 100644 --- a/les/flowcontrol/control.go +++ b/les/flowcontrol/control.go @@ -56,11 +56,12 @@ type scheduledUpdate struct { // (used in server mode only) type ClientNode struct { params ServerParams - bufValue uint64 + bufValue int64 lastTime mclock.AbsTime updateSchedule []scheduledUpdate sumCost uint64 // sum of req costs received from this client accepted map[uint64]uint64 // value = sumCost after accepting the given req + connected bool lock sync.Mutex cm *ClientManager log *logger @@ -70,11 +71,12 @@ type ClientNode struct { // NewClientNode returns a new ClientNode func NewClientNode(cm *ClientManager, params ServerParams) *ClientNode { node := &ClientNode{ - cm: cm, - params: params, - bufValue: params.BufLimit, - lastTime: cm.clock.Now(), - accepted: make(map[uint64]uint64), + cm: cm, + params: params, + bufValue: int64(params.BufLimit), + lastTime: cm.clock.Now(), + accepted: make(map[uint64]uint64), + connected: true, } if keepLogs > 0 { node.log = newLogger(keepLogs) @@ -85,9 +87,55 @@ func NewClientNode(cm *ClientManager, params ServerParams) *ClientNode { // Disconnect should be called when a client is disconnected func (node *ClientNode) Disconnect() { + node.lock.Lock() + defer node.lock.Unlock() + + node.connected = false node.cm.disconnect(node) } +// BufferStatus returns the current buffer value and limit +func (node *ClientNode) BufferStatus() (uint64, uint64) { + node.lock.Lock() + defer node.lock.Unlock() + + if !node.connected { + return 0, 0 + } + now := node.cm.clock.Now() + node.update(now) + node.cm.updateBuffer(node, 0, now) + bv := node.bufValue + if bv < 0 { + bv = 0 + } + return uint64(bv), node.params.BufLimit +} + +// OneTimeCost subtracts the given amount from the node's buffer. +// +// Note: this call can take the buffer into the negative region internally. +// In this case zero buffer value is returned by exported calls and no requests +// are accepted. +func (node *ClientNode) OneTimeCost(cost uint64) { + node.lock.Lock() + defer node.lock.Unlock() + + now := node.cm.clock.Now() + node.update(now) + node.bufValue -= int64(cost) + node.cm.updateBuffer(node, -int64(cost), now) +} + +// Freeze notifies the client manager about a client freeze event in which case +// the total capacity allowance is slightly reduced. +func (node *ClientNode) Freeze() { + node.lock.Lock() + frozenCap := node.params.MinRecharge + node.lock.Unlock() + node.cm.reduceTotalCapacity(frozenCap) +} + // update recalculates the buffer value at a specified time while also performing // scheduled flow control parameter updates if necessary func (node *ClientNode) update(now mclock.AbsTime) { @@ -105,9 +153,9 @@ func (node *ClientNode) recalcBV(now mclock.AbsTime) { if now < node.lastTime { dt = 0 } - node.bufValue += node.params.MinRecharge * dt / uint64(fcTimeConst) - if node.bufValue > node.params.BufLimit { - node.bufValue = node.params.BufLimit + node.bufValue += int64(node.params.MinRecharge * dt / uint64(fcTimeConst)) + if node.bufValue > int64(node.params.BufLimit) { + node.bufValue = int64(node.params.BufLimit) } if node.log != nil { node.log.add(now, fmt.Sprintf("updated bv=%d MRR=%d BufLimit=%d", node.bufValue, node.params.MinRecharge, node.params.BufLimit)) @@ -139,11 +187,11 @@ func (node *ClientNode) UpdateParams(params ServerParams) { // updateParams updates the flow control parameters of the node func (node *ClientNode) updateParams(params ServerParams, now mclock.AbsTime) { - diff := params.BufLimit - node.params.BufLimit - if int64(diff) > 0 { + diff := int64(params.BufLimit - node.params.BufLimit) + if diff > 0 { node.bufValue += diff - } else if node.bufValue > params.BufLimit { - node.bufValue = params.BufLimit + } else if node.bufValue > int64(params.BufLimit) { + node.bufValue = int64(params.BufLimit) } node.cm.updateParams(node, params, now) } @@ -157,14 +205,14 @@ func (node *ClientNode) AcceptRequest(reqID, index, maxCost uint64) (accepted bo now := node.cm.clock.Now() node.update(now) - if maxCost > node.bufValue { + if int64(maxCost) > node.bufValue { if node.log != nil { node.log.add(now, fmt.Sprintf("rejected reqID=%d bv=%d maxCost=%d", reqID, node.bufValue, maxCost)) node.log.dump(now) } - return false, maxCost - node.bufValue, 0 + return false, maxCost - uint64(node.bufValue), 0 } - node.bufValue -= maxCost + node.bufValue -= int64(maxCost) node.sumCost += maxCost if node.log != nil { node.log.add(now, fmt.Sprintf("accepted reqID=%d bv=%d maxCost=%d sumCost=%d", reqID, node.bufValue, maxCost, node.sumCost)) @@ -174,19 +222,22 @@ func (node *ClientNode) AcceptRequest(reqID, index, maxCost uint64) (accepted bo } // RequestProcessed should be called when the request has been processed -func (node *ClientNode) RequestProcessed(reqID, index, maxCost, realCost uint64) (bv uint64) { +func (node *ClientNode) RequestProcessed(reqID, index, maxCost, realCost uint64) uint64 { node.lock.Lock() defer node.lock.Unlock() now := node.cm.clock.Now() node.update(now) node.cm.processed(node, maxCost, realCost, now) - bv = node.bufValue + node.sumCost - node.accepted[index] + bv := node.bufValue + int64(node.sumCost-node.accepted[index]) if node.log != nil { node.log.add(now, fmt.Sprintf("processed reqID=%d bv=%d maxCost=%d realCost=%d sumCost=%d oldSumCost=%d reportedBV=%d", reqID, node.bufValue, maxCost, realCost, node.sumCost, node.accepted[index], bv)) } delete(node.accepted, index) - return + if bv < 0 { + return 0 + } + return uint64(bv) } // ServerNode is the flow control system's representation of a server @@ -345,6 +396,28 @@ func (node *ServerNode) ReceivedReply(reqID, bv uint64) { } } +// ResumeFreeze cleans all pending requests and sets the buffer estimate to the +// reported value after resuming from a frozen state +func (node *ServerNode) ResumeFreeze(bv uint64) { + node.lock.Lock() + defer node.lock.Unlock() + + for reqID := range node.pending { + delete(node.pending, reqID) + } + now := node.clock.Now() + node.recalcBLE(now) + if bv > node.params.BufLimit { + bv = node.params.BufLimit + } + node.bufEstimate = bv + node.bufRecharge = node.bufEstimate < node.params.BufLimit + node.lastTime = now + if node.log != nil { + node.log.add(now, fmt.Sprintf("unfreeze bv=%d sumCost=%d", bv, node.sumCost)) + } +} + // DumpLogs dumps the event log if logging is used func (node *ServerNode) DumpLogs() { node.lock.Lock() diff --git a/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index 532e6a4050..68f1a47c97 100644 --- a/les/flowcontrol/manager.go +++ b/les/flowcontrol/manager.go @@ -47,9 +47,9 @@ type cmNodeFields struct { const FixedPointMultiplier = 1000000 var ( - capFactorDropTC = 1 / float64(time.Second*10) // time constant for dropping the capacity factor - capFactorRaiseTC = 1 / float64(time.Hour) // time constant for raising the capacity factor - capFactorRaiseThreshold = 0.75 // connected / total capacity ratio threshold for raising the capacity factor + capacityDropFactor = 0.1 + capacityRaiseTC = 1 / (3 * float64(time.Hour)) // time constant for raising the capacity factor + capacityRaiseThresholdRatio = 1.125 // total/connected capacity ratio threshold for raising the capacity factor ) // ClientManager controls the capacity assigned to the clients of a server. @@ -61,10 +61,14 @@ type ClientManager struct { clock mclock.Clock lock sync.Mutex enabledCh chan struct{} + stop chan chan struct{} curve PieceWiseLinear sumRecharge, totalRecharge, totalConnected uint64 - capLogFactor, totalCapacity float64 + logTotalCap, totalCapacity float64 + logTotalCapRaiseLimit float64 + minLogTotalCap, maxLogTotalCap float64 + capacityRaiseThreshold uint64 capLastUpdate mclock.AbsTime totalCapacityCh chan uint64 @@ -106,13 +110,35 @@ func NewClientManager(curve PieceWiseLinear, clock mclock.Clock) *ClientManager clock: clock, rcQueue: prque.New(func(a interface{}, i int) { a.(*ClientNode).queueIndex = i }), capLastUpdate: clock.Now(), + stop: make(chan chan struct{}), } if curve != nil { cm.SetRechargeCurve(curve) } + go func() { + // regularly recalculate and update total capacity + for { + select { + case <-time.After(time.Minute): + cm.lock.Lock() + cm.updateTotalCapacity(cm.clock.Now(), true) + cm.lock.Unlock() + case stop := <-cm.stop: + close(stop) + return + } + } + }() return cm } +// Stop stops the client manager +func (cm *ClientManager) Stop() { + stop := make(chan struct{}) + cm.stop <- stop + <-stop +} + // SetRechargeCurve updates the recharge curve func (cm *ClientManager) SetRechargeCurve(curve PieceWiseLinear) { cm.lock.Lock() @@ -120,13 +146,29 @@ func (cm *ClientManager) SetRechargeCurve(curve PieceWiseLinear) { now := cm.clock.Now() cm.updateRecharge(now) - cm.updateCapFactor(now, false) cm.curve = curve if len(curve) > 0 { cm.totalRecharge = curve[len(curve)-1].Y } else { cm.totalRecharge = 0 } +} + +// SetCapacityRaiseThreshold sets a threshold value used for raising capFactor. +// Either if the difference between total allowed and connected capacity is less +// than this threshold or if their ratio is less than capacityRaiseThresholdRatio +// then capFactor is allowed to slowly raise. +func (cm *ClientManager) SetCapacityLimits(min, max, raiseThreshold uint64) { + if min < 1 { + min = 1 + } + cm.minLogTotalCap = math.Log(float64(min)) + if max < 1 { + max = 1 + } + cm.maxLogTotalCap = math.Log(float64(max)) + cm.logTotalCap = cm.maxLogTotalCap + cm.capacityRaiseThreshold = raiseThreshold cm.refreshCapacity() } @@ -141,8 +183,9 @@ func (cm *ClientManager) connect(node *ClientNode) { node.corrBufValue = int64(node.params.BufLimit) node.rcLastIntValue = cm.rcLastIntValue node.queueIndex = -1 - cm.updateCapFactor(now, true) + cm.updateTotalCapacity(now, true) cm.totalConnected += node.params.MinRecharge + cm.updateRaiseLimit() } // disconnect should be called when a client is disconnected @@ -152,8 +195,9 @@ func (cm *ClientManager) disconnect(node *ClientNode) { now := cm.clock.Now() cm.updateRecharge(cm.clock.Now()) - cm.updateCapFactor(now, true) + cm.updateTotalCapacity(now, true) cm.totalConnected -= node.params.MinRecharge + cm.updateRaiseLimit() } // accepted is called when a request with given maximum cost is accepted. @@ -174,18 +218,24 @@ func (cm *ClientManager) accepted(node *ClientNode, maxCost uint64, now mclock.A // // Note: processed should always be called for all accepted requests func (cm *ClientManager) processed(node *ClientNode, maxCost, realCost uint64, now mclock.AbsTime) { - cm.lock.Lock() - defer cm.lock.Unlock() - if realCost > maxCost { realCost = maxCost } - cm.updateNodeRc(node, int64(maxCost-realCost), &node.params, now) - if uint64(node.corrBufValue) > node.bufValue { + cm.updateBuffer(node, int64(maxCost-realCost), now) +} + +// updateBuffer recalulates the corrected buffer value, adds the given value to it +// and updates the node's actual buffer value if possible +func (cm *ClientManager) updateBuffer(node *ClientNode, add int64, now mclock.AbsTime) { + cm.lock.Lock() + defer cm.lock.Unlock() + + cm.updateNodeRc(node, add, &node.params, now) + if node.corrBufValue > node.bufValue { if node.log != nil { node.log.add(now, fmt.Sprintf("corrected bv=%d oldBv=%d", node.corrBufValue, node.bufValue)) } - node.bufValue = uint64(node.corrBufValue) + node.bufValue = node.corrBufValue } } @@ -195,11 +245,30 @@ func (cm *ClientManager) updateParams(node *ClientNode, params ServerParams, now defer cm.lock.Unlock() cm.updateRecharge(now) - cm.updateCapFactor(now, true) + cm.updateTotalCapacity(now, true) cm.totalConnected += params.MinRecharge - node.params.MinRecharge + cm.updateRaiseLimit() cm.updateNodeRc(node, 0, ¶ms, now) } +// updateRaiseLimit recalculates the limiting value until which logTotalCap +// can be raised when no client freeze events occur +func (cm *ClientManager) updateRaiseLimit() { + if cm.capacityRaiseThreshold == 0 { + cm.logTotalCapRaiseLimit = 0 + return + } + limit := float64(cm.totalConnected + cm.capacityRaiseThreshold) + limit2 := float64(cm.totalConnected) * capacityRaiseThresholdRatio + if limit2 > limit { + limit = limit2 + } + if limit < 1 { + limit = 1 + } + cm.logTotalCapRaiseLimit = math.Log(limit) +} + // updateRecharge updates the recharge integrator and checks the recharge queue // for nodes with recently filled buffers func (cm *ClientManager) updateRecharge(now mclock.AbsTime) { @@ -208,9 +277,15 @@ func (cm *ClientManager) updateRecharge(now mclock.AbsTime) { // updating is done in multiple steps if node buffers are filled and sumRecharge // is decreased before the given target time for cm.sumRecharge > 0 { - bonusRatio := cm.curve.ValueAt(cm.sumRecharge) / float64(cm.sumRecharge) - if bonusRatio < 1 { - bonusRatio = 1 + sumRecharge := cm.sumRecharge + if sumRecharge > cm.totalRecharge { + sumRecharge = cm.totalRecharge + } + bonusRatio := float64(1) + v := cm.curve.ValueAt(sumRecharge) + s := float64(sumRecharge) + if v > s && s > 0 { + bonusRatio = v / s } dt := now - lastUpdate // fetch the client that finishes first @@ -228,7 +303,6 @@ func (cm *ClientManager) updateRecharge(now mclock.AbsTime) { // finished recharging, update corrBufValue and sumRecharge if necessary and do next step if rcqNode.corrBufValue < int64(rcqNode.params.BufLimit) { rcqNode.corrBufValue = int64(rcqNode.params.BufLimit) - cm.updateCapFactor(lastUpdate, true) cm.sumRecharge -= rcqNode.params.MinRecharge } cm.rcLastIntValue = rcqNode.rcFullIntValue @@ -249,9 +323,6 @@ func (cm *ClientManager) updateNodeRc(node *ClientNode, bvc int64, params *Serve node.rcLastIntValue = cm.rcLastIntValue } node.corrBufValue += bvc - if node.corrBufValue < 0 { - node.corrBufValue = 0 - } diff := int64(params.BufLimit - node.params.BufLimit) if diff > 0 { node.corrBufValue += diff @@ -261,15 +332,14 @@ func (cm *ClientManager) updateNodeRc(node *ClientNode, bvc int64, params *Serve node.corrBufValue = int64(params.BufLimit) isFull = true } - sumRecharge := cm.sumRecharge if !wasFull { - sumRecharge -= node.params.MinRecharge + cm.sumRecharge -= node.params.MinRecharge } if params != &node.params { node.params = *params } if !isFull { - sumRecharge += node.params.MinRecharge + cm.sumRecharge += node.params.MinRecharge if node.queueIndex != -1 { cm.rcQueue.Remove(node.queueIndex) } @@ -277,63 +347,54 @@ func (cm *ClientManager) updateNodeRc(node *ClientNode, bvc int64, params *Serve node.rcFullIntValue = cm.rcLastIntValue + (int64(node.params.BufLimit)-node.corrBufValue)*FixedPointMultiplier/int64(node.params.MinRecharge) cm.rcQueue.Push(node, -node.rcFullIntValue) } - if sumRecharge != cm.sumRecharge { - cm.updateCapFactor(now, true) - cm.sumRecharge = sumRecharge - } - } -// updateCapFactor updates the total capacity factor. The capacity factor allows -// the total capacity of the system to go over the allowed total recharge value -// if the sum of momentarily recharging clients only exceeds the total recharge -// allowance in a very small fraction of time. -// The capacity factor is dropped quickly (with a small time constant) if sumRecharge -// exceeds totalRecharge. It is raised slowly (with a large time constant) if most -// of the total capacity is used by connected clients (totalConnected is larger than -// totalCapacity*capFactorRaiseThreshold) and sumRecharge stays under -// totalRecharge*totalConnected/totalCapacity. -func (cm *ClientManager) updateCapFactor(now mclock.AbsTime, refresh bool) { - if cm.totalRecharge == 0 { - return +// reduceTotalCapacity reduces the total capacity allowance in case of a client freeze event +func (cm *ClientManager) reduceTotalCapacity(frozenCap uint64) { + cm.lock.Lock() + defer cm.lock.Unlock() + + ratio := float64(1) + if frozenCap < cm.totalConnected { + ratio = float64(frozenCap) / float64(cm.totalConnected) } + now := cm.clock.Now() + cm.updateTotalCapacity(now, false) + cm.logTotalCap -= capacityDropFactor * ratio + if cm.logTotalCap < cm.minLogTotalCap { + cm.logTotalCap = cm.minLogTotalCap + } + cm.updateTotalCapacity(now, true) +} + +// updateTotalCapacity updates the total capacity factor. The capacity factor allows +// the total capacity of the system to go over the allowed total recharge value +// if clients go to frozen state sufficiently rarely. +// The capacity factor is dropped instantly by a small amount if a clients is frozen. +// It is raised slowly (with a large time constant) if the total connected capacity +// is close to the total allowed amount and no clients are frozen. +func (cm *ClientManager) updateTotalCapacity(now mclock.AbsTime, refresh bool) { dt := now - cm.capLastUpdate cm.capLastUpdate = now - var d float64 - if cm.sumRecharge > cm.totalRecharge { - d = (1 - float64(cm.sumRecharge)/float64(cm.totalRecharge)) * capFactorDropTC - } else { - totalConnected := float64(cm.totalConnected) - var connRatio float64 - if totalConnected < cm.totalCapacity { - connRatio = totalConnected / cm.totalCapacity - } else { - connRatio = 1 - } - if connRatio > capFactorRaiseThreshold { - sumRecharge := float64(cm.sumRecharge) - limit := float64(cm.totalRecharge) * connRatio - if sumRecharge < limit { - d = (1 - sumRecharge/limit) * (connRatio - capFactorRaiseThreshold) * (1 / (1 - capFactorRaiseThreshold)) * capFactorRaiseTC - } + if cm.logTotalCap < cm.logTotalCapRaiseLimit { + cm.logTotalCap += capacityRaiseTC * float64(dt) + if cm.logTotalCap > cm.logTotalCapRaiseLimit { + cm.logTotalCap = cm.logTotalCapRaiseLimit } } - if d != 0 { - cm.capLogFactor += d * float64(dt) - if cm.capLogFactor < 0 { - cm.capLogFactor = 0 - } - if refresh { - cm.refreshCapacity() - } + if cm.logTotalCap > cm.maxLogTotalCap { + cm.logTotalCap = cm.maxLogTotalCap + } + if refresh { + cm.refreshCapacity() } } // refreshCapacity recalculates the total capacity value and sends an update to the subscription // channel if the relative change of the value since the last update is more than 0.1 percent func (cm *ClientManager) refreshCapacity() { - totalCapacity := float64(cm.totalRecharge) * math.Exp(cm.capLogFactor) + totalCapacity := math.Exp(cm.logTotalCap) if totalCapacity >= cm.totalCapacity*0.999 && totalCapacity <= cm.totalCapacity*1.001 { return } diff --git a/les/flowcontrol/manager_test.go b/les/flowcontrol/manager_test.go index 4e7746d400..b32ec55990 100644 --- a/les/flowcontrol/manager_test.go +++ b/les/flowcontrol/manager_test.go @@ -63,7 +63,7 @@ func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, random } m := NewClientManager(PieceWiseLinear{{0, totalCapacity}}, clock) for _, n := range nodes { - n.bufLimit = n.capacity * 6000 //uint64(2000+rand.Intn(10000)) + n.bufLimit = n.capacity * 6000 n.node = NewClientNode(m, ServerParams{BufLimit: n.bufLimit, MinRecharge: n.capacity}) } maxNodes := make([]int, maxCapacityNodes) @@ -73,6 +73,7 @@ func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, random maxNodes[i] = rand.Intn(nodeCount) } + var sendCount int for i := 0; i < testLength; i++ { now := clock.Now() for _, idx := range maxNodes { @@ -83,13 +84,15 @@ func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, random maxNodes[rand.Intn(maxCapacityNodes)] = rand.Intn(nodeCount) } - sendCount := randomSend - for sendCount > 0 { + sendCount += randomSend + failCount := randomSend * 10 + for sendCount > 0 && failCount > 0 { if nodes[rand.Intn(nodeCount)].send(t, now) { sendCount-- + } else { + failCount-- } } - clock.Run(time.Millisecond) } @@ -117,7 +120,6 @@ func (n *testNode) send(t *testing.T, now mclock.AbsTime) bool { if bv < testMaxCost { n.waitUntil = now + mclock.AbsTime((testMaxCost-bv)*1001000/n.capacity) } - //n.waitUntil = now + mclock.AbsTime(float64(testMaxCost)*1001000/float64(n.capacity)*(1-float64(bv)/float64(n.bufLimit))) n.totalCost += rcost return true } diff --git a/les/freeclient.go b/les/freeclient.go index d859337c26..958b7daa78 100644 --- a/les/freeclient.go +++ b/les/freeclient.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/les/csvlogger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) @@ -52,6 +53,8 @@ type freeClientPool struct { connectedLimit, totalLimit int freeClientCap uint64 + logger *csvlogger.Logger + logTotalFreeConn *csvlogger.Channel addressMap map[string]*freeClientPoolEntry connPool, disconnPool *prque.Prque @@ -66,16 +69,18 @@ const ( ) // newFreeClientPool creates a new free client pool -func newFreeClientPool(db ethdb.Database, freeClientCap uint64, totalLimit int, clock mclock.Clock, removePeer func(string)) *freeClientPool { +func newFreeClientPool(db ethdb.Database, freeClientCap uint64, totalLimit int, clock mclock.Clock, removePeer func(string), metricsLogger, eventLogger *csvlogger.Logger) *freeClientPool { pool := &freeClientPool{ - db: db, - clock: clock, - addressMap: make(map[string]*freeClientPoolEntry), - connPool: prque.New(poolSetIndex), - disconnPool: prque.New(poolSetIndex), - freeClientCap: freeClientCap, - totalLimit: totalLimit, - removePeer: removePeer, + db: db, + clock: clock, + addressMap: make(map[string]*freeClientPoolEntry), + connPool: prque.New(poolSetIndex), + disconnPool: prque.New(poolSetIndex), + freeClientCap: freeClientCap, + totalLimit: totalLimit, + logger: eventLogger, + logTotalFreeConn: metricsLogger.NewChannel("totalFreeConn", 0), + removePeer: removePeer, } pool.loadFromDb() return pool @@ -88,10 +93,25 @@ func (f *freeClientPool) stop() { f.lock.Unlock() } +// freeClientId returns a string identifier for the peer. Multiple peers with the +// same identifier can not be in the free client pool simultaneously. +func freeClientId(p *peer) string { + if addr, ok := p.RemoteAddr().(*net.TCPAddr); ok { + if addr.IP.IsLoopback() { + // using peer id instead of loopback ip address allows multiple free + // connections from local machine to own server + return p.id + } else { + return addr.IP.String() + } + } + return "" +} + // registerPeer implements clientPool func (f *freeClientPool) registerPeer(p *peer) { - if addr, ok := p.RemoteAddr().(*net.TCPAddr); ok { - if !f.connect(addr.IP.String(), p.id) { + if freeId := freeClientId(p); freeId != "" { + if !f.connect(freeId, p.id) { f.removePeer(p.id) } } @@ -107,7 +127,9 @@ func (f *freeClientPool) connect(address, id string) bool { return false } + f.logger.Event("freeClientPool: connecting from " + address + ", " + id) if f.connectedLimit == 0 { + f.logger.Event("freeClientPool: rejected, " + id) log.Debug("Client rejected", "address", address) return false } @@ -119,6 +141,7 @@ func (f *freeClientPool) connect(address, id string) bool { f.addressMap[address] = e } else { if e.connected { + f.logger.Event("freeClientPool: already connected, " + id) log.Debug("Client already connected", "address", address) return false } @@ -131,9 +154,11 @@ func (f *freeClientPool) connect(address, id string) bool { if e.linUsage+int64(connectedBias)-i.linUsage < 0 { // kick it out and accept the new client f.dropClient(i, now) + f.logger.Event("freeClientPool: kicked out, " + i.id) } else { // keep the old client and reject the new one f.connPool.Push(i, i.linUsage) + f.logger.Event("freeClientPool: rejected, " + id) log.Debug("Client rejected", "address", address) return false } @@ -142,17 +167,19 @@ func (f *freeClientPool) connect(address, id string) bool { e.connected = true e.id = id f.connPool.Push(e, e.linUsage) + f.logTotalFreeConn.Update(float64(uint64(f.connPool.Size()) * f.freeClientCap)) if f.connPool.Size()+f.disconnPool.Size() > f.totalLimit { f.disconnPool.Pop() } + f.logger.Event("freeClientPool: accepted, " + id) log.Debug("Client accepted", "address", address) return true } // unregisterPeer implements clientPool func (f *freeClientPool) unregisterPeer(p *peer) { - if addr, ok := p.RemoteAddr().(*net.TCPAddr); ok { - f.disconnect(addr.IP.String()) + if freeId := freeClientId(p); freeId != "" { + f.disconnect(freeId) } } @@ -174,9 +201,11 @@ func (f *freeClientPool) disconnect(address string) { } f.connPool.Remove(e.index) + f.logTotalFreeConn.Update(float64(uint64(f.connPool.Size()) * f.freeClientCap)) f.calcLogUsage(e, now) e.connected = false f.disconnPool.Push(e, -e.logUsage) + f.logger.Event("freeClientPool: disconnected, " + e.id) log.Debug("Client disconnected", "address", address) } @@ -194,6 +223,7 @@ func (f *freeClientPool) setLimits(count int, totalCap uint64) { for f.connPool.Size() > f.connectedLimit { i := f.connPool.PopItem().(*freeClientPoolEntry) f.dropClient(i, now) + f.logger.Event("freeClientPool: setLimits kicked out, " + i.id) } } @@ -201,6 +231,7 @@ func (f *freeClientPool) setLimits(count int, totalCap uint64) { // disconnected pool func (f *freeClientPool) dropClient(i *freeClientPoolEntry, now mclock.AbsTime) { f.connPool.Remove(i.index) + f.logTotalFreeConn.Update(float64(uint64(f.connPool.Size()) * f.freeClientCap)) f.calcLogUsage(i, now) i.connected = false f.disconnPool.Push(i, -i.logUsage) diff --git a/les/freeclient_test.go b/les/freeclient_test.go index 1918222641..5a58a6c1c7 100644 --- a/les/freeclient_test.go +++ b/les/freeclient_test.go @@ -61,7 +61,7 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) { } disconnCh <- i } - pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn) + pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn, nil, nil) ) pool.setLimits(connLimit, uint64(connLimit)) @@ -130,7 +130,7 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) { // close and restart pool pool.stop() - pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn) + pool = newFreeClientPool(db, 1, 10000, &clock, disconnFn, nil, nil) pool.setLimits(connLimit, uint64(connLimit)) // try connecting all known peers (connLimit should be filled up) diff --git a/les/handler.go b/les/handler.go index f53a4722f1..59bfd81cd7 100644 --- a/les/handler.go +++ b/les/handler.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/les/csvlogger" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" @@ -118,6 +119,7 @@ type ProtocolManager struct { wg *sync.WaitGroup eventMux *event.TypeMux + logger *csvlogger.Logger // Callbacks synced func() bool @@ -165,8 +167,6 @@ func NewProtocolManager( if odr != nil { manager.retriever = odr.retriever manager.reqDist = odr.retriever.dist - } else { - manager.servingQueue = newServingQueue(int64(time.Millisecond * 10)) } if ulcConfig != nil { @@ -272,6 +272,7 @@ func (pm *ProtocolManager) handle(p *peer) error { // Ignore maxPeers if this is a trusted peer // In server mode we try to check into the client pool after handshake if pm.client && pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted { + pm.logger.Event("Rejected (too many peers), " + p.id) return p2p.DiscTooManyPeers } // Reject light clients if server is not synced. @@ -290,6 +291,7 @@ func (pm *ProtocolManager) handle(p *peer) error { ) if err := p.Handshake(td, hash, number, genesis.Hash(), pm.server); err != nil { p.Log().Debug("Light Ethereum handshake failed", "err", err) + pm.logger.Event("Handshake error: " + err.Error() + ", " + p.id) return err } if p.fcClient != nil { @@ -303,9 +305,12 @@ func (pm *ProtocolManager) handle(p *peer) error { // Register the peer locally if err := pm.peers.Register(p); err != nil { p.Log().Error("Light Ethereum peer registration failed", "err", err) + pm.logger.Event("Peer registration error: " + err.Error() + ", " + p.id) return err } + pm.logger.Event("Connection established, " + p.id) defer func() { + pm.logger.Event("Closed connection, " + p.id) pm.removePeer(p.id) }() @@ -326,6 +331,7 @@ func (pm *ProtocolManager) handle(p *peer) error { // main loop. handle incoming messages. for { if err := pm.handleMsg(p); err != nil { + pm.logger.Event("Message handling error: " + err.Error() + ", " + p.id) p.Log().Debug("Light Ethereum message handling failed", "err", err) if p.fcServer != nil { p.fcServer.DumpLogs() @@ -358,23 +364,40 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { ) accept := func(reqID, reqCnt, maxCnt uint64) bool { - if reqCnt == 0 { + inSizeCost := func() uint64 { + if pm.server.costTracker != nil { + return pm.server.costTracker.realCost(0, msg.Size, 0) + } + return 0 + } + if p.isFrozen() || reqCnt == 0 || p.fcClient == nil || reqCnt > maxCnt { + p.fcClient.OneTimeCost(inSizeCost()) return false } - if p.fcClient == nil || reqCnt > maxCnt { - return false + maxCost = p.fcCosts.getMaxCost(msg.Code, reqCnt) + gf := float64(1) + if pm.server.costTracker != nil { + gf = pm.server.costTracker.globalFactor() + if gf < 0.001 { + p.Log().Error("Invalid global cost factor", "globalFactor", gf) + gf = 1 + } } - maxCost = p.fcCosts.getCost(msg.Code, reqCnt) + maxTime := uint64(float64(maxCost) / gf) if accepted, bufShort, servingPriority := p.fcClient.AcceptRequest(reqID, responseCount, maxCost); !accepted { - if bufShort > 0 { - p.Log().Error("Request came too early", "remaining", common.PrettyDuration(time.Duration(bufShort*1000000/p.fcParams.MinRecharge))) - } + p.freezeClient() + p.Log().Warn("Request came too early", "remaining", common.PrettyDuration(time.Duration(bufShort*1000000/p.fcParams.MinRecharge))) + p.fcClient.OneTimeCost(inSizeCost()) return false } else { - task = pm.servingQueue.newTask(servingPriority) + task = pm.servingQueue.newTask(p, maxTime, servingPriority) } - return task.start() + if task.start() { + return true + } + p.fcClient.RequestProcessed(reqID, responseCount, maxCost, inSizeCost()) + return false } if msg.Size > ProtocolMaxMsgSize { @@ -388,6 +411,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { p.responseLock.Lock() defer p.responseLock.Unlock() + if p.isFrozen() { + amount = 0 + reply = nil + } var replySize uint32 if reply != nil { replySize = reply.size() @@ -395,7 +422,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { var realCost uint64 if pm.server.costTracker != nil { realCost = pm.server.costTracker.realCost(servingTime, msg.Size, replySize) - pm.server.costTracker.updateStats(msg.Code, amount, servingTime, realCost) + if amount != 0 { + pm.server.costTracker.updateStats(msg.Code, amount, servingTime, realCost) + } } else { realCost = maxCost } @@ -463,94 +492,94 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } query := req.Query - if !accept(req.ReqID, query.Amount, MaxHeaderFetch) { - return errResp(ErrRequestRejected, "") - } - go func() { - hashMode := query.Origin.Hash != (common.Hash{}) - first := true - maxNonCanonical := uint64(100) + if accept(req.ReqID, query.Amount, MaxHeaderFetch) { + go func() { + hashMode := query.Origin.Hash != (common.Hash{}) + first := true + maxNonCanonical := uint64(100) - // Gather headers until the fetch or network limits is reached - var ( - bytes common.StorageSize - headers []*types.Header - unknown bool - ) - for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit { - if !first && !task.waitOrStop() { - return - } - // Retrieve the next header satisfying the query - var origin *types.Header - if hashMode { - if first { - origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) - if origin != nil { - query.Origin.Number = origin.Number.Uint64() + // Gather headers until the fetch or network limits is reached + var ( + bytes common.StorageSize + headers []*types.Header + unknown bool + ) + for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit { + if !first && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return + } + // Retrieve the next header satisfying the query + var origin *types.Header + if hashMode { + if first { + origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) + if origin != nil { + query.Origin.Number = origin.Number.Uint64() + } + } else { + origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number) } } else { - origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number) + origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) } - } else { - origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) - } - if origin == nil { - break - } - headers = append(headers, origin) - bytes += estHeaderRlpSize + if origin == nil { + break + } + headers = append(headers, origin) + bytes += estHeaderRlpSize - // Advance to the next header of the query - switch { - case hashMode && query.Reverse: - // Hash based traversal towards the genesis block - ancestor := query.Skip + 1 - if ancestor == 0 { - unknown = true - } else { - query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical) - unknown = (query.Origin.Hash == common.Hash{}) - } - case hashMode && !query.Reverse: - // Hash based traversal towards the leaf block - var ( - current = origin.Number.Uint64() - next = current + query.Skip + 1 - ) - if next <= current { - infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ") - p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos) - unknown = true - } else { - if header := pm.blockchain.GetHeaderByNumber(next); header != nil { - nextHash := header.Hash() - expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical) - if expOldHash == query.Origin.Hash { - query.Origin.Hash, query.Origin.Number = nextHash, next + // Advance to the next header of the query + switch { + case hashMode && query.Reverse: + // Hash based traversal towards the genesis block + ancestor := query.Skip + 1 + if ancestor == 0 { + unknown = true + } else { + query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical) + unknown = (query.Origin.Hash == common.Hash{}) + } + case hashMode && !query.Reverse: + // Hash based traversal towards the leaf block + var ( + current = origin.Number.Uint64() + next = current + query.Skip + 1 + ) + if next <= current { + infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ") + p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos) + unknown = true + } else { + if header := pm.blockchain.GetHeaderByNumber(next); header != nil { + nextHash := header.Hash() + expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical) + if expOldHash == query.Origin.Hash { + query.Origin.Hash, query.Origin.Number = nextHash, next + } else { + unknown = true + } } else { unknown = true } + } + case query.Reverse: + // Number based traversal towards the genesis block + if query.Origin.Number >= query.Skip+1 { + query.Origin.Number -= query.Skip + 1 } else { unknown = true } - } - case query.Reverse: - // Number based traversal towards the genesis block - if query.Origin.Number >= query.Skip+1 { - query.Origin.Number -= query.Skip + 1 - } else { - unknown = true - } - case !query.Reverse: - // Number based traversal towards the leaf block - query.Origin.Number += query.Skip + 1 + case !query.Reverse: + // Number based traversal towards the leaf block + query.Origin.Number += query.Skip + 1 + } + first = false } - first = false - } - sendResponse(req.ReqID, query.Amount, p.ReplyBlockHeaders(req.ReqID, headers), task.done()) - }() + sendResponse(req.ReqID, query.Amount, p.ReplyBlockHeaders(req.ReqID, headers), task.done()) + }() + } case BlockHeadersMsg: if pm.downloader == nil { @@ -592,27 +621,27 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { bodies []rlp.RawValue ) reqCnt := len(req.Hashes) - if !accept(req.ReqID, uint64(reqCnt), MaxBodyFetch) { - return errResp(ErrRequestRejected, "") - } - go func() { - for i, hash := range req.Hashes { - if i != 0 && !task.waitOrStop() { - return - } - if bytes >= softResponseLimit { - break - } - // Retrieve the requested block body, stopping if enough was found - if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { - if data := rawdb.ReadBodyRLP(pm.chainDb, hash, *number); len(data) != 0 { - bodies = append(bodies, data) - bytes += len(data) + if accept(req.ReqID, uint64(reqCnt), MaxBodyFetch) { + go func() { + for i, hash := range req.Hashes { + if i != 0 && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return + } + if bytes >= softResponseLimit { + break + } + // Retrieve the requested block body, stopping if enough was found + if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { + if data := rawdb.ReadBodyRLP(pm.chainDb, hash, *number); len(data) != 0 { + bodies = append(bodies, data) + bytes += len(data) + } } } - } - sendResponse(req.ReqID, uint64(reqCnt), p.ReplyBlockBodiesRLP(req.ReqID, bodies), task.done()) - }() + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyBlockBodiesRLP(req.ReqID, bodies), task.done()) + }() + } case BlockBodiesMsg: if pm.odr == nil { @@ -651,45 +680,45 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { data [][]byte ) reqCnt := len(req.Reqs) - if !accept(req.ReqID, uint64(reqCnt), MaxCodeFetch) { - return errResp(ErrRequestRejected, "") - } - go func() { - for i, req := range req.Reqs { - if i != 0 && !task.waitOrStop() { - return - } - // Look up the root hash belonging to the request - number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash) - if number == nil { - p.Log().Warn("Failed to retrieve block num for code", "hash", req.BHash) - continue - } - header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number) - if header == nil { - p.Log().Warn("Failed to retrieve header for code", "block", *number, "hash", req.BHash) - continue - } - triedb := pm.blockchain.StateCache().TrieDB() + if accept(req.ReqID, uint64(reqCnt), MaxCodeFetch) { + go func() { + for i, request := range req.Reqs { + if i != 0 && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return + } + // Look up the root hash belonging to the request + number := rawdb.ReadHeaderNumber(pm.chainDb, request.BHash) + if number == nil { + p.Log().Warn("Failed to retrieve block num for code", "hash", request.BHash) + continue + } + header := rawdb.ReadHeader(pm.chainDb, request.BHash, *number) + if header == nil { + p.Log().Warn("Failed to retrieve header for code", "block", *number, "hash", request.BHash) + continue + } + triedb := pm.blockchain.StateCache().TrieDB() - account, err := pm.getAccount(triedb, header.Root, common.BytesToHash(req.AccKey)) - if err != nil { - p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err) - continue + account, err := pm.getAccount(triedb, header.Root, common.BytesToHash(request.AccKey)) + if err != nil { + p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err) + continue + } + code, err := triedb.Node(common.BytesToHash(account.CodeHash)) + if err != nil { + p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err) + continue + } + // Accumulate the code and abort if enough data was retrieved + data = append(data, code) + if bytes += len(code); bytes >= softResponseLimit { + break + } } - code, err := triedb.Node(common.BytesToHash(account.CodeHash)) - if err != nil { - p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err) - continue - } - // Accumulate the code and abort if enough data was retrieved - data = append(data, code) - if bytes += len(code); bytes >= softResponseLimit { - break - } - } - sendResponse(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done()) - }() + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done()) + }() + } case CodeMsg: if pm.odr == nil { @@ -728,37 +757,37 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { receipts []rlp.RawValue ) reqCnt := len(req.Hashes) - if !accept(req.ReqID, uint64(reqCnt), MaxReceiptFetch) { - return errResp(ErrRequestRejected, "") - } - go func() { - for i, hash := range req.Hashes { - if i != 0 && !task.waitOrStop() { - return - } - if bytes >= softResponseLimit { - break - } - // Retrieve the requested block's receipts, skipping if unknown to us - var results types.Receipts - if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { - results = rawdb.ReadRawReceipts(pm.chainDb, hash, *number) - } - if results == nil { - if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { - continue + if accept(req.ReqID, uint64(reqCnt), MaxReceiptFetch) { + go func() { + for i, hash := range req.Hashes { + if i != 0 && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return + } + if bytes >= softResponseLimit { + break + } + // Retrieve the requested block's receipts, skipping if unknown to us + var results types.Receipts + if number := rawdb.ReadHeaderNumber(pm.chainDb, hash); number != nil { + results = rawdb.ReadRawReceipts(pm.chainDb, hash, *number) + } + if results == nil { + if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { + continue + } + } + // If known, encode and queue for response packet + if encoded, err := rlp.EncodeToBytes(results); err != nil { + log.Error("Failed to encode receipt", "err", err) + } else { + receipts = append(receipts, encoded) + bytes += len(encoded) } } - // If known, encode and queue for response packet - if encoded, err := rlp.EncodeToBytes(results); err != nil { - log.Error("Failed to encode receipt", "err", err) - } else { - receipts = append(receipts, encoded) - bytes += len(encoded) - } - } - sendResponse(req.ReqID, uint64(reqCnt), p.ReplyReceiptsRLP(req.ReqID, receipts), task.done()) - }() + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyReceiptsRLP(req.ReqID, receipts), task.done()) + }() + } case ReceiptsMsg: if pm.odr == nil { @@ -797,70 +826,70 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { root common.Hash ) reqCnt := len(req.Reqs) - if !accept(req.ReqID, uint64(reqCnt), MaxProofsFetch) { - return errResp(ErrRequestRejected, "") + if accept(req.ReqID, uint64(reqCnt), MaxProofsFetch) { + go func() { + nodes := light.NewNodeSet() + + for i, request := range req.Reqs { + if i != 0 && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return + } + // Look up the root hash belonging to the request + var ( + number *uint64 + header *types.Header + trie state.Trie + ) + if request.BHash != lastBHash { + root, lastBHash = common.Hash{}, request.BHash + + if number = rawdb.ReadHeaderNumber(pm.chainDb, request.BHash); number == nil { + p.Log().Warn("Failed to retrieve block num for proof", "hash", request.BHash) + continue + } + if header = rawdb.ReadHeader(pm.chainDb, request.BHash, *number); header == nil { + p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", request.BHash) + continue + } + root = header.Root + } + // Open the account or storage trie for the request + statedb := pm.blockchain.StateCache() + + switch len(request.AccKey) { + case 0: + // No account key specified, open an account trie + trie, err = statedb.OpenTrie(root) + if trie == nil || err != nil { + p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err) + continue + } + default: + // Account key specified, open a storage trie + account, err := pm.getAccount(statedb.TrieDB(), root, common.BytesToHash(request.AccKey)) + if err != nil { + p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err) + continue + } + trie, err = statedb.OpenStorageTrie(common.BytesToHash(request.AccKey), account.Root) + if trie == nil || err != nil { + p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "root", account.Root, "err", err) + continue + } + } + // Prove the user's request from the account or stroage trie + if err := trie.Prove(request.Key, request.FromLevel, nodes); err != nil { + p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err) + continue + } + if nodes.DataSize() >= softResponseLimit { + break + } + } + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofsV2(req.ReqID, nodes.NodeList()), task.done()) + }() } - go func() { - nodes := light.NewNodeSet() - - for i, req := range req.Reqs { - if i != 0 && !task.waitOrStop() { - return - } - // Look up the root hash belonging to the request - var ( - number *uint64 - header *types.Header - trie state.Trie - ) - if req.BHash != lastBHash { - root, lastBHash = common.Hash{}, req.BHash - - if number = rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number == nil { - p.Log().Warn("Failed to retrieve block num for proof", "hash", req.BHash) - continue - } - if header = rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header == nil { - p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", req.BHash) - continue - } - root = header.Root - } - // Open the account or storage trie for the request - statedb := pm.blockchain.StateCache() - - switch len(req.AccKey) { - case 0: - // No account key specified, open an account trie - trie, err = statedb.OpenTrie(root) - if trie == nil || err != nil { - p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err) - continue - } - default: - // Account key specified, open a storage trie - account, err := pm.getAccount(statedb.TrieDB(), root, common.BytesToHash(req.AccKey)) - if err != nil { - p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err) - continue - } - trie, err = statedb.OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root) - if trie == nil || err != nil { - p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "root", account.Root, "err", err) - continue - } - } - // Prove the user's request from the account or stroage trie - if err := trie.Prove(req.Key, req.FromLevel, nodes); err != nil { - p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err) - continue - } - if nodes.DataSize() >= softResponseLimit { - break - } - } - sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofsV2(req.ReqID, nodes.NodeList()), task.done()) - }() case ProofsV2Msg: if pm.odr == nil { @@ -899,53 +928,53 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { auxData [][]byte ) reqCnt := len(req.Reqs) - if !accept(req.ReqID, uint64(reqCnt), MaxHelperTrieProofsFetch) { - return errResp(ErrRequestRejected, "") - } - go func() { + if accept(req.ReqID, uint64(reqCnt), MaxHelperTrieProofsFetch) { + go func() { - var ( - lastIdx uint64 - lastType uint - root common.Hash - auxTrie *trie.Trie - ) - nodes := light.NewNodeSet() - for i, req := range req.Reqs { - if i != 0 && !task.waitOrStop() { - return - } - if auxTrie == nil || req.Type != lastType || req.TrieIdx != lastIdx { - auxTrie, lastType, lastIdx = nil, req.Type, req.TrieIdx + var ( + lastIdx uint64 + lastType uint + root common.Hash + auxTrie *trie.Trie + ) + nodes := light.NewNodeSet() + for i, request := range req.Reqs { + if i != 0 && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return + } + if auxTrie == nil || request.Type != lastType || request.TrieIdx != lastIdx { + auxTrie, lastType, lastIdx = nil, request.Type, request.TrieIdx - var prefix string - if root, prefix = pm.getHelperTrie(req.Type, req.TrieIdx); root != (common.Hash{}) { - auxTrie, _ = trie.New(root, trie.NewDatabase(rawdb.NewTable(pm.chainDb, prefix))) + var prefix string + if root, prefix = pm.getHelperTrie(request.Type, request.TrieIdx); root != (common.Hash{}) { + auxTrie, _ = trie.New(root, trie.NewDatabase(rawdb.NewTable(pm.chainDb, prefix))) + } } - } - if req.AuxReq == auxRoot { - var data []byte - if root != (common.Hash{}) { - data = root[:] - } - auxData = append(auxData, data) - auxBytes += len(data) - } else { - if auxTrie != nil { - auxTrie.Prove(req.Key, req.FromLevel, nodes) - } - if req.AuxReq != 0 { - data := pm.getHelperTrieAuxData(req) + if request.AuxReq == auxRoot { + var data []byte + if root != (common.Hash{}) { + data = root[:] + } auxData = append(auxData, data) auxBytes += len(data) + } else { + if auxTrie != nil { + auxTrie.Prove(request.Key, request.FromLevel, nodes) + } + if request.AuxReq != 0 { + data := pm.getHelperTrieAuxData(request) + auxData = append(auxData, data) + auxBytes += len(data) + } + } + if nodes.DataSize()+auxBytes >= softResponseLimit { + break } } - if nodes.DataSize()+auxBytes >= softResponseLimit { - break - } - } - sendResponse(req.ReqID, uint64(reqCnt), p.ReplyHelperTrieProofs(req.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}), task.done()) - }() + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyHelperTrieProofs(req.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}), task.done()) + }() + } case HelperTrieProofsMsg: if pm.odr == nil { @@ -981,27 +1010,27 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } reqCnt := len(req.Txs) - if !accept(req.ReqID, uint64(reqCnt), MaxTxSend) { - return errResp(ErrRequestRejected, "") - } - go func() { - stats := make([]light.TxStatus, len(req.Txs)) - for i, tx := range req.Txs { - if i != 0 && !task.waitOrStop() { - return - } - hash := tx.Hash() - stats[i] = pm.txStatus(hash) - if stats[i].Status == core.TxStatusUnknown { - if errs := pm.txpool.AddRemotes([]*types.Transaction{tx}); errs[0] != nil { - stats[i].Error = errs[0].Error() - continue + if accept(req.ReqID, uint64(reqCnt), MaxTxSend) { + go func() { + stats := make([]light.TxStatus, len(req.Txs)) + for i, tx := range req.Txs { + if i != 0 && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return } + hash := tx.Hash() stats[i] = pm.txStatus(hash) + if stats[i].Status == core.TxStatusUnknown { + if errs := pm.txpool.AddRemotes([]*types.Transaction{tx}); errs[0] != nil { + stats[i].Error = errs[0].Error() + continue + } + stats[i] = pm.txStatus(hash) + } } - } - sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done()) - }() + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done()) + }() + } case GetTxStatusMsg: if pm.txpool == nil { @@ -1016,19 +1045,19 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } reqCnt := len(req.Hashes) - if !accept(req.ReqID, uint64(reqCnt), MaxTxStatus) { - return errResp(ErrRequestRejected, "") - } - go func() { - stats := make([]light.TxStatus, len(req.Hashes)) - for i, hash := range req.Hashes { - if i != 0 && !task.waitOrStop() { - return + if accept(req.ReqID, uint64(reqCnt), MaxTxStatus) { + go func() { + stats := make([]light.TxStatus, len(req.Hashes)) + for i, hash := range req.Hashes { + if i != 0 && !task.waitOrStop() { + sendResponse(req.ReqID, 0, nil, task.servingTime) + return + } + stats[i] = pm.txStatus(hash) } - stats[i] = pm.txStatus(hash) - } - sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done()) - }() + sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done()) + }() + } case TxStatusMsg: if pm.odr == nil { @@ -1053,6 +1082,26 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { Obj: resp.Status, } + case StopMsg: + if pm.odr == nil { + return errResp(ErrUnexpectedResponse, "") + } + p.freezeServer(true) + pm.retriever.frozen(p) + p.Log().Warn("Service stopped") + + case ResumeMsg: + if pm.odr == nil { + return errResp(ErrUnexpectedResponse, "") + } + var bv uint64 + if err := msg.Decode(&bv); err != nil { + return errResp(ErrDecode, "msg %v: %v", msg, err) + } + p.fcServer.ResumeFreeze(bv) + p.freezeServer(false) + p.Log().Warn("Service resumed") + default: p.Log().Trace("Received unknown message", "code", msg.Code) return errResp(ErrInvalidMsgCode, "%v", msg.Code) diff --git a/les/handler_test.go b/les/handler_test.go index d8051c1450..6e24165cf6 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -438,7 +439,7 @@ func TestTransactionStatusLes2(t *testing.T) { config.Journal = "" txpool := core.NewTxPool(config, params.TestChainConfig, chain) pm.txpool = txpool - peer, _ := newTestPeer(t, "peer", 2, pm, true) + peer, _ := newTestPeer(t, "peer", 2, pm, true, 0) defer peer.close() var reqID uint64 @@ -519,3 +520,51 @@ func TestTransactionStatusLes2(t *testing.T) { test(tx1, false, light.TxStatus{Status: core.TxStatusPending}) test(tx2, false, light.TxStatus{Status: core.TxStatusPending}) } + +func TestStopResumeLes3(t *testing.T) { + db := rawdb.NewMemoryDatabase() + clock := &mclock.Simulated{} + testCost := testBufLimit / 10 + pm, err := newTestProtocolManager(false, 0, nil, nil, nil, db, nil, testCost, clock) + if err != nil { + t.Fatalf("Failed to create protocol manager: %v", err) + } + peer, _ := newTestPeer(t, "peer", 3, pm, true, testCost) + defer peer.close() + + expBuf := testBufLimit + var reqID uint64 + + req := func() { + reqID++ + sendRequest(peer.app, GetBlockHeadersMsg, reqID, testCost, &getBlockHeadersData{Origin: hashOrNumber{Hash: common.Hash{1}}, Amount: 1}) + } + + for i := 1; i <= 5; i++ { + // send requests while we still have enough buffer and expect a response + for expBuf >= testCost { + req() + expBuf -= testCost + if err := expectResponse(peer.app, BlockHeadersMsg, reqID, expBuf, nil); err != nil { + t.Errorf("expected response and failed: %v", err) + } + } + // send some more requests in excess and expect a single StopMsg + c := i + for c > 0 { + req() + c-- + } + if err := p2p.ExpectMsg(peer.app, StopMsg, nil); err != nil { + t.Errorf("expected StopMsg and failed: %v", err) + } + // wait until the buffer is recharged by half of the limit + wait := testBufLimit / testBufRecharge / 2 + clock.Run(time.Millisecond * time.Duration(wait)) + // expect a ResumeMsg with the partially recharged buffer value + expBuf += testBufRecharge * wait + if err := p2p.ExpectMsg(peer.app, ResumeMsg, expBuf); err != nil { + t.Errorf("expected ResumeMsg and failed: %v", err) + } + } +} diff --git a/les/helper_test.go b/les/helper_test.go index 878e44404c..dbb0813444 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -62,7 +62,8 @@ var ( testEventEmitterCode = common.Hex2Bytes("60606040523415600e57600080fd5b7f57050ab73f6b9ebdd9f76b8d4997793f48cf956e965ee070551b9ca0bb71584e60405160405180910390a160358060476000396000f3006060604052600080fd00a165627a7a723058203f727efcad8b5811f8cb1fc2620ce5e8c63570d697aef968172de296ea3994140029") testEventEmitterAddr common.Address - testBufLimit = uint64(100) + testBufLimit = uint64(1000000) + testBufRecharge = uint64(1000) ) /* @@ -138,7 +139,7 @@ func testIndexers(db ethdb.Database, odr light.OdrBackend, iConfig *light.Indexe // newTestProtocolManager creates a new protocol manager for testing purposes, // with the given number of blocks already known, potential notification // channels for different events and relative chain indexers array. -func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig) (*ProtocolManager, error) { +func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig, testCost uint64, clock mclock.Clock) (*ProtocolManager, error) { var ( evmux = new(event.TypeMux) engine = ethash.NewFaker() @@ -177,14 +178,15 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor if !lightSync { srv := &LesServer{lesCommons: lesCommons{protocolManager: pm}} pm.server = srv + pm.servingQueue = newServingQueue(int64(time.Millisecond*10), 1, nil) pm.servingQueue.setThreads(4) srv.defParams = flowcontrol.ServerParams{ BufLimit: testBufLimit, - MinRecharge: 1, + MinRecharge: testBufRecharge, } - - srv.fcManager = flowcontrol.NewClientManager(nil, &mclock.System{}) + srv.testCost = testCost + srv.fcManager = flowcontrol.NewClientManager(nil, clock) } pm.Start(1000) return pm, nil @@ -195,7 +197,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor // channels for different events and relative chain indexers array. In case of an error, the constructor force- // fails the test. func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig) *ProtocolManager { - pm, err := newTestProtocolManager(lightSync, blocks, generator, odr, peers, db, ulcConfig) + pm, err := newTestProtocolManager(lightSync, blocks, generator, odr, peers, db, ulcConfig, 0, &mclock.System{}) if err != nil { t.Fatalf("Failed to create protocol manager: %v", err) } @@ -210,7 +212,7 @@ type testPeer struct { } // newTestPeer creates a new peer registered at the given protocol manager. -func newTestPeer(t *testing.T, name string, version int, pm *ProtocolManager, shake bool) (*testPeer, <-chan error) { +func newTestPeer(t *testing.T, name string, version int, pm *ProtocolManager, shake bool, testCost uint64) (*testPeer, <-chan error) { // Create a message pipe to communicate through app, net := p2p.MsgPipe() @@ -242,7 +244,7 @@ func newTestPeer(t *testing.T, name string, version int, pm *ProtocolManager, sh head = pm.blockchain.CurrentHeader() td = pm.blockchain.GetTd(head.Hash(), head.Number.Uint64()) ) - tp.handshake(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash()) + tp.handshake(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), testCost) } return tp, errc } @@ -282,7 +284,7 @@ func newTestPeerPair(name string, version int, pm, pm2 *ProtocolManager) (*peer, // handshake simulates a trivial handshake that expects the same state from the // remote side as we are simulating locally. -func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash) { +func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, testCost uint64) { var expList keyValueList expList = expList.add("protocolVersion", uint64(p.version)) expList = expList.add("networkId", uint64(NetworkId)) @@ -295,10 +297,11 @@ func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNu expList = expList.add("serveHeaders", nil) expList = expList.add("serveChainSince", uint64(0)) expList = expList.add("serveStateSince", uint64(0)) + expList = expList.add("serveRecentState", uint64(core.TriesInMemory-4)) expList = expList.add("txRelay", nil) expList = expList.add("flowControl/BL", testBufLimit) - expList = expList.add("flowControl/MRR", uint64(1)) - expList = expList.add("flowControl/MRC", testCostList()) + expList = expList.add("flowControl/MRR", testBufRecharge) + expList = expList.add("flowControl/MRC", testCostList(testCost)) if err := p2p.ExpectMsg(p.app, StatusMsg, expList); err != nil { t.Fatalf("status recv: %v", err) @@ -309,7 +312,7 @@ func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNu p.fcParams = flowcontrol.ServerParams{ BufLimit: testBufLimit, - MinRecharge: 1, + MinRecharge: testBufRecharge, } } @@ -338,7 +341,7 @@ func newServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*cor cIndexer, bIndexer, btIndexer := testIndexers(db, nil, light.TestServerIndexerConfig) pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, nil, db, nil) - peer, _ := newTestPeer(t, "peer", protocol, pm, true) + peer, _ := newTestPeer(t, "peer", protocol, pm, true, 0) cIndexer.Start(pm.blockchain.(*core.BlockChain)) bIndexer.Start(pm.blockchain.(*core.BlockChain)) diff --git a/les/peer.go b/les/peer.go index 42c13ab7d1..6792d0611e 100644 --- a/les/peer.go +++ b/les/peer.go @@ -20,11 +20,14 @@ import ( "errors" "fmt" "math/big" + "math/rand" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/les/flowcontrol" @@ -47,10 +50,16 @@ const ( allowedUpdateRate = time.Millisecond * 10 // time constant for recharging one byte of allowance ) +const ( + freezeTimeBase = time.Millisecond * 700 // fixed component of client freeze time + freezeTimeRandom = time.Millisecond * 600 // random component of client freeze time + freezeCheckPeriod = time.Millisecond * 100 // buffer value recheck period after initial freeze time has elapsed +) + // if the total encoded size of a sent transaction batch is over txSizeCostLimit // per transaction then the request cost is calculated as proportional to the // encoded size instead of the transaction count -const txSizeCostLimit = 0x10000 +const txSizeCostLimit = 0x4000 const ( announceTypeNone = iota @@ -86,14 +95,17 @@ type peer struct { responseErrors int updateCounter uint64 updateTime mclock.AbsTime + frozen uint32 // 1 if client is in frozen state fcClient *flowcontrol.ClientNode // nil if the peer is server only fcServer *flowcontrol.ServerNode // nil if the peer is client only fcParams flowcontrol.ServerParams fcCosts requestCostTable - isTrusted bool - isOnlyAnnounce bool + isTrusted bool + isOnlyAnnounce bool + chainSince, chainRecent uint64 + stateSince, stateRecent uint64 } func newPeer(version int, network uint64, isTrusted bool, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { @@ -129,8 +141,59 @@ func (p *peer) rejectUpdate(size uint64) bool { return p.updateCounter > allowedUpdateBytes } +// freezeClient temporarily puts the client in a frozen state which means all +// unprocessed and subsequent requests are dropped. Unfreezing happens automatically +// after a short time if the client's buffer value is at least in the slightly positive +// region. The client is also notified about being frozen/unfrozen with a Stop/Resume +// message. +func (p *peer) freezeClient() { + if p.version < lpv3 { + // if Stop/Resume is not supported then just drop the peer after setting + // its frozen status permanently + atomic.StoreUint32(&p.frozen, 1) + p.Peer.Disconnect(p2p.DiscUselessPeer) + return + } + if atomic.SwapUint32(&p.frozen, 1) == 0 { + go func() { + p.SendStop() + time.Sleep(freezeTimeBase + time.Duration(rand.Int63n(int64(freezeTimeRandom)))) + for { + bufValue, bufLimit := p.fcClient.BufferStatus() + if bufLimit == 0 { + return + } + if bufValue <= bufLimit/8 { + time.Sleep(freezeCheckPeriod) + } else { + atomic.StoreUint32(&p.frozen, 0) + p.SendResume(bufValue) + break + } + } + }() + } +} + +// freezeServer processes Stop/Resume messages from the given server +func (p *peer) freezeServer(frozen bool) { + var f uint32 + if frozen { + f = 1 + } + if atomic.SwapUint32(&p.frozen, f) != f && frozen { + p.sendQueue.clear() + } +} + +// isFrozen returns true if the client is frozen or the server has put our +// client in frozen state +func (p *peer) isFrozen() bool { + return atomic.LoadUint32(&p.frozen) != 0 +} + func (p *peer) canQueue() bool { - return p.sendQueue.canQueue() + return p.sendQueue.canQueue() && !p.isFrozen() } func (p *peer) queueSend(f func()) { @@ -265,10 +328,21 @@ func (p *peer) GetTxRelayCost(amount, size int) uint64 { // HasBlock checks if the peer has a given block func (p *peer) HasBlock(hash common.Hash, number uint64, hasState bool) bool { + var head, since, recent uint64 p.lock.RLock() + if p.headInfo != nil { + head = p.headInfo.Number + } + if hasState { + since = p.stateSince + recent = p.stateRecent + } else { + since = p.chainSince + recent = p.chainRecent + } hasBlock := p.hasBlock p.lock.RUnlock() - return hasBlock != nil && hasBlock(hash, number, hasState) + return head >= number && number >= since && (recent == 0 || number+recent+4 > head) && hasBlock != nil && hasBlock(hash, number, hasState) } // SendAnnounce announces the availability of a number of blocks through @@ -277,6 +351,16 @@ func (p *peer) SendAnnounce(request announceData) error { return p2p.Send(p.rw, AnnounceMsg, request) } +// SendStop notifies the client about being in frozen state +func (p *peer) SendStop() error { + return p2p.Send(p.rw, StopMsg, struct{}{}) +} + +// SendResume notifies the client about getting out of frozen state +func (p *peer) SendResume(bv uint64) error { + return p2p.Send(p.rw, ResumeMsg, bv) +} + // ReplyBlockHeaders creates a reply with a batch of block headers func (p *peer) ReplyBlockHeaders(reqID uint64, headers []*types.Header) *reply { data, _ := rlp.EncodeToBytes(headers) @@ -464,19 +548,19 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis send = send.add("genesisHash", genesis) if server != nil { if !server.onlyAnnounce { - //only announce server. It sends only announse requests send = send.add("serveHeaders", nil) send = send.add("serveChainSince", uint64(0)) send = send.add("serveStateSince", uint64(0)) + send = send.add("serveRecentState", uint64(core.TriesInMemory-4)) send = send.add("txRelay", nil) } send = send.add("flowControl/BL", server.defParams.BufLimit) send = send.add("flowControl/MRR", server.defParams.MinRecharge) var costList RequestCostList if server.costTracker != nil { - costList = server.costTracker.makeCostList() + costList = server.costTracker.makeCostList(server.costTracker.globalFactor()) } else { - costList = testCostList() + costList = testCostList(server.testCost) } send = send.add("flowControl/MRC", costList) p.fcCosts = costList.decode(ProtocolLengths[uint(p.version)]) @@ -544,12 +628,18 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis p.fcClient = flowcontrol.NewClientNode(server.fcManager, server.defParams) } else { //mark OnlyAnnounce server if "serveHeaders", "serveChainSince", "serveStateSince" or "txRelay" fields don't exist - if recv.get("serveChainSince", nil) != nil { + if recv.get("serveChainSince", &p.chainSince) != nil { p.isOnlyAnnounce = true } - if recv.get("serveStateSince", nil) != nil { + if recv.get("serveRecentChain", &p.chainRecent) != nil { + p.chainRecent = 0 + } + if recv.get("serveStateSince", &p.stateSince) != nil { p.isOnlyAnnounce = true } + if recv.get("serveRecentState", &p.stateRecent) != nil { + p.stateRecent = 0 + } if recv.get("txRelay", nil) != nil { p.isOnlyAnnounce = true } diff --git a/les/peer_test.go b/les/peer_test.go index 62adf90fe1..d5ce166945 100644 --- a/les/peer_test.go +++ b/les/peer_test.go @@ -54,7 +54,7 @@ func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testi l = l.add("txRelay", nil) l = l.add("flowControl/BL", uint64(0)) l = l.add("flowControl/MRR", uint64(0)) - l = l.add("flowControl/MRC", testCostList()) + l = l.add("flowControl/MRC", testCostList(0)) return l }, @@ -99,7 +99,7 @@ func TestPeerHandshakeAnnounceTypeSignedForTrustedPeersPeerNotInTrusted(t *testi l = l.add("txRelay", nil) l = l.add("flowControl/BL", uint64(0)) l = l.add("flowControl/MRR", uint64(0)) - l = l.add("flowControl/MRC", testCostList()) + l = l.add("flowControl/MRC", testCostList(0)) return l }, diff --git a/les/protocol.go b/les/protocol.go index 24dc9bdeae..ebf5814732 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -32,17 +32,18 @@ import ( // Constants to match up protocol versions and messages const ( lpv2 = 2 + lpv3 = 3 ) // Supported versions of the les protocol (first is primary) var ( - ClientProtocolVersions = []uint{lpv2} - ServerProtocolVersions = []uint{lpv2} + ClientProtocolVersions = []uint{lpv2, lpv3} + ServerProtocolVersions = []uint{lpv2, lpv3} AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list ) // Number of implemented message corresponding to different protocol versions. -var ProtocolLengths = map[uint]uint64{lpv2: 22} +var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24} const ( NetworkId = 1 @@ -70,6 +71,9 @@ const ( SendTxV2Msg = 0x13 GetTxStatusMsg = 0x14 TxStatusMsg = 0x15 + // Protocol messages introduced in LPV3 + StopMsg = 0x16 + ResumeMsg = 0x17 ) type requestInfo struct { diff --git a/les/retrieve.go b/les/retrieve.go index dd9d14598b..d17a02e1ae 100644 --- a/les/retrieve.go +++ b/les/retrieve.go @@ -78,8 +78,8 @@ type sentReq struct { // after which delivered is set to true, the validity of the response is sent on the // valid channel and no more responses are accepted. type sentReqToPeer struct { - delivered bool - valid chan bool + delivered, frozen bool + event chan int } // reqPeerEvent is sent by the request-from-peer goroutine (tryRequest) to the @@ -95,6 +95,7 @@ const ( rpHardTimeout rpDeliveredValid rpDeliveredInvalid + rpNotDelivered ) // newRetrieveManager creates the retrieve manager @@ -149,7 +150,7 @@ func (rm *retrieveManager) sendReq(reqID uint64, req *distReq, val validatorFunc req.request = func(p distPeer) func() { // before actually sending the request, put an entry into the sentTo map r.lock.Lock() - r.sentTo[p] = sentReqToPeer{false, make(chan bool, 1)} + r.sentTo[p] = sentReqToPeer{delivered: false, frozen: false, event: make(chan int, 1)} r.lock.Unlock() return request(p) } @@ -173,6 +174,17 @@ func (rm *retrieveManager) deliver(peer distPeer, msg *Msg) error { return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID) } +// frozen is called by the LES protocol manager when a server has suspended its service and we +// should not expect an answer for the requests already sent there +func (rm *retrieveManager) frozen(peer distPeer) { + rm.lock.RLock() + defer rm.lock.RUnlock() + + for _, req := range rm.sentReqs { + req.frozen(peer) + } +} + // reqStateFn represents a state of the retrieve loop state machine type reqStateFn func() reqStateFn @@ -215,7 +227,7 @@ func (r *sentReq) stateRequesting() reqStateFn { go r.tryRequest() r.lastReqQueued = true return r.stateRequesting - case rpDeliveredInvalid: + case rpDeliveredInvalid, rpNotDelivered: // if it was the last sent request (set to nil by update) then start a new one if !r.lastReqQueued && r.lastReqSentTo == nil { go r.tryRequest() @@ -277,7 +289,7 @@ func (r *sentReq) update(ev reqPeerEvent) { r.reqSrtoCount++ case rpHardTimeout: r.reqSrtoCount-- - case rpDeliveredValid, rpDeliveredInvalid: + case rpDeliveredValid, rpDeliveredInvalid, rpNotDelivered: if ev.peer == r.lastReqSentTo { r.lastReqSentTo = nil } else { @@ -343,12 +355,13 @@ func (r *sentReq) tryRequest() { }() select { - case ok := <-s.valid: - if ok { - r.eventsCh <- reqPeerEvent{rpDeliveredValid, p} - } else { - r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p} + case event := <-s.event: + if event == rpNotDelivered { + r.lock.Lock() + delete(r.sentTo, p) + r.lock.Unlock() } + r.eventsCh <- reqPeerEvent{event, p} return case <-time.After(softRequestTimeout): srto = true @@ -356,12 +369,13 @@ func (r *sentReq) tryRequest() { } select { - case ok := <-s.valid: - if ok { - r.eventsCh <- reqPeerEvent{rpDeliveredValid, p} - } else { - r.eventsCh <- reqPeerEvent{rpDeliveredInvalid, p} + case event := <-s.event: + if event == rpNotDelivered { + r.lock.Lock() + delete(r.sentTo, p) + r.lock.Unlock() } + r.eventsCh <- reqPeerEvent{event, p} case <-time.After(hardRequestTimeout): hrto = true r.eventsCh <- reqPeerEvent{rpHardTimeout, p} @@ -377,15 +391,37 @@ func (r *sentReq) deliver(peer distPeer, msg *Msg) error { if !ok || s.delivered { return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID) } + if s.frozen { + return nil + } valid := r.validate(peer, msg) == nil - r.sentTo[peer] = sentReqToPeer{true, s.valid} - s.valid <- valid + r.sentTo[peer] = sentReqToPeer{delivered: true, frozen: false, event: s.event} + if valid { + s.event <- rpDeliveredValid + } else { + s.event <- rpDeliveredInvalid + } if !valid { return errResp(ErrInvalidResponse, "reqID = %v", msg.ReqID) } return nil } +// frozen sends a "not delivered" event to the peer event channel belonging to the +// given peer if the request has been sent there, causing the state machine to not +// expect an answer and potentially even send the request to the same peer again +// when canSend allows it. +func (r *sentReq) frozen(peer distPeer) { + r.lock.Lock() + defer r.lock.Unlock() + + s, ok := r.sentTo[peer] + if ok && !s.delivered && !s.frozen { + r.sentTo[peer] = sentReqToPeer{delivered: false, frozen: true, event: s.event} + s.event <- rpNotDelivered + } +} + // stop stops the retrieval process and sets an error code that will be returned // by getError func (r *sentReq) stop(err error) { diff --git a/les/server.go b/les/server.go index 6b93b846db..836fa0d552 100644 --- a/les/server.go +++ b/les/server.go @@ -19,6 +19,7 @@ package les import ( "crypto/ecdsa" "sync" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" @@ -26,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/les/csvlogger" "github.com/ethereum/go-ethereum/les/flowcontrol" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" @@ -37,26 +39,43 @@ import ( const bufLimitRatio = 6000 // fixed bufLimit/MRR ratio +const ( + logFileName = "" // csv log file name (disabled if empty) + logClientPoolMetrics = true // log client pool metrics + logClientPoolEvents = false // detailed client pool event logging + logRequestServing = true // log request serving metrics and events + logBlockProcEvents = true // log block processing events + logProtocolHandler = true // log protocol handler events +) + type LesServer struct { lesCommons fcManager *flowcontrol.ClientManager // nil if our node is client only costTracker *costTracker + testCost uint64 defParams flowcontrol.ServerParams lesTopics []discv5.Topic privateKey *ecdsa.PrivateKey quitSync chan struct{} onlyAnnounce bool + csvLogger *csvlogger.Logger + logTotalCap *csvlogger.Channel thcNormal, thcBlockProcessing int // serving thread count for normal operation and block processing mode - maxPeers int - freeClientCap uint64 - freeClientPool *freeClientPool - priorityClientPool *priorityClientPool + maxPeers int + minCapacity, freeClientCap uint64 + freeClientPool *freeClientPool + priorityClientPool *priorityClientPool } func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { + var csvLogger *csvlogger.Logger + if logFileName != "" { + csvLogger = csvlogger.NewLogger(logFileName, time.Second*10, "event, peerId") + } + quitSync := make(chan struct{}) pm, err := NewProtocolManager( eth.BlockChain().Config(), @@ -78,6 +97,14 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { if err != nil { return nil, err } + if logProtocolHandler { + pm.logger = csvLogger + } + requestLogger := csvLogger + if !logRequestServing { + requestLogger = nil + } + pm.servingQueue = newServingQueue(int64(time.Millisecond*10), float64(config.LightServ)/100, requestLogger) lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions)) for i, pv := range AdvertiseProtocolVersions { @@ -93,11 +120,13 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency), protocolManager: pm, }, - costTracker: newCostTracker(eth.ChainDb(), config), quitSync: quitSync, lesTopics: lesTopics, onlyAnnounce: config.OnlyAnnounce, + csvLogger: csvLogger, + logTotalCap: requestLogger.NewChannel("totalCapacity", 0.01), } + srv.costTracker, srv.minCapacity = newCostTracker(eth.ChainDb(), config, requestLogger) logger := log.New() pm.server = srv @@ -144,7 +173,11 @@ func (s *LesServer) APIs() []rpc.API { func (s *LesServer) startEventLoop() { s.protocolManager.wg.Add(1) - var processing bool + blockProcLogger := s.csvLogger + if !logBlockProcEvents { + blockProcLogger = nil + } + var processing, procLast bool blockProcFeed := make(chan bool, 100) s.protocolManager.blockchain.(*core.BlockChain).SubscribeBlockProcessingEvent(blockProcFeed) totalRechargeCh := make(chan uint64, 100) @@ -152,17 +185,25 @@ func (s *LesServer) startEventLoop() { totalCapacityCh := make(chan uint64, 100) updateRecharge := func() { if processing { + if !procLast { + blockProcLogger.Event("block processing started") + } s.protocolManager.servingQueue.setThreads(s.thcBlockProcessing) s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge, totalRecharge}}) } else { + if procLast { + blockProcLogger.Event("block processing finished") + } s.protocolManager.servingQueue.setThreads(s.thcNormal) - s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge / 10, totalRecharge}, {totalRecharge, totalRecharge}}) + s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge / 16, totalRecharge / 2}, {totalRecharge / 2, totalRecharge / 2}, {totalRecharge, totalRecharge}}) } + procLast = processing } updateRecharge() totalCapacity := s.fcManager.SubscribeTotalCapacity(totalCapacityCh) s.priorityClientPool.setLimits(s.maxPeers, totalCapacity) + var maxFreePeers uint64 go func() { for { select { @@ -171,6 +212,12 @@ func (s *LesServer) startEventLoop() { case totalRecharge = <-totalRechargeCh: updateRecharge() case totalCapacity = <-totalCapacityCh: + s.logTotalCap.Update(float64(totalCapacity)) + newFreePeers := totalCapacity / s.freeClientCap + if newFreePeers < maxFreePeers && newFreePeers < uint64(s.maxPeers) { + log.Warn("Reduced total capacity", "maxFreePeers", newFreePeers) + } + maxFreePeers = newFreePeers s.priorityClientPool.setLimits(s.maxPeers, totalCapacity) case <-s.protocolManager.quitSync: s.protocolManager.wg.Done() @@ -189,9 +236,9 @@ func (s *LesServer) Start(srvr *p2p.Server) { s.maxPeers = s.config.LightPeers totalRecharge := s.costTracker.totalRecharge() if s.maxPeers > 0 { - s.freeClientCap = minCapacity //totalRecharge / uint64(s.maxPeers) - if s.freeClientCap < minCapacity { - s.freeClientCap = minCapacity + s.freeClientCap = s.minCapacity //totalRecharge / uint64(s.maxPeers) + if s.freeClientCap < s.minCapacity { + s.freeClientCap = s.minCapacity } if s.freeClientCap > 0 { s.defParams = flowcontrol.ServerParams{ @@ -200,15 +247,25 @@ func (s *LesServer) Start(srvr *p2p.Server) { } } } - freePeers := int(totalRecharge / s.freeClientCap) - if freePeers < s.maxPeers { - log.Warn("Light peer count limited", "specified", s.maxPeers, "allowed", freePeers) - } - s.freeClientPool = newFreeClientPool(s.chainDb, s.freeClientCap, 10000, mclock.System{}, func(id string) { go s.protocolManager.removePeer(id) }) - s.priorityClientPool = newPriorityClientPool(s.freeClientCap, s.protocolManager.peers, s.freeClientPool) + maxCapacity := s.freeClientCap * uint64(s.maxPeers) + if totalRecharge > maxCapacity { + maxCapacity = totalRecharge + } + s.fcManager.SetCapacityLimits(s.freeClientCap, maxCapacity, s.freeClientCap*2) + poolMetricsLogger := s.csvLogger + if !logClientPoolMetrics { + poolMetricsLogger = nil + } + poolEventLogger := s.csvLogger + if !logClientPoolEvents { + poolEventLogger = nil + } + s.freeClientPool = newFreeClientPool(s.chainDb, s.freeClientCap, 10000, mclock.System{}, func(id string) { go s.protocolManager.removePeer(id) }, poolMetricsLogger, poolEventLogger) + s.priorityClientPool = newPriorityClientPool(s.freeClientCap, s.protocolManager.peers, s.freeClientPool, poolMetricsLogger, poolEventLogger) s.protocolManager.peers.notify(s.priorityClientPool) + s.csvLogger.Start() s.startEventLoop() s.protocolManager.Start(s.config.LightPeers) if srvr.DiscV5 != nil { @@ -233,6 +290,7 @@ func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { // Stop stops the LES service func (s *LesServer) Stop() { + s.fcManager.Stop() s.chtIndexer.Close() // bloom trie indexer is closed by parent bloombits indexer go func() { @@ -241,6 +299,7 @@ func (s *LesServer) Stop() { s.freeClientPool.stop() s.costTracker.stop() s.protocolManager.Stop() + s.csvLogger.Stop() } // todo(rjl493456442) separate client and server implementation. diff --git a/les/servingqueue.go b/les/servingqueue.go index 2438fdfe3c..26656ec018 100644 --- a/les/servingqueue.go +++ b/les/servingqueue.go @@ -17,16 +17,24 @@ package les import ( + "fmt" + "sort" "sync" + "sync/atomic" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" + "github.com/ethereum/go-ethereum/les/csvlogger" ) // servingQueue allows running tasks in a limited number of threads and puts the // waiting tasks in a priority queue type servingQueue struct { - tokenCh chan runToken + recentTime, queuedTime, servingTimeDiff uint64 + burstLimit, burstDropLimit uint64 + burstDecRate float64 + lastUpdate mclock.AbsTime + queueAddCh, queueBestCh chan *servingTask stopThreadCh, quit chan struct{} setThreadsCh chan int @@ -36,6 +44,10 @@ type servingQueue struct { queue *prque.Prque // priority queue for waiting or suspended tasks best *servingTask // the highest priority task (not included in the queue) suspendBias int64 // priority bias against suspending an already running task + + logger *csvlogger.Logger + logRecentTime *csvlogger.Channel + logQueuedTime *csvlogger.Channel } // servingTask represents a request serving task. Tasks can be implemented to @@ -47,12 +59,13 @@ type servingQueue struct { // - run: execute a single step; return true if finished // - after: executed after run finishes or returns an error, receives the total serving time type servingTask struct { - sq *servingQueue - servingTime uint64 - priority int64 - biasAdded bool - token runToken - tokenCh chan runToken + sq *servingQueue + servingTime, timeAdded, maxTime, expTime uint64 + peer *peer + priority int64 + biasAdded bool + token runToken + tokenCh chan runToken } // runToken received by servingTask.start allows the task to run. Closing the @@ -63,20 +76,19 @@ type runToken chan struct{} // start blocks until the task can start and returns true if it is allowed to run. // Returning false means that the task should be cancelled. func (t *servingTask) start() bool { + if t.peer.isFrozen() { + return false + } + t.tokenCh = make(chan runToken, 1) select { - case t.token = <-t.sq.tokenCh: - default: - t.tokenCh = make(chan runToken, 1) - select { - case t.sq.queueAddCh <- t: - case <-t.sq.quit: - return false - } - select { - case t.token = <-t.tokenCh: - case <-t.sq.quit: - return false - } + case t.sq.queueAddCh <- t: + case <-t.sq.quit: + return false + } + select { + case t.token = <-t.tokenCh: + case <-t.sq.quit: + return false } if t.token == nil { return false @@ -90,6 +102,14 @@ func (t *servingTask) start() bool { func (t *servingTask) done() uint64 { t.servingTime += uint64(mclock.Now()) close(t.token) + diff := t.servingTime - t.timeAdded + t.timeAdded = t.servingTime + if t.expTime > diff { + t.expTime -= diff + atomic.AddUint64(&t.sq.servingTimeDiff, t.expTime) + } else { + t.expTime = 0 + } return t.servingTime } @@ -107,16 +127,22 @@ func (t *servingTask) waitOrStop() bool { } // newServingQueue returns a new servingQueue -func newServingQueue(suspendBias int64) *servingQueue { +func newServingQueue(suspendBias int64, utilTarget float64, logger *csvlogger.Logger) *servingQueue { sq := &servingQueue{ - queue: prque.New(nil), - suspendBias: suspendBias, - tokenCh: make(chan runToken), - queueAddCh: make(chan *servingTask, 100), - queueBestCh: make(chan *servingTask), - stopThreadCh: make(chan struct{}), - quit: make(chan struct{}), - setThreadsCh: make(chan int, 10), + queue: prque.New(nil), + suspendBias: suspendBias, + queueAddCh: make(chan *servingTask, 100), + queueBestCh: make(chan *servingTask), + stopThreadCh: make(chan struct{}), + quit: make(chan struct{}), + setThreadsCh: make(chan int, 10), + burstLimit: uint64(utilTarget * bufLimitRatio * 1200000), + burstDropLimit: uint64(utilTarget * bufLimitRatio * 1000000), + burstDecRate: utilTarget, + lastUpdate: mclock.Now(), + logger: logger, + logRecentTime: logger.NewMinMaxChannel("recentTime", false), + logQueuedTime: logger.NewMinMaxChannel("queuedTime", false), } sq.wg.Add(2) go sq.queueLoop() @@ -125,9 +151,12 @@ func newServingQueue(suspendBias int64) *servingQueue { } // newTask creates a new task with the given priority -func (sq *servingQueue) newTask(priority int64) *servingTask { +func (sq *servingQueue) newTask(peer *peer, maxTime uint64, priority int64) *servingTask { return &servingTask{ sq: sq, + peer: peer, + maxTime: maxTime, + expTime: maxTime, priority: priority, } } @@ -144,18 +173,12 @@ func (sq *servingQueue) threadController() { select { case best := <-sq.queueBestCh: best.tokenCh <- token - default: - select { - case best := <-sq.queueBestCh: - best.tokenCh <- token - case sq.tokenCh <- token: - case <-sq.stopThreadCh: - sq.wg.Done() - return - case <-sq.quit: - sq.wg.Done() - return - } + case <-sq.stopThreadCh: + sq.wg.Done() + return + case <-sq.quit: + sq.wg.Done() + return } <-token select { @@ -170,6 +193,100 @@ func (sq *servingQueue) threadController() { } } +type ( + // peerTasks lists the tasks received from a given peer when selecting peers to freeze + peerTasks struct { + peer *peer + list []*servingTask + sumTime uint64 + priority float64 + } + // peerList is a sortable list of peerTasks + peerList []*peerTasks +) + +func (l peerList) Len() int { + return len(l) +} + +func (l peerList) Less(i, j int) bool { + return l[i].priority < l[j].priority +} + +func (l peerList) Swap(i, j int) { + l[i], l[j] = l[j], l[i] +} + +// freezePeers selects the peers with the worst priority queued tasks and freezes +// them until burstTime goes under burstDropLimit or all peers are frozen +func (sq *servingQueue) freezePeers() { + peerMap := make(map[*peer]*peerTasks) + var peerList peerList + if sq.best != nil { + sq.queue.Push(sq.best, sq.best.priority) + } + sq.best = nil + for sq.queue.Size() > 0 { + task := sq.queue.PopItem().(*servingTask) + tasks := peerMap[task.peer] + if tasks == nil { + bufValue, bufLimit := task.peer.fcClient.BufferStatus() + if bufLimit < 1 { + bufLimit = 1 + } + tasks = &peerTasks{ + peer: task.peer, + priority: float64(bufValue) / float64(bufLimit), // lower value comes first + } + peerMap[task.peer] = tasks + peerList = append(peerList, tasks) + } + tasks.list = append(tasks.list, task) + tasks.sumTime += task.expTime + } + sort.Sort(peerList) + drop := true + sq.logger.Event("freezing peers") + for _, tasks := range peerList { + if drop { + tasks.peer.freezeClient() + tasks.peer.fcClient.Freeze() + sq.queuedTime -= tasks.sumTime + if sq.logQueuedTime != nil { + sq.logQueuedTime.Update(float64(sq.queuedTime) / 1000) + } + sq.logger.Event(fmt.Sprintf("frozen peer sumTime=%d, %v", tasks.sumTime, tasks.peer.id)) + drop = sq.recentTime+sq.queuedTime > sq.burstDropLimit + for _, task := range tasks.list { + task.tokenCh <- nil + } + } else { + for _, task := range tasks.list { + sq.queue.Push(task, task.priority) + } + } + } + if sq.queue.Size() > 0 { + sq.best = sq.queue.PopItem().(*servingTask) + } +} + +// updateRecentTime recalculates the recent serving time value +func (sq *servingQueue) updateRecentTime() { + subTime := atomic.SwapUint64(&sq.servingTimeDiff, 0) + now := mclock.Now() + dt := now - sq.lastUpdate + sq.lastUpdate = now + if dt > 0 { + subTime += uint64(float64(dt) * sq.burstDecRate) + } + if sq.recentTime > subTime { + sq.recentTime -= subTime + } else { + sq.recentTime = 0 + } +} + // addTask inserts a task into the priority queue func (sq *servingQueue) addTask(task *servingTask) { if sq.best == nil { @@ -177,10 +294,18 @@ func (sq *servingQueue) addTask(task *servingTask) { } else if task.priority > sq.best.priority { sq.queue.Push(sq.best, sq.best.priority) sq.best = task - return } else { sq.queue.Push(task, task.priority) } + sq.updateRecentTime() + sq.queuedTime += task.expTime + if sq.logQueuedTime != nil { + sq.logRecentTime.Update(float64(sq.recentTime) / 1000) + sq.logQueuedTime.Update(float64(sq.queuedTime) / 1000) + } + if sq.recentTime+sq.queuedTime > sq.burstLimit { + sq.freezePeers() + } } // queueLoop is an event loop running in a goroutine. It receives tasks from queueAddCh @@ -189,10 +314,18 @@ func (sq *servingQueue) addTask(task *servingTask) { func (sq *servingQueue) queueLoop() { for { if sq.best != nil { + expTime := sq.best.expTime select { case task := <-sq.queueAddCh: sq.addTask(task) case sq.queueBestCh <- sq.best: + sq.updateRecentTime() + sq.queuedTime -= expTime + sq.recentTime += expTime + if sq.logQueuedTime != nil { + sq.logRecentTime.Update(float64(sq.recentTime) / 1000) + sq.logQueuedTime.Update(float64(sq.queuedTime) / 1000) + } if sq.queue.Size() == 0 { sq.best = nil } else { From f2612ac948b1367adcae926a805e1ffce31fe078 Mon Sep 17 00:00:00 2001 From: gary rong Date: Fri, 31 May 2019 15:54:50 +0800 Subject: [PATCH 24/47] les: short circuit in the unregister if peer is not registered (#19644) --- les/freeclient.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/les/freeclient.go b/les/freeclient.go index 958b7daa78..f434ea0b95 100644 --- a/les/freeclient.go +++ b/les/freeclient.go @@ -193,7 +193,11 @@ func (f *freeClientPool) disconnect(address string) { if f.closed { return } + // Short circuit if the peer hasn't been registered. e := f.addressMap[address] + if e == nil { + return + } now := f.clock.Now() if !e.connected { log.Debug("Client already disconnected", "address", address) From 30263ad37d49c014512a9a7d8abdd17f305843e9 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Fri, 31 May 2019 11:13:34 +0200 Subject: [PATCH 25/47] swarm/storage: set false, only when we get a chunk back (#19599) --- swarm/network/stream/syncer.go | 4 -- swarm/storage/localstore/subscription_pull.go | 8 +-- .../localstore/subscription_pull_test.go | 49 +++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/swarm/network/stream/syncer.go b/swarm/network/stream/syncer.go index 7a61950eda..7957a8bf70 100644 --- a/swarm/network/stream/syncer.go +++ b/swarm/network/stream/syncer.go @@ -93,10 +93,6 @@ func (s *SwarmSyncerServer) SessionIndex() (uint64, error) { // are added in batchTimeout period, the batch will be returned. This function // will block until new chunks are received from localstore pull subscription. func (s *SwarmSyncerServer) SetNextBatch(from, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { - //TODO: maybe add unit test for intervals usage in netstore/localstore together with SwarmSyncerServer? - if from > 0 { - from-- - } batchStart := time.Now() descriptors, stop := s.netStore.SubscribePull(context.Background(), s.po, from, to) defer stop() diff --git a/swarm/storage/localstore/subscription_pull.go b/swarm/storage/localstore/subscription_pull.go index ce539924b4..0f7e487295 100644 --- a/swarm/storage/localstore/subscription_pull.go +++ b/swarm/storage/localstore/subscription_pull.go @@ -31,9 +31,9 @@ import ( // SubscribePull returns a channel that provides chunk addresses and stored times from pull syncing index. // Pull syncing index can be only subscribed to a particular proximity order bin. If since -// is not 0, the iteration will start from the first item stored after that id. If until is not 0, +// is not 0, the iteration will start from the since item (the item with binID == since). If until is not 0, // only chunks stored up to this id will be sent to the channel, and the returned channel will be -// closed. The since-until interval is open on since side, and closed on until side: (since,until] <=> [since+1,until]. Returned stop +// closed. The since-until interval is closed on since side, and closed on until side: [since,until]. Returned stop // function will terminate current and further iterations without errors, and also close the returned channel. // Make sure that you check the second returned parameter from the channel to stop iteration when its value // is false. @@ -135,7 +135,9 @@ func (db *DB) SubscribePull(ctx context.Context, bin uint8, since, until uint64) log.Error("localstore pull subscription iteration", "bin", bin, "since", since, "until", until, "err", err) return } - first = false + if count > 0 { + first = false + } case <-stopChan: // terminate the subscription // on stop diff --git a/swarm/storage/localstore/subscription_pull_test.go b/swarm/storage/localstore/subscription_pull_test.go index bf364ed444..95a2fa8b13 100644 --- a/swarm/storage/localstore/subscription_pull_test.go +++ b/swarm/storage/localstore/subscription_pull_test.go @@ -28,6 +28,55 @@ import ( "github.com/ethereum/go-ethereum/swarm/shed" ) +// TestDB_SubscribePull_first is a regression test for the first=false (from-1) bug +// The bug was that `first=false` was not behind an if-condition `if count > 0`. This resulted in chunks being missed, when +// the subscription is established before the chunk is actually uploaded. For example if a subscription is established with since=49, +// which means that the `SubscribePull` method should return chunk with BinID=49 via the channel, and the chunk for BinID=49 is uploaded, +// after the subscription, then it would have been skipped, where the correct behaviour is to not skip it and return it via the channel. +func TestDB_SubscribePull_first(t *testing.T) { + db, cleanupFunc := newTestDB(t, nil) + defer cleanupFunc() + + addrs := make(map[uint8][]chunk.Address) + var addrsMu sync.Mutex + var wantedChunksCount int + + // prepopulate database with some chunks + // before the subscription + uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 100) + + // any bin should do the trick + bin := uint8(1) + + chunksInGivenBin := uint64(len(addrs[bin])) + + errc := make(chan error) + + since := chunksInGivenBin + 1 + + go func() { + ch, stop := db.SubscribePull(context.TODO(), bin, since, 0) + defer stop() + + chnk := <-ch + + if chnk.BinID != since { + errc <- fmt.Errorf("expected chunk.BinID to be %v , but got %v", since, chnk.BinID) + } else { + errc <- nil + } + }() + + time.Sleep(100 * time.Millisecond) + + uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 100) + + err := <-errc + if err != nil { + t.Fatal(err) + } +} + // TestDB_SubscribePull uploads some chunks before and after // pull syncing subscription is created and validates if // all addresses are received in the right order From 7a22da98b9f81d206eb65d1fa4f5e773d888bac3 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Fri, 31 May 2019 11:30:28 +0200 Subject: [PATCH 26/47] accounts/scwallet: flag to specify path to smartcard daemon (#19439) * accounts/scwallet: Add a switch to enable smartcard support * accounts: change the meaning of the switch * disable card support in windows until tested * only activate account if pcscd socket file is present * the switch is now the path to the socket file * accounts/scwallet: holiman's review feedback * accounts/scwallet: send the path to go-pcsclite * accounts/scwallet: add default, per platform path * accounts/scwallet: fix error log warning * accounts/scwallet: update pcsc lib to latest * accounts/scwallet: use default path from pcsclite * scwallet: forgot to change switch name * cmd: minor style cleanups (error handling first, then happy path) --- accounts/scwallet/hub.go | 4 +-- cmd/geth/main.go | 1 + cmd/geth/usage.go | 1 + cmd/utils/flags.go | 27 ++++++++++++++ node/config.go | 15 +++++--- .../github.com/gballet/go-libpcsclite/doc.go | 2 -- .../gballet/go-libpcsclite/doc_bsd.go | 35 +++++++++++++++++++ .../gballet/go-libpcsclite/doc_linux.go | 35 +++++++++++++++++++ .../gballet/go-libpcsclite/doc_windows.go | 35 +++++++++++++++++++ .../github.com/gballet/go-libpcsclite/msg.go | 10 ++++-- .../gballet/go-libpcsclite/winscard.go | 4 +-- vendor/vendor.json | 6 ++-- 12 files changed, 158 insertions(+), 17 deletions(-) create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc_bsd.go create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc_linux.go create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc_windows.go diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index d1440cb96d..5f939c6586 100644 --- a/accounts/scwallet/hub.go +++ b/accounts/scwallet/hub.go @@ -152,8 +152,8 @@ func (hub *Hub) setPairing(wallet *Wallet, pairing *smartcardPairing) error { } // NewHub creates a new hardware wallet manager for smartcards. -func NewHub(scheme string, datadir string) (*Hub, error) { - context, err := pcsc.EstablishContext(pcsc.ScopeSystem) +func NewHub(daemonPath string, scheme string, datadir string) (*Hub, error) { + context, err := pcsc.EstablishContext(daemonPath, pcsc.ScopeSystem) if err != nil { return nil, err } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 1b23cbd9f2..d0a9bb08ae 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -66,6 +66,7 @@ var ( utils.KeyStoreDirFlag, utils.ExternalSignerFlag, utils.NoUSBFlag, + utils.SmartCardDaemonPathFlag, utils.DashboardEnabledFlag, utils.DashboardAddrFlag, utils.DashboardPortFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 67b0027f25..4cc77b9128 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -72,6 +72,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.AncientFlag, utils.KeyStoreDirFlag, utils.NoUSBFlag, + utils.SmartCardDaemonPathFlag, utils.NetworkIdFlag, utils.TestnetFlag, utils.RinkebyFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 93d162370a..7e19ebc0cb 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -58,6 +58,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" + pcsclite "github.com/gballet/go-libpcsclite" cli "gopkg.in/urfave/cli.v1" ) @@ -129,6 +130,11 @@ var ( Name: "nousb", Usage: "Disables monitoring for and managing USB hardware wallets", } + SmartCardDaemonPathFlag = cli.StringFlag{ + Name: "pcscdpath", + Usage: "Path to the smartcard daemon (pcscd) socket file", + Value: pcsclite.PCSCDSockName, + } NetworkIdFlag = cli.Uint64Flag{ Name: "networkid", Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)", @@ -1126,6 +1132,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { setWS(ctx, cfg) setNodeUserIdent(ctx, cfg) setDataDir(ctx, cfg) + setSmartCard(ctx, cfg) if ctx.GlobalIsSet(ExternalSignerFlag.Name) { cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name) @@ -1145,6 +1152,26 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { } } +func setSmartCard(ctx *cli.Context, cfg *node.Config) { + // Skip enabling smartcards if no path is set + path := ctx.GlobalString(SmartCardDaemonPathFlag.Name) + if path == "" { + return + } + // Sanity check that the smartcard path is valid + fi, err := os.Stat(path) + if err != nil { + log.Error("Failed to verify smartcard daemon path", "path", path, "err", err) + return + } + if fi.Mode()&os.ModeType != os.ModeSocket { + log.Error("Invalid smartcard daemon path", "path", path, "type", fi.Mode().String()) + return + } + // Smartcard daemon path exists and is a socket, enable it + cfg.SmartCardDaemonPath = path +} + func setDataDir(ctx *cli.Context, cfg *node.Config) { switch { case ctx.GlobalIsSet(DataDirFlag.Name): diff --git a/node/config.go b/node/config.go index 43ee5ec212..d76311ba65 100644 --- a/node/config.go +++ b/node/config.go @@ -95,6 +95,9 @@ type Config struct { // NoUSB disables hardware wallet monitoring and connectivity. NoUSB bool `toml:",omitempty"` + // SmartCardDaemonPath is the path to the smartcard daemon's socket + SmartCardDaemonPath string `toml:",omitempty"` + // IPCPath is the requested location to place the IPC endpoint. If the path is // a simple file name, it is placed inside the data directory (or on the root // pipe path on Windows), whereas if it's a resolvable path name (absolute or @@ -505,11 +508,13 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { backends = append(backends, trezorhub) } } - // Start a smart card hub - if schub, err := scwallet.NewHub(scwallet.Scheme, keydir); err != nil { - log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) - } else { - backends = append(backends, schub) + if len(conf.SmartCardDaemonPath) > 0 { + // Start a smart card hub + if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil { + log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) + } else { + backends = append(backends, schub) + } } } diff --git a/vendor/github.com/gballet/go-libpcsclite/doc.go b/vendor/github.com/gballet/go-libpcsclite/doc.go index d1085319ae..0f28c0c9c4 100644 --- a/vendor/github.com/gballet/go-libpcsclite/doc.go +++ b/vendor/github.com/gballet/go-libpcsclite/doc.go @@ -61,8 +61,6 @@ const ( SCardPowever = 0x0010 /* Card is powered */ SCardNegotiable = 0x0020 /* Ready for PTS */ SCardSpecific = 0x0040 /* PTS has been set */ - - PCSCDSockName = "/run/pcscd/pcscd.comm" ) // List of commands to send to the daemon diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go b/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go new file mode 100644 index 0000000000..ddec46c670 --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go @@ -0,0 +1,35 @@ +// BSD 3-Clause License +// +// Copyright (c) 2019, Guillaume Ballet +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build dragonfly darwin freebsd netbsd openbsd solaris + +package pcsc + +const PCSCDSockName string = "/var/run/pcscd/pcscd.comm" \ No newline at end of file diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_linux.go b/vendor/github.com/gballet/go-libpcsclite/doc_linux.go new file mode 100644 index 0000000000..becbf16775 --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/doc_linux.go @@ -0,0 +1,35 @@ +// BSD 3-Clause License +// +// Copyright (c) 2019, Guillaume Ballet +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build linux + +package pcsc + +const PCSCDSockName string = "/run/pcscd/pcscd.comm" \ No newline at end of file diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_windows.go b/vendor/github.com/gballet/go-libpcsclite/doc_windows.go new file mode 100644 index 0000000000..9bd6bd333f --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/doc_windows.go @@ -0,0 +1,35 @@ +// BSD 3-Clause License +// +// Copyright (c) 2019, Guillaume Ballet +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build windows + +package pcsc + +const PCSCDSockName string = "" diff --git a/vendor/github.com/gballet/go-libpcsclite/msg.go b/vendor/github.com/gballet/go-libpcsclite/msg.go index 53f5435308..1377082b14 100644 --- a/vendor/github.com/gballet/go-libpcsclite/msg.go +++ b/vendor/github.com/gballet/go-libpcsclite/msg.go @@ -62,7 +62,7 @@ func messageSendWithHeader(command uint32, conn net.Conn, data []byte) error { return err } -// ClientSetupSession prepares a communication channel for the client to talk to the server. +// clientSetupSession prepares a communication channel for the client to talk to the server. // This is called by the application to create a socket for local IPC with the // server. The socket is associated to the file \c PCSCLITE_CSOCK_NAME. /* @@ -73,6 +73,10 @@ func messageSendWithHeader(command uint32, conn net.Conn, data []byte) error { * @retval -1 The socket can not open a connection. * @retval -1 Can not set the socket to non-blocking. */ -func clientSetupSession() (net.Conn, error) { - return net.Dial("unix", PCSCDSockName) +func clientSetupSession(daemonPath string) (net.Conn, error) { + path := PCSCDSockName + if len(daemonPath) > 0 { + path = daemonPath + } + return net.Dial("unix", path) } diff --git a/vendor/github.com/gballet/go-libpcsclite/winscard.go b/vendor/github.com/gballet/go-libpcsclite/winscard.go index e4692ed165..b916db1621 100644 --- a/vendor/github.com/gballet/go-libpcsclite/winscard.go +++ b/vendor/github.com/gballet/go-libpcsclite/winscard.go @@ -56,10 +56,10 @@ type Client struct { // EstablishContext asks the PCSC daemon to create a context // handle for further communication with connected cards and // readers. -func EstablishContext(scope uint32) (*Client, error) { +func EstablishContext(path string, scope uint32) (*Client, error) { client := &Client{} - conn, err := clientSetupSession() + conn, err := clientSetupSession(path) if err != nil { return nil, err } diff --git a/vendor/vendor.json b/vendor/vendor.json index b3e1118007..a33a1d4e25 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -135,10 +135,10 @@ "revisionTime": "2018-04-18T12:24:29Z" }, { - "checksumSHA1": "GXqHzd0XkPLX/iulpOncaxbxzZo=", + "checksumSHA1": "+fiJGimxPPRSfi9sED4Lp6ytBeo=", "path": "github.com/gballet/go-libpcsclite", - "revision": "312b5175032f98274685a4dd81935a92ad2412a5", - "revisionTime": "2019-04-03T18:15:18Z" + "revision": "2fd9b619dd3c5d74acbd975f997a6441984d74a7", + "revisionTime": "2019-05-28T10:50:17Z" }, { "checksumSHA1": "gxV/cPPLkByTdY8y172t7v4qcZA=", From 4799b5abd411631920e0fcc907aba59a9fd09237 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Thu, 16 May 2019 14:37:36 +0200 Subject: [PATCH 27/47] accounts/usbwallet: support webusb for Trezor wallets --- accounts/usbwallet/hub.go | 22 +- accounts/usbwallet/trezor.go | 2 + accounts/usbwallet/wallet.go | 2 +- node/config.go | 6 + signer/core/api.go | 7 + vendor/github.com/karalabe/hid/generic.go | 54 ++++ vendor/github.com/karalabe/hid/hid.go | 19 +- .../github.com/karalabe/hid/hid_disabled.go | 41 ++- vendor/github.com/karalabe/hid/hid_enabled.go | 263 ++++++++++++++++-- vendor/github.com/karalabe/hid/usb.go | 53 ++++ vendor/github.com/karalabe/hid/wchar.go | 2 +- vendor/vendor.json | 6 +- 12 files changed, 443 insertions(+), 34 deletions(-) create mode 100644 vendor/github.com/karalabe/hid/generic.go create mode 100644 vendor/github.com/karalabe/hid/usb.go diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index fc711bb3e9..35695dd1c5 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -89,6 +89,12 @@ func NewTrezorHub() (*Hub, error) { return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor 1 */}, 0xff00, 0, newTrezorDriver) } +// NewWebUSBTrezorHub creates a new hardware wallet manager for Trezor devices with +// firmware version > 1.8.0 +func NewWebUSBTrezorHub() (*Hub, error) { + return newHub(TrezorScheme, 0x1209, []uint16{0x53c1 /* Trezor 1 WebUSB */}, 0, 0, newTrezorDriver) +} + // newHub creates a new hardware wallet manager for generic USB devices. func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) { if !hid.Supported() { @@ -148,9 +154,19 @@ func (hub *Hub) refreshWallets() { return } } - for _, info := range hid.Enumerate(hub.vendorID, 0) { + infos, err := hid.Enumerate(hub.vendorID, 0) + if err != nil { + if runtime.GOOS == "linux" { + // See rationale before the enumeration why this is needed and only on Linux. + hub.commsLock.Unlock() + } + log.Error("error enumerating USB enumeration: ", "code", err) + return + } + for _, info := range infos { for _, id := range hub.productIDs { - if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { + _, pid, endpoint, _ /* FIXME usageID */ := info.IDs() + if pid == id && ( /* FIXME usageID == hub.usageID || */ endpoint == hub.endpointID) { devices = append(devices, info) break } @@ -169,7 +185,7 @@ func (hub *Hub) refreshWallets() { ) for _, device := range devices { - url := accounts.URL{Scheme: hub.scheme, Path: device.Path} + url := accounts.URL{Scheme: hub.scheme, Path: device.GetPath()} // Drop wallets in front of the next device or those that failed for some reason for len(hub.wallets) > 0 { diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 31c2a7d8a9..9453b52c30 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -36,6 +36,8 @@ import ( "github.com/golang/protobuf/proto" ) +var ErrInvalidDeviceType = errors.New("trezor: invalid device type") + // ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In // this case, the calling application should display a pinpad and send back the // encoded passphrase. diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 7ff9c5372a..df38f953dd 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -78,7 +78,7 @@ type wallet struct { url *accounts.URL // Textual URL uniquely identifying this wallet info hid.DeviceInfo // Known USB device infos about the wallet - device *hid.Device // USB device advertising itself as a hardware wallet + device hid.Device // USB device advertising itself as a hardware wallet accounts []accounts.Account // List of derive accounts pinned on the hardware wallet paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations diff --git a/node/config.go b/node/config.go index d76311ba65..c864fea9c1 100644 --- a/node/config.go +++ b/node/config.go @@ -507,6 +507,12 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { } else { backends = append(backends, trezorhub) } + // Start a USB hub for Trezor hardware wallets (WebUSB version) + if trezorhub, err := usbwallet.NewWebUSBTrezorHub(); err != nil { + log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + } else { + backends = append(backends, trezorhub) + } } if len(conf.SmartCardDaemonPath) > 0 { // Start a smart card hub diff --git a/signer/core/api.go b/signer/core/api.go index 783aaece46..12bbd7bd3d 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -151,6 +151,13 @@ func StartClefAccountManager(ksLocation string, nousb, lightKDF bool) *accounts. backends = append(backends, trezorhub) log.Debug("Trezor support enabled") } + // Start a USB hub for Trezor hardware wallets (WebUSB version) + if trezorhub, err := usbwallet.NewWebUSBTrezorHub(); err != nil { + log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + } else { + backends = append(backends, trezorhub) + log.Debug("Trezor support enabled") + } } // Clef doesn't allow insecure http account unlock. return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: false}, backends...) diff --git a/vendor/github.com/karalabe/hid/generic.go b/vendor/github.com/karalabe/hid/generic.go new file mode 100644 index 0000000000..8de16fcbfc --- /dev/null +++ b/vendor/github.com/karalabe/hid/generic.go @@ -0,0 +1,54 @@ +// hid - Gopher Interface Devices (USB HID) +// Copyright (c) 2019 Péter Szilágyi, Guillaume Ballet. All rights reserved. + +package hid + +import ( + "C" +) + +type GenericEndpointDirection uint8 + +// List of endpoint direction types +const ( + GenericEndpointDirectionOut = 0x00 + GenericEndpointDirectionIn = 0x80 +) + +// List of endpoint attributes +const ( + GenericEndpointAttributeInterrupt = 3 +) + +// GenericEndpoint represents a USB endpoint +type GenericEndpoint struct { + Address uint8 + Direction GenericEndpointDirection + Attributes uint8 +} + +type GenericDeviceInfo struct { + Path string // Platform-specific device path + VendorID uint16 // Device Vendor ID + ProductID uint16 // Device Product ID + + device *GenericDevice + + Interface int + + Endpoints []GenericEndpoint +} + +func (gdi *GenericDeviceInfo) Type() DeviceType { + return DeviceTypeGeneric +} + +// Platform-specific device path +func (gdi *GenericDeviceInfo) GetPath() string { + return gdi.Path +} + +// IDs returns the vendor and product IDs for the device +func (gdi *GenericDeviceInfo) IDs() (uint16, uint16, int, uint16) { + return gdi.VendorID, gdi.ProductID, gdi.Interface, 0 +} diff --git a/vendor/github.com/karalabe/hid/hid.go b/vendor/github.com/karalabe/hid/hid.go index 60a40b8c24..f929006d8b 100644 --- a/vendor/github.com/karalabe/hid/hid.go +++ b/vendor/github.com/karalabe/hid/hid.go @@ -17,8 +17,8 @@ var ErrDeviceClosed = errors.New("hid: device closed") // operating system is not supported by the library. var ErrUnsupportedPlatform = errors.New("hid: unsupported platform") -// DeviceInfo is a hidapi info structure. -type DeviceInfo struct { +// HidDeviceInfo is a hidapi info structure. +type HidDeviceInfo struct { Path string // Platform-specific device path VendorID uint16 // Device Vendor ID ProductID uint16 // Device Product ID @@ -35,3 +35,18 @@ type DeviceInfo struct { // only if the device contains more than one interface. Interface int } + +// GetPath returns the system-dependent path to the device +func (hdi *HidDeviceInfo) GetPath() string { + return hdi.Path +} + +// IDs returns the vendor and product id of the device +func (hdi *HidDeviceInfo) IDs() (uint16, uint16, int, uint16) { + return hdi.VendorID, hdi.ProductID, hdi.Interface, hdi.UsagePage +} + +// Type returns the type of the device (HID or generic) +func (hdi *HidDeviceInfo) Type() DeviceType { + return DeviceTypeHID +} diff --git a/vendor/github.com/karalabe/hid/hid_disabled.go b/vendor/github.com/karalabe/hid/hid_disabled.go index 0f266ba58a..ce98279531 100644 --- a/vendor/github.com/karalabe/hid/hid_disabled.go +++ b/vendor/github.com/karalabe/hid/hid_disabled.go @@ -4,7 +4,7 @@ // This file is released under the 3-clause BSD license. Note however that Linux // support depends on libusb, released under GNU LGPL 2.1 or later. -// +build !linux,!darwin,!windows ios !cgo +// +build !freebsd,!linux,!darwin,!windows ios !cgo package hid @@ -22,30 +22,55 @@ func Enumerate(vendorID uint16, productID uint16) []DeviceInfo { return nil } -// Device is a live HID USB connected device handle. On platforms that this file +// HidDevice is a live HID USB connected device handle. On platforms that this file // implements the type lacks the actual HID device and all methods are noop. -type Device struct { - DeviceInfo // Embed the infos for easier access +type HidDevice struct { + HidDeviceInfo // Embed the infos for easier access } // Open connects to an HID device by its path name. On platforms that this file // implements the method just returns an error. -func (info DeviceInfo) Open() (*Device, error) { +func (info HidDeviceInfo) Open() (*Device, error) { return nil, ErrUnsupportedPlatform } // Close releases the HID USB device handle. On platforms that this file implements // the method is just a noop. -func (dev *Device) Close() error { return nil } +func (dev *HidDevice) Close() error { return ErrUnsupportedPlatform } // Write sends an output report to a HID device. On platforms that this file // implements the method just returns an error. -func (dev *Device) Write(b []byte) (int, error) { +func (dev *HidDevice) Write(b []byte) (int, error) { return 0, ErrUnsupportedPlatform } // Read retrieves an input report from a HID device. On platforms that this file // implements the method just returns an error. -func (dev *Device) Read(b []byte) (int, error) { +func (dev *HidDevice) Read(b []byte) (int, error) { return 0, ErrUnsupportedPlatform } + +// Open tries to open the USB device represented by the current DeviceInfo +func (gdi *GenericDeviceInfo) Open() (Device, error) { + return nil, ErrUnsupportedPlatform +} + +// GenericDevice represents a generic USB device +type GenericDevice struct { + *GenericDeviceInfo // Embed the infos for easier access +} + +// Write implements io.ReaderWriter +func (gd *GenericDevice) Write(b []byte) (int, error) { + return 0, ErrUnsupportedPlatform +} + +// Read implements io.ReaderWriter +func (gd *GenericDevice) Read(b []byte) (int, error) { + return 0, ErrUnsupportedPlatform +} + +// Close a previously opened generic USB device +func (gd *GenericDevice) Close() error { + return ErrUnsupportedPlatform +} diff --git a/vendor/github.com/karalabe/hid/hid_enabled.go b/vendor/github.com/karalabe/hid/hid_enabled.go index e95e5792d9..ee27ff98df 100644 --- a/vendor/github.com/karalabe/hid/hid_enabled.go +++ b/vendor/github.com/karalabe/hid/hid_enabled.go @@ -4,7 +4,7 @@ // This file is released under the 3-clause BSD license. Note however that Linux // support depends on libusb, released under LGNU GPL 2.1 or later. -// +build linux,cgo darwin,!ios,cgo windows,cgo +// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo package hid @@ -13,13 +13,15 @@ package hid #cgo linux CFLAGS: -I./libusb/libusb -DDEFAULT_VISIBILITY="" -DOS_LINUX -D_GNU_SOURCE -DPOLL_NFDS_TYPE=int #cgo linux,!android LDFLAGS: -lrt -#cgo darwin CFLAGS: -DOS_DARWIN -#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit +#cgo darwin CFLAGS: -DOS_DARWIN -I./libusb/libusb +#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit -lusb-1.0.0 #cgo windows CFLAGS: -DOS_WINDOWS #cgo windows LDFLAGS: -lsetupapi +#cgo freebsd CFLAGS: -DOS_FREEBSD +#cgo freebsd LDFLAGS: -lusb #ifdef OS_LINUX - #include + #include #include "os/threads_posix.c" #include "os/poll_posix.c" @@ -35,15 +37,50 @@ package hid #include "hidapi/libusb/hid.c" #elif OS_DARWIN + #include #include "hidapi/mac/hid.c" #elif OS_WINDOWS #include "hidapi/windows/hid.c" +#elif OS_FREEBSD + #include + #include + #include "hidapi/libusb/hid.c" #endif + +#if defined(OS_LINUX) || defined(OS_WINDOWS) + void copy_device_list_to_slice(struct libusb_device **data, struct libusb_device **list, int count) + { + int i; + struct libusb_device *current = *list; + for (i=0; ilist.next, struct libusb_device, list); + } + } +#elif defined(OS_DARWIN) || defined(OS_FREEBSD) + void copy_device_list_to_slice(struct libusb_device **data, struct libusb_device **list, int count) + { + int i; + // No memcopy because the struct size isn't available for a sizeof() + for (i=0; i Date: Tue, 28 May 2019 23:17:00 +0300 Subject: [PATCH 28/47] accounts/usbwallet: recreate Trezor protocol, support old and new --- accounts/usbwallet/trezor.go | 13 +- .../usbwallet/trezor/messages-common.pb.go | 811 ++++ .../usbwallet/trezor/messages-common.proto | 147 + .../usbwallet/trezor/messages-ethereum.pb.go | 698 +++ .../usbwallet/trezor/messages-ethereum.proto | 131 + .../trezor/messages-management.pb.go | 1621 +++++++ .../trezor/messages-management.proto | 289 ++ accounts/usbwallet/trezor/messages.pb.go | 3782 ++++------------- accounts/usbwallet/trezor/messages.proto | 1131 ++--- accounts/usbwallet/trezor/trezor.go | 32 +- accounts/usbwallet/trezor/types.pb.go | 1333 ------ accounts/usbwallet/trezor/types.proto | 278 -- vendor/github.com/golang/protobuf/LICENSE | 3 - .../github.com/golang/protobuf/proto/Makefile | 43 - .../github.com/golang/protobuf/proto/clone.go | 46 +- .../golang/protobuf/proto/decode.go | 669 +-- .../golang/protobuf/proto/deprecated.go | 63 + .../golang/protobuf/proto/discard.go | 350 ++ .../golang/protobuf/proto/encode.go | 1207 +----- .../github.com/golang/protobuf/proto/equal.go | 33 +- .../golang/protobuf/proto/extensions.go | 286 +- .../github.com/golang/protobuf/proto/lib.go | 166 +- .../golang/protobuf/proto/message_set.go | 138 +- .../golang/protobuf/proto/pointer_reflect.go | 648 ++- .../golang/protobuf/proto/pointer_unsafe.go | 427 +- .../golang/protobuf/proto/properties.go | 472 +- .../golang/protobuf/proto/table_marshal.go | 2776 ++++++++++++ .../golang/protobuf/proto/table_merge.go | 654 +++ .../golang/protobuf/proto/table_unmarshal.go | 2053 +++++++++ .../github.com/golang/protobuf/proto/text.go | 65 +- .../golang/protobuf/proto/text_parser.go | 83 +- .../protoc-gen-go/descriptor/Makefile | 36 - .../protoc-gen-go/descriptor/descriptor.pb.go | 1447 +++++-- .../protoc-gen-go/descriptor/descriptor.proto | 883 ++++ vendor/vendor.json | 12 +- 35 files changed, 13695 insertions(+), 9131 deletions(-) create mode 100644 accounts/usbwallet/trezor/messages-common.pb.go create mode 100644 accounts/usbwallet/trezor/messages-common.proto create mode 100644 accounts/usbwallet/trezor/messages-ethereum.pb.go create mode 100644 accounts/usbwallet/trezor/messages-ethereum.proto create mode 100644 accounts/usbwallet/trezor/messages-management.pb.go create mode 100644 accounts/usbwallet/trezor/messages-management.proto delete mode 100644 accounts/usbwallet/trezor/types.pb.go delete mode 100644 accounts/usbwallet/trezor/types.proto delete mode 100644 vendor/github.com/golang/protobuf/proto/Makefile create mode 100644 vendor/github.com/golang/protobuf/proto/deprecated.go create mode 100644 vendor/github.com/golang/protobuf/proto/discard.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_marshal.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_merge.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_unmarshal.go delete mode 100644 vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile create mode 100644 vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 9453b52c30..34079c8812 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -194,7 +194,13 @@ func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, er if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil { return common.Address{}, err } - return common.BytesToAddress(address.GetAddress()), nil + if addr := address.GetAddressBin(); len(addr) > 0 { // Older firmwares use binary fomats + return common.BytesToAddress(addr), nil + } + if addr := address.GetAddressHex(); len(addr) > 0 { // Newer firmwares use hexadecimal fomats + return common.HexToAddress(addr), nil + } + return common.Address{}, errors.New("missing derived address") } // trezorSign sends the transaction to the Trezor wallet, and waits for the user @@ -213,7 +219,10 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction DataLength: &length, } if to := tx.To(); to != nil { - request.To = (*to)[:] // Non contract deploy, set recipient explicitly + // Non contract deploy, set recipient explicitly + hex := to.Hex() + request.ToHex = &hex // Newer firmwares (old will ignore) + request.ToBin = (*to)[:] // Older firmwares (new will ignore) } if length > 1024 { // Send the data chunked if that was requested request.DataInitialChunk, data = data[:1024], data[1024:] diff --git a/accounts/usbwallet/trezor/messages-common.pb.go b/accounts/usbwallet/trezor/messages-common.pb.go new file mode 100644 index 0000000000..304bec0e36 --- /dev/null +++ b/accounts/usbwallet/trezor/messages-common.pb.go @@ -0,0 +1,811 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: messages-common.proto + +package trezor + +import ( + fmt "fmt" + math "math" + + proto "github.com/golang/protobuf/proto" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Failure_FailureType int32 + +const ( + Failure_Failure_UnexpectedMessage Failure_FailureType = 1 + Failure_Failure_ButtonExpected Failure_FailureType = 2 + Failure_Failure_DataError Failure_FailureType = 3 + Failure_Failure_ActionCancelled Failure_FailureType = 4 + Failure_Failure_PinExpected Failure_FailureType = 5 + Failure_Failure_PinCancelled Failure_FailureType = 6 + Failure_Failure_PinInvalid Failure_FailureType = 7 + Failure_Failure_InvalidSignature Failure_FailureType = 8 + Failure_Failure_ProcessError Failure_FailureType = 9 + Failure_Failure_NotEnoughFunds Failure_FailureType = 10 + Failure_Failure_NotInitialized Failure_FailureType = 11 + Failure_Failure_PinMismatch Failure_FailureType = 12 + Failure_Failure_FirmwareError Failure_FailureType = 99 +) + +var Failure_FailureType_name = map[int32]string{ + 1: "Failure_UnexpectedMessage", + 2: "Failure_ButtonExpected", + 3: "Failure_DataError", + 4: "Failure_ActionCancelled", + 5: "Failure_PinExpected", + 6: "Failure_PinCancelled", + 7: "Failure_PinInvalid", + 8: "Failure_InvalidSignature", + 9: "Failure_ProcessError", + 10: "Failure_NotEnoughFunds", + 11: "Failure_NotInitialized", + 12: "Failure_PinMismatch", + 99: "Failure_FirmwareError", +} + +var Failure_FailureType_value = map[string]int32{ + "Failure_UnexpectedMessage": 1, + "Failure_ButtonExpected": 2, + "Failure_DataError": 3, + "Failure_ActionCancelled": 4, + "Failure_PinExpected": 5, + "Failure_PinCancelled": 6, + "Failure_PinInvalid": 7, + "Failure_InvalidSignature": 8, + "Failure_ProcessError": 9, + "Failure_NotEnoughFunds": 10, + "Failure_NotInitialized": 11, + "Failure_PinMismatch": 12, + "Failure_FirmwareError": 99, +} + +func (x Failure_FailureType) Enum() *Failure_FailureType { + p := new(Failure_FailureType) + *p = x + return p +} + +func (x Failure_FailureType) String() string { + return proto.EnumName(Failure_FailureType_name, int32(x)) +} + +func (x *Failure_FailureType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Failure_FailureType_value, data, "Failure_FailureType") + if err != nil { + return err + } + *x = Failure_FailureType(value) + return nil +} + +func (Failure_FailureType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{1, 0} +} + +//* +// Type of button request +type ButtonRequest_ButtonRequestType int32 + +const ( + ButtonRequest_ButtonRequest_Other ButtonRequest_ButtonRequestType = 1 + ButtonRequest_ButtonRequest_FeeOverThreshold ButtonRequest_ButtonRequestType = 2 + ButtonRequest_ButtonRequest_ConfirmOutput ButtonRequest_ButtonRequestType = 3 + ButtonRequest_ButtonRequest_ResetDevice ButtonRequest_ButtonRequestType = 4 + ButtonRequest_ButtonRequest_ConfirmWord ButtonRequest_ButtonRequestType = 5 + ButtonRequest_ButtonRequest_WipeDevice ButtonRequest_ButtonRequestType = 6 + ButtonRequest_ButtonRequest_ProtectCall ButtonRequest_ButtonRequestType = 7 + ButtonRequest_ButtonRequest_SignTx ButtonRequest_ButtonRequestType = 8 + ButtonRequest_ButtonRequest_FirmwareCheck ButtonRequest_ButtonRequestType = 9 + ButtonRequest_ButtonRequest_Address ButtonRequest_ButtonRequestType = 10 + ButtonRequest_ButtonRequest_PublicKey ButtonRequest_ButtonRequestType = 11 + ButtonRequest_ButtonRequest_MnemonicWordCount ButtonRequest_ButtonRequestType = 12 + ButtonRequest_ButtonRequest_MnemonicInput ButtonRequest_ButtonRequestType = 13 + ButtonRequest_ButtonRequest_PassphraseType ButtonRequest_ButtonRequestType = 14 + ButtonRequest_ButtonRequest_UnknownDerivationPath ButtonRequest_ButtonRequestType = 15 +) + +var ButtonRequest_ButtonRequestType_name = map[int32]string{ + 1: "ButtonRequest_Other", + 2: "ButtonRequest_FeeOverThreshold", + 3: "ButtonRequest_ConfirmOutput", + 4: "ButtonRequest_ResetDevice", + 5: "ButtonRequest_ConfirmWord", + 6: "ButtonRequest_WipeDevice", + 7: "ButtonRequest_ProtectCall", + 8: "ButtonRequest_SignTx", + 9: "ButtonRequest_FirmwareCheck", + 10: "ButtonRequest_Address", + 11: "ButtonRequest_PublicKey", + 12: "ButtonRequest_MnemonicWordCount", + 13: "ButtonRequest_MnemonicInput", + 14: "ButtonRequest_PassphraseType", + 15: "ButtonRequest_UnknownDerivationPath", +} + +var ButtonRequest_ButtonRequestType_value = map[string]int32{ + "ButtonRequest_Other": 1, + "ButtonRequest_FeeOverThreshold": 2, + "ButtonRequest_ConfirmOutput": 3, + "ButtonRequest_ResetDevice": 4, + "ButtonRequest_ConfirmWord": 5, + "ButtonRequest_WipeDevice": 6, + "ButtonRequest_ProtectCall": 7, + "ButtonRequest_SignTx": 8, + "ButtonRequest_FirmwareCheck": 9, + "ButtonRequest_Address": 10, + "ButtonRequest_PublicKey": 11, + "ButtonRequest_MnemonicWordCount": 12, + "ButtonRequest_MnemonicInput": 13, + "ButtonRequest_PassphraseType": 14, + "ButtonRequest_UnknownDerivationPath": 15, +} + +func (x ButtonRequest_ButtonRequestType) Enum() *ButtonRequest_ButtonRequestType { + p := new(ButtonRequest_ButtonRequestType) + *p = x + return p +} + +func (x ButtonRequest_ButtonRequestType) String() string { + return proto.EnumName(ButtonRequest_ButtonRequestType_name, int32(x)) +} + +func (x *ButtonRequest_ButtonRequestType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(ButtonRequest_ButtonRequestType_value, data, "ButtonRequest_ButtonRequestType") + if err != nil { + return err + } + *x = ButtonRequest_ButtonRequestType(value) + return nil +} + +func (ButtonRequest_ButtonRequestType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{2, 0} +} + +//* +// Type of PIN request +type PinMatrixRequest_PinMatrixRequestType int32 + +const ( + PinMatrixRequest_PinMatrixRequestType_Current PinMatrixRequest_PinMatrixRequestType = 1 + PinMatrixRequest_PinMatrixRequestType_NewFirst PinMatrixRequest_PinMatrixRequestType = 2 + PinMatrixRequest_PinMatrixRequestType_NewSecond PinMatrixRequest_PinMatrixRequestType = 3 +) + +var PinMatrixRequest_PinMatrixRequestType_name = map[int32]string{ + 1: "PinMatrixRequestType_Current", + 2: "PinMatrixRequestType_NewFirst", + 3: "PinMatrixRequestType_NewSecond", +} + +var PinMatrixRequest_PinMatrixRequestType_value = map[string]int32{ + "PinMatrixRequestType_Current": 1, + "PinMatrixRequestType_NewFirst": 2, + "PinMatrixRequestType_NewSecond": 3, +} + +func (x PinMatrixRequest_PinMatrixRequestType) Enum() *PinMatrixRequest_PinMatrixRequestType { + p := new(PinMatrixRequest_PinMatrixRequestType) + *p = x + return p +} + +func (x PinMatrixRequest_PinMatrixRequestType) String() string { + return proto.EnumName(PinMatrixRequest_PinMatrixRequestType_name, int32(x)) +} + +func (x *PinMatrixRequest_PinMatrixRequestType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(PinMatrixRequest_PinMatrixRequestType_value, data, "PinMatrixRequest_PinMatrixRequestType") + if err != nil { + return err + } + *x = PinMatrixRequest_PinMatrixRequestType(value) + return nil +} + +func (PinMatrixRequest_PinMatrixRequestType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{4, 0} +} + +//* +// Response: Success of the previous request +// @end +type Success struct { + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Success) Reset() { *m = Success{} } +func (m *Success) String() string { return proto.CompactTextString(m) } +func (*Success) ProtoMessage() {} +func (*Success) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{0} +} + +func (m *Success) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Success.Unmarshal(m, b) +} +func (m *Success) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Success.Marshal(b, m, deterministic) +} +func (m *Success) XXX_Merge(src proto.Message) { + xxx_messageInfo_Success.Merge(m, src) +} +func (m *Success) XXX_Size() int { + return xxx_messageInfo_Success.Size(m) +} +func (m *Success) XXX_DiscardUnknown() { + xxx_messageInfo_Success.DiscardUnknown(m) +} + +var xxx_messageInfo_Success proto.InternalMessageInfo + +func (m *Success) GetMessage() string { + if m != nil && m.Message != nil { + return *m.Message + } + return "" +} + +//* +// Response: Failure of the previous request +// @end +type Failure struct { + Code *Failure_FailureType `protobuf:"varint,1,opt,name=code,enum=hw.trezor.messages.common.Failure_FailureType" json:"code,omitempty"` + Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Failure) Reset() { *m = Failure{} } +func (m *Failure) String() string { return proto.CompactTextString(m) } +func (*Failure) ProtoMessage() {} +func (*Failure) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{1} +} + +func (m *Failure) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Failure.Unmarshal(m, b) +} +func (m *Failure) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Failure.Marshal(b, m, deterministic) +} +func (m *Failure) XXX_Merge(src proto.Message) { + xxx_messageInfo_Failure.Merge(m, src) +} +func (m *Failure) XXX_Size() int { + return xxx_messageInfo_Failure.Size(m) +} +func (m *Failure) XXX_DiscardUnknown() { + xxx_messageInfo_Failure.DiscardUnknown(m) +} + +var xxx_messageInfo_Failure proto.InternalMessageInfo + +func (m *Failure) GetCode() Failure_FailureType { + if m != nil && m.Code != nil { + return *m.Code + } + return Failure_Failure_UnexpectedMessage +} + +func (m *Failure) GetMessage() string { + if m != nil && m.Message != nil { + return *m.Message + } + return "" +} + +//* +// Response: Device is waiting for HW button press. +// @auxstart +// @next ButtonAck +type ButtonRequest struct { + Code *ButtonRequest_ButtonRequestType `protobuf:"varint,1,opt,name=code,enum=hw.trezor.messages.common.ButtonRequest_ButtonRequestType" json:"code,omitempty"` + Data *string `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ButtonRequest) Reset() { *m = ButtonRequest{} } +func (m *ButtonRequest) String() string { return proto.CompactTextString(m) } +func (*ButtonRequest) ProtoMessage() {} +func (*ButtonRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{2} +} + +func (m *ButtonRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ButtonRequest.Unmarshal(m, b) +} +func (m *ButtonRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ButtonRequest.Marshal(b, m, deterministic) +} +func (m *ButtonRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ButtonRequest.Merge(m, src) +} +func (m *ButtonRequest) XXX_Size() int { + return xxx_messageInfo_ButtonRequest.Size(m) +} +func (m *ButtonRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ButtonRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ButtonRequest proto.InternalMessageInfo + +func (m *ButtonRequest) GetCode() ButtonRequest_ButtonRequestType { + if m != nil && m.Code != nil { + return *m.Code + } + return ButtonRequest_ButtonRequest_Other +} + +func (m *ButtonRequest) GetData() string { + if m != nil && m.Data != nil { + return *m.Data + } + return "" +} + +//* +// Request: Computer agrees to wait for HW button press +// @auxend +type ButtonAck struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ButtonAck) Reset() { *m = ButtonAck{} } +func (m *ButtonAck) String() string { return proto.CompactTextString(m) } +func (*ButtonAck) ProtoMessage() {} +func (*ButtonAck) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{3} +} + +func (m *ButtonAck) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ButtonAck.Unmarshal(m, b) +} +func (m *ButtonAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ButtonAck.Marshal(b, m, deterministic) +} +func (m *ButtonAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_ButtonAck.Merge(m, src) +} +func (m *ButtonAck) XXX_Size() int { + return xxx_messageInfo_ButtonAck.Size(m) +} +func (m *ButtonAck) XXX_DiscardUnknown() { + xxx_messageInfo_ButtonAck.DiscardUnknown(m) +} + +var xxx_messageInfo_ButtonAck proto.InternalMessageInfo + +//* +// Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme +// @auxstart +// @next PinMatrixAck +type PinMatrixRequest struct { + Type *PinMatrixRequest_PinMatrixRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.common.PinMatrixRequest_PinMatrixRequestType" json:"type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PinMatrixRequest) Reset() { *m = PinMatrixRequest{} } +func (m *PinMatrixRequest) String() string { return proto.CompactTextString(m) } +func (*PinMatrixRequest) ProtoMessage() {} +func (*PinMatrixRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{4} +} + +func (m *PinMatrixRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PinMatrixRequest.Unmarshal(m, b) +} +func (m *PinMatrixRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PinMatrixRequest.Marshal(b, m, deterministic) +} +func (m *PinMatrixRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PinMatrixRequest.Merge(m, src) +} +func (m *PinMatrixRequest) XXX_Size() int { + return xxx_messageInfo_PinMatrixRequest.Size(m) +} +func (m *PinMatrixRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PinMatrixRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_PinMatrixRequest proto.InternalMessageInfo + +func (m *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { + if m != nil && m.Type != nil { + return *m.Type + } + return PinMatrixRequest_PinMatrixRequestType_Current +} + +//* +// Request: Computer responds with encoded PIN +// @auxend +type PinMatrixAck struct { + Pin *string `protobuf:"bytes,1,req,name=pin" json:"pin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PinMatrixAck) Reset() { *m = PinMatrixAck{} } +func (m *PinMatrixAck) String() string { return proto.CompactTextString(m) } +func (*PinMatrixAck) ProtoMessage() {} +func (*PinMatrixAck) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{5} +} + +func (m *PinMatrixAck) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PinMatrixAck.Unmarshal(m, b) +} +func (m *PinMatrixAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PinMatrixAck.Marshal(b, m, deterministic) +} +func (m *PinMatrixAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_PinMatrixAck.Merge(m, src) +} +func (m *PinMatrixAck) XXX_Size() int { + return xxx_messageInfo_PinMatrixAck.Size(m) +} +func (m *PinMatrixAck) XXX_DiscardUnknown() { + xxx_messageInfo_PinMatrixAck.DiscardUnknown(m) +} + +var xxx_messageInfo_PinMatrixAck proto.InternalMessageInfo + +func (m *PinMatrixAck) GetPin() string { + if m != nil && m.Pin != nil { + return *m.Pin + } + return "" +} + +//* +// Response: Device awaits encryption passphrase +// @auxstart +// @next PassphraseAck +type PassphraseRequest struct { + OnDevice *bool `protobuf:"varint,1,opt,name=on_device,json=onDevice" json:"on_device,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PassphraseRequest) Reset() { *m = PassphraseRequest{} } +func (m *PassphraseRequest) String() string { return proto.CompactTextString(m) } +func (*PassphraseRequest) ProtoMessage() {} +func (*PassphraseRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{6} +} + +func (m *PassphraseRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PassphraseRequest.Unmarshal(m, b) +} +func (m *PassphraseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PassphraseRequest.Marshal(b, m, deterministic) +} +func (m *PassphraseRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PassphraseRequest.Merge(m, src) +} +func (m *PassphraseRequest) XXX_Size() int { + return xxx_messageInfo_PassphraseRequest.Size(m) +} +func (m *PassphraseRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PassphraseRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_PassphraseRequest proto.InternalMessageInfo + +func (m *PassphraseRequest) GetOnDevice() bool { + if m != nil && m.OnDevice != nil { + return *m.OnDevice + } + return false +} + +//* +// Request: Send passphrase back +// @next PassphraseStateRequest +type PassphraseAck struct { + Passphrase *string `protobuf:"bytes,1,opt,name=passphrase" json:"passphrase,omitempty"` + State []byte `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PassphraseAck) Reset() { *m = PassphraseAck{} } +func (m *PassphraseAck) String() string { return proto.CompactTextString(m) } +func (*PassphraseAck) ProtoMessage() {} +func (*PassphraseAck) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{7} +} + +func (m *PassphraseAck) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PassphraseAck.Unmarshal(m, b) +} +func (m *PassphraseAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PassphraseAck.Marshal(b, m, deterministic) +} +func (m *PassphraseAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_PassphraseAck.Merge(m, src) +} +func (m *PassphraseAck) XXX_Size() int { + return xxx_messageInfo_PassphraseAck.Size(m) +} +func (m *PassphraseAck) XXX_DiscardUnknown() { + xxx_messageInfo_PassphraseAck.DiscardUnknown(m) +} + +var xxx_messageInfo_PassphraseAck proto.InternalMessageInfo + +func (m *PassphraseAck) GetPassphrase() string { + if m != nil && m.Passphrase != nil { + return *m.Passphrase + } + return "" +} + +func (m *PassphraseAck) GetState() []byte { + if m != nil { + return m.State + } + return nil +} + +//* +// Response: Device awaits passphrase state +// @next PassphraseStateAck +type PassphraseStateRequest struct { + State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PassphraseStateRequest) Reset() { *m = PassphraseStateRequest{} } +func (m *PassphraseStateRequest) String() string { return proto.CompactTextString(m) } +func (*PassphraseStateRequest) ProtoMessage() {} +func (*PassphraseStateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{8} +} + +func (m *PassphraseStateRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PassphraseStateRequest.Unmarshal(m, b) +} +func (m *PassphraseStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PassphraseStateRequest.Marshal(b, m, deterministic) +} +func (m *PassphraseStateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PassphraseStateRequest.Merge(m, src) +} +func (m *PassphraseStateRequest) XXX_Size() int { + return xxx_messageInfo_PassphraseStateRequest.Size(m) +} +func (m *PassphraseStateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PassphraseStateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_PassphraseStateRequest proto.InternalMessageInfo + +func (m *PassphraseStateRequest) GetState() []byte { + if m != nil { + return m.State + } + return nil +} + +//* +// Request: Send passphrase state back +// @auxend +type PassphraseStateAck struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PassphraseStateAck) Reset() { *m = PassphraseStateAck{} } +func (m *PassphraseStateAck) String() string { return proto.CompactTextString(m) } +func (*PassphraseStateAck) ProtoMessage() {} +func (*PassphraseStateAck) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{9} +} + +func (m *PassphraseStateAck) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PassphraseStateAck.Unmarshal(m, b) +} +func (m *PassphraseStateAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PassphraseStateAck.Marshal(b, m, deterministic) +} +func (m *PassphraseStateAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_PassphraseStateAck.Merge(m, src) +} +func (m *PassphraseStateAck) XXX_Size() int { + return xxx_messageInfo_PassphraseStateAck.Size(m) +} +func (m *PassphraseStateAck) XXX_DiscardUnknown() { + xxx_messageInfo_PassphraseStateAck.DiscardUnknown(m) +} + +var xxx_messageInfo_PassphraseStateAck proto.InternalMessageInfo + +//* +// Structure representing BIP32 (hierarchical deterministic) node +// Used for imports of private key into the device and exporting public key out of device +// @embed +type HDNodeType struct { + Depth *uint32 `protobuf:"varint,1,req,name=depth" json:"depth,omitempty"` + Fingerprint *uint32 `protobuf:"varint,2,req,name=fingerprint" json:"fingerprint,omitempty"` + ChildNum *uint32 `protobuf:"varint,3,req,name=child_num,json=childNum" json:"child_num,omitempty"` + ChainCode []byte `protobuf:"bytes,4,req,name=chain_code,json=chainCode" json:"chain_code,omitempty"` + PrivateKey []byte `protobuf:"bytes,5,opt,name=private_key,json=privateKey" json:"private_key,omitempty"` + PublicKey []byte `protobuf:"bytes,6,opt,name=public_key,json=publicKey" json:"public_key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HDNodeType) Reset() { *m = HDNodeType{} } +func (m *HDNodeType) String() string { return proto.CompactTextString(m) } +func (*HDNodeType) ProtoMessage() {} +func (*HDNodeType) Descriptor() ([]byte, []int) { + return fileDescriptor_aaf30d059fdbc38d, []int{10} +} + +func (m *HDNodeType) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HDNodeType.Unmarshal(m, b) +} +func (m *HDNodeType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HDNodeType.Marshal(b, m, deterministic) +} +func (m *HDNodeType) XXX_Merge(src proto.Message) { + xxx_messageInfo_HDNodeType.Merge(m, src) +} +func (m *HDNodeType) XXX_Size() int { + return xxx_messageInfo_HDNodeType.Size(m) +} +func (m *HDNodeType) XXX_DiscardUnknown() { + xxx_messageInfo_HDNodeType.DiscardUnknown(m) +} + +var xxx_messageInfo_HDNodeType proto.InternalMessageInfo + +func (m *HDNodeType) GetDepth() uint32 { + if m != nil && m.Depth != nil { + return *m.Depth + } + return 0 +} + +func (m *HDNodeType) GetFingerprint() uint32 { + if m != nil && m.Fingerprint != nil { + return *m.Fingerprint + } + return 0 +} + +func (m *HDNodeType) GetChildNum() uint32 { + if m != nil && m.ChildNum != nil { + return *m.ChildNum + } + return 0 +} + +func (m *HDNodeType) GetChainCode() []byte { + if m != nil { + return m.ChainCode + } + return nil +} + +func (m *HDNodeType) GetPrivateKey() []byte { + if m != nil { + return m.PrivateKey + } + return nil +} + +func (m *HDNodeType) GetPublicKey() []byte { + if m != nil { + return m.PublicKey + } + return nil +} + +func init() { + proto.RegisterEnum("hw.trezor.messages.common.Failure_FailureType", Failure_FailureType_name, Failure_FailureType_value) + proto.RegisterEnum("hw.trezor.messages.common.ButtonRequest_ButtonRequestType", ButtonRequest_ButtonRequestType_name, ButtonRequest_ButtonRequestType_value) + proto.RegisterEnum("hw.trezor.messages.common.PinMatrixRequest_PinMatrixRequestType", PinMatrixRequest_PinMatrixRequestType_name, PinMatrixRequest_PinMatrixRequestType_value) + proto.RegisterType((*Success)(nil), "hw.trezor.messages.common.Success") + proto.RegisterType((*Failure)(nil), "hw.trezor.messages.common.Failure") + proto.RegisterType((*ButtonRequest)(nil), "hw.trezor.messages.common.ButtonRequest") + proto.RegisterType((*ButtonAck)(nil), "hw.trezor.messages.common.ButtonAck") + proto.RegisterType((*PinMatrixRequest)(nil), "hw.trezor.messages.common.PinMatrixRequest") + proto.RegisterType((*PinMatrixAck)(nil), "hw.trezor.messages.common.PinMatrixAck") + proto.RegisterType((*PassphraseRequest)(nil), "hw.trezor.messages.common.PassphraseRequest") + proto.RegisterType((*PassphraseAck)(nil), "hw.trezor.messages.common.PassphraseAck") + proto.RegisterType((*PassphraseStateRequest)(nil), "hw.trezor.messages.common.PassphraseStateRequest") + proto.RegisterType((*PassphraseStateAck)(nil), "hw.trezor.messages.common.PassphraseStateAck") + proto.RegisterType((*HDNodeType)(nil), "hw.trezor.messages.common.HDNodeType") +} + +func init() { proto.RegisterFile("messages-common.proto", fileDescriptor_aaf30d059fdbc38d) } + +var fileDescriptor_aaf30d059fdbc38d = []byte{ + // 846 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xcd, 0x52, 0x23, 0x37, + 0x10, 0x2e, 0xff, 0x80, 0xed, 0xb6, 0xd9, 0x08, 0xc5, 0x80, 0x09, 0xb0, 0x38, 0xc3, 0x21, 0x5c, + 0xe2, 0x4a, 0xe5, 0x98, 0x53, 0x58, 0x83, 0x2b, 0xd4, 0x16, 0x86, 0x1a, 0xd8, 0xda, 0xa3, 0x4b, + 0xd1, 0xf4, 0x32, 0x2a, 0xcf, 0x48, 0x13, 0x8d, 0x06, 0xf0, 0x5e, 0xf2, 0x6a, 0x79, 0x89, 0xbc, + 0x42, 0xaa, 0x52, 0xb9, 0xe4, 0x11, 0xb6, 0x34, 0x3f, 0x78, 0xc6, 0x66, 0x39, 0xcd, 0xe8, 0xfb, + 0xbe, 0xee, 0x96, 0xba, 0x3f, 0x09, 0x76, 0x42, 0x8c, 0x63, 0x76, 0x8f, 0xf1, 0x8f, 0x5c, 0x85, + 0xa1, 0x92, 0xa3, 0x48, 0x2b, 0xa3, 0xe8, 0xbe, 0xff, 0x38, 0x32, 0x1a, 0x3f, 0x2b, 0x3d, 0x2a, + 0x04, 0xa3, 0x4c, 0xe0, 0x9c, 0x40, 0xeb, 0x36, 0xe1, 0x1c, 0xe3, 0x98, 0x0e, 0xa0, 0x95, 0xb3, + 0x83, 0xda, 0xb0, 0x76, 0xda, 0x71, 0x8b, 0xa5, 0xf3, 0x77, 0x03, 0x5a, 0x13, 0x26, 0x82, 0x44, + 0x23, 0x7d, 0x07, 0x4d, 0xae, 0xbc, 0x4c, 0xf2, 0xe6, 0xe7, 0xd1, 0xe8, 0xab, 0xa9, 0x47, 0x79, + 0x44, 0xf1, 0xbd, 0x5b, 0x44, 0xe8, 0xa6, 0xb1, 0xe5, 0x4a, 0xf5, 0x6a, 0xa5, 0xff, 0xea, 0xd0, + 0x2d, 0xe9, 0xe9, 0x11, 0xec, 0xe7, 0xcb, 0xd9, 0x07, 0x89, 0x4f, 0x11, 0x72, 0x83, 0xde, 0x55, + 0x26, 0x26, 0x35, 0xfa, 0x1d, 0xec, 0x16, 0xf4, 0xbb, 0xc4, 0x18, 0x25, 0x2f, 0x72, 0x09, 0xa9, + 0xd3, 0x1d, 0xd8, 0x2e, 0xb8, 0x73, 0x66, 0xd8, 0x85, 0xd6, 0x4a, 0x93, 0x06, 0x3d, 0x80, 0xbd, + 0x02, 0x3e, 0xe3, 0x46, 0x28, 0x39, 0x66, 0x92, 0x63, 0x10, 0xa0, 0x47, 0x9a, 0x74, 0x0f, 0xbe, + 0x2d, 0xc8, 0x1b, 0xb1, 0x4c, 0xb6, 0x41, 0x07, 0xd0, 0x2f, 0x11, 0xcb, 0x90, 0x4d, 0xba, 0x0b, + 0xb4, 0xc4, 0x5c, 0xca, 0x07, 0x16, 0x08, 0x8f, 0xb4, 0xe8, 0x21, 0x0c, 0x0a, 0x3c, 0x07, 0x6f, + 0xc5, 0xbd, 0x64, 0x26, 0xd1, 0x48, 0xda, 0x95, 0x7c, 0x5a, 0xd9, 0xf6, 0x67, 0xfb, 0xeb, 0x94, + 0x8f, 0x34, 0x55, 0xe6, 0x42, 0xaa, 0xe4, 0xde, 0x9f, 0x24, 0xd2, 0x8b, 0x09, 0xac, 0x70, 0x97, + 0x52, 0x18, 0xc1, 0x02, 0xf1, 0x19, 0x3d, 0xd2, 0x5d, 0xd9, 0xfa, 0x95, 0x88, 0x43, 0x66, 0xb8, + 0x4f, 0x7a, 0x74, 0x1f, 0x76, 0x0a, 0x62, 0x22, 0x74, 0xf8, 0xc8, 0x34, 0x66, 0xb5, 0xb8, 0xf3, + 0x4f, 0x13, 0xb6, 0xb2, 0xbe, 0xb9, 0xf8, 0x47, 0x82, 0xb1, 0xa1, 0xd3, 0xca, 0x74, 0x7f, 0x79, + 0x65, 0xba, 0x95, 0xb8, 0xea, 0xaa, 0x34, 0x69, 0x0a, 0x4d, 0x8f, 0x19, 0x96, 0x8f, 0x39, 0xfd, + 0x77, 0xfe, 0x6f, 0xc0, 0xf6, 0x9a, 0xde, 0xee, 0xbf, 0x02, 0xce, 0xae, 0x8d, 0x8f, 0x9a, 0xd4, + 0xa8, 0x03, 0x6f, 0xab, 0xc4, 0x04, 0xf1, 0xfa, 0x01, 0xf5, 0x9d, 0xaf, 0x31, 0xf6, 0x55, 0x60, + 0x67, 0x7d, 0x0c, 0x07, 0x55, 0xcd, 0x58, 0xc9, 0x4f, 0x42, 0x87, 0xd7, 0x89, 0x89, 0x12, 0x43, + 0x1a, 0xd6, 0x47, 0x55, 0x81, 0x8b, 0x31, 0x9a, 0x73, 0x7c, 0x10, 0x1c, 0x49, 0x73, 0x9d, 0xce, + 0xe3, 0x3f, 0x2a, 0x6d, 0xa7, 0x7f, 0x08, 0x83, 0x2a, 0xfd, 0x51, 0x44, 0x98, 0x07, 0x6f, 0xae, + 0x07, 0xdf, 0x68, 0x65, 0x90, 0x9b, 0x31, 0x0b, 0x02, 0xd2, 0xb2, 0xa3, 0xae, 0xd2, 0xd6, 0x07, + 0x77, 0x4f, 0xa4, 0xbd, 0xbe, 0xeb, 0x62, 0x3e, 0x63, 0x1f, 0xf9, 0x9c, 0x74, 0xec, 0xe8, 0xaa, + 0x82, 0x33, 0xcf, 0xd3, 0x18, 0x5b, 0x2b, 0x1c, 0xc0, 0xde, 0x4a, 0xd1, 0xe4, 0xf7, 0x40, 0xf0, + 0xf7, 0xb8, 0x20, 0x5d, 0x7a, 0x02, 0xc7, 0x55, 0xf2, 0x4a, 0x62, 0xa8, 0xa4, 0xe0, 0xf6, 0x3c, + 0x63, 0x95, 0x48, 0x43, 0x7a, 0xeb, 0xd5, 0x0b, 0xd1, 0xa5, 0xb4, 0x3d, 0xdb, 0xa2, 0x43, 0x38, + 0x5c, 0x29, 0xc1, 0xe2, 0x38, 0xf2, 0x35, 0x8b, 0xd3, 0xbb, 0x49, 0xde, 0xd0, 0x1f, 0xe0, 0xa4, + 0xaa, 0xf8, 0x20, 0xe7, 0x52, 0x3d, 0xca, 0x73, 0xd4, 0xe2, 0x81, 0xd9, 0xcb, 0x75, 0xc3, 0x8c, + 0x4f, 0xbe, 0x71, 0xba, 0xd0, 0xc9, 0x84, 0x67, 0x7c, 0xee, 0xfc, 0x5b, 0x03, 0x62, 0x2d, 0xca, + 0x8c, 0x16, 0x4f, 0x85, 0xf1, 0xee, 0xa0, 0x69, 0x16, 0x51, 0x61, 0xbc, 0x5f, 0x5f, 0x31, 0xde, + 0x6a, 0xe8, 0x1a, 0x90, 0xd9, 0xcf, 0x66, 0x73, 0xfe, 0x84, 0xfe, 0x4b, 0xac, 0x3d, 0xda, 0x4b, + 0xf8, 0x6c, 0x9c, 0x68, 0x8d, 0xd2, 0x90, 0x1a, 0xfd, 0x1e, 0x8e, 0x5e, 0x54, 0x4c, 0xf1, 0x71, + 0x22, 0x74, 0x6c, 0x48, 0xdd, 0x1a, 0xf3, 0x6b, 0x92, 0x5b, 0xe4, 0x4a, 0x7a, 0xa4, 0xe1, 0x0c, + 0xa1, 0xf7, 0xac, 0x39, 0xe3, 0x73, 0x4a, 0xa0, 0x11, 0x09, 0x39, 0xa8, 0x0d, 0xeb, 0xa7, 0x1d, + 0xd7, 0xfe, 0x3a, 0x3f, 0xc1, 0xf6, 0xb2, 0xaf, 0x45, 0x37, 0x0e, 0xa0, 0xa3, 0xe4, 0xcc, 0x4b, + 0x1d, 0x96, 0xb6, 0xa4, 0xed, 0xb6, 0x95, 0xcc, 0x1c, 0xe7, 0x5c, 0xc0, 0xd6, 0x32, 0xc2, 0x26, + 0x7d, 0x0b, 0x10, 0x3d, 0x03, 0xf9, 0xdb, 0x5d, 0x42, 0x68, 0x1f, 0x36, 0x62, 0xc3, 0x4c, 0xf6, + 0xd8, 0xf6, 0xdc, 0x6c, 0xe1, 0x8c, 0x60, 0x77, 0x99, 0xe6, 0xd6, 0x42, 0x45, 0xf5, 0x67, 0x7d, + 0xad, 0xac, 0xef, 0x03, 0x5d, 0xd1, 0xdb, 0x61, 0xfe, 0x55, 0x03, 0xf8, 0xed, 0x7c, 0xaa, 0xbc, + 0xec, 0xbd, 0xee, 0xc3, 0x86, 0x87, 0x91, 0xf1, 0xd3, 0x13, 0x6e, 0xb9, 0xd9, 0x82, 0x0e, 0xa1, + 0xfb, 0x49, 0xc8, 0x7b, 0xd4, 0x91, 0x16, 0xd2, 0x0c, 0xea, 0x29, 0x57, 0x86, 0xec, 0x81, 0xb9, + 0x2f, 0x02, 0x6f, 0x26, 0x93, 0x70, 0xd0, 0x48, 0xf9, 0x76, 0x0a, 0x4c, 0x93, 0x90, 0x1e, 0x01, + 0x70, 0x9f, 0x09, 0x39, 0x4b, 0x9f, 0xa6, 0xe6, 0xb0, 0x7e, 0xda, 0x73, 0x3b, 0x29, 0x32, 0xb6, + 0x6f, 0xcc, 0x31, 0x74, 0xa3, 0xd4, 0x6f, 0x38, 0x9b, 0xe3, 0x62, 0xb0, 0x91, 0x6e, 0x1a, 0x72, + 0xe8, 0x3d, 0x2e, 0x6c, 0x7c, 0x94, 0xde, 0x8e, 0x94, 0xdf, 0x4c, 0xf9, 0x4e, 0x54, 0xdc, 0x97, + 0x2f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb2, 0x7d, 0x20, 0xa6, 0x35, 0x07, 0x00, 0x00, +} diff --git a/accounts/usbwallet/trezor/messages-common.proto b/accounts/usbwallet/trezor/messages-common.proto new file mode 100644 index 0000000000..75a983b0a3 --- /dev/null +++ b/accounts/usbwallet/trezor/messages-common.proto @@ -0,0 +1,147 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages-common.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + +syntax = "proto2"; +package hw.trezor.messages.common; + +/** + * Response: Success of the previous request + * @end + */ +message Success { + optional string message = 1; // human readable description of action or request-specific payload +} + +/** + * Response: Failure of the previous request + * @end + */ +message Failure { + optional FailureType code = 1; // computer-readable definition of the error state + optional string message = 2; // human-readable message of the error state + enum FailureType { + Failure_UnexpectedMessage = 1; + Failure_ButtonExpected = 2; + Failure_DataError = 3; + Failure_ActionCancelled = 4; + Failure_PinExpected = 5; + Failure_PinCancelled = 6; + Failure_PinInvalid = 7; + Failure_InvalidSignature = 8; + Failure_ProcessError = 9; + Failure_NotEnoughFunds = 10; + Failure_NotInitialized = 11; + Failure_PinMismatch = 12; + Failure_FirmwareError = 99; + } +} + +/** + * Response: Device is waiting for HW button press. + * @auxstart + * @next ButtonAck + */ +message ButtonRequest { + optional ButtonRequestType code = 1; + optional string data = 2; + /** + * Type of button request + */ + enum ButtonRequestType { + ButtonRequest_Other = 1; + ButtonRequest_FeeOverThreshold = 2; + ButtonRequest_ConfirmOutput = 3; + ButtonRequest_ResetDevice = 4; + ButtonRequest_ConfirmWord = 5; + ButtonRequest_WipeDevice = 6; + ButtonRequest_ProtectCall = 7; + ButtonRequest_SignTx = 8; + ButtonRequest_FirmwareCheck = 9; + ButtonRequest_Address = 10; + ButtonRequest_PublicKey = 11; + ButtonRequest_MnemonicWordCount = 12; + ButtonRequest_MnemonicInput = 13; + ButtonRequest_PassphraseType = 14; + ButtonRequest_UnknownDerivationPath = 15; + } +} + +/** + * Request: Computer agrees to wait for HW button press + * @auxend + */ +message ButtonAck { +} + +/** + * Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme + * @auxstart + * @next PinMatrixAck + */ +message PinMatrixRequest { + optional PinMatrixRequestType type = 1; + /** + * Type of PIN request + */ + enum PinMatrixRequestType { + PinMatrixRequestType_Current = 1; + PinMatrixRequestType_NewFirst = 2; + PinMatrixRequestType_NewSecond = 3; + } +} + +/** + * Request: Computer responds with encoded PIN + * @auxend + */ +message PinMatrixAck { + required string pin = 1; // matrix encoded PIN entered by user +} + +/** + * Response: Device awaits encryption passphrase + * @auxstart + * @next PassphraseAck + */ +message PassphraseRequest { + optional bool on_device = 1; // passphrase is being entered on the device +} + +/** + * Request: Send passphrase back + * @next PassphraseStateRequest + */ +message PassphraseAck { + optional string passphrase = 1; + optional bytes state = 2; // expected device state +} + +/** + * Response: Device awaits passphrase state + * @next PassphraseStateAck + */ +message PassphraseStateRequest { + optional bytes state = 1; // actual device state +} + +/** + * Request: Send passphrase state back + * @auxend + */ +message PassphraseStateAck { +} + +/** + * Structure representing BIP32 (hierarchical deterministic) node + * Used for imports of private key into the device and exporting public key out of device + * @embed + */ +message HDNodeType { + required uint32 depth = 1; + required uint32 fingerprint = 2; + required uint32 child_num = 3; + required bytes chain_code = 4; + optional bytes private_key = 5; + optional bytes public_key = 6; +} diff --git a/accounts/usbwallet/trezor/messages-ethereum.pb.go b/accounts/usbwallet/trezor/messages-ethereum.pb.go new file mode 100644 index 0000000000..5d664f5ba4 --- /dev/null +++ b/accounts/usbwallet/trezor/messages-ethereum.pb.go @@ -0,0 +1,698 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: messages-ethereum.proto + +package trezor + +import ( + fmt "fmt" + math "math" + + proto "github.com/golang/protobuf/proto" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +//* +// Request: Ask device for public key corresponding to address_n path +// @start +// @next EthereumPublicKey +// @next Failure +type EthereumGetPublicKey struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumGetPublicKey) Reset() { *m = EthereumGetPublicKey{} } +func (m *EthereumGetPublicKey) String() string { return proto.CompactTextString(m) } +func (*EthereumGetPublicKey) ProtoMessage() {} +func (*EthereumGetPublicKey) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{0} +} + +func (m *EthereumGetPublicKey) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumGetPublicKey.Unmarshal(m, b) +} +func (m *EthereumGetPublicKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumGetPublicKey.Marshal(b, m, deterministic) +} +func (m *EthereumGetPublicKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumGetPublicKey.Merge(m, src) +} +func (m *EthereumGetPublicKey) XXX_Size() int { + return xxx_messageInfo_EthereumGetPublicKey.Size(m) +} +func (m *EthereumGetPublicKey) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumGetPublicKey.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumGetPublicKey proto.InternalMessageInfo + +func (m *EthereumGetPublicKey) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EthereumGetPublicKey) GetShowDisplay() bool { + if m != nil && m.ShowDisplay != nil { + return *m.ShowDisplay + } + return false +} + +//* +// Response: Contains public key derived from device private seed +// @end +type EthereumPublicKey struct { + Node *HDNodeType `protobuf:"bytes,1,opt,name=node" json:"node,omitempty"` + Xpub *string `protobuf:"bytes,2,opt,name=xpub" json:"xpub,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumPublicKey) Reset() { *m = EthereumPublicKey{} } +func (m *EthereumPublicKey) String() string { return proto.CompactTextString(m) } +func (*EthereumPublicKey) ProtoMessage() {} +func (*EthereumPublicKey) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{1} +} + +func (m *EthereumPublicKey) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumPublicKey.Unmarshal(m, b) +} +func (m *EthereumPublicKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumPublicKey.Marshal(b, m, deterministic) +} +func (m *EthereumPublicKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumPublicKey.Merge(m, src) +} +func (m *EthereumPublicKey) XXX_Size() int { + return xxx_messageInfo_EthereumPublicKey.Size(m) +} +func (m *EthereumPublicKey) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumPublicKey.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumPublicKey proto.InternalMessageInfo + +func (m *EthereumPublicKey) GetNode() *HDNodeType { + if m != nil { + return m.Node + } + return nil +} + +func (m *EthereumPublicKey) GetXpub() string { + if m != nil && m.Xpub != nil { + return *m.Xpub + } + return "" +} + +//* +// Request: Ask device for Ethereum address corresponding to address_n path +// @start +// @next EthereumAddress +// @next Failure +type EthereumGetAddress struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumGetAddress) Reset() { *m = EthereumGetAddress{} } +func (m *EthereumGetAddress) String() string { return proto.CompactTextString(m) } +func (*EthereumGetAddress) ProtoMessage() {} +func (*EthereumGetAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{2} +} + +func (m *EthereumGetAddress) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumGetAddress.Unmarshal(m, b) +} +func (m *EthereumGetAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumGetAddress.Marshal(b, m, deterministic) +} +func (m *EthereumGetAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumGetAddress.Merge(m, src) +} +func (m *EthereumGetAddress) XXX_Size() int { + return xxx_messageInfo_EthereumGetAddress.Size(m) +} +func (m *EthereumGetAddress) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumGetAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumGetAddress proto.InternalMessageInfo + +func (m *EthereumGetAddress) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EthereumGetAddress) GetShowDisplay() bool { + if m != nil && m.ShowDisplay != nil { + return *m.ShowDisplay + } + return false +} + +//* +// Response: Contains an Ethereum address derived from device private seed +// @end +type EthereumAddress struct { + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` + AddressHex *string `protobuf:"bytes,2,opt,name=addressHex" json:"addressHex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumAddress) Reset() { *m = EthereumAddress{} } +func (m *EthereumAddress) String() string { return proto.CompactTextString(m) } +func (*EthereumAddress) ProtoMessage() {} +func (*EthereumAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{3} +} + +func (m *EthereumAddress) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumAddress.Unmarshal(m, b) +} +func (m *EthereumAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumAddress.Marshal(b, m, deterministic) +} +func (m *EthereumAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumAddress.Merge(m, src) +} +func (m *EthereumAddress) XXX_Size() int { + return xxx_messageInfo_EthereumAddress.Size(m) +} +func (m *EthereumAddress) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumAddress proto.InternalMessageInfo + +func (m *EthereumAddress) GetAddressBin() []byte { + if m != nil { + return m.AddressBin + } + return nil +} + +func (m *EthereumAddress) GetAddressHex() string { + if m != nil && m.AddressHex != nil { + return *m.AddressHex + } + return "" +} + +//* +// Request: Ask device to sign transaction +// All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing. +// Note: the first at most 1024 bytes of data MUST be transmitted as part of this message. +// @start +// @next EthereumTxRequest +// @next Failure +type EthereumSignTx struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` + GasPrice []byte `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice" json:"gas_price,omitempty"` + GasLimit []byte `protobuf:"bytes,4,opt,name=gas_limit,json=gasLimit" json:"gas_limit,omitempty"` + ToBin []byte `protobuf:"bytes,5,opt,name=toBin" json:"toBin,omitempty"` + ToHex *string `protobuf:"bytes,11,opt,name=toHex" json:"toHex,omitempty"` + Value []byte `protobuf:"bytes,6,opt,name=value" json:"value,omitempty"` + DataInitialChunk []byte `protobuf:"bytes,7,opt,name=data_initial_chunk,json=dataInitialChunk" json:"data_initial_chunk,omitempty"` + DataLength *uint32 `protobuf:"varint,8,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` + ChainId *uint32 `protobuf:"varint,9,opt,name=chain_id,json=chainId" json:"chain_id,omitempty"` + TxType *uint32 `protobuf:"varint,10,opt,name=tx_type,json=txType" json:"tx_type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumSignTx) Reset() { *m = EthereumSignTx{} } +func (m *EthereumSignTx) String() string { return proto.CompactTextString(m) } +func (*EthereumSignTx) ProtoMessage() {} +func (*EthereumSignTx) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{4} +} + +func (m *EthereumSignTx) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumSignTx.Unmarshal(m, b) +} +func (m *EthereumSignTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumSignTx.Marshal(b, m, deterministic) +} +func (m *EthereumSignTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumSignTx.Merge(m, src) +} +func (m *EthereumSignTx) XXX_Size() int { + return xxx_messageInfo_EthereumSignTx.Size(m) +} +func (m *EthereumSignTx) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumSignTx.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumSignTx proto.InternalMessageInfo + +func (m *EthereumSignTx) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EthereumSignTx) GetNonce() []byte { + if m != nil { + return m.Nonce + } + return nil +} + +func (m *EthereumSignTx) GetGasPrice() []byte { + if m != nil { + return m.GasPrice + } + return nil +} + +func (m *EthereumSignTx) GetGasLimit() []byte { + if m != nil { + return m.GasLimit + } + return nil +} + +func (m *EthereumSignTx) GetToBin() []byte { + if m != nil { + return m.ToBin + } + return nil +} + +func (m *EthereumSignTx) GetToHex() string { + if m != nil && m.ToHex != nil { + return *m.ToHex + } + return "" +} + +func (m *EthereumSignTx) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func (m *EthereumSignTx) GetDataInitialChunk() []byte { + if m != nil { + return m.DataInitialChunk + } + return nil +} + +func (m *EthereumSignTx) GetDataLength() uint32 { + if m != nil && m.DataLength != nil { + return *m.DataLength + } + return 0 +} + +func (m *EthereumSignTx) GetChainId() uint32 { + if m != nil && m.ChainId != nil { + return *m.ChainId + } + return 0 +} + +func (m *EthereumSignTx) GetTxType() uint32 { + if m != nil && m.TxType != nil { + return *m.TxType + } + return 0 +} + +//* +// Response: Device asks for more data from transaction payload, or returns the signature. +// If data_length is set, device awaits that many more bytes of payload. +// Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present. +// @end +// @next EthereumTxAck +type EthereumTxRequest struct { + DataLength *uint32 `protobuf:"varint,1,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` + SignatureV *uint32 `protobuf:"varint,2,opt,name=signature_v,json=signatureV" json:"signature_v,omitempty"` + SignatureR []byte `protobuf:"bytes,3,opt,name=signature_r,json=signatureR" json:"signature_r,omitempty"` + SignatureS []byte `protobuf:"bytes,4,opt,name=signature_s,json=signatureS" json:"signature_s,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumTxRequest) Reset() { *m = EthereumTxRequest{} } +func (m *EthereumTxRequest) String() string { return proto.CompactTextString(m) } +func (*EthereumTxRequest) ProtoMessage() {} +func (*EthereumTxRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{5} +} + +func (m *EthereumTxRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumTxRequest.Unmarshal(m, b) +} +func (m *EthereumTxRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumTxRequest.Marshal(b, m, deterministic) +} +func (m *EthereumTxRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumTxRequest.Merge(m, src) +} +func (m *EthereumTxRequest) XXX_Size() int { + return xxx_messageInfo_EthereumTxRequest.Size(m) +} +func (m *EthereumTxRequest) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumTxRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumTxRequest proto.InternalMessageInfo + +func (m *EthereumTxRequest) GetDataLength() uint32 { + if m != nil && m.DataLength != nil { + return *m.DataLength + } + return 0 +} + +func (m *EthereumTxRequest) GetSignatureV() uint32 { + if m != nil && m.SignatureV != nil { + return *m.SignatureV + } + return 0 +} + +func (m *EthereumTxRequest) GetSignatureR() []byte { + if m != nil { + return m.SignatureR + } + return nil +} + +func (m *EthereumTxRequest) GetSignatureS() []byte { + if m != nil { + return m.SignatureS + } + return nil +} + +//* +// Request: Transaction payload data. +// @next EthereumTxRequest +type EthereumTxAck struct { + DataChunk []byte `protobuf:"bytes,1,opt,name=data_chunk,json=dataChunk" json:"data_chunk,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumTxAck) Reset() { *m = EthereumTxAck{} } +func (m *EthereumTxAck) String() string { return proto.CompactTextString(m) } +func (*EthereumTxAck) ProtoMessage() {} +func (*EthereumTxAck) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{6} +} + +func (m *EthereumTxAck) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumTxAck.Unmarshal(m, b) +} +func (m *EthereumTxAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumTxAck.Marshal(b, m, deterministic) +} +func (m *EthereumTxAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumTxAck.Merge(m, src) +} +func (m *EthereumTxAck) XXX_Size() int { + return xxx_messageInfo_EthereumTxAck.Size(m) +} +func (m *EthereumTxAck) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumTxAck.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumTxAck proto.InternalMessageInfo + +func (m *EthereumTxAck) GetDataChunk() []byte { + if m != nil { + return m.DataChunk + } + return nil +} + +//* +// Request: Ask device to sign message +// @start +// @next EthereumMessageSignature +// @next Failure +type EthereumSignMessage struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumSignMessage) Reset() { *m = EthereumSignMessage{} } +func (m *EthereumSignMessage) String() string { return proto.CompactTextString(m) } +func (*EthereumSignMessage) ProtoMessage() {} +func (*EthereumSignMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{7} +} + +func (m *EthereumSignMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumSignMessage.Unmarshal(m, b) +} +func (m *EthereumSignMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumSignMessage.Marshal(b, m, deterministic) +} +func (m *EthereumSignMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumSignMessage.Merge(m, src) +} +func (m *EthereumSignMessage) XXX_Size() int { + return xxx_messageInfo_EthereumSignMessage.Size(m) +} +func (m *EthereumSignMessage) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumSignMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumSignMessage proto.InternalMessageInfo + +func (m *EthereumSignMessage) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EthereumSignMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +//* +// Response: Signed message +// @end +type EthereumMessageSignature struct { + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + AddressHex *string `protobuf:"bytes,3,opt,name=addressHex" json:"addressHex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumMessageSignature) Reset() { *m = EthereumMessageSignature{} } +func (m *EthereumMessageSignature) String() string { return proto.CompactTextString(m) } +func (*EthereumMessageSignature) ProtoMessage() {} +func (*EthereumMessageSignature) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{8} +} + +func (m *EthereumMessageSignature) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumMessageSignature.Unmarshal(m, b) +} +func (m *EthereumMessageSignature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumMessageSignature.Marshal(b, m, deterministic) +} +func (m *EthereumMessageSignature) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumMessageSignature.Merge(m, src) +} +func (m *EthereumMessageSignature) XXX_Size() int { + return xxx_messageInfo_EthereumMessageSignature.Size(m) +} +func (m *EthereumMessageSignature) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumMessageSignature.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumMessageSignature proto.InternalMessageInfo + +func (m *EthereumMessageSignature) GetAddressBin() []byte { + if m != nil { + return m.AddressBin + } + return nil +} + +func (m *EthereumMessageSignature) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func (m *EthereumMessageSignature) GetAddressHex() string { + if m != nil && m.AddressHex != nil { + return *m.AddressHex + } + return "" +} + +//* +// Request: Ask device to verify message +// @start +// @next Success +// @next Failure +type EthereumVerifyMessage struct { + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` + AddressHex *string `protobuf:"bytes,4,opt,name=addressHex" json:"addressHex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumVerifyMessage) Reset() { *m = EthereumVerifyMessage{} } +func (m *EthereumVerifyMessage) String() string { return proto.CompactTextString(m) } +func (*EthereumVerifyMessage) ProtoMessage() {} +func (*EthereumVerifyMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_cb33f46ba915f15c, []int{9} +} + +func (m *EthereumVerifyMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumVerifyMessage.Unmarshal(m, b) +} +func (m *EthereumVerifyMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumVerifyMessage.Marshal(b, m, deterministic) +} +func (m *EthereumVerifyMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumVerifyMessage.Merge(m, src) +} +func (m *EthereumVerifyMessage) XXX_Size() int { + return xxx_messageInfo_EthereumVerifyMessage.Size(m) +} +func (m *EthereumVerifyMessage) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumVerifyMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumVerifyMessage proto.InternalMessageInfo + +func (m *EthereumVerifyMessage) GetAddressBin() []byte { + if m != nil { + return m.AddressBin + } + return nil +} + +func (m *EthereumVerifyMessage) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func (m *EthereumVerifyMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *EthereumVerifyMessage) GetAddressHex() string { + if m != nil && m.AddressHex != nil { + return *m.AddressHex + } + return "" +} + +func init() { + proto.RegisterType((*EthereumGetPublicKey)(nil), "hw.trezor.messages.ethereum.EthereumGetPublicKey") + proto.RegisterType((*EthereumPublicKey)(nil), "hw.trezor.messages.ethereum.EthereumPublicKey") + proto.RegisterType((*EthereumGetAddress)(nil), "hw.trezor.messages.ethereum.EthereumGetAddress") + proto.RegisterType((*EthereumAddress)(nil), "hw.trezor.messages.ethereum.EthereumAddress") + proto.RegisterType((*EthereumSignTx)(nil), "hw.trezor.messages.ethereum.EthereumSignTx") + proto.RegisterType((*EthereumTxRequest)(nil), "hw.trezor.messages.ethereum.EthereumTxRequest") + proto.RegisterType((*EthereumTxAck)(nil), "hw.trezor.messages.ethereum.EthereumTxAck") + proto.RegisterType((*EthereumSignMessage)(nil), "hw.trezor.messages.ethereum.EthereumSignMessage") + proto.RegisterType((*EthereumMessageSignature)(nil), "hw.trezor.messages.ethereum.EthereumMessageSignature") + proto.RegisterType((*EthereumVerifyMessage)(nil), "hw.trezor.messages.ethereum.EthereumVerifyMessage") +} + +func init() { proto.RegisterFile("messages-ethereum.proto", fileDescriptor_cb33f46ba915f15c) } + +var fileDescriptor_cb33f46ba915f15c = []byte{ + // 593 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4d, 0x6f, 0xd3, 0x40, + 0x10, 0x95, 0x9b, 0xb4, 0x49, 0x26, 0x0d, 0x1f, 0xa6, 0x55, 0x17, 0x0a, 0x34, 0x18, 0x21, 0xe5, + 0x00, 0x3e, 0x70, 0x43, 0xe2, 0xd2, 0x52, 0x44, 0x2b, 0x4a, 0x55, 0xdc, 0xa8, 0x57, 0x6b, 0x63, + 0x6f, 0xe3, 0x55, 0x9d, 0xdd, 0xe0, 0x5d, 0xb7, 0x0e, 0x7f, 0x82, 0x23, 0xff, 0x87, 0x5f, 0x86, + 0xf6, 0x2b, 0x71, 0x52, 0x54, 0x0e, 0xbd, 0x65, 0xde, 0xbc, 0x7d, 0xf3, 0x66, 0xf4, 0x62, 0xd8, + 0x99, 0x10, 0x21, 0xf0, 0x98, 0x88, 0x77, 0x44, 0x66, 0xa4, 0x20, 0xe5, 0x24, 0x9c, 0x16, 0x5c, + 0x72, 0x7f, 0x37, 0xbb, 0x09, 0x65, 0x41, 0x7e, 0xf2, 0x22, 0x74, 0x94, 0xd0, 0x51, 0x9e, 0x6d, + 0xcf, 0x5f, 0x25, 0x7c, 0x32, 0xe1, 0xcc, 0xbc, 0x09, 0x2e, 0x60, 0xeb, 0xb3, 0xa5, 0x7c, 0x21, + 0xf2, 0xac, 0x1c, 0xe5, 0x34, 0xf9, 0x4a, 0x66, 0xfe, 0x2e, 0x74, 0x70, 0x9a, 0x16, 0x44, 0x88, + 0x98, 0x21, 0xaf, 0xdf, 0x18, 0xf4, 0xa2, 0xb6, 0x05, 0x4e, 0xfd, 0x57, 0xb0, 0x29, 0x32, 0x7e, + 0x13, 0xa7, 0x54, 0x4c, 0x73, 0x3c, 0x43, 0x6b, 0x7d, 0x6f, 0xd0, 0x8e, 0xba, 0x0a, 0x3b, 0x34, + 0x50, 0x30, 0x82, 0xc7, 0x4e, 0x77, 0x21, 0xfa, 0x01, 0x9a, 0x8c, 0xa7, 0x04, 0x79, 0x7d, 0x6f, + 0xd0, 0x7d, 0xff, 0x26, 0xfc, 0x87, 0x5f, 0x6b, 0xee, 0xe8, 0xf0, 0x94, 0xa7, 0x64, 0x38, 0x9b, + 0x92, 0x48, 0x3f, 0xf1, 0x7d, 0x68, 0x56, 0xd3, 0x72, 0xa4, 0x47, 0x75, 0x22, 0xfd, 0x3b, 0x18, + 0x82, 0x5f, 0xf3, 0xbe, 0x6f, 0xdc, 0xdd, 0xdb, 0xf9, 0x77, 0x78, 0xe8, 0x54, 0x9d, 0xe4, 0x4b, + 0x00, 0xab, 0x70, 0x40, 0x99, 0x76, 0xbf, 0x19, 0xd5, 0x90, 0x5a, 0xff, 0x88, 0x54, 0xd6, 0x62, + 0x0d, 0x09, 0xfe, 0xac, 0xc1, 0x03, 0xa7, 0x79, 0x4e, 0xc7, 0x6c, 0x58, 0xdd, 0xed, 0x72, 0x0b, + 0xd6, 0x19, 0x67, 0x09, 0xd1, 0x52, 0x9b, 0x91, 0x29, 0xd4, 0x93, 0x31, 0x16, 0xf1, 0xb4, 0xa0, + 0x09, 0x41, 0x0d, 0xdd, 0x69, 0x8f, 0xb1, 0x38, 0x53, 0xb5, 0x6b, 0xe6, 0x74, 0x42, 0x25, 0x6a, + 0xce, 0x9b, 0x27, 0xaa, 0x56, 0x7a, 0x92, 0x2b, 0xeb, 0xeb, 0x46, 0x4f, 0x17, 0x06, 0x55, 0x86, + 0xbb, 0xda, 0xb0, 0x29, 0x14, 0x7a, 0x8d, 0xf3, 0x92, 0xa0, 0x0d, 0xc3, 0xd5, 0x85, 0xff, 0x16, + 0xfc, 0x14, 0x4b, 0x1c, 0x53, 0x46, 0x25, 0xc5, 0x79, 0x9c, 0x64, 0x25, 0xbb, 0x42, 0x2d, 0x4d, + 0x79, 0xa4, 0x3a, 0xc7, 0xa6, 0xf1, 0x49, 0xe1, 0xfe, 0x1e, 0x74, 0x35, 0x3b, 0x27, 0x6c, 0x2c, + 0x33, 0xd4, 0xee, 0x7b, 0x83, 0x5e, 0x04, 0x0a, 0x3a, 0xd1, 0x88, 0xff, 0x14, 0xda, 0x49, 0x86, + 0x29, 0x8b, 0x69, 0x8a, 0x3a, 0xba, 0xdb, 0xd2, 0xf5, 0x71, 0xea, 0xef, 0x40, 0x4b, 0x56, 0xb1, + 0x9c, 0x4d, 0x09, 0x02, 0xdd, 0xd9, 0x90, 0x95, 0xca, 0x41, 0xf0, 0xdb, 0x5b, 0x44, 0x6a, 0x58, + 0x45, 0xe4, 0x47, 0x49, 0x84, 0x5c, 0x1d, 0xe5, 0xdd, 0x1a, 0xb5, 0x07, 0x5d, 0x41, 0xc7, 0x0c, + 0xcb, 0xb2, 0x20, 0xf1, 0xb5, 0xbe, 0x68, 0x2f, 0x82, 0x39, 0x74, 0xb1, 0x4c, 0x28, 0xec, 0x61, + 0x17, 0x84, 0x68, 0x99, 0x20, 0xec, 0x71, 0x17, 0x84, 0xf3, 0x20, 0x84, 0xde, 0xc2, 0xd8, 0x7e, + 0x72, 0xe5, 0xbf, 0x00, 0xed, 0xc0, 0x5e, 0xc9, 0xe4, 0xa5, 0xa3, 0x10, 0x7d, 0x9e, 0xe0, 0x04, + 0x9e, 0xd4, 0xd3, 0xf0, 0xcd, 0x64, 0xff, 0xee, 0x48, 0x20, 0x68, 0xd9, 0xff, 0x88, 0x0d, 0x85, + 0x2b, 0x83, 0x0a, 0x90, 0x53, 0xb3, 0x4a, 0xe7, 0xce, 0xda, 0x7f, 0x83, 0xfb, 0x1c, 0x3a, 0xf3, + 0x3d, 0xac, 0xee, 0x02, 0x58, 0x89, 0x75, 0xe3, 0x56, 0xac, 0x7f, 0x79, 0xb0, 0xed, 0x46, 0x5f, + 0x90, 0x82, 0x5e, 0xce, 0xdc, 0x2a, 0xf7, 0x9b, 0x5b, 0xdb, 0xb5, 0xb1, 0xb4, 0xeb, 0x8a, 0xa3, + 0xe6, 0xaa, 0xa3, 0x83, 0x8f, 0xf0, 0x3a, 0xe1, 0x93, 0x50, 0x60, 0xc9, 0x45, 0x46, 0x73, 0x3c, + 0x12, 0xee, 0x03, 0x93, 0xd3, 0x91, 0xf9, 0xe2, 0x8d, 0xca, 0xcb, 0x83, 0xed, 0xa1, 0x06, 0xad, + 0x5b, 0xb7, 0xc2, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8a, 0xce, 0x81, 0xc8, 0x59, 0x05, 0x00, + 0x00, +} diff --git a/accounts/usbwallet/trezor/messages-ethereum.proto b/accounts/usbwallet/trezor/messages-ethereum.proto new file mode 100644 index 0000000000..096bed2e4a --- /dev/null +++ b/accounts/usbwallet/trezor/messages-ethereum.proto @@ -0,0 +1,131 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages-ethereum.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + +syntax = "proto2"; +package hw.trezor.messages.ethereum; + +// Sugar for easier handling in Java +option java_package = "com.satoshilabs.trezor.lib.protobuf"; +option java_outer_classname = "TrezorMessageEthereum"; + +import "messages-common.proto"; + + +/** + * Request: Ask device for public key corresponding to address_n path + * @start + * @next EthereumPublicKey + * @next Failure + */ +message EthereumGetPublicKey { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bool show_display = 2; // optionally show on display before sending the result +} + +/** + * Response: Contains public key derived from device private seed + * @end + */ +message EthereumPublicKey { + optional hw.trezor.messages.common.HDNodeType node = 1; // BIP32 public node + optional string xpub = 2; // serialized form of public node +} + +/** + * Request: Ask device for Ethereum address corresponding to address_n path + * @start + * @next EthereumAddress + * @next Failure + */ +message EthereumGetAddress { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bool show_display = 2; // optionally show on display before sending the result +} + +/** + * Response: Contains an Ethereum address derived from device private seed + * @end + */ +message EthereumAddress { + optional bytes addressBin = 1; // Ethereum address as 20 bytes (legacy firmwares) + optional string addressHex = 2; // Ethereum address as hex string (newer firmwares) +} + +/** + * Request: Ask device to sign transaction + * All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing. + * Note: the first at most 1024 bytes of data MUST be transmitted as part of this message. + * @start + * @next EthereumTxRequest + * @next Failure + */ +message EthereumSignTx { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bytes nonce = 2; // <=256 bit unsigned big endian + optional bytes gas_price = 3; // <=256 bit unsigned big endian (in wei) + optional bytes gas_limit = 4; // <=256 bit unsigned big endian + optional bytes toBin = 5; // recipient address (20 bytes, legacy firmware) + optional string toHex = 11; // recipient address (hex string, newer firmware) + optional bytes value = 6; // <=256 bit unsigned big endian (in wei) + optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes) + optional uint32 data_length = 8; // Length of transaction payload + optional uint32 chain_id = 9; // Chain Id for EIP 155 + optional uint32 tx_type = 10; // (only for Wanchain) +} + +/** + * Response: Device asks for more data from transaction payload, or returns the signature. + * If data_length is set, device awaits that many more bytes of payload. + * Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present. + * @end + * @next EthereumTxAck + */ +message EthereumTxRequest { + optional uint32 data_length = 1; // Number of bytes being requested (<= 1024) + optional uint32 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28) + optional bytes signature_r = 3; // Computed signature R component (256 bit) + optional bytes signature_s = 4; // Computed signature S component (256 bit) +} + +/** + * Request: Transaction payload data. + * @next EthereumTxRequest + */ +message EthereumTxAck { + optional bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes) +} + +/** + * Request: Ask device to sign message + * @start + * @next EthereumMessageSignature + * @next Failure + */ +message EthereumSignMessage { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bytes message = 2; // message to be signed +} + +/** + * Response: Signed message + * @end + */ +message EthereumMessageSignature { + optional bytes addressBin = 1; // address used to sign the message (20 bytes, legacy firmware) + optional bytes signature = 2; // signature of the message + optional string addressHex = 3; // address used to sign the message (hex string, newer firmware) +} + +/** + * Request: Ask device to verify message + * @start + * @next Success + * @next Failure + */ +message EthereumVerifyMessage { + optional bytes addressBin = 1; // address to verify (20 bytes, legacy firmware) + optional bytes signature = 2; // signature to verify + optional bytes message = 3; // message to verify + optional string addressHex = 4; // address to verify (hex string, newer firmware) +} diff --git a/accounts/usbwallet/trezor/messages-management.pb.go b/accounts/usbwallet/trezor/messages-management.pb.go new file mode 100644 index 0000000000..f5c872f1fb --- /dev/null +++ b/accounts/usbwallet/trezor/messages-management.pb.go @@ -0,0 +1,1621 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: messages-management.proto + +package trezor + +import ( + fmt "fmt" + math "math" + + proto "github.com/golang/protobuf/proto" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +//* +// Structure representing passphrase source +type ApplySettings_PassphraseSourceType int32 + +const ( + ApplySettings_ASK ApplySettings_PassphraseSourceType = 0 + ApplySettings_DEVICE ApplySettings_PassphraseSourceType = 1 + ApplySettings_HOST ApplySettings_PassphraseSourceType = 2 +) + +var ApplySettings_PassphraseSourceType_name = map[int32]string{ + 0: "ASK", + 1: "DEVICE", + 2: "HOST", +} + +var ApplySettings_PassphraseSourceType_value = map[string]int32{ + "ASK": 0, + "DEVICE": 1, + "HOST": 2, +} + +func (x ApplySettings_PassphraseSourceType) Enum() *ApplySettings_PassphraseSourceType { + p := new(ApplySettings_PassphraseSourceType) + *p = x + return p +} + +func (x ApplySettings_PassphraseSourceType) String() string { + return proto.EnumName(ApplySettings_PassphraseSourceType_name, int32(x)) +} + +func (x *ApplySettings_PassphraseSourceType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(ApplySettings_PassphraseSourceType_value, data, "ApplySettings_PassphraseSourceType") + if err != nil { + return err + } + *x = ApplySettings_PassphraseSourceType(value) + return nil +} + +func (ApplySettings_PassphraseSourceType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{4, 0} +} + +//* +// Type of recovery procedure. These should be used as bitmask, e.g., +// `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` +// listing every method supported by the host computer. +// +// Note that ScrambledWords must be supported by every implementation +// for backward compatibility; there is no way to not support it. +type RecoveryDevice_RecoveryDeviceType int32 + +const ( + // use powers of two when extending this field + RecoveryDevice_RecoveryDeviceType_ScrambledWords RecoveryDevice_RecoveryDeviceType = 0 + RecoveryDevice_RecoveryDeviceType_Matrix RecoveryDevice_RecoveryDeviceType = 1 +) + +var RecoveryDevice_RecoveryDeviceType_name = map[int32]string{ + 0: "RecoveryDeviceType_ScrambledWords", + 1: "RecoveryDeviceType_Matrix", +} + +var RecoveryDevice_RecoveryDeviceType_value = map[string]int32{ + "RecoveryDeviceType_ScrambledWords": 0, + "RecoveryDeviceType_Matrix": 1, +} + +func (x RecoveryDevice_RecoveryDeviceType) Enum() *RecoveryDevice_RecoveryDeviceType { + p := new(RecoveryDevice_RecoveryDeviceType) + *p = x + return p +} + +func (x RecoveryDevice_RecoveryDeviceType) String() string { + return proto.EnumName(RecoveryDevice_RecoveryDeviceType_name, int32(x)) +} + +func (x *RecoveryDevice_RecoveryDeviceType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(RecoveryDevice_RecoveryDeviceType_value, data, "RecoveryDevice_RecoveryDeviceType") + if err != nil { + return err + } + *x = RecoveryDevice_RecoveryDeviceType(value) + return nil +} + +func (RecoveryDevice_RecoveryDeviceType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{17, 0} +} + +//* +// Type of Recovery Word request +type WordRequest_WordRequestType int32 + +const ( + WordRequest_WordRequestType_Plain WordRequest_WordRequestType = 0 + WordRequest_WordRequestType_Matrix9 WordRequest_WordRequestType = 1 + WordRequest_WordRequestType_Matrix6 WordRequest_WordRequestType = 2 +) + +var WordRequest_WordRequestType_name = map[int32]string{ + 0: "WordRequestType_Plain", + 1: "WordRequestType_Matrix9", + 2: "WordRequestType_Matrix6", +} + +var WordRequest_WordRequestType_value = map[string]int32{ + "WordRequestType_Plain": 0, + "WordRequestType_Matrix9": 1, + "WordRequestType_Matrix6": 2, +} + +func (x WordRequest_WordRequestType) Enum() *WordRequest_WordRequestType { + p := new(WordRequest_WordRequestType) + *p = x + return p +} + +func (x WordRequest_WordRequestType) String() string { + return proto.EnumName(WordRequest_WordRequestType_name, int32(x)) +} + +func (x *WordRequest_WordRequestType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(WordRequest_WordRequestType_value, data, "WordRequest_WordRequestType") + if err != nil { + return err + } + *x = WordRequest_WordRequestType(value) + return nil +} + +func (WordRequest_WordRequestType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{18, 0} +} + +//* +// Request: Reset device to default state and ask for device details +// @start +// @next Features +type Initialize struct { + State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` + SkipPassphrase *bool `protobuf:"varint,2,opt,name=skip_passphrase,json=skipPassphrase" json:"skip_passphrase,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Initialize) Reset() { *m = Initialize{} } +func (m *Initialize) String() string { return proto.CompactTextString(m) } +func (*Initialize) ProtoMessage() {} +func (*Initialize) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{0} +} + +func (m *Initialize) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Initialize.Unmarshal(m, b) +} +func (m *Initialize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Initialize.Marshal(b, m, deterministic) +} +func (m *Initialize) XXX_Merge(src proto.Message) { + xxx_messageInfo_Initialize.Merge(m, src) +} +func (m *Initialize) XXX_Size() int { + return xxx_messageInfo_Initialize.Size(m) +} +func (m *Initialize) XXX_DiscardUnknown() { + xxx_messageInfo_Initialize.DiscardUnknown(m) +} + +var xxx_messageInfo_Initialize proto.InternalMessageInfo + +func (m *Initialize) GetState() []byte { + if m != nil { + return m.State + } + return nil +} + +func (m *Initialize) GetSkipPassphrase() bool { + if m != nil && m.SkipPassphrase != nil { + return *m.SkipPassphrase + } + return false +} + +//* +// Request: Ask for device details (no device reset) +// @start +// @next Features +type GetFeatures struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetFeatures) Reset() { *m = GetFeatures{} } +func (m *GetFeatures) String() string { return proto.CompactTextString(m) } +func (*GetFeatures) ProtoMessage() {} +func (*GetFeatures) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{1} +} + +func (m *GetFeatures) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetFeatures.Unmarshal(m, b) +} +func (m *GetFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetFeatures.Marshal(b, m, deterministic) +} +func (m *GetFeatures) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetFeatures.Merge(m, src) +} +func (m *GetFeatures) XXX_Size() int { + return xxx_messageInfo_GetFeatures.Size(m) +} +func (m *GetFeatures) XXX_DiscardUnknown() { + xxx_messageInfo_GetFeatures.DiscardUnknown(m) +} + +var xxx_messageInfo_GetFeatures proto.InternalMessageInfo + +//* +// Response: Reports various information about the device +// @end +type Features struct { + Vendor *string `protobuf:"bytes,1,opt,name=vendor" json:"vendor,omitempty"` + MajorVersion *uint32 `protobuf:"varint,2,opt,name=major_version,json=majorVersion" json:"major_version,omitempty"` + MinorVersion *uint32 `protobuf:"varint,3,opt,name=minor_version,json=minorVersion" json:"minor_version,omitempty"` + PatchVersion *uint32 `protobuf:"varint,4,opt,name=patch_version,json=patchVersion" json:"patch_version,omitempty"` + BootloaderMode *bool `protobuf:"varint,5,opt,name=bootloader_mode,json=bootloaderMode" json:"bootloader_mode,omitempty"` + DeviceId *string `protobuf:"bytes,6,opt,name=device_id,json=deviceId" json:"device_id,omitempty"` + PinProtection *bool `protobuf:"varint,7,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + PassphraseProtection *bool `protobuf:"varint,8,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + Language *string `protobuf:"bytes,9,opt,name=language" json:"language,omitempty"` + Label *string `protobuf:"bytes,10,opt,name=label" json:"label,omitempty"` + Initialized *bool `protobuf:"varint,12,opt,name=initialized" json:"initialized,omitempty"` + Revision []byte `protobuf:"bytes,13,opt,name=revision" json:"revision,omitempty"` + BootloaderHash []byte `protobuf:"bytes,14,opt,name=bootloader_hash,json=bootloaderHash" json:"bootloader_hash,omitempty"` + Imported *bool `protobuf:"varint,15,opt,name=imported" json:"imported,omitempty"` + PinCached *bool `protobuf:"varint,16,opt,name=pin_cached,json=pinCached" json:"pin_cached,omitempty"` + PassphraseCached *bool `protobuf:"varint,17,opt,name=passphrase_cached,json=passphraseCached" json:"passphrase_cached,omitempty"` + FirmwarePresent *bool `protobuf:"varint,18,opt,name=firmware_present,json=firmwarePresent" json:"firmware_present,omitempty"` + NeedsBackup *bool `protobuf:"varint,19,opt,name=needs_backup,json=needsBackup" json:"needs_backup,omitempty"` + Flags *uint32 `protobuf:"varint,20,opt,name=flags" json:"flags,omitempty"` + Model *string `protobuf:"bytes,21,opt,name=model" json:"model,omitempty"` + FwMajor *uint32 `protobuf:"varint,22,opt,name=fw_major,json=fwMajor" json:"fw_major,omitempty"` + FwMinor *uint32 `protobuf:"varint,23,opt,name=fw_minor,json=fwMinor" json:"fw_minor,omitempty"` + FwPatch *uint32 `protobuf:"varint,24,opt,name=fw_patch,json=fwPatch" json:"fw_patch,omitempty"` + FwVendor *string `protobuf:"bytes,25,opt,name=fw_vendor,json=fwVendor" json:"fw_vendor,omitempty"` + FwVendorKeys []byte `protobuf:"bytes,26,opt,name=fw_vendor_keys,json=fwVendorKeys" json:"fw_vendor_keys,omitempty"` + UnfinishedBackup *bool `protobuf:"varint,27,opt,name=unfinished_backup,json=unfinishedBackup" json:"unfinished_backup,omitempty"` + NoBackup *bool `protobuf:"varint,28,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Features) Reset() { *m = Features{} } +func (m *Features) String() string { return proto.CompactTextString(m) } +func (*Features) ProtoMessage() {} +func (*Features) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{2} +} + +func (m *Features) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Features.Unmarshal(m, b) +} +func (m *Features) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Features.Marshal(b, m, deterministic) +} +func (m *Features) XXX_Merge(src proto.Message) { + xxx_messageInfo_Features.Merge(m, src) +} +func (m *Features) XXX_Size() int { + return xxx_messageInfo_Features.Size(m) +} +func (m *Features) XXX_DiscardUnknown() { + xxx_messageInfo_Features.DiscardUnknown(m) +} + +var xxx_messageInfo_Features proto.InternalMessageInfo + +func (m *Features) GetVendor() string { + if m != nil && m.Vendor != nil { + return *m.Vendor + } + return "" +} + +func (m *Features) GetMajorVersion() uint32 { + if m != nil && m.MajorVersion != nil { + return *m.MajorVersion + } + return 0 +} + +func (m *Features) GetMinorVersion() uint32 { + if m != nil && m.MinorVersion != nil { + return *m.MinorVersion + } + return 0 +} + +func (m *Features) GetPatchVersion() uint32 { + if m != nil && m.PatchVersion != nil { + return *m.PatchVersion + } + return 0 +} + +func (m *Features) GetBootloaderMode() bool { + if m != nil && m.BootloaderMode != nil { + return *m.BootloaderMode + } + return false +} + +func (m *Features) GetDeviceId() string { + if m != nil && m.DeviceId != nil { + return *m.DeviceId + } + return "" +} + +func (m *Features) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *Features) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *Features) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return "" +} + +func (m *Features) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *Features) GetInitialized() bool { + if m != nil && m.Initialized != nil { + return *m.Initialized + } + return false +} + +func (m *Features) GetRevision() []byte { + if m != nil { + return m.Revision + } + return nil +} + +func (m *Features) GetBootloaderHash() []byte { + if m != nil { + return m.BootloaderHash + } + return nil +} + +func (m *Features) GetImported() bool { + if m != nil && m.Imported != nil { + return *m.Imported + } + return false +} + +func (m *Features) GetPinCached() bool { + if m != nil && m.PinCached != nil { + return *m.PinCached + } + return false +} + +func (m *Features) GetPassphraseCached() bool { + if m != nil && m.PassphraseCached != nil { + return *m.PassphraseCached + } + return false +} + +func (m *Features) GetFirmwarePresent() bool { + if m != nil && m.FirmwarePresent != nil { + return *m.FirmwarePresent + } + return false +} + +func (m *Features) GetNeedsBackup() bool { + if m != nil && m.NeedsBackup != nil { + return *m.NeedsBackup + } + return false +} + +func (m *Features) GetFlags() uint32 { + if m != nil && m.Flags != nil { + return *m.Flags + } + return 0 +} + +func (m *Features) GetModel() string { + if m != nil && m.Model != nil { + return *m.Model + } + return "" +} + +func (m *Features) GetFwMajor() uint32 { + if m != nil && m.FwMajor != nil { + return *m.FwMajor + } + return 0 +} + +func (m *Features) GetFwMinor() uint32 { + if m != nil && m.FwMinor != nil { + return *m.FwMinor + } + return 0 +} + +func (m *Features) GetFwPatch() uint32 { + if m != nil && m.FwPatch != nil { + return *m.FwPatch + } + return 0 +} + +func (m *Features) GetFwVendor() string { + if m != nil && m.FwVendor != nil { + return *m.FwVendor + } + return "" +} + +func (m *Features) GetFwVendorKeys() []byte { + if m != nil { + return m.FwVendorKeys + } + return nil +} + +func (m *Features) GetUnfinishedBackup() bool { + if m != nil && m.UnfinishedBackup != nil { + return *m.UnfinishedBackup + } + return false +} + +func (m *Features) GetNoBackup() bool { + if m != nil && m.NoBackup != nil { + return *m.NoBackup + } + return false +} + +//* +// Request: clear session (removes cached PIN, passphrase, etc). +// @start +// @next Success +type ClearSession struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ClearSession) Reset() { *m = ClearSession{} } +func (m *ClearSession) String() string { return proto.CompactTextString(m) } +func (*ClearSession) ProtoMessage() {} +func (*ClearSession) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{3} +} + +func (m *ClearSession) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ClearSession.Unmarshal(m, b) +} +func (m *ClearSession) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ClearSession.Marshal(b, m, deterministic) +} +func (m *ClearSession) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClearSession.Merge(m, src) +} +func (m *ClearSession) XXX_Size() int { + return xxx_messageInfo_ClearSession.Size(m) +} +func (m *ClearSession) XXX_DiscardUnknown() { + xxx_messageInfo_ClearSession.DiscardUnknown(m) +} + +var xxx_messageInfo_ClearSession proto.InternalMessageInfo + +//* +// Request: change language and/or label of the device +// @start +// @next Success +// @next Failure +type ApplySettings struct { + Language *string `protobuf:"bytes,1,opt,name=language" json:"language,omitempty"` + Label *string `protobuf:"bytes,2,opt,name=label" json:"label,omitempty"` + UsePassphrase *bool `protobuf:"varint,3,opt,name=use_passphrase,json=usePassphrase" json:"use_passphrase,omitempty"` + Homescreen []byte `protobuf:"bytes,4,opt,name=homescreen" json:"homescreen,omitempty"` + PassphraseSource *ApplySettings_PassphraseSourceType `protobuf:"varint,5,opt,name=passphrase_source,json=passphraseSource,enum=hw.trezor.messages.management.ApplySettings_PassphraseSourceType" json:"passphrase_source,omitempty"` + AutoLockDelayMs *uint32 `protobuf:"varint,6,opt,name=auto_lock_delay_ms,json=autoLockDelayMs" json:"auto_lock_delay_ms,omitempty"` + DisplayRotation *uint32 `protobuf:"varint,7,opt,name=display_rotation,json=displayRotation" json:"display_rotation,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ApplySettings) Reset() { *m = ApplySettings{} } +func (m *ApplySettings) String() string { return proto.CompactTextString(m) } +func (*ApplySettings) ProtoMessage() {} +func (*ApplySettings) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{4} +} + +func (m *ApplySettings) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ApplySettings.Unmarshal(m, b) +} +func (m *ApplySettings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ApplySettings.Marshal(b, m, deterministic) +} +func (m *ApplySettings) XXX_Merge(src proto.Message) { + xxx_messageInfo_ApplySettings.Merge(m, src) +} +func (m *ApplySettings) XXX_Size() int { + return xxx_messageInfo_ApplySettings.Size(m) +} +func (m *ApplySettings) XXX_DiscardUnknown() { + xxx_messageInfo_ApplySettings.DiscardUnknown(m) +} + +var xxx_messageInfo_ApplySettings proto.InternalMessageInfo + +func (m *ApplySettings) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return "" +} + +func (m *ApplySettings) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *ApplySettings) GetUsePassphrase() bool { + if m != nil && m.UsePassphrase != nil { + return *m.UsePassphrase + } + return false +} + +func (m *ApplySettings) GetHomescreen() []byte { + if m != nil { + return m.Homescreen + } + return nil +} + +func (m *ApplySettings) GetPassphraseSource() ApplySettings_PassphraseSourceType { + if m != nil && m.PassphraseSource != nil { + return *m.PassphraseSource + } + return ApplySettings_ASK +} + +func (m *ApplySettings) GetAutoLockDelayMs() uint32 { + if m != nil && m.AutoLockDelayMs != nil { + return *m.AutoLockDelayMs + } + return 0 +} + +func (m *ApplySettings) GetDisplayRotation() uint32 { + if m != nil && m.DisplayRotation != nil { + return *m.DisplayRotation + } + return 0 +} + +//* +// Request: set flags of the device +// @start +// @next Success +// @next Failure +type ApplyFlags struct { + Flags *uint32 `protobuf:"varint,1,opt,name=flags" json:"flags,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ApplyFlags) Reset() { *m = ApplyFlags{} } +func (m *ApplyFlags) String() string { return proto.CompactTextString(m) } +func (*ApplyFlags) ProtoMessage() {} +func (*ApplyFlags) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{5} +} + +func (m *ApplyFlags) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ApplyFlags.Unmarshal(m, b) +} +func (m *ApplyFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ApplyFlags.Marshal(b, m, deterministic) +} +func (m *ApplyFlags) XXX_Merge(src proto.Message) { + xxx_messageInfo_ApplyFlags.Merge(m, src) +} +func (m *ApplyFlags) XXX_Size() int { + return xxx_messageInfo_ApplyFlags.Size(m) +} +func (m *ApplyFlags) XXX_DiscardUnknown() { + xxx_messageInfo_ApplyFlags.DiscardUnknown(m) +} + +var xxx_messageInfo_ApplyFlags proto.InternalMessageInfo + +func (m *ApplyFlags) GetFlags() uint32 { + if m != nil && m.Flags != nil { + return *m.Flags + } + return 0 +} + +//* +// Request: Starts workflow for setting/changing/removing the PIN +// @start +// @next Success +// @next Failure +type ChangePin struct { + Remove *bool `protobuf:"varint,1,opt,name=remove" json:"remove,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ChangePin) Reset() { *m = ChangePin{} } +func (m *ChangePin) String() string { return proto.CompactTextString(m) } +func (*ChangePin) ProtoMessage() {} +func (*ChangePin) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{6} +} + +func (m *ChangePin) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ChangePin.Unmarshal(m, b) +} +func (m *ChangePin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ChangePin.Marshal(b, m, deterministic) +} +func (m *ChangePin) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChangePin.Merge(m, src) +} +func (m *ChangePin) XXX_Size() int { + return xxx_messageInfo_ChangePin.Size(m) +} +func (m *ChangePin) XXX_DiscardUnknown() { + xxx_messageInfo_ChangePin.DiscardUnknown(m) +} + +var xxx_messageInfo_ChangePin proto.InternalMessageInfo + +func (m *ChangePin) GetRemove() bool { + if m != nil && m.Remove != nil { + return *m.Remove + } + return false +} + +//* +// Request: Test if the device is alive, device sends back the message in Success response +// @start +// @next Success +type Ping struct { + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + ButtonProtection *bool `protobuf:"varint,2,opt,name=button_protection,json=buttonProtection" json:"button_protection,omitempty"` + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Ping) Reset() { *m = Ping{} } +func (m *Ping) String() string { return proto.CompactTextString(m) } +func (*Ping) ProtoMessage() {} +func (*Ping) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{7} +} + +func (m *Ping) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Ping.Unmarshal(m, b) +} +func (m *Ping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Ping.Marshal(b, m, deterministic) +} +func (m *Ping) XXX_Merge(src proto.Message) { + xxx_messageInfo_Ping.Merge(m, src) +} +func (m *Ping) XXX_Size() int { + return xxx_messageInfo_Ping.Size(m) +} +func (m *Ping) XXX_DiscardUnknown() { + xxx_messageInfo_Ping.DiscardUnknown(m) +} + +var xxx_messageInfo_Ping proto.InternalMessageInfo + +func (m *Ping) GetMessage() string { + if m != nil && m.Message != nil { + return *m.Message + } + return "" +} + +func (m *Ping) GetButtonProtection() bool { + if m != nil && m.ButtonProtection != nil { + return *m.ButtonProtection + } + return false +} + +func (m *Ping) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *Ping) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +//* +// Request: Abort last operation that required user interaction +// @start +// @next Failure +type Cancel struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Cancel) Reset() { *m = Cancel{} } +func (m *Cancel) String() string { return proto.CompactTextString(m) } +func (*Cancel) ProtoMessage() {} +func (*Cancel) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{8} +} + +func (m *Cancel) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Cancel.Unmarshal(m, b) +} +func (m *Cancel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Cancel.Marshal(b, m, deterministic) +} +func (m *Cancel) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cancel.Merge(m, src) +} +func (m *Cancel) XXX_Size() int { + return xxx_messageInfo_Cancel.Size(m) +} +func (m *Cancel) XXX_DiscardUnknown() { + xxx_messageInfo_Cancel.DiscardUnknown(m) +} + +var xxx_messageInfo_Cancel proto.InternalMessageInfo + +//* +// Request: Request a sample of random data generated by hardware RNG. May be used for testing. +// @start +// @next Entropy +// @next Failure +type GetEntropy struct { + Size *uint32 `protobuf:"varint,1,req,name=size" json:"size,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetEntropy) Reset() { *m = GetEntropy{} } +func (m *GetEntropy) String() string { return proto.CompactTextString(m) } +func (*GetEntropy) ProtoMessage() {} +func (*GetEntropy) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{9} +} + +func (m *GetEntropy) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetEntropy.Unmarshal(m, b) +} +func (m *GetEntropy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetEntropy.Marshal(b, m, deterministic) +} +func (m *GetEntropy) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetEntropy.Merge(m, src) +} +func (m *GetEntropy) XXX_Size() int { + return xxx_messageInfo_GetEntropy.Size(m) +} +func (m *GetEntropy) XXX_DiscardUnknown() { + xxx_messageInfo_GetEntropy.DiscardUnknown(m) +} + +var xxx_messageInfo_GetEntropy proto.InternalMessageInfo + +func (m *GetEntropy) GetSize() uint32 { + if m != nil && m.Size != nil { + return *m.Size + } + return 0 +} + +//* +// Response: Reply with random data generated by internal RNG +// @end +type Entropy struct { + Entropy []byte `protobuf:"bytes,1,req,name=entropy" json:"entropy,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Entropy) Reset() { *m = Entropy{} } +func (m *Entropy) String() string { return proto.CompactTextString(m) } +func (*Entropy) ProtoMessage() {} +func (*Entropy) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{10} +} + +func (m *Entropy) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Entropy.Unmarshal(m, b) +} +func (m *Entropy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Entropy.Marshal(b, m, deterministic) +} +func (m *Entropy) XXX_Merge(src proto.Message) { + xxx_messageInfo_Entropy.Merge(m, src) +} +func (m *Entropy) XXX_Size() int { + return xxx_messageInfo_Entropy.Size(m) +} +func (m *Entropy) XXX_DiscardUnknown() { + xxx_messageInfo_Entropy.DiscardUnknown(m) +} + +var xxx_messageInfo_Entropy proto.InternalMessageInfo + +func (m *Entropy) GetEntropy() []byte { + if m != nil { + return m.Entropy + } + return nil +} + +//* +// Request: Request device to wipe all sensitive data and settings +// @start +// @next Success +// @next Failure +type WipeDevice struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WipeDevice) Reset() { *m = WipeDevice{} } +func (m *WipeDevice) String() string { return proto.CompactTextString(m) } +func (*WipeDevice) ProtoMessage() {} +func (*WipeDevice) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{11} +} + +func (m *WipeDevice) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_WipeDevice.Unmarshal(m, b) +} +func (m *WipeDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_WipeDevice.Marshal(b, m, deterministic) +} +func (m *WipeDevice) XXX_Merge(src proto.Message) { + xxx_messageInfo_WipeDevice.Merge(m, src) +} +func (m *WipeDevice) XXX_Size() int { + return xxx_messageInfo_WipeDevice.Size(m) +} +func (m *WipeDevice) XXX_DiscardUnknown() { + xxx_messageInfo_WipeDevice.DiscardUnknown(m) +} + +var xxx_messageInfo_WipeDevice proto.InternalMessageInfo + +//* +// Request: Load seed and related internal settings from the computer +// @start +// @next Success +// @next Failure +type LoadDevice struct { + Mnemonic *string `protobuf:"bytes,1,opt,name=mnemonic" json:"mnemonic,omitempty"` + Node *HDNodeType `protobuf:"bytes,2,opt,name=node" json:"node,omitempty"` + Pin *string `protobuf:"bytes,3,opt,name=pin" json:"pin,omitempty"` + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` + SkipChecksum *bool `protobuf:"varint,7,opt,name=skip_checksum,json=skipChecksum" json:"skip_checksum,omitempty"` + U2FCounter *uint32 `protobuf:"varint,8,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LoadDevice) Reset() { *m = LoadDevice{} } +func (m *LoadDevice) String() string { return proto.CompactTextString(m) } +func (*LoadDevice) ProtoMessage() {} +func (*LoadDevice) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{12} +} + +func (m *LoadDevice) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LoadDevice.Unmarshal(m, b) +} +func (m *LoadDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LoadDevice.Marshal(b, m, deterministic) +} +func (m *LoadDevice) XXX_Merge(src proto.Message) { + xxx_messageInfo_LoadDevice.Merge(m, src) +} +func (m *LoadDevice) XXX_Size() int { + return xxx_messageInfo_LoadDevice.Size(m) +} +func (m *LoadDevice) XXX_DiscardUnknown() { + xxx_messageInfo_LoadDevice.DiscardUnknown(m) +} + +var xxx_messageInfo_LoadDevice proto.InternalMessageInfo + +const Default_LoadDevice_Language string = "english" + +func (m *LoadDevice) GetMnemonic() string { + if m != nil && m.Mnemonic != nil { + return *m.Mnemonic + } + return "" +} + +func (m *LoadDevice) GetNode() *HDNodeType { + if m != nil { + return m.Node + } + return nil +} + +func (m *LoadDevice) GetPin() string { + if m != nil && m.Pin != nil { + return *m.Pin + } + return "" +} + +func (m *LoadDevice) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *LoadDevice) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return Default_LoadDevice_Language +} + +func (m *LoadDevice) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *LoadDevice) GetSkipChecksum() bool { + if m != nil && m.SkipChecksum != nil { + return *m.SkipChecksum + } + return false +} + +func (m *LoadDevice) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +//* +// Request: Ask device to do initialization involving user interaction +// @start +// @next EntropyRequest +// @next Failure +type ResetDevice struct { + DisplayRandom *bool `protobuf:"varint,1,opt,name=display_random,json=displayRandom" json:"display_random,omitempty"` + Strength *uint32 `protobuf:"varint,2,opt,name=strength,def=256" json:"strength,omitempty"` + PassphraseProtection *bool `protobuf:"varint,3,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + PinProtection *bool `protobuf:"varint,4,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` + U2FCounter *uint32 `protobuf:"varint,7,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + SkipBackup *bool `protobuf:"varint,8,opt,name=skip_backup,json=skipBackup" json:"skip_backup,omitempty"` + NoBackup *bool `protobuf:"varint,9,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResetDevice) Reset() { *m = ResetDevice{} } +func (m *ResetDevice) String() string { return proto.CompactTextString(m) } +func (*ResetDevice) ProtoMessage() {} +func (*ResetDevice) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{13} +} + +func (m *ResetDevice) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResetDevice.Unmarshal(m, b) +} +func (m *ResetDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResetDevice.Marshal(b, m, deterministic) +} +func (m *ResetDevice) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResetDevice.Merge(m, src) +} +func (m *ResetDevice) XXX_Size() int { + return xxx_messageInfo_ResetDevice.Size(m) +} +func (m *ResetDevice) XXX_DiscardUnknown() { + xxx_messageInfo_ResetDevice.DiscardUnknown(m) +} + +var xxx_messageInfo_ResetDevice proto.InternalMessageInfo + +const Default_ResetDevice_Strength uint32 = 256 +const Default_ResetDevice_Language string = "english" + +func (m *ResetDevice) GetDisplayRandom() bool { + if m != nil && m.DisplayRandom != nil { + return *m.DisplayRandom + } + return false +} + +func (m *ResetDevice) GetStrength() uint32 { + if m != nil && m.Strength != nil { + return *m.Strength + } + return Default_ResetDevice_Strength +} + +func (m *ResetDevice) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *ResetDevice) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *ResetDevice) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return Default_ResetDevice_Language +} + +func (m *ResetDevice) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *ResetDevice) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +func (m *ResetDevice) GetSkipBackup() bool { + if m != nil && m.SkipBackup != nil { + return *m.SkipBackup + } + return false +} + +func (m *ResetDevice) GetNoBackup() bool { + if m != nil && m.NoBackup != nil { + return *m.NoBackup + } + return false +} + +//* +// Request: Perform backup of the device seed if not backed up using ResetDevice +// @start +// @next Success +type BackupDevice struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BackupDevice) Reset() { *m = BackupDevice{} } +func (m *BackupDevice) String() string { return proto.CompactTextString(m) } +func (*BackupDevice) ProtoMessage() {} +func (*BackupDevice) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{14} +} + +func (m *BackupDevice) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BackupDevice.Unmarshal(m, b) +} +func (m *BackupDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BackupDevice.Marshal(b, m, deterministic) +} +func (m *BackupDevice) XXX_Merge(src proto.Message) { + xxx_messageInfo_BackupDevice.Merge(m, src) +} +func (m *BackupDevice) XXX_Size() int { + return xxx_messageInfo_BackupDevice.Size(m) +} +func (m *BackupDevice) XXX_DiscardUnknown() { + xxx_messageInfo_BackupDevice.DiscardUnknown(m) +} + +var xxx_messageInfo_BackupDevice proto.InternalMessageInfo + +//* +// Response: Ask for additional entropy from host computer +// @next EntropyAck +type EntropyRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EntropyRequest) Reset() { *m = EntropyRequest{} } +func (m *EntropyRequest) String() string { return proto.CompactTextString(m) } +func (*EntropyRequest) ProtoMessage() {} +func (*EntropyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{15} +} + +func (m *EntropyRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EntropyRequest.Unmarshal(m, b) +} +func (m *EntropyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EntropyRequest.Marshal(b, m, deterministic) +} +func (m *EntropyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EntropyRequest.Merge(m, src) +} +func (m *EntropyRequest) XXX_Size() int { + return xxx_messageInfo_EntropyRequest.Size(m) +} +func (m *EntropyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_EntropyRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_EntropyRequest proto.InternalMessageInfo + +//* +// Request: Provide additional entropy for seed generation function +// @next Success +type EntropyAck struct { + Entropy []byte `protobuf:"bytes,1,opt,name=entropy" json:"entropy,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EntropyAck) Reset() { *m = EntropyAck{} } +func (m *EntropyAck) String() string { return proto.CompactTextString(m) } +func (*EntropyAck) ProtoMessage() {} +func (*EntropyAck) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{16} +} + +func (m *EntropyAck) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EntropyAck.Unmarshal(m, b) +} +func (m *EntropyAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EntropyAck.Marshal(b, m, deterministic) +} +func (m *EntropyAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_EntropyAck.Merge(m, src) +} +func (m *EntropyAck) XXX_Size() int { + return xxx_messageInfo_EntropyAck.Size(m) +} +func (m *EntropyAck) XXX_DiscardUnknown() { + xxx_messageInfo_EntropyAck.DiscardUnknown(m) +} + +var xxx_messageInfo_EntropyAck proto.InternalMessageInfo + +func (m *EntropyAck) GetEntropy() []byte { + if m != nil { + return m.Entropy + } + return nil +} + +//* +// Request: Start recovery workflow asking user for specific words of mnemonic +// Used to recovery device safely even on untrusted computer. +// @start +// @next WordRequest +type RecoveryDevice struct { + WordCount *uint32 `protobuf:"varint,1,opt,name=word_count,json=wordCount" json:"word_count,omitempty"` + PassphraseProtection *bool `protobuf:"varint,2,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + Language *string `protobuf:"bytes,4,opt,name=language,def=english" json:"language,omitempty"` + Label *string `protobuf:"bytes,5,opt,name=label" json:"label,omitempty"` + EnforceWordlist *bool `protobuf:"varint,6,opt,name=enforce_wordlist,json=enforceWordlist" json:"enforce_wordlist,omitempty"` + // 7 reserved for unused recovery method + Type *RecoveryDevice_RecoveryDeviceType `protobuf:"varint,8,opt,name=type,enum=hw.trezor.messages.management.RecoveryDevice_RecoveryDeviceType" json:"type,omitempty"` + U2FCounter *uint32 `protobuf:"varint,9,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + DryRun *bool `protobuf:"varint,10,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RecoveryDevice) Reset() { *m = RecoveryDevice{} } +func (m *RecoveryDevice) String() string { return proto.CompactTextString(m) } +func (*RecoveryDevice) ProtoMessage() {} +func (*RecoveryDevice) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{17} +} + +func (m *RecoveryDevice) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RecoveryDevice.Unmarshal(m, b) +} +func (m *RecoveryDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RecoveryDevice.Marshal(b, m, deterministic) +} +func (m *RecoveryDevice) XXX_Merge(src proto.Message) { + xxx_messageInfo_RecoveryDevice.Merge(m, src) +} +func (m *RecoveryDevice) XXX_Size() int { + return xxx_messageInfo_RecoveryDevice.Size(m) +} +func (m *RecoveryDevice) XXX_DiscardUnknown() { + xxx_messageInfo_RecoveryDevice.DiscardUnknown(m) +} + +var xxx_messageInfo_RecoveryDevice proto.InternalMessageInfo + +const Default_RecoveryDevice_Language string = "english" + +func (m *RecoveryDevice) GetWordCount() uint32 { + if m != nil && m.WordCount != nil { + return *m.WordCount + } + return 0 +} + +func (m *RecoveryDevice) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *RecoveryDevice) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *RecoveryDevice) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return Default_RecoveryDevice_Language +} + +func (m *RecoveryDevice) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *RecoveryDevice) GetEnforceWordlist() bool { + if m != nil && m.EnforceWordlist != nil { + return *m.EnforceWordlist + } + return false +} + +func (m *RecoveryDevice) GetType() RecoveryDevice_RecoveryDeviceType { + if m != nil && m.Type != nil { + return *m.Type + } + return RecoveryDevice_RecoveryDeviceType_ScrambledWords +} + +func (m *RecoveryDevice) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +func (m *RecoveryDevice) GetDryRun() bool { + if m != nil && m.DryRun != nil { + return *m.DryRun + } + return false +} + +//* +// Response: Device is waiting for user to enter word of the mnemonic +// Its position is shown only on device's internal display. +// @next WordAck +type WordRequest struct { + Type *WordRequest_WordRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.management.WordRequest_WordRequestType" json:"type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WordRequest) Reset() { *m = WordRequest{} } +func (m *WordRequest) String() string { return proto.CompactTextString(m) } +func (*WordRequest) ProtoMessage() {} +func (*WordRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{18} +} + +func (m *WordRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_WordRequest.Unmarshal(m, b) +} +func (m *WordRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_WordRequest.Marshal(b, m, deterministic) +} +func (m *WordRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WordRequest.Merge(m, src) +} +func (m *WordRequest) XXX_Size() int { + return xxx_messageInfo_WordRequest.Size(m) +} +func (m *WordRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WordRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_WordRequest proto.InternalMessageInfo + +func (m *WordRequest) GetType() WordRequest_WordRequestType { + if m != nil && m.Type != nil { + return *m.Type + } + return WordRequest_WordRequestType_Plain +} + +//* +// Request: Computer replies with word from the mnemonic +// @next WordRequest +// @next Success +// @next Failure +type WordAck struct { + Word *string `protobuf:"bytes,1,req,name=word" json:"word,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WordAck) Reset() { *m = WordAck{} } +func (m *WordAck) String() string { return proto.CompactTextString(m) } +func (*WordAck) ProtoMessage() {} +func (*WordAck) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{19} +} + +func (m *WordAck) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_WordAck.Unmarshal(m, b) +} +func (m *WordAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_WordAck.Marshal(b, m, deterministic) +} +func (m *WordAck) XXX_Merge(src proto.Message) { + xxx_messageInfo_WordAck.Merge(m, src) +} +func (m *WordAck) XXX_Size() int { + return xxx_messageInfo_WordAck.Size(m) +} +func (m *WordAck) XXX_DiscardUnknown() { + xxx_messageInfo_WordAck.DiscardUnknown(m) +} + +var xxx_messageInfo_WordAck proto.InternalMessageInfo + +func (m *WordAck) GetWord() string { + if m != nil && m.Word != nil { + return *m.Word + } + return "" +} + +//* +// Request: Set U2F counter +// @start +// @next Success +type SetU2FCounter struct { + U2FCounter *uint32 `protobuf:"varint,1,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetU2FCounter) Reset() { *m = SetU2FCounter{} } +func (m *SetU2FCounter) String() string { return proto.CompactTextString(m) } +func (*SetU2FCounter) ProtoMessage() {} +func (*SetU2FCounter) Descriptor() ([]byte, []int) { + return fileDescriptor_0c720c20d27aa029, []int{20} +} + +func (m *SetU2FCounter) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetU2FCounter.Unmarshal(m, b) +} +func (m *SetU2FCounter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetU2FCounter.Marshal(b, m, deterministic) +} +func (m *SetU2FCounter) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetU2FCounter.Merge(m, src) +} +func (m *SetU2FCounter) XXX_Size() int { + return xxx_messageInfo_SetU2FCounter.Size(m) +} +func (m *SetU2FCounter) XXX_DiscardUnknown() { + xxx_messageInfo_SetU2FCounter.DiscardUnknown(m) +} + +var xxx_messageInfo_SetU2FCounter proto.InternalMessageInfo + +func (m *SetU2FCounter) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +func init() { + proto.RegisterEnum("hw.trezor.messages.management.ApplySettings_PassphraseSourceType", ApplySettings_PassphraseSourceType_name, ApplySettings_PassphraseSourceType_value) + proto.RegisterEnum("hw.trezor.messages.management.RecoveryDevice_RecoveryDeviceType", RecoveryDevice_RecoveryDeviceType_name, RecoveryDevice_RecoveryDeviceType_value) + proto.RegisterEnum("hw.trezor.messages.management.WordRequest_WordRequestType", WordRequest_WordRequestType_name, WordRequest_WordRequestType_value) + proto.RegisterType((*Initialize)(nil), "hw.trezor.messages.management.Initialize") + proto.RegisterType((*GetFeatures)(nil), "hw.trezor.messages.management.GetFeatures") + proto.RegisterType((*Features)(nil), "hw.trezor.messages.management.Features") + proto.RegisterType((*ClearSession)(nil), "hw.trezor.messages.management.ClearSession") + proto.RegisterType((*ApplySettings)(nil), "hw.trezor.messages.management.ApplySettings") + proto.RegisterType((*ApplyFlags)(nil), "hw.trezor.messages.management.ApplyFlags") + proto.RegisterType((*ChangePin)(nil), "hw.trezor.messages.management.ChangePin") + proto.RegisterType((*Ping)(nil), "hw.trezor.messages.management.Ping") + proto.RegisterType((*Cancel)(nil), "hw.trezor.messages.management.Cancel") + proto.RegisterType((*GetEntropy)(nil), "hw.trezor.messages.management.GetEntropy") + proto.RegisterType((*Entropy)(nil), "hw.trezor.messages.management.Entropy") + proto.RegisterType((*WipeDevice)(nil), "hw.trezor.messages.management.WipeDevice") + proto.RegisterType((*LoadDevice)(nil), "hw.trezor.messages.management.LoadDevice") + proto.RegisterType((*ResetDevice)(nil), "hw.trezor.messages.management.ResetDevice") + proto.RegisterType((*BackupDevice)(nil), "hw.trezor.messages.management.BackupDevice") + proto.RegisterType((*EntropyRequest)(nil), "hw.trezor.messages.management.EntropyRequest") + proto.RegisterType((*EntropyAck)(nil), "hw.trezor.messages.management.EntropyAck") + proto.RegisterType((*RecoveryDevice)(nil), "hw.trezor.messages.management.RecoveryDevice") + proto.RegisterType((*WordRequest)(nil), "hw.trezor.messages.management.WordRequest") + proto.RegisterType((*WordAck)(nil), "hw.trezor.messages.management.WordAck") + proto.RegisterType((*SetU2FCounter)(nil), "hw.trezor.messages.management.SetU2FCounter") +} + +func init() { proto.RegisterFile("messages-management.proto", fileDescriptor_0c720c20d27aa029) } + +var fileDescriptor_0c720c20d27aa029 = []byte{ + // 1393 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0xdd, 0x6e, 0xdb, 0xc8, + 0x15, 0x8e, 0x7e, 0x62, 0x49, 0xc7, 0xfa, 0xcb, 0xd4, 0x8e, 0xe9, 0xb8, 0x6e, 0x1c, 0xba, 0x6e, + 0x12, 0x04, 0x15, 0x0a, 0x17, 0x09, 0x90, 0x5c, 0x14, 0x75, 0xec, 0xfc, 0x21, 0x71, 0x6a, 0xd0, + 0x6e, 0x02, 0xf4, 0x86, 0x18, 0x91, 0x47, 0xd2, 0xd4, 0xe4, 0x0c, 0xcb, 0x19, 0xda, 0x55, 0x5e, + 0x60, 0x6f, 0xf6, 0x45, 0x16, 0xfb, 0x1c, 0x7b, 0xb5, 0xcf, 0xb0, 0xef, 0xb2, 0x98, 0x19, 0x52, + 0xa2, 0x65, 0x3b, 0x46, 0x76, 0xef, 0xe6, 0x7c, 0xe7, 0xe3, 0x68, 0xce, 0x77, 0xbe, 0x39, 0x63, + 0xc3, 0x7a, 0x8c, 0x52, 0xd2, 0x31, 0xca, 0xbf, 0xc6, 0x94, 0xd3, 0x31, 0xc6, 0xc8, 0xd5, 0x20, + 0x49, 0x85, 0x12, 0x64, 0x73, 0x72, 0x3e, 0x50, 0x29, 0x7e, 0x11, 0xe9, 0xa0, 0x20, 0x0d, 0xe6, + 0xa4, 0x7b, 0xab, 0xb3, 0x2f, 0x03, 0x11, 0xc7, 0x82, 0xdb, 0xaf, 0xdc, 0xf7, 0x00, 0xef, 0x38, + 0x53, 0x8c, 0x46, 0xec, 0x0b, 0x92, 0x15, 0xb8, 0x2d, 0x15, 0x55, 0xe8, 0x54, 0xb6, 0x2a, 0x8f, + 0xda, 0x9e, 0x0d, 0xc8, 0x43, 0xe8, 0xc9, 0x53, 0x96, 0xf8, 0x09, 0x95, 0x32, 0x99, 0xa4, 0x54, + 0xa2, 0x53, 0xdd, 0xaa, 0x3c, 0x6a, 0x7a, 0x5d, 0x0d, 0x1f, 0xcd, 0x50, 0xb7, 0x03, 0xcb, 0x6f, + 0x50, 0xbd, 0x46, 0xaa, 0xb2, 0x14, 0xa5, 0xfb, 0x7d, 0x03, 0x9a, 0x45, 0x40, 0xee, 0xc2, 0xd2, + 0x19, 0xf2, 0x50, 0xa4, 0x66, 0xef, 0x96, 0x97, 0x47, 0x64, 0x1b, 0x3a, 0x31, 0xfd, 0xaf, 0x48, + 0xfd, 0x33, 0x4c, 0x25, 0x13, 0xdc, 0x6c, 0xdd, 0xf1, 0xda, 0x06, 0xfc, 0x64, 0x31, 0x43, 0x62, + 0xbc, 0x44, 0xaa, 0xe5, 0x24, 0x0d, 0x96, 0x48, 0x09, 0x55, 0xc1, 0x64, 0x46, 0xaa, 0x5b, 0x92, + 0x01, 0x0b, 0xd2, 0x43, 0xe8, 0x0d, 0x85, 0x50, 0x91, 0xa0, 0x21, 0xa6, 0x7e, 0x2c, 0x42, 0x74, + 0x6e, 0xdb, 0x5a, 0xe6, 0xf0, 0xa1, 0x08, 0x91, 0x6c, 0x40, 0x2b, 0xc4, 0x33, 0x16, 0xa0, 0xcf, + 0x42, 0x67, 0xc9, 0x1c, 0xb9, 0x69, 0x81, 0x77, 0x21, 0xd9, 0x81, 0x6e, 0xc2, 0xb8, 0xaf, 0x25, + 0xc4, 0x40, 0xe9, 0xdf, 0x6a, 0x98, 0x4d, 0x3a, 0x09, 0xe3, 0x47, 0x33, 0x90, 0xfc, 0x1d, 0x56, + 0xe7, 0x9a, 0x95, 0xd9, 0x4d, 0xc3, 0x5e, 0x99, 0x27, 0x4b, 0x1f, 0xdd, 0x83, 0x66, 0x44, 0xf9, + 0x38, 0xa3, 0x63, 0x74, 0x5a, 0xf6, 0x77, 0x8b, 0x58, 0xf7, 0x27, 0xa2, 0x43, 0x8c, 0x1c, 0x30, + 0x09, 0x1b, 0x90, 0x2d, 0x58, 0x66, 0xb3, 0x1e, 0x86, 0x4e, 0xdb, 0x6c, 0x5e, 0x86, 0xf4, 0x9e, + 0x29, 0x9e, 0x31, 0xa3, 0x4a, 0xc7, 0xb4, 0x76, 0x16, 0x2f, 0x28, 0x32, 0xa1, 0x72, 0xe2, 0x74, + 0x0d, 0xa5, 0xa4, 0xc8, 0x5b, 0x2a, 0x27, 0x7a, 0x13, 0x16, 0x27, 0x22, 0x55, 0x18, 0x3a, 0x3d, + 0xf3, 0x1b, 0xb3, 0x98, 0x6c, 0x02, 0x68, 0x41, 0x02, 0x1a, 0x4c, 0x30, 0x74, 0xfa, 0x26, 0xdb, + 0x4a, 0x18, 0xdf, 0x37, 0x00, 0x79, 0x02, 0x77, 0x4a, 0x42, 0xe4, 0xac, 0x3b, 0x86, 0xd5, 0x9f, + 0x27, 0x72, 0xf2, 0x63, 0xe8, 0x8f, 0x58, 0x1a, 0x9f, 0xd3, 0x54, 0x6b, 0x86, 0x12, 0xb9, 0x72, + 0x88, 0xe1, 0xf6, 0x0a, 0xfc, 0xc8, 0xc2, 0xe4, 0x01, 0xb4, 0x39, 0x62, 0x28, 0xfd, 0x21, 0x0d, + 0x4e, 0xb3, 0xc4, 0xf9, 0x83, 0x2d, 0xdd, 0x60, 0x2f, 0x0d, 0xa4, 0x25, 0x1b, 0x45, 0x74, 0x2c, + 0x9d, 0x15, 0xe3, 0x06, 0x1b, 0x68, 0x54, 0xf7, 0x3e, 0x72, 0x56, 0xad, 0x90, 0x26, 0x20, 0xeb, + 0xd0, 0x1c, 0x9d, 0xfb, 0xc6, 0x79, 0xce, 0x5d, 0x43, 0x6f, 0x8c, 0xce, 0x0f, 0x75, 0x58, 0xa4, + 0xb4, 0xdf, 0x9c, 0xb5, 0x59, 0x4a, 0x87, 0x79, 0xca, 0xb8, 0xcc, 0x71, 0x8a, 0xd4, 0x91, 0x0e, + 0xb5, 0x89, 0x46, 0xe7, 0x7e, 0xee, 0xfb, 0x75, 0xdb, 0xcc, 0xd1, 0xf9, 0x27, 0xeb, 0xfc, 0x3f, + 0x43, 0x77, 0x96, 0xf4, 0x4f, 0x71, 0x2a, 0x9d, 0x7b, 0x46, 0xf7, 0x76, 0xc1, 0x78, 0x8f, 0x53, + 0xa9, 0xa5, 0xcb, 0xf8, 0x88, 0x71, 0x26, 0x27, 0x18, 0x16, 0x75, 0x6e, 0x58, 0xe9, 0xe6, 0x89, + 0xbc, 0xd8, 0x0d, 0x68, 0x71, 0x51, 0x90, 0xfe, 0x68, 0x7b, 0xc4, 0x85, 0x4d, 0xba, 0x5d, 0x68, + 0xef, 0x47, 0x48, 0xd3, 0x63, 0x94, 0xba, 0xf1, 0xee, 0x77, 0x35, 0xe8, 0xec, 0x25, 0x49, 0x34, + 0x3d, 0x46, 0xa5, 0x18, 0x1f, 0xcb, 0x0b, 0xd6, 0xab, 0x5c, 0x67, 0xbd, 0x6a, 0xd9, 0x7a, 0x3b, + 0xd0, 0xcd, 0xb4, 0xb5, 0xe7, 0x93, 0xa1, 0x66, 0x2f, 0x42, 0x26, 0x71, 0x3e, 0x18, 0xc8, 0x9f, + 0x00, 0x26, 0x22, 0x46, 0x19, 0xa4, 0x88, 0xf6, 0x5e, 0xb6, 0xbd, 0x12, 0x42, 0xf8, 0x05, 0x7f, + 0x48, 0x91, 0xa5, 0x81, 0xbd, 0x97, 0xdd, 0xdd, 0xbd, 0xc1, 0x57, 0xe7, 0xda, 0xe0, 0x42, 0x05, + 0x83, 0xf9, 0x6f, 0x1e, 0x9b, 0x4d, 0x4e, 0xa6, 0x09, 0x96, 0x2d, 0x66, 0x51, 0xf2, 0x04, 0x08, + 0xcd, 0x94, 0xf0, 0x23, 0x11, 0x9c, 0xfa, 0x21, 0x46, 0x74, 0xea, 0xc7, 0xd2, 0xdc, 0xf2, 0x8e, + 0xd7, 0xd3, 0x99, 0x0f, 0x22, 0x38, 0x3d, 0xd0, 0xf8, 0xa1, 0xd4, 0x7e, 0x0c, 0x99, 0x4c, 0x34, + 0x29, 0x15, 0x8a, 0xce, 0xae, 0x7b, 0xc7, 0xeb, 0xe5, 0xb8, 0x97, 0xc3, 0xee, 0x53, 0x58, 0xb9, + 0xea, 0x04, 0xa4, 0x01, 0xb5, 0xbd, 0xe3, 0xf7, 0xfd, 0x5b, 0x04, 0x60, 0xe9, 0xe0, 0xd5, 0xa7, + 0x77, 0xfb, 0xaf, 0xfa, 0x15, 0xd2, 0x84, 0xfa, 0xdb, 0x7f, 0x1d, 0x9f, 0xf4, 0xab, 0xae, 0x0b, + 0x60, 0xca, 0x78, 0x5d, 0x78, 0xd3, 0x3a, 0xb6, 0x52, 0x72, 0xac, 0xbb, 0x0d, 0xad, 0xfd, 0x09, + 0xe5, 0x63, 0x3c, 0x62, 0x5c, 0x0f, 0xd3, 0x14, 0x63, 0x71, 0x66, 0xdb, 0xd4, 0xf4, 0xf2, 0xc8, + 0xfd, 0xa1, 0x02, 0xf5, 0x23, 0xc6, 0xc7, 0xc4, 0x81, 0x46, 0x2e, 0x56, 0xde, 0xc8, 0x22, 0xd4, + 0x7e, 0x1a, 0x66, 0x4a, 0x89, 0x0b, 0xd3, 0xcb, 0x8e, 0xf3, 0xbe, 0x4d, 0x94, 0x66, 0xd1, 0xe5, + 0x39, 0x57, 0xfb, 0xa6, 0x39, 0x57, 0xbf, 0x7e, 0xce, 0xb9, 0x4d, 0x58, 0xda, 0xa7, 0x3c, 0xc0, + 0xc8, 0xdd, 0x02, 0x78, 0x83, 0xea, 0x15, 0x57, 0xa9, 0x48, 0xa6, 0x84, 0x40, 0x5d, 0xb2, 0x2f, + 0xfa, 0xdc, 0xd5, 0x47, 0x1d, 0xcf, 0xac, 0xdd, 0x6d, 0x68, 0x14, 0x69, 0x07, 0x1a, 0x68, 0x97, + 0x86, 0xd1, 0xf6, 0x8a, 0xd0, 0x6d, 0x03, 0x7c, 0x66, 0x09, 0x1e, 0x98, 0x21, 0xed, 0xfe, 0x58, + 0x05, 0xf8, 0x20, 0x68, 0x68, 0x43, 0x6d, 0xed, 0x98, 0x63, 0x2c, 0x38, 0x0b, 0x0a, 0x6b, 0x17, + 0x31, 0x79, 0x0e, 0x75, 0xae, 0x1f, 0x02, 0xad, 0xc2, 0xf2, 0xee, 0xce, 0x55, 0x86, 0xcb, 0xdf, + 0xcc, 0xb7, 0x07, 0x1f, 0x45, 0x68, 0x4d, 0x65, 0x3e, 0x21, 0x7d, 0xa8, 0x25, 0xcc, 0xaa, 0xd2, + 0xf2, 0xf4, 0xf2, 0x37, 0x69, 0x41, 0xb6, 0x4b, 0x17, 0x4f, 0xdb, 0xbe, 0xf5, 0xa2, 0x81, 0x7c, + 0x1c, 0x31, 0x39, 0xb9, 0xea, 0x06, 0x2e, 0x95, 0x6f, 0xe0, 0x36, 0x74, 0xcc, 0xe3, 0x1c, 0x4c, + 0x30, 0x38, 0x95, 0x59, 0x9c, 0xbf, 0x44, 0x6d, 0x0d, 0xee, 0xe7, 0x18, 0xb9, 0x0f, 0xcb, 0xd9, + 0xee, 0xc8, 0x0f, 0x44, 0xc6, 0x15, 0xa6, 0xe6, 0xf9, 0xe9, 0x78, 0x90, 0xed, 0x8e, 0xf6, 0x2d, + 0xe2, 0xfe, 0x5c, 0x85, 0x65, 0x0f, 0x25, 0xaa, 0x5c, 0xae, 0x1d, 0xe8, 0xce, 0x3c, 0x4f, 0x79, + 0x28, 0xe2, 0xdc, 0x68, 0x9d, 0xc2, 0xf1, 0x06, 0x24, 0xf7, 0xa1, 0x29, 0x55, 0x8a, 0x7c, 0xac, + 0x26, 0xf6, 0xdd, 0x7e, 0x51, 0xdb, 0x7d, 0xfa, 0xcc, 0x9b, 0x81, 0xd7, 0xab, 0x51, 0xfb, 0x8a, + 0x1a, 0x97, 0x5d, 0x57, 0xbf, 0xca, 0x75, 0xbf, 0x43, 0xb4, 0x05, 0x3d, 0x1a, 0x8b, 0x7a, 0x68, + 0x82, 0x51, 0x35, 0x1f, 0xa5, 0xf6, 0xbd, 0x06, 0x0d, 0x5d, 0x35, 0x69, 0x5b, 0x97, 0x27, 0xad, + 0x5d, 0xe5, 0x5e, 0xec, 0x43, 0x37, 0xb7, 0xaf, 0x87, 0xff, 0xcb, 0x50, 0x2a, 0xf7, 0x2f, 0x00, + 0x39, 0xb2, 0x17, 0x9c, 0x5e, 0xf4, 0x74, 0xa5, 0xec, 0xe9, 0x5f, 0x6a, 0xd0, 0xf5, 0x30, 0x10, + 0x67, 0x98, 0x4e, 0xf3, 0xd6, 0x6c, 0x02, 0x9c, 0x8b, 0x34, 0xb4, 0x87, 0xcf, 0x67, 0x44, 0x4b, + 0x23, 0xe6, 0xec, 0xd7, 0x2b, 0x5e, 0xfd, 0x26, 0xc5, 0x6b, 0x37, 0x29, 0x5e, 0xbf, 0x51, 0xf1, + 0xdb, 0x65, 0xc5, 0x1f, 0x43, 0x1f, 0xf9, 0x48, 0xa4, 0x01, 0xfa, 0xfa, 0xac, 0x11, 0x93, 0xca, + 0xb4, 0xa4, 0xe9, 0xf5, 0x72, 0xfc, 0x73, 0x0e, 0x93, 0x13, 0xa8, 0xab, 0x69, 0x82, 0x46, 0xf4, + 0xee, 0xee, 0x3f, 0x6f, 0x98, 0xff, 0x17, 0xd5, 0x59, 0x08, 0xed, 0x4d, 0xd5, 0xbb, 0x2d, 0xb6, + 0xbc, 0x75, 0xa9, 0xe5, 0x6b, 0xd0, 0x08, 0xd3, 0xa9, 0x9f, 0x66, 0xdc, 0xfc, 0x75, 0xd5, 0xf4, + 0x96, 0xc2, 0x74, 0xea, 0x65, 0xdc, 0xfd, 0x0f, 0x90, 0xcb, 0xbb, 0x92, 0x1d, 0x78, 0x70, 0x19, + 0xf5, 0x8f, 0x83, 0x94, 0xc6, 0xc3, 0x08, 0x43, 0x5d, 0x8d, 0xec, 0xdf, 0x22, 0x9b, 0xb0, 0x7e, + 0x05, 0xed, 0x90, 0xaa, 0x94, 0xfd, 0xbf, 0x5f, 0x71, 0x7f, 0xaa, 0xc0, 0xb2, 0xa6, 0xe6, 0xbe, + 0x20, 0x1f, 0xf3, 0xda, 0x2b, 0xa6, 0xf6, 0x17, 0x37, 0xd4, 0x5e, 0xfa, 0xb2, 0xbc, 0x9e, 0x57, + 0xed, 0x8e, 0xa0, 0xb7, 0x90, 0x20, 0xeb, 0xb0, 0xba, 0x00, 0xf9, 0x47, 0x11, 0x65, 0xbc, 0x7f, + 0x8b, 0x6c, 0xc0, 0xda, 0x62, 0xca, 0x9e, 0xf4, 0x79, 0xbf, 0x72, 0x7d, 0xf2, 0x59, 0xbf, 0xea, + 0x6e, 0x42, 0x43, 0x27, 0xb5, 0x99, 0x09, 0xd4, 0x75, 0x87, 0xcd, 0x74, 0x6e, 0x79, 0x66, 0xed, + 0xfe, 0x0d, 0x3a, 0xc7, 0xa8, 0xfe, 0xbd, 0xfb, 0xba, 0x74, 0xbf, 0xca, 0xdd, 0xa8, 0x2c, 0x76, + 0xe3, 0xe5, 0x3f, 0x60, 0x3b, 0x10, 0xf1, 0x40, 0x52, 0x25, 0xe4, 0x84, 0x45, 0x74, 0x28, 0x0b, + 0x21, 0x22, 0x36, 0xb4, 0xff, 0xbb, 0x0c, 0xb3, 0xd1, 0xcb, 0xb5, 0x13, 0x03, 0x1e, 0x5a, 0x71, + 0x0e, 0x67, 0xd2, 0xfc, 0x1a, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x6e, 0xfc, 0x59, 0x29, 0x0d, 0x00, + 0x00, +} diff --git a/accounts/usbwallet/trezor/messages-management.proto b/accounts/usbwallet/trezor/messages-management.proto new file mode 100644 index 0000000000..0ab825a1bc --- /dev/null +++ b/accounts/usbwallet/trezor/messages-management.proto @@ -0,0 +1,289 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages-management.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + +syntax = "proto2"; +package hw.trezor.messages.management; + +// Sugar for easier handling in Java +option java_package = "com.satoshilabs.trezor.lib.protobuf"; +option java_outer_classname = "TrezorMessageManagement"; + +import "messages-common.proto"; + +/** + * Request: Reset device to default state and ask for device details + * @start + * @next Features + */ +message Initialize { + optional bytes state = 1; // assumed device state, clear session if set and different + optional bool skip_passphrase = 2; // this session should always assume empty passphrase +} + +/** + * Request: Ask for device details (no device reset) + * @start + * @next Features + */ +message GetFeatures { +} + +/** + * Response: Reports various information about the device + * @end + */ +message Features { + optional string vendor = 1; // name of the manufacturer, e.g. "trezor.io" + optional uint32 major_version = 2; // major version of the firmware/bootloader, e.g. 1 + optional uint32 minor_version = 3; // minor version of the firmware/bootloader, e.g. 0 + optional uint32 patch_version = 4; // patch version of the firmware/bootloader, e.g. 0 + optional bool bootloader_mode = 5; // is device in bootloader mode? + optional string device_id = 6; // device's unique identifier + optional bool pin_protection = 7; // is device protected by PIN? + optional bool passphrase_protection = 8; // is node/mnemonic encrypted using passphrase? + optional string language = 9; // device language + optional string label = 10; // device description label + optional bool initialized = 12; // does device contain seed? + optional bytes revision = 13; // SCM revision of firmware + optional bytes bootloader_hash = 14; // hash of the bootloader + optional bool imported = 15; // was storage imported from an external source? + optional bool pin_cached = 16; // is PIN already cached in session? + optional bool passphrase_cached = 17; // is passphrase already cached in session? + optional bool firmware_present = 18; // is valid firmware loaded? + optional bool needs_backup = 19; // does storage need backup? (equals to Storage.needs_backup) + optional uint32 flags = 20; // device flags (equals to Storage.flags) + optional string model = 21; // device hardware model + optional uint32 fw_major = 22; // reported firmware version if in bootloader mode + optional uint32 fw_minor = 23; // reported firmware version if in bootloader mode + optional uint32 fw_patch = 24; // reported firmware version if in bootloader mode + optional string fw_vendor = 25; // reported firmware vendor if in bootloader mode + optional bytes fw_vendor_keys = 26; // reported firmware vendor keys (their hash) + optional bool unfinished_backup = 27; // report unfinished backup (equals to Storage.unfinished_backup) + optional bool no_backup = 28; // report no backup (equals to Storage.no_backup) +} + +/** + * Request: clear session (removes cached PIN, passphrase, etc). + * @start + * @next Success + */ +message ClearSession { +} + +/** + * Request: change language and/or label of the device + * @start + * @next Success + * @next Failure + */ +message ApplySettings { + optional string language = 1; + optional string label = 2; + optional bool use_passphrase = 3; + optional bytes homescreen = 4; + optional PassphraseSourceType passphrase_source = 5; + optional uint32 auto_lock_delay_ms = 6; + optional uint32 display_rotation = 7; // in degrees from North + /** + * Structure representing passphrase source + */ + enum PassphraseSourceType { + ASK = 0; + DEVICE = 1; + HOST = 2; + } +} + +/** + * Request: set flags of the device + * @start + * @next Success + * @next Failure + */ +message ApplyFlags { + optional uint32 flags = 1; // bitmask, can only set bits, not unset +} + +/** + * Request: Starts workflow for setting/changing/removing the PIN + * @start + * @next Success + * @next Failure + */ +message ChangePin { + optional bool remove = 1; // is PIN removal requested? +} + +/** + * Request: Test if the device is alive, device sends back the message in Success response + * @start + * @next Success + */ +message Ping { + optional string message = 1; // message to send back in Success message + optional bool button_protection = 2; // ask for button press + optional bool pin_protection = 3; // ask for PIN if set in device + optional bool passphrase_protection = 4; // ask for passphrase if set in device +} + +/** + * Request: Abort last operation that required user interaction + * @start + * @next Failure + */ +message Cancel { +} + +/** + * Request: Request a sample of random data generated by hardware RNG. May be used for testing. + * @start + * @next Entropy + * @next Failure + */ +message GetEntropy { + required uint32 size = 1; // size of requested entropy +} + +/** + * Response: Reply with random data generated by internal RNG + * @end + */ +message Entropy { + required bytes entropy = 1; // chunk of random generated bytes +} + +/** + * Request: Request device to wipe all sensitive data and settings + * @start + * @next Success + * @next Failure + */ +message WipeDevice { +} + +/** + * Request: Load seed and related internal settings from the computer + * @start + * @next Success + * @next Failure + */ +message LoadDevice { + optional string mnemonic = 1; // seed encoded as BIP-39 mnemonic (12, 18 or 24 words) + optional hw.trezor.messages.common.HDNodeType node = 2; // BIP-32 node + optional string pin = 3; // set PIN protection + optional bool passphrase_protection = 4; // enable master node encryption using passphrase + optional string language = 5 [default='english']; // device language + optional string label = 6; // device label + optional bool skip_checksum = 7; // do not test mnemonic for valid BIP-39 checksum + optional uint32 u2f_counter = 8; // U2F counter +} + +/** + * Request: Ask device to do initialization involving user interaction + * @start + * @next EntropyRequest + * @next Failure + */ +message ResetDevice { + optional bool display_random = 1; // display entropy generated by the device before asking for additional entropy + optional uint32 strength = 2 [default=256]; // strength of seed in bits + optional bool passphrase_protection = 3; // enable master node encryption using passphrase + optional bool pin_protection = 4; // enable PIN protection + optional string language = 5 [default='english']; // device language + optional string label = 6; // device label + optional uint32 u2f_counter = 7; // U2F counter + optional bool skip_backup = 8; // postpone seed backup to BackupDevice workflow + optional bool no_backup = 9; // indicate that no backup is going to be made +} + +/** + * Request: Perform backup of the device seed if not backed up using ResetDevice + * @start + * @next Success + */ +message BackupDevice { +} + +/** + * Response: Ask for additional entropy from host computer + * @next EntropyAck + */ +message EntropyRequest { +} + +/** + * Request: Provide additional entropy for seed generation function + * @next Success + */ +message EntropyAck { + optional bytes entropy = 1; // 256 bits (32 bytes) of random data +} + +/** + * Request: Start recovery workflow asking user for specific words of mnemonic + * Used to recovery device safely even on untrusted computer. + * @start + * @next WordRequest + */ +message RecoveryDevice { + optional uint32 word_count = 1; // number of words in BIP-39 mnemonic + optional bool passphrase_protection = 2; // enable master node encryption using passphrase + optional bool pin_protection = 3; // enable PIN protection + optional string language = 4 [default='english']; // device language + optional string label = 5; // device label + optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process + // 7 reserved for unused recovery method + optional RecoveryDeviceType type = 8; // supported recovery type + optional uint32 u2f_counter = 9; // U2F counter + optional bool dry_run = 10; // perform dry-run recovery workflow (for safe mnemonic validation) + /** + * Type of recovery procedure. These should be used as bitmask, e.g., + * `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` + * listing every method supported by the host computer. + * + * Note that ScrambledWords must be supported by every implementation + * for backward compatibility; there is no way to not support it. + */ + enum RecoveryDeviceType { + // use powers of two when extending this field + RecoveryDeviceType_ScrambledWords = 0; // words in scrambled order + RecoveryDeviceType_Matrix = 1; // matrix recovery type + } +} + +/** + * Response: Device is waiting for user to enter word of the mnemonic + * Its position is shown only on device's internal display. + * @next WordAck + */ +message WordRequest { + optional WordRequestType type = 1; + /** + * Type of Recovery Word request + */ + enum WordRequestType { + WordRequestType_Plain = 0; + WordRequestType_Matrix9 = 1; + WordRequestType_Matrix6 = 2; + } +} + +/** + * Request: Computer replies with word from the mnemonic + * @next WordRequest + * @next Success + * @next Failure + */ +message WordAck { + required string word = 1; // one word of mnemonic on asked position +} + +/** + * Request: Set U2F counter + * @start + * @next Success + */ +message SetU2FCounter { + optional uint32 u2f_counter = 1; // counter +} diff --git a/accounts/usbwallet/trezor/messages.pb.go b/accounts/usbwallet/trezor/messages.pb.go index 15bb6fb73b..6278bd8ee0 100644 --- a/accounts/usbwallet/trezor/messages.pb.go +++ b/accounts/usbwallet/trezor/messages.pb.go @@ -3,93 +3,242 @@ package trezor -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + math "math" + + proto "github.com/golang/protobuf/proto" + descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf -// * -// Mapping between Trezor wire identifier (uint) and a protobuf message +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +//* +// Mapping between TREZOR wire identifier (uint) and a protobuf message type MessageType int32 const ( - MessageType_MessageType_Initialize MessageType = 0 - MessageType_MessageType_Ping MessageType = 1 - MessageType_MessageType_Success MessageType = 2 - MessageType_MessageType_Failure MessageType = 3 - MessageType_MessageType_ChangePin MessageType = 4 - MessageType_MessageType_WipeDevice MessageType = 5 - MessageType_MessageType_FirmwareErase MessageType = 6 - MessageType_MessageType_FirmwareUpload MessageType = 7 - MessageType_MessageType_FirmwareRequest MessageType = 8 - MessageType_MessageType_GetEntropy MessageType = 9 - MessageType_MessageType_Entropy MessageType = 10 - MessageType_MessageType_GetPublicKey MessageType = 11 - MessageType_MessageType_PublicKey MessageType = 12 - MessageType_MessageType_LoadDevice MessageType = 13 - MessageType_MessageType_ResetDevice MessageType = 14 - MessageType_MessageType_SignTx MessageType = 15 - MessageType_MessageType_SimpleSignTx MessageType = 16 - MessageType_MessageType_Features MessageType = 17 - MessageType_MessageType_PinMatrixRequest MessageType = 18 - MessageType_MessageType_PinMatrixAck MessageType = 19 - MessageType_MessageType_Cancel MessageType = 20 - MessageType_MessageType_TxRequest MessageType = 21 - MessageType_MessageType_TxAck MessageType = 22 - MessageType_MessageType_CipherKeyValue MessageType = 23 - MessageType_MessageType_ClearSession MessageType = 24 - MessageType_MessageType_ApplySettings MessageType = 25 - MessageType_MessageType_ButtonRequest MessageType = 26 - MessageType_MessageType_ButtonAck MessageType = 27 - MessageType_MessageType_ApplyFlags MessageType = 28 - MessageType_MessageType_GetAddress MessageType = 29 - MessageType_MessageType_Address MessageType = 30 - MessageType_MessageType_SelfTest MessageType = 32 - MessageType_MessageType_BackupDevice MessageType = 34 - MessageType_MessageType_EntropyRequest MessageType = 35 - MessageType_MessageType_EntropyAck MessageType = 36 - MessageType_MessageType_SignMessage MessageType = 38 - MessageType_MessageType_VerifyMessage MessageType = 39 - MessageType_MessageType_MessageSignature MessageType = 40 - MessageType_MessageType_PassphraseRequest MessageType = 41 - MessageType_MessageType_PassphraseAck MessageType = 42 - MessageType_MessageType_EstimateTxSize MessageType = 43 - MessageType_MessageType_TxSize MessageType = 44 - MessageType_MessageType_RecoveryDevice MessageType = 45 - MessageType_MessageType_WordRequest MessageType = 46 - MessageType_MessageType_WordAck MessageType = 47 - MessageType_MessageType_CipheredKeyValue MessageType = 48 - MessageType_MessageType_EncryptMessage MessageType = 49 - MessageType_MessageType_EncryptedMessage MessageType = 50 - MessageType_MessageType_DecryptMessage MessageType = 51 - MessageType_MessageType_DecryptedMessage MessageType = 52 - MessageType_MessageType_SignIdentity MessageType = 53 - MessageType_MessageType_SignedIdentity MessageType = 54 - MessageType_MessageType_GetFeatures MessageType = 55 + // Management + MessageType_MessageType_Initialize MessageType = 0 + MessageType_MessageType_Ping MessageType = 1 + MessageType_MessageType_Success MessageType = 2 + MessageType_MessageType_Failure MessageType = 3 + MessageType_MessageType_ChangePin MessageType = 4 + MessageType_MessageType_WipeDevice MessageType = 5 + MessageType_MessageType_GetEntropy MessageType = 9 + MessageType_MessageType_Entropy MessageType = 10 + MessageType_MessageType_LoadDevice MessageType = 13 + MessageType_MessageType_ResetDevice MessageType = 14 + MessageType_MessageType_Features MessageType = 17 + MessageType_MessageType_PinMatrixRequest MessageType = 18 + MessageType_MessageType_PinMatrixAck MessageType = 19 + MessageType_MessageType_Cancel MessageType = 20 + MessageType_MessageType_ClearSession MessageType = 24 + MessageType_MessageType_ApplySettings MessageType = 25 + MessageType_MessageType_ButtonRequest MessageType = 26 + MessageType_MessageType_ButtonAck MessageType = 27 + MessageType_MessageType_ApplyFlags MessageType = 28 + MessageType_MessageType_BackupDevice MessageType = 34 + MessageType_MessageType_EntropyRequest MessageType = 35 + MessageType_MessageType_EntropyAck MessageType = 36 + MessageType_MessageType_PassphraseRequest MessageType = 41 + MessageType_MessageType_PassphraseAck MessageType = 42 + MessageType_MessageType_PassphraseStateRequest MessageType = 77 + MessageType_MessageType_PassphraseStateAck MessageType = 78 + MessageType_MessageType_RecoveryDevice MessageType = 45 + MessageType_MessageType_WordRequest MessageType = 46 + MessageType_MessageType_WordAck MessageType = 47 + MessageType_MessageType_GetFeatures MessageType = 55 + MessageType_MessageType_SetU2FCounter MessageType = 63 + // Bootloader + MessageType_MessageType_FirmwareErase MessageType = 6 + MessageType_MessageType_FirmwareUpload MessageType = 7 + MessageType_MessageType_FirmwareRequest MessageType = 8 + MessageType_MessageType_SelfTest MessageType = 32 + // Bitcoin + MessageType_MessageType_GetPublicKey MessageType = 11 + MessageType_MessageType_PublicKey MessageType = 12 + MessageType_MessageType_SignTx MessageType = 15 + MessageType_MessageType_TxRequest MessageType = 21 + MessageType_MessageType_TxAck MessageType = 22 + MessageType_MessageType_GetAddress MessageType = 29 + MessageType_MessageType_Address MessageType = 30 + MessageType_MessageType_SignMessage MessageType = 38 + MessageType_MessageType_VerifyMessage MessageType = 39 + MessageType_MessageType_MessageSignature MessageType = 40 + // Crypto + MessageType_MessageType_CipherKeyValue MessageType = 23 + MessageType_MessageType_CipheredKeyValue MessageType = 48 + MessageType_MessageType_SignIdentity MessageType = 53 + MessageType_MessageType_SignedIdentity MessageType = 54 + MessageType_MessageType_GetECDHSessionKey MessageType = 61 + MessageType_MessageType_ECDHSessionKey MessageType = 62 + MessageType_MessageType_CosiCommit MessageType = 71 + MessageType_MessageType_CosiCommitment MessageType = 72 + MessageType_MessageType_CosiSign MessageType = 73 + MessageType_MessageType_CosiSignature MessageType = 74 + // Debug + MessageType_MessageType_DebugLinkDecision MessageType = 100 + MessageType_MessageType_DebugLinkGetState MessageType = 101 + MessageType_MessageType_DebugLinkState MessageType = 102 + MessageType_MessageType_DebugLinkStop MessageType = 103 + MessageType_MessageType_DebugLinkLog MessageType = 104 + MessageType_MessageType_DebugLinkMemoryRead MessageType = 110 + MessageType_MessageType_DebugLinkMemory MessageType = 111 + MessageType_MessageType_DebugLinkMemoryWrite MessageType = 112 + MessageType_MessageType_DebugLinkFlashErase MessageType = 113 + // Ethereum + MessageType_MessageType_EthereumGetPublicKey MessageType = 450 + MessageType_MessageType_EthereumPublicKey MessageType = 451 MessageType_MessageType_EthereumGetAddress MessageType = 56 MessageType_MessageType_EthereumAddress MessageType = 57 MessageType_MessageType_EthereumSignTx MessageType = 58 MessageType_MessageType_EthereumTxRequest MessageType = 59 MessageType_MessageType_EthereumTxAck MessageType = 60 - MessageType_MessageType_GetECDHSessionKey MessageType = 61 - MessageType_MessageType_ECDHSessionKey MessageType = 62 - MessageType_MessageType_SetU2FCounter MessageType = 63 MessageType_MessageType_EthereumSignMessage MessageType = 64 MessageType_MessageType_EthereumVerifyMessage MessageType = 65 MessageType_MessageType_EthereumMessageSignature MessageType = 66 - MessageType_MessageType_DebugLinkDecision MessageType = 100 - MessageType_MessageType_DebugLinkGetState MessageType = 101 - MessageType_MessageType_DebugLinkState MessageType = 102 - MessageType_MessageType_DebugLinkStop MessageType = 103 - MessageType_MessageType_DebugLinkLog MessageType = 104 - MessageType_MessageType_DebugLinkMemoryRead MessageType = 110 - MessageType_MessageType_DebugLinkMemory MessageType = 111 - MessageType_MessageType_DebugLinkMemoryWrite MessageType = 112 - MessageType_MessageType_DebugLinkFlashErase MessageType = 113 + // NEM + MessageType_MessageType_NEMGetAddress MessageType = 67 + MessageType_MessageType_NEMAddress MessageType = 68 + MessageType_MessageType_NEMSignTx MessageType = 69 + MessageType_MessageType_NEMSignedTx MessageType = 70 + MessageType_MessageType_NEMDecryptMessage MessageType = 75 + MessageType_MessageType_NEMDecryptedMessage MessageType = 76 + // Lisk + MessageType_MessageType_LiskGetAddress MessageType = 114 + MessageType_MessageType_LiskAddress MessageType = 115 + MessageType_MessageType_LiskSignTx MessageType = 116 + MessageType_MessageType_LiskSignedTx MessageType = 117 + MessageType_MessageType_LiskSignMessage MessageType = 118 + MessageType_MessageType_LiskMessageSignature MessageType = 119 + MessageType_MessageType_LiskVerifyMessage MessageType = 120 + MessageType_MessageType_LiskGetPublicKey MessageType = 121 + MessageType_MessageType_LiskPublicKey MessageType = 122 + // Tezos + MessageType_MessageType_TezosGetAddress MessageType = 150 + MessageType_MessageType_TezosAddress MessageType = 151 + MessageType_MessageType_TezosSignTx MessageType = 152 + MessageType_MessageType_TezosSignedTx MessageType = 153 + MessageType_MessageType_TezosGetPublicKey MessageType = 154 + MessageType_MessageType_TezosPublicKey MessageType = 155 + // Stellar + MessageType_MessageType_StellarSignTx MessageType = 202 + MessageType_MessageType_StellarTxOpRequest MessageType = 203 + MessageType_MessageType_StellarGetAddress MessageType = 207 + MessageType_MessageType_StellarAddress MessageType = 208 + MessageType_MessageType_StellarCreateAccountOp MessageType = 210 + MessageType_MessageType_StellarPaymentOp MessageType = 211 + MessageType_MessageType_StellarPathPaymentOp MessageType = 212 + MessageType_MessageType_StellarManageOfferOp MessageType = 213 + MessageType_MessageType_StellarCreatePassiveOfferOp MessageType = 214 + MessageType_MessageType_StellarSetOptionsOp MessageType = 215 + MessageType_MessageType_StellarChangeTrustOp MessageType = 216 + MessageType_MessageType_StellarAllowTrustOp MessageType = 217 + MessageType_MessageType_StellarAccountMergeOp MessageType = 218 + // omitted: StellarInflationOp is not a supported operation, would be 219 + MessageType_MessageType_StellarManageDataOp MessageType = 220 + MessageType_MessageType_StellarBumpSequenceOp MessageType = 221 + MessageType_MessageType_StellarSignedTx MessageType = 230 + // TRON + MessageType_MessageType_TronGetAddress MessageType = 250 + MessageType_MessageType_TronAddress MessageType = 251 + MessageType_MessageType_TronSignTx MessageType = 252 + MessageType_MessageType_TronSignedTx MessageType = 253 + // Cardano + // dropped Sign/VerifyMessage ids 300-302 + MessageType_MessageType_CardanoSignTx MessageType = 303 + MessageType_MessageType_CardanoTxRequest MessageType = 304 + MessageType_MessageType_CardanoGetPublicKey MessageType = 305 + MessageType_MessageType_CardanoPublicKey MessageType = 306 + MessageType_MessageType_CardanoGetAddress MessageType = 307 + MessageType_MessageType_CardanoAddress MessageType = 308 + MessageType_MessageType_CardanoTxAck MessageType = 309 + MessageType_MessageType_CardanoSignedTx MessageType = 310 + // Ontology + MessageType_MessageType_OntologyGetAddress MessageType = 350 + MessageType_MessageType_OntologyAddress MessageType = 351 + MessageType_MessageType_OntologyGetPublicKey MessageType = 352 + MessageType_MessageType_OntologyPublicKey MessageType = 353 + MessageType_MessageType_OntologySignTransfer MessageType = 354 + MessageType_MessageType_OntologySignedTransfer MessageType = 355 + MessageType_MessageType_OntologySignWithdrawOng MessageType = 356 + MessageType_MessageType_OntologySignedWithdrawOng MessageType = 357 + MessageType_MessageType_OntologySignOntIdRegister MessageType = 358 + MessageType_MessageType_OntologySignedOntIdRegister MessageType = 359 + MessageType_MessageType_OntologySignOntIdAddAttributes MessageType = 360 + MessageType_MessageType_OntologySignedOntIdAddAttributes MessageType = 361 + // Ripple + MessageType_MessageType_RippleGetAddress MessageType = 400 + MessageType_MessageType_RippleAddress MessageType = 401 + MessageType_MessageType_RippleSignTx MessageType = 402 + MessageType_MessageType_RippleSignedTx MessageType = 403 + // Monero + MessageType_MessageType_MoneroTransactionInitRequest MessageType = 501 + MessageType_MessageType_MoneroTransactionInitAck MessageType = 502 + MessageType_MessageType_MoneroTransactionSetInputRequest MessageType = 503 + MessageType_MessageType_MoneroTransactionSetInputAck MessageType = 504 + MessageType_MessageType_MoneroTransactionInputsPermutationRequest MessageType = 505 + MessageType_MessageType_MoneroTransactionInputsPermutationAck MessageType = 506 + MessageType_MessageType_MoneroTransactionInputViniRequest MessageType = 507 + MessageType_MessageType_MoneroTransactionInputViniAck MessageType = 508 + MessageType_MessageType_MoneroTransactionAllInputsSetRequest MessageType = 509 + MessageType_MessageType_MoneroTransactionAllInputsSetAck MessageType = 510 + MessageType_MessageType_MoneroTransactionSetOutputRequest MessageType = 511 + MessageType_MessageType_MoneroTransactionSetOutputAck MessageType = 512 + MessageType_MessageType_MoneroTransactionAllOutSetRequest MessageType = 513 + MessageType_MessageType_MoneroTransactionAllOutSetAck MessageType = 514 + MessageType_MessageType_MoneroTransactionSignInputRequest MessageType = 515 + MessageType_MessageType_MoneroTransactionSignInputAck MessageType = 516 + MessageType_MessageType_MoneroTransactionFinalRequest MessageType = 517 + MessageType_MessageType_MoneroTransactionFinalAck MessageType = 518 + MessageType_MessageType_MoneroKeyImageExportInitRequest MessageType = 530 + MessageType_MessageType_MoneroKeyImageExportInitAck MessageType = 531 + MessageType_MessageType_MoneroKeyImageSyncStepRequest MessageType = 532 + MessageType_MessageType_MoneroKeyImageSyncStepAck MessageType = 533 + MessageType_MessageType_MoneroKeyImageSyncFinalRequest MessageType = 534 + MessageType_MessageType_MoneroKeyImageSyncFinalAck MessageType = 535 + MessageType_MessageType_MoneroGetAddress MessageType = 540 + MessageType_MessageType_MoneroAddress MessageType = 541 + MessageType_MessageType_MoneroGetWatchKey MessageType = 542 + MessageType_MessageType_MoneroWatchKey MessageType = 543 + MessageType_MessageType_DebugMoneroDiagRequest MessageType = 546 + MessageType_MessageType_DebugMoneroDiagAck MessageType = 547 + MessageType_MessageType_MoneroGetTxKeyRequest MessageType = 550 + MessageType_MessageType_MoneroGetTxKeyAck MessageType = 551 + MessageType_MessageType_MoneroLiveRefreshStartRequest MessageType = 552 + MessageType_MessageType_MoneroLiveRefreshStartAck MessageType = 553 + MessageType_MessageType_MoneroLiveRefreshStepRequest MessageType = 554 + MessageType_MessageType_MoneroLiveRefreshStepAck MessageType = 555 + MessageType_MessageType_MoneroLiveRefreshFinalRequest MessageType = 556 + MessageType_MessageType_MoneroLiveRefreshFinalAck MessageType = 557 + // EOS + MessageType_MessageType_EosGetPublicKey MessageType = 600 + MessageType_MessageType_EosPublicKey MessageType = 601 + MessageType_MessageType_EosSignTx MessageType = 602 + MessageType_MessageType_EosTxActionRequest MessageType = 603 + MessageType_MessageType_EosTxActionAck MessageType = 604 + MessageType_MessageType_EosSignedTx MessageType = 605 + // Binance + MessageType_MessageType_BinanceGetAddress MessageType = 700 + MessageType_MessageType_BinanceAddress MessageType = 701 + MessageType_MessageType_BinanceGetPublicKey MessageType = 702 + MessageType_MessageType_BinancePublicKey MessageType = 703 + MessageType_MessageType_BinanceSignTx MessageType = 704 + MessageType_MessageType_BinanceTxRequest MessageType = 705 + MessageType_MessageType_BinanceTransferMsg MessageType = 706 + MessageType_MessageType_BinanceOrderMsg MessageType = 707 + MessageType_MessageType_BinanceCancelMsg MessageType = 708 + MessageType_MessageType_BinanceSignedTx MessageType = 709 ) var MessageType_name = map[int32]string{ @@ -99,64 +248,55 @@ var MessageType_name = map[int32]string{ 3: "MessageType_Failure", 4: "MessageType_ChangePin", 5: "MessageType_WipeDevice", - 6: "MessageType_FirmwareErase", - 7: "MessageType_FirmwareUpload", - 8: "MessageType_FirmwareRequest", 9: "MessageType_GetEntropy", 10: "MessageType_Entropy", - 11: "MessageType_GetPublicKey", - 12: "MessageType_PublicKey", 13: "MessageType_LoadDevice", 14: "MessageType_ResetDevice", - 15: "MessageType_SignTx", - 16: "MessageType_SimpleSignTx", 17: "MessageType_Features", 18: "MessageType_PinMatrixRequest", 19: "MessageType_PinMatrixAck", 20: "MessageType_Cancel", - 21: "MessageType_TxRequest", - 22: "MessageType_TxAck", - 23: "MessageType_CipherKeyValue", 24: "MessageType_ClearSession", 25: "MessageType_ApplySettings", 26: "MessageType_ButtonRequest", 27: "MessageType_ButtonAck", 28: "MessageType_ApplyFlags", - 29: "MessageType_GetAddress", - 30: "MessageType_Address", - 32: "MessageType_SelfTest", 34: "MessageType_BackupDevice", 35: "MessageType_EntropyRequest", 36: "MessageType_EntropyAck", - 38: "MessageType_SignMessage", - 39: "MessageType_VerifyMessage", - 40: "MessageType_MessageSignature", 41: "MessageType_PassphraseRequest", 42: "MessageType_PassphraseAck", - 43: "MessageType_EstimateTxSize", - 44: "MessageType_TxSize", + 77: "MessageType_PassphraseStateRequest", + 78: "MessageType_PassphraseStateAck", 45: "MessageType_RecoveryDevice", 46: "MessageType_WordRequest", 47: "MessageType_WordAck", + 55: "MessageType_GetFeatures", + 63: "MessageType_SetU2FCounter", + 6: "MessageType_FirmwareErase", + 7: "MessageType_FirmwareUpload", + 8: "MessageType_FirmwareRequest", + 32: "MessageType_SelfTest", + 11: "MessageType_GetPublicKey", + 12: "MessageType_PublicKey", + 15: "MessageType_SignTx", + 21: "MessageType_TxRequest", + 22: "MessageType_TxAck", + 29: "MessageType_GetAddress", + 30: "MessageType_Address", + 38: "MessageType_SignMessage", + 39: "MessageType_VerifyMessage", + 40: "MessageType_MessageSignature", + 23: "MessageType_CipherKeyValue", 48: "MessageType_CipheredKeyValue", - 49: "MessageType_EncryptMessage", - 50: "MessageType_EncryptedMessage", - 51: "MessageType_DecryptMessage", - 52: "MessageType_DecryptedMessage", 53: "MessageType_SignIdentity", 54: "MessageType_SignedIdentity", - 55: "MessageType_GetFeatures", - 56: "MessageType_EthereumGetAddress", - 57: "MessageType_EthereumAddress", - 58: "MessageType_EthereumSignTx", - 59: "MessageType_EthereumTxRequest", - 60: "MessageType_EthereumTxAck", 61: "MessageType_GetECDHSessionKey", 62: "MessageType_ECDHSessionKey", - 63: "MessageType_SetU2FCounter", - 64: "MessageType_EthereumSignMessage", - 65: "MessageType_EthereumVerifyMessage", - 66: "MessageType_EthereumMessageSignature", + 71: "MessageType_CosiCommit", + 72: "MessageType_CosiCommitment", + 73: "MessageType_CosiSign", + 74: "MessageType_CosiSignature", 100: "MessageType_DebugLinkDecision", 101: "MessageType_DebugLinkGetState", 102: "MessageType_DebugLinkState", @@ -166,81 +306,331 @@ var MessageType_name = map[int32]string{ 111: "MessageType_DebugLinkMemory", 112: "MessageType_DebugLinkMemoryWrite", 113: "MessageType_DebugLinkFlashErase", + 450: "MessageType_EthereumGetPublicKey", + 451: "MessageType_EthereumPublicKey", + 56: "MessageType_EthereumGetAddress", + 57: "MessageType_EthereumAddress", + 58: "MessageType_EthereumSignTx", + 59: "MessageType_EthereumTxRequest", + 60: "MessageType_EthereumTxAck", + 64: "MessageType_EthereumSignMessage", + 65: "MessageType_EthereumVerifyMessage", + 66: "MessageType_EthereumMessageSignature", + 67: "MessageType_NEMGetAddress", + 68: "MessageType_NEMAddress", + 69: "MessageType_NEMSignTx", + 70: "MessageType_NEMSignedTx", + 75: "MessageType_NEMDecryptMessage", + 76: "MessageType_NEMDecryptedMessage", + 114: "MessageType_LiskGetAddress", + 115: "MessageType_LiskAddress", + 116: "MessageType_LiskSignTx", + 117: "MessageType_LiskSignedTx", + 118: "MessageType_LiskSignMessage", + 119: "MessageType_LiskMessageSignature", + 120: "MessageType_LiskVerifyMessage", + 121: "MessageType_LiskGetPublicKey", + 122: "MessageType_LiskPublicKey", + 150: "MessageType_TezosGetAddress", + 151: "MessageType_TezosAddress", + 152: "MessageType_TezosSignTx", + 153: "MessageType_TezosSignedTx", + 154: "MessageType_TezosGetPublicKey", + 155: "MessageType_TezosPublicKey", + 202: "MessageType_StellarSignTx", + 203: "MessageType_StellarTxOpRequest", + 207: "MessageType_StellarGetAddress", + 208: "MessageType_StellarAddress", + 210: "MessageType_StellarCreateAccountOp", + 211: "MessageType_StellarPaymentOp", + 212: "MessageType_StellarPathPaymentOp", + 213: "MessageType_StellarManageOfferOp", + 214: "MessageType_StellarCreatePassiveOfferOp", + 215: "MessageType_StellarSetOptionsOp", + 216: "MessageType_StellarChangeTrustOp", + 217: "MessageType_StellarAllowTrustOp", + 218: "MessageType_StellarAccountMergeOp", + 220: "MessageType_StellarManageDataOp", + 221: "MessageType_StellarBumpSequenceOp", + 230: "MessageType_StellarSignedTx", + 250: "MessageType_TronGetAddress", + 251: "MessageType_TronAddress", + 252: "MessageType_TronSignTx", + 253: "MessageType_TronSignedTx", + 303: "MessageType_CardanoSignTx", + 304: "MessageType_CardanoTxRequest", + 305: "MessageType_CardanoGetPublicKey", + 306: "MessageType_CardanoPublicKey", + 307: "MessageType_CardanoGetAddress", + 308: "MessageType_CardanoAddress", + 309: "MessageType_CardanoTxAck", + 310: "MessageType_CardanoSignedTx", + 350: "MessageType_OntologyGetAddress", + 351: "MessageType_OntologyAddress", + 352: "MessageType_OntologyGetPublicKey", + 353: "MessageType_OntologyPublicKey", + 354: "MessageType_OntologySignTransfer", + 355: "MessageType_OntologySignedTransfer", + 356: "MessageType_OntologySignWithdrawOng", + 357: "MessageType_OntologySignedWithdrawOng", + 358: "MessageType_OntologySignOntIdRegister", + 359: "MessageType_OntologySignedOntIdRegister", + 360: "MessageType_OntologySignOntIdAddAttributes", + 361: "MessageType_OntologySignedOntIdAddAttributes", + 400: "MessageType_RippleGetAddress", + 401: "MessageType_RippleAddress", + 402: "MessageType_RippleSignTx", + 403: "MessageType_RippleSignedTx", + 501: "MessageType_MoneroTransactionInitRequest", + 502: "MessageType_MoneroTransactionInitAck", + 503: "MessageType_MoneroTransactionSetInputRequest", + 504: "MessageType_MoneroTransactionSetInputAck", + 505: "MessageType_MoneroTransactionInputsPermutationRequest", + 506: "MessageType_MoneroTransactionInputsPermutationAck", + 507: "MessageType_MoneroTransactionInputViniRequest", + 508: "MessageType_MoneroTransactionInputViniAck", + 509: "MessageType_MoneroTransactionAllInputsSetRequest", + 510: "MessageType_MoneroTransactionAllInputsSetAck", + 511: "MessageType_MoneroTransactionSetOutputRequest", + 512: "MessageType_MoneroTransactionSetOutputAck", + 513: "MessageType_MoneroTransactionAllOutSetRequest", + 514: "MessageType_MoneroTransactionAllOutSetAck", + 515: "MessageType_MoneroTransactionSignInputRequest", + 516: "MessageType_MoneroTransactionSignInputAck", + 517: "MessageType_MoneroTransactionFinalRequest", + 518: "MessageType_MoneroTransactionFinalAck", + 530: "MessageType_MoneroKeyImageExportInitRequest", + 531: "MessageType_MoneroKeyImageExportInitAck", + 532: "MessageType_MoneroKeyImageSyncStepRequest", + 533: "MessageType_MoneroKeyImageSyncStepAck", + 534: "MessageType_MoneroKeyImageSyncFinalRequest", + 535: "MessageType_MoneroKeyImageSyncFinalAck", + 540: "MessageType_MoneroGetAddress", + 541: "MessageType_MoneroAddress", + 542: "MessageType_MoneroGetWatchKey", + 543: "MessageType_MoneroWatchKey", + 546: "MessageType_DebugMoneroDiagRequest", + 547: "MessageType_DebugMoneroDiagAck", + 550: "MessageType_MoneroGetTxKeyRequest", + 551: "MessageType_MoneroGetTxKeyAck", + 552: "MessageType_MoneroLiveRefreshStartRequest", + 553: "MessageType_MoneroLiveRefreshStartAck", + 554: "MessageType_MoneroLiveRefreshStepRequest", + 555: "MessageType_MoneroLiveRefreshStepAck", + 556: "MessageType_MoneroLiveRefreshFinalRequest", + 557: "MessageType_MoneroLiveRefreshFinalAck", + 600: "MessageType_EosGetPublicKey", + 601: "MessageType_EosPublicKey", + 602: "MessageType_EosSignTx", + 603: "MessageType_EosTxActionRequest", + 604: "MessageType_EosTxActionAck", + 605: "MessageType_EosSignedTx", + 700: "MessageType_BinanceGetAddress", + 701: "MessageType_BinanceAddress", + 702: "MessageType_BinanceGetPublicKey", + 703: "MessageType_BinancePublicKey", + 704: "MessageType_BinanceSignTx", + 705: "MessageType_BinanceTxRequest", + 706: "MessageType_BinanceTransferMsg", + 707: "MessageType_BinanceOrderMsg", + 708: "MessageType_BinanceCancelMsg", + 709: "MessageType_BinanceSignedTx", } + var MessageType_value = map[string]int32{ - "MessageType_Initialize": 0, - "MessageType_Ping": 1, - "MessageType_Success": 2, - "MessageType_Failure": 3, - "MessageType_ChangePin": 4, - "MessageType_WipeDevice": 5, - "MessageType_FirmwareErase": 6, - "MessageType_FirmwareUpload": 7, - "MessageType_FirmwareRequest": 8, - "MessageType_GetEntropy": 9, - "MessageType_Entropy": 10, - "MessageType_GetPublicKey": 11, - "MessageType_PublicKey": 12, - "MessageType_LoadDevice": 13, - "MessageType_ResetDevice": 14, - "MessageType_SignTx": 15, - "MessageType_SimpleSignTx": 16, - "MessageType_Features": 17, - "MessageType_PinMatrixRequest": 18, - "MessageType_PinMatrixAck": 19, - "MessageType_Cancel": 20, - "MessageType_TxRequest": 21, - "MessageType_TxAck": 22, - "MessageType_CipherKeyValue": 23, - "MessageType_ClearSession": 24, - "MessageType_ApplySettings": 25, - "MessageType_ButtonRequest": 26, - "MessageType_ButtonAck": 27, - "MessageType_ApplyFlags": 28, - "MessageType_GetAddress": 29, - "MessageType_Address": 30, - "MessageType_SelfTest": 32, - "MessageType_BackupDevice": 34, - "MessageType_EntropyRequest": 35, - "MessageType_EntropyAck": 36, - "MessageType_SignMessage": 38, - "MessageType_VerifyMessage": 39, - "MessageType_MessageSignature": 40, - "MessageType_PassphraseRequest": 41, - "MessageType_PassphraseAck": 42, - "MessageType_EstimateTxSize": 43, - "MessageType_TxSize": 44, - "MessageType_RecoveryDevice": 45, - "MessageType_WordRequest": 46, - "MessageType_WordAck": 47, - "MessageType_CipheredKeyValue": 48, - "MessageType_EncryptMessage": 49, - "MessageType_EncryptedMessage": 50, - "MessageType_DecryptMessage": 51, - "MessageType_DecryptedMessage": 52, - "MessageType_SignIdentity": 53, - "MessageType_SignedIdentity": 54, - "MessageType_GetFeatures": 55, - "MessageType_EthereumGetAddress": 56, - "MessageType_EthereumAddress": 57, - "MessageType_EthereumSignTx": 58, - "MessageType_EthereumTxRequest": 59, - "MessageType_EthereumTxAck": 60, - "MessageType_GetECDHSessionKey": 61, - "MessageType_ECDHSessionKey": 62, - "MessageType_SetU2FCounter": 63, - "MessageType_EthereumSignMessage": 64, - "MessageType_EthereumVerifyMessage": 65, - "MessageType_EthereumMessageSignature": 66, - "MessageType_DebugLinkDecision": 100, - "MessageType_DebugLinkGetState": 101, - "MessageType_DebugLinkState": 102, - "MessageType_DebugLinkStop": 103, - "MessageType_DebugLinkLog": 104, - "MessageType_DebugLinkMemoryRead": 110, - "MessageType_DebugLinkMemory": 111, - "MessageType_DebugLinkMemoryWrite": 112, - "MessageType_DebugLinkFlashErase": 113, + "MessageType_Initialize": 0, + "MessageType_Ping": 1, + "MessageType_Success": 2, + "MessageType_Failure": 3, + "MessageType_ChangePin": 4, + "MessageType_WipeDevice": 5, + "MessageType_GetEntropy": 9, + "MessageType_Entropy": 10, + "MessageType_LoadDevice": 13, + "MessageType_ResetDevice": 14, + "MessageType_Features": 17, + "MessageType_PinMatrixRequest": 18, + "MessageType_PinMatrixAck": 19, + "MessageType_Cancel": 20, + "MessageType_ClearSession": 24, + "MessageType_ApplySettings": 25, + "MessageType_ButtonRequest": 26, + "MessageType_ButtonAck": 27, + "MessageType_ApplyFlags": 28, + "MessageType_BackupDevice": 34, + "MessageType_EntropyRequest": 35, + "MessageType_EntropyAck": 36, + "MessageType_PassphraseRequest": 41, + "MessageType_PassphraseAck": 42, + "MessageType_PassphraseStateRequest": 77, + "MessageType_PassphraseStateAck": 78, + "MessageType_RecoveryDevice": 45, + "MessageType_WordRequest": 46, + "MessageType_WordAck": 47, + "MessageType_GetFeatures": 55, + "MessageType_SetU2FCounter": 63, + "MessageType_FirmwareErase": 6, + "MessageType_FirmwareUpload": 7, + "MessageType_FirmwareRequest": 8, + "MessageType_SelfTest": 32, + "MessageType_GetPublicKey": 11, + "MessageType_PublicKey": 12, + "MessageType_SignTx": 15, + "MessageType_TxRequest": 21, + "MessageType_TxAck": 22, + "MessageType_GetAddress": 29, + "MessageType_Address": 30, + "MessageType_SignMessage": 38, + "MessageType_VerifyMessage": 39, + "MessageType_MessageSignature": 40, + "MessageType_CipherKeyValue": 23, + "MessageType_CipheredKeyValue": 48, + "MessageType_SignIdentity": 53, + "MessageType_SignedIdentity": 54, + "MessageType_GetECDHSessionKey": 61, + "MessageType_ECDHSessionKey": 62, + "MessageType_CosiCommit": 71, + "MessageType_CosiCommitment": 72, + "MessageType_CosiSign": 73, + "MessageType_CosiSignature": 74, + "MessageType_DebugLinkDecision": 100, + "MessageType_DebugLinkGetState": 101, + "MessageType_DebugLinkState": 102, + "MessageType_DebugLinkStop": 103, + "MessageType_DebugLinkLog": 104, + "MessageType_DebugLinkMemoryRead": 110, + "MessageType_DebugLinkMemory": 111, + "MessageType_DebugLinkMemoryWrite": 112, + "MessageType_DebugLinkFlashErase": 113, + "MessageType_EthereumGetPublicKey": 450, + "MessageType_EthereumPublicKey": 451, + "MessageType_EthereumGetAddress": 56, + "MessageType_EthereumAddress": 57, + "MessageType_EthereumSignTx": 58, + "MessageType_EthereumTxRequest": 59, + "MessageType_EthereumTxAck": 60, + "MessageType_EthereumSignMessage": 64, + "MessageType_EthereumVerifyMessage": 65, + "MessageType_EthereumMessageSignature": 66, + "MessageType_NEMGetAddress": 67, + "MessageType_NEMAddress": 68, + "MessageType_NEMSignTx": 69, + "MessageType_NEMSignedTx": 70, + "MessageType_NEMDecryptMessage": 75, + "MessageType_NEMDecryptedMessage": 76, + "MessageType_LiskGetAddress": 114, + "MessageType_LiskAddress": 115, + "MessageType_LiskSignTx": 116, + "MessageType_LiskSignedTx": 117, + "MessageType_LiskSignMessage": 118, + "MessageType_LiskMessageSignature": 119, + "MessageType_LiskVerifyMessage": 120, + "MessageType_LiskGetPublicKey": 121, + "MessageType_LiskPublicKey": 122, + "MessageType_TezosGetAddress": 150, + "MessageType_TezosAddress": 151, + "MessageType_TezosSignTx": 152, + "MessageType_TezosSignedTx": 153, + "MessageType_TezosGetPublicKey": 154, + "MessageType_TezosPublicKey": 155, + "MessageType_StellarSignTx": 202, + "MessageType_StellarTxOpRequest": 203, + "MessageType_StellarGetAddress": 207, + "MessageType_StellarAddress": 208, + "MessageType_StellarCreateAccountOp": 210, + "MessageType_StellarPaymentOp": 211, + "MessageType_StellarPathPaymentOp": 212, + "MessageType_StellarManageOfferOp": 213, + "MessageType_StellarCreatePassiveOfferOp": 214, + "MessageType_StellarSetOptionsOp": 215, + "MessageType_StellarChangeTrustOp": 216, + "MessageType_StellarAllowTrustOp": 217, + "MessageType_StellarAccountMergeOp": 218, + "MessageType_StellarManageDataOp": 220, + "MessageType_StellarBumpSequenceOp": 221, + "MessageType_StellarSignedTx": 230, + "MessageType_TronGetAddress": 250, + "MessageType_TronAddress": 251, + "MessageType_TronSignTx": 252, + "MessageType_TronSignedTx": 253, + "MessageType_CardanoSignTx": 303, + "MessageType_CardanoTxRequest": 304, + "MessageType_CardanoGetPublicKey": 305, + "MessageType_CardanoPublicKey": 306, + "MessageType_CardanoGetAddress": 307, + "MessageType_CardanoAddress": 308, + "MessageType_CardanoTxAck": 309, + "MessageType_CardanoSignedTx": 310, + "MessageType_OntologyGetAddress": 350, + "MessageType_OntologyAddress": 351, + "MessageType_OntologyGetPublicKey": 352, + "MessageType_OntologyPublicKey": 353, + "MessageType_OntologySignTransfer": 354, + "MessageType_OntologySignedTransfer": 355, + "MessageType_OntologySignWithdrawOng": 356, + "MessageType_OntologySignedWithdrawOng": 357, + "MessageType_OntologySignOntIdRegister": 358, + "MessageType_OntologySignedOntIdRegister": 359, + "MessageType_OntologySignOntIdAddAttributes": 360, + "MessageType_OntologySignedOntIdAddAttributes": 361, + "MessageType_RippleGetAddress": 400, + "MessageType_RippleAddress": 401, + "MessageType_RippleSignTx": 402, + "MessageType_RippleSignedTx": 403, + "MessageType_MoneroTransactionInitRequest": 501, + "MessageType_MoneroTransactionInitAck": 502, + "MessageType_MoneroTransactionSetInputRequest": 503, + "MessageType_MoneroTransactionSetInputAck": 504, + "MessageType_MoneroTransactionInputsPermutationRequest": 505, + "MessageType_MoneroTransactionInputsPermutationAck": 506, + "MessageType_MoneroTransactionInputViniRequest": 507, + "MessageType_MoneroTransactionInputViniAck": 508, + "MessageType_MoneroTransactionAllInputsSetRequest": 509, + "MessageType_MoneroTransactionAllInputsSetAck": 510, + "MessageType_MoneroTransactionSetOutputRequest": 511, + "MessageType_MoneroTransactionSetOutputAck": 512, + "MessageType_MoneroTransactionAllOutSetRequest": 513, + "MessageType_MoneroTransactionAllOutSetAck": 514, + "MessageType_MoneroTransactionSignInputRequest": 515, + "MessageType_MoneroTransactionSignInputAck": 516, + "MessageType_MoneroTransactionFinalRequest": 517, + "MessageType_MoneroTransactionFinalAck": 518, + "MessageType_MoneroKeyImageExportInitRequest": 530, + "MessageType_MoneroKeyImageExportInitAck": 531, + "MessageType_MoneroKeyImageSyncStepRequest": 532, + "MessageType_MoneroKeyImageSyncStepAck": 533, + "MessageType_MoneroKeyImageSyncFinalRequest": 534, + "MessageType_MoneroKeyImageSyncFinalAck": 535, + "MessageType_MoneroGetAddress": 540, + "MessageType_MoneroAddress": 541, + "MessageType_MoneroGetWatchKey": 542, + "MessageType_MoneroWatchKey": 543, + "MessageType_DebugMoneroDiagRequest": 546, + "MessageType_DebugMoneroDiagAck": 547, + "MessageType_MoneroGetTxKeyRequest": 550, + "MessageType_MoneroGetTxKeyAck": 551, + "MessageType_MoneroLiveRefreshStartRequest": 552, + "MessageType_MoneroLiveRefreshStartAck": 553, + "MessageType_MoneroLiveRefreshStepRequest": 554, + "MessageType_MoneroLiveRefreshStepAck": 555, + "MessageType_MoneroLiveRefreshFinalRequest": 556, + "MessageType_MoneroLiveRefreshFinalAck": 557, + "MessageType_EosGetPublicKey": 600, + "MessageType_EosPublicKey": 601, + "MessageType_EosSignTx": 602, + "MessageType_EosTxActionRequest": 603, + "MessageType_EosTxActionAck": 604, + "MessageType_EosSignedTx": 605, + "MessageType_BinanceGetAddress": 700, + "MessageType_BinanceAddress": 701, + "MessageType_BinanceGetPublicKey": 702, + "MessageType_BinancePublicKey": 703, + "MessageType_BinanceSignTx": 704, + "MessageType_BinanceTxRequest": 705, + "MessageType_BinanceTransferMsg": 706, + "MessageType_BinanceOrderMsg": 707, + "MessageType_BinanceCancelMsg": 708, + "MessageType_BinanceSignedTx": 709, } func (x MessageType) Enum() *MessageType { @@ -248,9 +638,11 @@ func (x MessageType) Enum() *MessageType { *p = x return p } + func (x MessageType) String() string { return proto.EnumName(MessageType_name, int32(x)) } + func (x *MessageType) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(MessageType_value, data, "MessageType") if err != nil { @@ -259,2823 +651,239 @@ func (x *MessageType) UnmarshalJSON(data []byte) error { *x = MessageType(value) return nil } -func (MessageType) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } -// * -// Request: Reset device to default state and ask for device details -// @next Features -type Initialize struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *Initialize) Reset() { *m = Initialize{} } -func (m *Initialize) String() string { return proto.CompactTextString(m) } -func (*Initialize) ProtoMessage() {} -func (*Initialize) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } - -// * -// Request: Ask for device details (no device reset) -// @next Features -type GetFeatures struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *GetFeatures) Reset() { *m = GetFeatures{} } -func (m *GetFeatures) String() string { return proto.CompactTextString(m) } -func (*GetFeatures) ProtoMessage() {} -func (*GetFeatures) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } - -// * -// Response: Reports various information about the device -// @prev Initialize -// @prev GetFeatures -type Features struct { - Vendor *string `protobuf:"bytes,1,opt,name=vendor" json:"vendor,omitempty"` - MajorVersion *uint32 `protobuf:"varint,2,opt,name=major_version,json=majorVersion" json:"major_version,omitempty"` - MinorVersion *uint32 `protobuf:"varint,3,opt,name=minor_version,json=minorVersion" json:"minor_version,omitempty"` - PatchVersion *uint32 `protobuf:"varint,4,opt,name=patch_version,json=patchVersion" json:"patch_version,omitempty"` - BootloaderMode *bool `protobuf:"varint,5,opt,name=bootloader_mode,json=bootloaderMode" json:"bootloader_mode,omitempty"` - DeviceId *string `protobuf:"bytes,6,opt,name=device_id,json=deviceId" json:"device_id,omitempty"` - PinProtection *bool `protobuf:"varint,7,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - PassphraseProtection *bool `protobuf:"varint,8,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - Language *string `protobuf:"bytes,9,opt,name=language" json:"language,omitempty"` - Label *string `protobuf:"bytes,10,opt,name=label" json:"label,omitempty"` - Coins []*CoinType `protobuf:"bytes,11,rep,name=coins" json:"coins,omitempty"` - Initialized *bool `protobuf:"varint,12,opt,name=initialized" json:"initialized,omitempty"` - Revision []byte `protobuf:"bytes,13,opt,name=revision" json:"revision,omitempty"` - BootloaderHash []byte `protobuf:"bytes,14,opt,name=bootloader_hash,json=bootloaderHash" json:"bootloader_hash,omitempty"` - Imported *bool `protobuf:"varint,15,opt,name=imported" json:"imported,omitempty"` - PinCached *bool `protobuf:"varint,16,opt,name=pin_cached,json=pinCached" json:"pin_cached,omitempty"` - PassphraseCached *bool `protobuf:"varint,17,opt,name=passphrase_cached,json=passphraseCached" json:"passphrase_cached,omitempty"` - FirmwarePresent *bool `protobuf:"varint,18,opt,name=firmware_present,json=firmwarePresent" json:"firmware_present,omitempty"` - NeedsBackup *bool `protobuf:"varint,19,opt,name=needs_backup,json=needsBackup" json:"needs_backup,omitempty"` - Flags *uint32 `protobuf:"varint,20,opt,name=flags" json:"flags,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Features) Reset() { *m = Features{} } -func (m *Features) String() string { return proto.CompactTextString(m) } -func (*Features) ProtoMessage() {} -func (*Features) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } - -func (m *Features) GetVendor() string { - if m != nil && m.Vendor != nil { - return *m.Vendor - } - return "" -} - -func (m *Features) GetMajorVersion() uint32 { - if m != nil && m.MajorVersion != nil { - return *m.MajorVersion - } - return 0 -} - -func (m *Features) GetMinorVersion() uint32 { - if m != nil && m.MinorVersion != nil { - return *m.MinorVersion - } - return 0 -} - -func (m *Features) GetPatchVersion() uint32 { - if m != nil && m.PatchVersion != nil { - return *m.PatchVersion - } - return 0 -} - -func (m *Features) GetBootloaderMode() bool { - if m != nil && m.BootloaderMode != nil { - return *m.BootloaderMode - } - return false -} - -func (m *Features) GetDeviceId() string { - if m != nil && m.DeviceId != nil { - return *m.DeviceId - } - return "" -} - -func (m *Features) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection - } - return false -} - -func (m *Features) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection - } - return false -} - -func (m *Features) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language - } - return "" -} - -func (m *Features) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" -} - -func (m *Features) GetCoins() []*CoinType { - if m != nil { - return m.Coins - } - return nil -} - -func (m *Features) GetInitialized() bool { - if m != nil && m.Initialized != nil { - return *m.Initialized - } - return false -} - -func (m *Features) GetRevision() []byte { - if m != nil { - return m.Revision - } - return nil -} - -func (m *Features) GetBootloaderHash() []byte { - if m != nil { - return m.BootloaderHash - } - return nil -} - -func (m *Features) GetImported() bool { - if m != nil && m.Imported != nil { - return *m.Imported - } - return false -} - -func (m *Features) GetPinCached() bool { - if m != nil && m.PinCached != nil { - return *m.PinCached - } - return false -} - -func (m *Features) GetPassphraseCached() bool { - if m != nil && m.PassphraseCached != nil { - return *m.PassphraseCached - } - return false -} - -func (m *Features) GetFirmwarePresent() bool { - if m != nil && m.FirmwarePresent != nil { - return *m.FirmwarePresent - } - return false -} - -func (m *Features) GetNeedsBackup() bool { - if m != nil && m.NeedsBackup != nil { - return *m.NeedsBackup - } - return false -} - -func (m *Features) GetFlags() uint32 { - if m != nil && m.Flags != nil { - return *m.Flags - } - return 0 -} - -// * -// Request: clear session (removes cached PIN, passphrase, etc). -// @next Success -type ClearSession struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *ClearSession) Reset() { *m = ClearSession{} } -func (m *ClearSession) String() string { return proto.CompactTextString(m) } -func (*ClearSession) ProtoMessage() {} -func (*ClearSession) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } - -// * -// Request: change language and/or label of the device -// @next Success -// @next Failure -// @next ButtonRequest -// @next PinMatrixRequest -type ApplySettings struct { - Language *string `protobuf:"bytes,1,opt,name=language" json:"language,omitempty"` - Label *string `protobuf:"bytes,2,opt,name=label" json:"label,omitempty"` - UsePassphrase *bool `protobuf:"varint,3,opt,name=use_passphrase,json=usePassphrase" json:"use_passphrase,omitempty"` - Homescreen []byte `protobuf:"bytes,4,opt,name=homescreen" json:"homescreen,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ApplySettings) Reset() { *m = ApplySettings{} } -func (m *ApplySettings) String() string { return proto.CompactTextString(m) } -func (*ApplySettings) ProtoMessage() {} -func (*ApplySettings) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{4} } - -func (m *ApplySettings) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language - } - return "" -} - -func (m *ApplySettings) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" -} - -func (m *ApplySettings) GetUsePassphrase() bool { - if m != nil && m.UsePassphrase != nil { - return *m.UsePassphrase - } - return false -} - -func (m *ApplySettings) GetHomescreen() []byte { - if m != nil { - return m.Homescreen - } - return nil -} - -// * -// Request: set flags of the device -// @next Success -// @next Failure -type ApplyFlags struct { - Flags *uint32 `protobuf:"varint,1,opt,name=flags" json:"flags,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ApplyFlags) Reset() { *m = ApplyFlags{} } -func (m *ApplyFlags) String() string { return proto.CompactTextString(m) } -func (*ApplyFlags) ProtoMessage() {} -func (*ApplyFlags) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{5} } - -func (m *ApplyFlags) GetFlags() uint32 { - if m != nil && m.Flags != nil { - return *m.Flags - } - return 0 -} - -// * -// Request: Starts workflow for setting/changing/removing the PIN -// @next ButtonRequest -// @next PinMatrixRequest -type ChangePin struct { - Remove *bool `protobuf:"varint,1,opt,name=remove" json:"remove,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ChangePin) Reset() { *m = ChangePin{} } -func (m *ChangePin) String() string { return proto.CompactTextString(m) } -func (*ChangePin) ProtoMessage() {} -func (*ChangePin) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{6} } - -func (m *ChangePin) GetRemove() bool { - if m != nil && m.Remove != nil { - return *m.Remove - } - return false -} - -// * -// Request: Test if the device is alive, device sends back the message in Success response -// @next Success -type Ping struct { - Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` - ButtonProtection *bool `protobuf:"varint,2,opt,name=button_protection,json=buttonProtection" json:"button_protection,omitempty"` - PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Ping) Reset() { *m = Ping{} } -func (m *Ping) String() string { return proto.CompactTextString(m) } -func (*Ping) ProtoMessage() {} -func (*Ping) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{7} } - -func (m *Ping) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message - } - return "" -} - -func (m *Ping) GetButtonProtection() bool { - if m != nil && m.ButtonProtection != nil { - return *m.ButtonProtection - } - return false -} - -func (m *Ping) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection - } - return false -} - -func (m *Ping) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection - } - return false -} - -// * -// Response: Success of the previous request -type Success struct { - Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Success) Reset() { *m = Success{} } -func (m *Success) String() string { return proto.CompactTextString(m) } -func (*Success) ProtoMessage() {} -func (*Success) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{8} } - -func (m *Success) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message - } - return "" -} - -// * -// Response: Failure of the previous request -type Failure struct { - Code *FailureType `protobuf:"varint,1,opt,name=code,enum=FailureType" json:"code,omitempty"` - Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Failure) Reset() { *m = Failure{} } -func (m *Failure) String() string { return proto.CompactTextString(m) } -func (*Failure) ProtoMessage() {} -func (*Failure) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{9} } - -func (m *Failure) GetCode() FailureType { - if m != nil && m.Code != nil { - return *m.Code - } - return FailureType_Failure_UnexpectedMessage -} - -func (m *Failure) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message - } - return "" -} - -// * -// Response: Device is waiting for HW button press. -// @next ButtonAck -// @next Cancel -type ButtonRequest struct { - Code *ButtonRequestType `protobuf:"varint,1,opt,name=code,enum=ButtonRequestType" json:"code,omitempty"` - Data *string `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ButtonRequest) Reset() { *m = ButtonRequest{} } -func (m *ButtonRequest) String() string { return proto.CompactTextString(m) } -func (*ButtonRequest) ProtoMessage() {} -func (*ButtonRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{10} } - -func (m *ButtonRequest) GetCode() ButtonRequestType { - if m != nil && m.Code != nil { - return *m.Code - } - return ButtonRequestType_ButtonRequest_Other -} - -func (m *ButtonRequest) GetData() string { - if m != nil && m.Data != nil { - return *m.Data - } - return "" -} - -// * -// Request: Computer agrees to wait for HW button press -// @prev ButtonRequest -type ButtonAck struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *ButtonAck) Reset() { *m = ButtonAck{} } -func (m *ButtonAck) String() string { return proto.CompactTextString(m) } -func (*ButtonAck) ProtoMessage() {} -func (*ButtonAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{11} } - -// * -// Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme -// @next PinMatrixAck -// @next Cancel -type PinMatrixRequest struct { - Type *PinMatrixRequestType `protobuf:"varint,1,opt,name=type,enum=PinMatrixRequestType" json:"type,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PinMatrixRequest) Reset() { *m = PinMatrixRequest{} } -func (m *PinMatrixRequest) String() string { return proto.CompactTextString(m) } -func (*PinMatrixRequest) ProtoMessage() {} -func (*PinMatrixRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{12} } - -func (m *PinMatrixRequest) GetType() PinMatrixRequestType { - if m != nil && m.Type != nil { - return *m.Type - } - return PinMatrixRequestType_PinMatrixRequestType_Current -} - -// * -// Request: Computer responds with encoded PIN -// @prev PinMatrixRequest -type PinMatrixAck struct { - Pin *string `protobuf:"bytes,1,req,name=pin" json:"pin,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PinMatrixAck) Reset() { *m = PinMatrixAck{} } -func (m *PinMatrixAck) String() string { return proto.CompactTextString(m) } -func (*PinMatrixAck) ProtoMessage() {} -func (*PinMatrixAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{13} } - -func (m *PinMatrixAck) GetPin() string { - if m != nil && m.Pin != nil { - return *m.Pin - } - return "" -} - -// * -// Request: Abort last operation that required user interaction -// @prev ButtonRequest -// @prev PinMatrixRequest -// @prev PassphraseRequest -type Cancel struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *Cancel) Reset() { *m = Cancel{} } -func (m *Cancel) String() string { return proto.CompactTextString(m) } -func (*Cancel) ProtoMessage() {} -func (*Cancel) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{14} } - -// * -// Response: Device awaits encryption passphrase -// @next PassphraseAck -// @next Cancel -type PassphraseRequest struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *PassphraseRequest) Reset() { *m = PassphraseRequest{} } -func (m *PassphraseRequest) String() string { return proto.CompactTextString(m) } -func (*PassphraseRequest) ProtoMessage() {} -func (*PassphraseRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{15} } - -// * -// Request: Send passphrase back -// @prev PassphraseRequest -type PassphraseAck struct { - Passphrase *string `protobuf:"bytes,1,req,name=passphrase" json:"passphrase,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PassphraseAck) Reset() { *m = PassphraseAck{} } -func (m *PassphraseAck) String() string { return proto.CompactTextString(m) } -func (*PassphraseAck) ProtoMessage() {} -func (*PassphraseAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{16} } - -func (m *PassphraseAck) GetPassphrase() string { - if m != nil && m.Passphrase != nil { - return *m.Passphrase - } - return "" -} - -// * -// Request: Request a sample of random data generated by hardware RNG. May be used for testing. -// @next ButtonRequest -// @next Entropy -// @next Failure -type GetEntropy struct { - Size *uint32 `protobuf:"varint,1,req,name=size" json:"size,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GetEntropy) Reset() { *m = GetEntropy{} } -func (m *GetEntropy) String() string { return proto.CompactTextString(m) } -func (*GetEntropy) ProtoMessage() {} -func (*GetEntropy) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{17} } - -func (m *GetEntropy) GetSize() uint32 { - if m != nil && m.Size != nil { - return *m.Size - } - return 0 -} - -// * -// Response: Reply with random data generated by internal RNG -// @prev GetEntropy -type Entropy struct { - Entropy []byte `protobuf:"bytes,1,req,name=entropy" json:"entropy,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Entropy) Reset() { *m = Entropy{} } -func (m *Entropy) String() string { return proto.CompactTextString(m) } -func (*Entropy) ProtoMessage() {} -func (*Entropy) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{18} } - -func (m *Entropy) GetEntropy() []byte { - if m != nil { - return m.Entropy - } - return nil -} - -// * -// Request: Ask device for public key corresponding to address_n path -// @next PassphraseRequest -// @next PublicKey -// @next Failure -type GetPublicKey struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - EcdsaCurveName *string `protobuf:"bytes,2,opt,name=ecdsa_curve_name,json=ecdsaCurveName" json:"ecdsa_curve_name,omitempty"` - ShowDisplay *bool `protobuf:"varint,3,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` - CoinName *string `protobuf:"bytes,4,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GetPublicKey) Reset() { *m = GetPublicKey{} } -func (m *GetPublicKey) String() string { return proto.CompactTextString(m) } -func (*GetPublicKey) ProtoMessage() {} -func (*GetPublicKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{19} } - -const Default_GetPublicKey_CoinName string = "Bitcoin" - -func (m *GetPublicKey) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *GetPublicKey) GetEcdsaCurveName() string { - if m != nil && m.EcdsaCurveName != nil { - return *m.EcdsaCurveName - } - return "" -} - -func (m *GetPublicKey) GetShowDisplay() bool { - if m != nil && m.ShowDisplay != nil { - return *m.ShowDisplay - } - return false -} - -func (m *GetPublicKey) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_GetPublicKey_CoinName -} - -// * -// Response: Contains public key derived from device private seed -// @prev GetPublicKey -type PublicKey struct { - Node *HDNodeType `protobuf:"bytes,1,req,name=node" json:"node,omitempty"` - Xpub *string `protobuf:"bytes,2,opt,name=xpub" json:"xpub,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PublicKey) Reset() { *m = PublicKey{} } -func (m *PublicKey) String() string { return proto.CompactTextString(m) } -func (*PublicKey) ProtoMessage() {} -func (*PublicKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{20} } - -func (m *PublicKey) GetNode() *HDNodeType { - if m != nil { - return m.Node - } - return nil -} - -func (m *PublicKey) GetXpub() string { - if m != nil && m.Xpub != nil { - return *m.Xpub - } - return "" -} - -// * -// Request: Ask device for address corresponding to address_n path -// @next PassphraseRequest -// @next Address -// @next Failure -type GetAddress struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - CoinName *string `protobuf:"bytes,2,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - ShowDisplay *bool `protobuf:"varint,3,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` - Multisig *MultisigRedeemScriptType `protobuf:"bytes,4,opt,name=multisig" json:"multisig,omitempty"` - ScriptType *InputScriptType `protobuf:"varint,5,opt,name=script_type,json=scriptType,enum=InputScriptType,def=0" json:"script_type,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GetAddress) Reset() { *m = GetAddress{} } -func (m *GetAddress) String() string { return proto.CompactTextString(m) } -func (*GetAddress) ProtoMessage() {} -func (*GetAddress) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{21} } - -const Default_GetAddress_CoinName string = "Bitcoin" -const Default_GetAddress_ScriptType InputScriptType = InputScriptType_SPENDADDRESS - -func (m *GetAddress) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *GetAddress) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_GetAddress_CoinName -} - -func (m *GetAddress) GetShowDisplay() bool { - if m != nil && m.ShowDisplay != nil { - return *m.ShowDisplay - } - return false -} - -func (m *GetAddress) GetMultisig() *MultisigRedeemScriptType { - if m != nil { - return m.Multisig - } - return nil -} - -func (m *GetAddress) GetScriptType() InputScriptType { - if m != nil && m.ScriptType != nil { - return *m.ScriptType - } - return Default_GetAddress_ScriptType -} - -// * -// Request: Ask device for Ethereum address corresponding to address_n path -// @next PassphraseRequest -// @next EthereumAddress -// @next Failure -type EthereumGetAddress struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumGetAddress) Reset() { *m = EthereumGetAddress{} } -func (m *EthereumGetAddress) String() string { return proto.CompactTextString(m) } -func (*EthereumGetAddress) ProtoMessage() {} -func (*EthereumGetAddress) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{22} } - -func (m *EthereumGetAddress) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *EthereumGetAddress) GetShowDisplay() bool { - if m != nil && m.ShowDisplay != nil { - return *m.ShowDisplay - } - return false -} - -// * -// Response: Contains address derived from device private seed -// @prev GetAddress -type Address struct { - Address *string `protobuf:"bytes,1,req,name=address" json:"address,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Address) Reset() { *m = Address{} } -func (m *Address) String() string { return proto.CompactTextString(m) } -func (*Address) ProtoMessage() {} -func (*Address) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{23} } - -func (m *Address) GetAddress() string { - if m != nil && m.Address != nil { - return *m.Address - } - return "" -} - -// * -// Response: Contains an Ethereum address derived from device private seed -// @prev EthereumGetAddress -type EthereumAddress struct { - Address []byte `protobuf:"bytes,1,req,name=address" json:"address,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumAddress) Reset() { *m = EthereumAddress{} } -func (m *EthereumAddress) String() string { return proto.CompactTextString(m) } -func (*EthereumAddress) ProtoMessage() {} -func (*EthereumAddress) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{24} } - -func (m *EthereumAddress) GetAddress() []byte { - if m != nil { - return m.Address - } - return nil -} - -// * -// Request: Request device to wipe all sensitive data and settings -// @next ButtonRequest -type WipeDevice struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *WipeDevice) Reset() { *m = WipeDevice{} } -func (m *WipeDevice) String() string { return proto.CompactTextString(m) } -func (*WipeDevice) ProtoMessage() {} -func (*WipeDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{25} } - -// * -// Request: Load seed and related internal settings from the computer -// @next ButtonRequest -// @next Success -// @next Failure -type LoadDevice struct { - Mnemonic *string `protobuf:"bytes,1,opt,name=mnemonic" json:"mnemonic,omitempty"` - Node *HDNodeType `protobuf:"bytes,2,opt,name=node" json:"node,omitempty"` - Pin *string `protobuf:"bytes,3,opt,name=pin" json:"pin,omitempty"` - PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` - Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` - SkipChecksum *bool `protobuf:"varint,7,opt,name=skip_checksum,json=skipChecksum" json:"skip_checksum,omitempty"` - U2FCounter *uint32 `protobuf:"varint,8,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *LoadDevice) Reset() { *m = LoadDevice{} } -func (m *LoadDevice) String() string { return proto.CompactTextString(m) } -func (*LoadDevice) ProtoMessage() {} -func (*LoadDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{26} } - -const Default_LoadDevice_Language string = "english" - -func (m *LoadDevice) GetMnemonic() string { - if m != nil && m.Mnemonic != nil { - return *m.Mnemonic - } - return "" -} - -func (m *LoadDevice) GetNode() *HDNodeType { - if m != nil { - return m.Node - } - return nil -} - -func (m *LoadDevice) GetPin() string { - if m != nil && m.Pin != nil { - return *m.Pin - } - return "" -} - -func (m *LoadDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection - } - return false -} - -func (m *LoadDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language - } - return Default_LoadDevice_Language -} - -func (m *LoadDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" -} - -func (m *LoadDevice) GetSkipChecksum() bool { - if m != nil && m.SkipChecksum != nil { - return *m.SkipChecksum - } - return false -} - -func (m *LoadDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter - } - return 0 -} - -// * -// Request: Ask device to do initialization involving user interaction -// @next EntropyRequest -// @next Failure -type ResetDevice struct { - DisplayRandom *bool `protobuf:"varint,1,opt,name=display_random,json=displayRandom" json:"display_random,omitempty"` - Strength *uint32 `protobuf:"varint,2,opt,name=strength,def=256" json:"strength,omitempty"` - PassphraseProtection *bool `protobuf:"varint,3,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - PinProtection *bool `protobuf:"varint,4,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` - Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` - U2FCounter *uint32 `protobuf:"varint,7,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - SkipBackup *bool `protobuf:"varint,8,opt,name=skip_backup,json=skipBackup" json:"skip_backup,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ResetDevice) Reset() { *m = ResetDevice{} } -func (m *ResetDevice) String() string { return proto.CompactTextString(m) } -func (*ResetDevice) ProtoMessage() {} -func (*ResetDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{27} } - -const Default_ResetDevice_Strength uint32 = 256 -const Default_ResetDevice_Language string = "english" - -func (m *ResetDevice) GetDisplayRandom() bool { - if m != nil && m.DisplayRandom != nil { - return *m.DisplayRandom - } - return false -} - -func (m *ResetDevice) GetStrength() uint32 { - if m != nil && m.Strength != nil { - return *m.Strength - } - return Default_ResetDevice_Strength -} - -func (m *ResetDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection - } - return false -} - -func (m *ResetDevice) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection - } - return false -} - -func (m *ResetDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language - } - return Default_ResetDevice_Language -} - -func (m *ResetDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" -} - -func (m *ResetDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter - } - return 0 -} - -func (m *ResetDevice) GetSkipBackup() bool { - if m != nil && m.SkipBackup != nil { - return *m.SkipBackup - } - return false -} - -// * -// Request: Perform backup of the device seed if not backed up using ResetDevice -// @next ButtonRequest -type BackupDevice struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *BackupDevice) Reset() { *m = BackupDevice{} } -func (m *BackupDevice) String() string { return proto.CompactTextString(m) } -func (*BackupDevice) ProtoMessage() {} -func (*BackupDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{28} } - -// * -// Response: Ask for additional entropy from host computer -// @prev ResetDevice -// @next EntropyAck -type EntropyRequest struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *EntropyRequest) Reset() { *m = EntropyRequest{} } -func (m *EntropyRequest) String() string { return proto.CompactTextString(m) } -func (*EntropyRequest) ProtoMessage() {} -func (*EntropyRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{29} } - -// * -// Request: Provide additional entropy for seed generation function -// @prev EntropyRequest -// @next ButtonRequest -type EntropyAck struct { - Entropy []byte `protobuf:"bytes,1,opt,name=entropy" json:"entropy,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EntropyAck) Reset() { *m = EntropyAck{} } -func (m *EntropyAck) String() string { return proto.CompactTextString(m) } -func (*EntropyAck) ProtoMessage() {} -func (*EntropyAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{30} } - -func (m *EntropyAck) GetEntropy() []byte { - if m != nil { - return m.Entropy - } - return nil -} - -// * -// Request: Start recovery workflow asking user for specific words of mnemonic -// Used to recovery device safely even on untrusted computer. -// @next WordRequest -type RecoveryDevice struct { - WordCount *uint32 `protobuf:"varint,1,opt,name=word_count,json=wordCount" json:"word_count,omitempty"` - PassphraseProtection *bool `protobuf:"varint,2,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - Language *string `protobuf:"bytes,4,opt,name=language,def=english" json:"language,omitempty"` - Label *string `protobuf:"bytes,5,opt,name=label" json:"label,omitempty"` - EnforceWordlist *bool `protobuf:"varint,6,opt,name=enforce_wordlist,json=enforceWordlist" json:"enforce_wordlist,omitempty"` - // 7 reserved for unused recovery method - Type *uint32 `protobuf:"varint,8,opt,name=type" json:"type,omitempty"` - U2FCounter *uint32 `protobuf:"varint,9,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - DryRun *bool `protobuf:"varint,10,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *RecoveryDevice) Reset() { *m = RecoveryDevice{} } -func (m *RecoveryDevice) String() string { return proto.CompactTextString(m) } -func (*RecoveryDevice) ProtoMessage() {} -func (*RecoveryDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{31} } - -const Default_RecoveryDevice_Language string = "english" - -func (m *RecoveryDevice) GetWordCount() uint32 { - if m != nil && m.WordCount != nil { - return *m.WordCount - } - return 0 -} - -func (m *RecoveryDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection - } - return false -} - -func (m *RecoveryDevice) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection - } - return false -} - -func (m *RecoveryDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language - } - return Default_RecoveryDevice_Language -} - -func (m *RecoveryDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" -} - -func (m *RecoveryDevice) GetEnforceWordlist() bool { - if m != nil && m.EnforceWordlist != nil { - return *m.EnforceWordlist - } - return false -} - -func (m *RecoveryDevice) GetType() uint32 { - if m != nil && m.Type != nil { - return *m.Type - } - return 0 -} - -func (m *RecoveryDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter - } - return 0 -} - -func (m *RecoveryDevice) GetDryRun() bool { - if m != nil && m.DryRun != nil { - return *m.DryRun - } - return false -} - -// * -// Response: Device is waiting for user to enter word of the mnemonic -// Its position is shown only on device's internal display. -// @prev RecoveryDevice -// @prev WordAck -type WordRequest struct { - Type *WordRequestType `protobuf:"varint,1,opt,name=type,enum=WordRequestType" json:"type,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *WordRequest) Reset() { *m = WordRequest{} } -func (m *WordRequest) String() string { return proto.CompactTextString(m) } -func (*WordRequest) ProtoMessage() {} -func (*WordRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{32} } - -func (m *WordRequest) GetType() WordRequestType { - if m != nil && m.Type != nil { - return *m.Type - } - return WordRequestType_WordRequestType_Plain -} - -// * -// Request: Computer replies with word from the mnemonic -// @prev WordRequest -// @next WordRequest -// @next Success -// @next Failure -type WordAck struct { - Word *string `protobuf:"bytes,1,req,name=word" json:"word,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *WordAck) Reset() { *m = WordAck{} } -func (m *WordAck) String() string { return proto.CompactTextString(m) } -func (*WordAck) ProtoMessage() {} -func (*WordAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{33} } - -func (m *WordAck) GetWord() string { - if m != nil && m.Word != nil { - return *m.Word - } - return "" -} - -// * -// Request: Ask device to sign message -// @next MessageSignature -// @next Failure -type SignMessage struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Message []byte `protobuf:"bytes,2,req,name=message" json:"message,omitempty"` - CoinName *string `protobuf:"bytes,3,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - ScriptType *InputScriptType `protobuf:"varint,4,opt,name=script_type,json=scriptType,enum=InputScriptType,def=0" json:"script_type,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SignMessage) Reset() { *m = SignMessage{} } -func (m *SignMessage) String() string { return proto.CompactTextString(m) } -func (*SignMessage) ProtoMessage() {} -func (*SignMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{34} } - -const Default_SignMessage_CoinName string = "Bitcoin" -const Default_SignMessage_ScriptType InputScriptType = InputScriptType_SPENDADDRESS - -func (m *SignMessage) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *SignMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -func (m *SignMessage) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_SignMessage_CoinName -} - -func (m *SignMessage) GetScriptType() InputScriptType { - if m != nil && m.ScriptType != nil { - return *m.ScriptType - } - return Default_SignMessage_ScriptType -} - -// * -// Request: Ask device to verify message -// @next Success -// @next Failure -type VerifyMessage struct { - Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` - CoinName *string `protobuf:"bytes,4,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *VerifyMessage) Reset() { *m = VerifyMessage{} } -func (m *VerifyMessage) String() string { return proto.CompactTextString(m) } -func (*VerifyMessage) ProtoMessage() {} -func (*VerifyMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{35} } - -const Default_VerifyMessage_CoinName string = "Bitcoin" - -func (m *VerifyMessage) GetAddress() string { - if m != nil && m.Address != nil { - return *m.Address - } - return "" -} - -func (m *VerifyMessage) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -func (m *VerifyMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -func (m *VerifyMessage) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_VerifyMessage_CoinName -} - -// * -// Response: Signed message -// @prev SignMessage -type MessageSignature struct { - Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MessageSignature) Reset() { *m = MessageSignature{} } -func (m *MessageSignature) String() string { return proto.CompactTextString(m) } -func (*MessageSignature) ProtoMessage() {} -func (*MessageSignature) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{36} } - -func (m *MessageSignature) GetAddress() string { - if m != nil && m.Address != nil { - return *m.Address - } - return "" -} - -func (m *MessageSignature) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -// * -// Request: Ask device to encrypt message -// @next EncryptedMessage -// @next Failure -type EncryptMessage struct { - Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey" json:"pubkey,omitempty"` - Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` - DisplayOnly *bool `protobuf:"varint,3,opt,name=display_only,json=displayOnly" json:"display_only,omitempty"` - AddressN []uint32 `protobuf:"varint,4,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - CoinName *string `protobuf:"bytes,5,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EncryptMessage) Reset() { *m = EncryptMessage{} } -func (m *EncryptMessage) String() string { return proto.CompactTextString(m) } -func (*EncryptMessage) ProtoMessage() {} -func (*EncryptMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{37} } - -const Default_EncryptMessage_CoinName string = "Bitcoin" - -func (m *EncryptMessage) GetPubkey() []byte { - if m != nil { - return m.Pubkey - } - return nil -} - -func (m *EncryptMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -func (m *EncryptMessage) GetDisplayOnly() bool { - if m != nil && m.DisplayOnly != nil { - return *m.DisplayOnly - } - return false -} - -func (m *EncryptMessage) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *EncryptMessage) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_EncryptMessage_CoinName -} - -// * -// Response: Encrypted message -// @prev EncryptMessage -type EncryptedMessage struct { - Nonce []byte `protobuf:"bytes,1,opt,name=nonce" json:"nonce,omitempty"` - Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` - Hmac []byte `protobuf:"bytes,3,opt,name=hmac" json:"hmac,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EncryptedMessage) Reset() { *m = EncryptedMessage{} } -func (m *EncryptedMessage) String() string { return proto.CompactTextString(m) } -func (*EncryptedMessage) ProtoMessage() {} -func (*EncryptedMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{38} } - -func (m *EncryptedMessage) GetNonce() []byte { - if m != nil { - return m.Nonce - } - return nil -} - -func (m *EncryptedMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -func (m *EncryptedMessage) GetHmac() []byte { - if m != nil { - return m.Hmac - } - return nil -} - -// * -// Request: Ask device to decrypt message -// @next Success -// @next Failure -type DecryptMessage struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` - Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` - Hmac []byte `protobuf:"bytes,4,opt,name=hmac" json:"hmac,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DecryptMessage) Reset() { *m = DecryptMessage{} } -func (m *DecryptMessage) String() string { return proto.CompactTextString(m) } -func (*DecryptMessage) ProtoMessage() {} -func (*DecryptMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{39} } - -func (m *DecryptMessage) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *DecryptMessage) GetNonce() []byte { - if m != nil { - return m.Nonce - } - return nil -} - -func (m *DecryptMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -func (m *DecryptMessage) GetHmac() []byte { - if m != nil { - return m.Hmac - } - return nil -} - -// * -// Response: Decrypted message -// @prev DecryptedMessage -type DecryptedMessage struct { - Message []byte `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` - Address *string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DecryptedMessage) Reset() { *m = DecryptedMessage{} } -func (m *DecryptedMessage) String() string { return proto.CompactTextString(m) } -func (*DecryptedMessage) ProtoMessage() {} -func (*DecryptedMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{40} } - -func (m *DecryptedMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -func (m *DecryptedMessage) GetAddress() string { - if m != nil && m.Address != nil { - return *m.Address - } - return "" -} - -// * -// Request: Ask device to encrypt or decrypt value of given key -// @next CipheredKeyValue -// @next Failure -type CipherKeyValue struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Key *string `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"` - Value []byte `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"` - Encrypt *bool `protobuf:"varint,4,opt,name=encrypt" json:"encrypt,omitempty"` - AskOnEncrypt *bool `protobuf:"varint,5,opt,name=ask_on_encrypt,json=askOnEncrypt" json:"ask_on_encrypt,omitempty"` - AskOnDecrypt *bool `protobuf:"varint,6,opt,name=ask_on_decrypt,json=askOnDecrypt" json:"ask_on_decrypt,omitempty"` - Iv []byte `protobuf:"bytes,7,opt,name=iv" json:"iv,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *CipherKeyValue) Reset() { *m = CipherKeyValue{} } -func (m *CipherKeyValue) String() string { return proto.CompactTextString(m) } -func (*CipherKeyValue) ProtoMessage() {} -func (*CipherKeyValue) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{41} } - -func (m *CipherKeyValue) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *CipherKeyValue) GetKey() string { - if m != nil && m.Key != nil { - return *m.Key - } - return "" -} - -func (m *CipherKeyValue) GetValue() []byte { - if m != nil { - return m.Value - } - return nil -} - -func (m *CipherKeyValue) GetEncrypt() bool { - if m != nil && m.Encrypt != nil { - return *m.Encrypt - } - return false -} - -func (m *CipherKeyValue) GetAskOnEncrypt() bool { - if m != nil && m.AskOnEncrypt != nil { - return *m.AskOnEncrypt - } - return false -} - -func (m *CipherKeyValue) GetAskOnDecrypt() bool { - if m != nil && m.AskOnDecrypt != nil { - return *m.AskOnDecrypt - } - return false -} - -func (m *CipherKeyValue) GetIv() []byte { - if m != nil { - return m.Iv - } - return nil -} - -// * -// Response: Return ciphered/deciphered value -// @prev CipherKeyValue -type CipheredKeyValue struct { - Value []byte `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *CipheredKeyValue) Reset() { *m = CipheredKeyValue{} } -func (m *CipheredKeyValue) String() string { return proto.CompactTextString(m) } -func (*CipheredKeyValue) ProtoMessage() {} -func (*CipheredKeyValue) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{42} } - -func (m *CipheredKeyValue) GetValue() []byte { - if m != nil { - return m.Value - } - return nil -} - -// * -// Request: Estimated size of the transaction -// This behaves exactly like SignTx, which means that it can ask using TxRequest -// This call is non-blocking (except possible PassphraseRequest to unlock the seed) -// @next TxSize -// @next Failure -type EstimateTxSize struct { - OutputsCount *uint32 `protobuf:"varint,1,req,name=outputs_count,json=outputsCount" json:"outputs_count,omitempty"` - InputsCount *uint32 `protobuf:"varint,2,req,name=inputs_count,json=inputsCount" json:"inputs_count,omitempty"` - CoinName *string `protobuf:"bytes,3,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EstimateTxSize) Reset() { *m = EstimateTxSize{} } -func (m *EstimateTxSize) String() string { return proto.CompactTextString(m) } -func (*EstimateTxSize) ProtoMessage() {} -func (*EstimateTxSize) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{43} } - -const Default_EstimateTxSize_CoinName string = "Bitcoin" - -func (m *EstimateTxSize) GetOutputsCount() uint32 { - if m != nil && m.OutputsCount != nil { - return *m.OutputsCount - } - return 0 -} - -func (m *EstimateTxSize) GetInputsCount() uint32 { - if m != nil && m.InputsCount != nil { - return *m.InputsCount - } - return 0 -} - -func (m *EstimateTxSize) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_EstimateTxSize_CoinName -} - -// * -// Response: Estimated size of the transaction -// @prev EstimateTxSize -type TxSize struct { - TxSize *uint32 `protobuf:"varint,1,opt,name=tx_size,json=txSize" json:"tx_size,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxSize) Reset() { *m = TxSize{} } -func (m *TxSize) String() string { return proto.CompactTextString(m) } -func (*TxSize) ProtoMessage() {} -func (*TxSize) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{44} } - -func (m *TxSize) GetTxSize() uint32 { - if m != nil && m.TxSize != nil { - return *m.TxSize - } - return 0 -} - -// * -// Request: Ask device to sign transaction -// @next PassphraseRequest -// @next PinMatrixRequest -// @next TxRequest -// @next Failure -type SignTx struct { - OutputsCount *uint32 `protobuf:"varint,1,req,name=outputs_count,json=outputsCount" json:"outputs_count,omitempty"` - InputsCount *uint32 `protobuf:"varint,2,req,name=inputs_count,json=inputsCount" json:"inputs_count,omitempty"` - CoinName *string `protobuf:"bytes,3,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - Version *uint32 `protobuf:"varint,4,opt,name=version,def=1" json:"version,omitempty"` - LockTime *uint32 `protobuf:"varint,5,opt,name=lock_time,json=lockTime,def=0" json:"lock_time,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SignTx) Reset() { *m = SignTx{} } -func (m *SignTx) String() string { return proto.CompactTextString(m) } -func (*SignTx) ProtoMessage() {} -func (*SignTx) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{45} } - -const Default_SignTx_CoinName string = "Bitcoin" -const Default_SignTx_Version uint32 = 1 -const Default_SignTx_LockTime uint32 = 0 - -func (m *SignTx) GetOutputsCount() uint32 { - if m != nil && m.OutputsCount != nil { - return *m.OutputsCount - } - return 0 -} - -func (m *SignTx) GetInputsCount() uint32 { - if m != nil && m.InputsCount != nil { - return *m.InputsCount - } - return 0 -} - -func (m *SignTx) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_SignTx_CoinName -} - -func (m *SignTx) GetVersion() uint32 { - if m != nil && m.Version != nil { - return *m.Version - } - return Default_SignTx_Version -} - -func (m *SignTx) GetLockTime() uint32 { - if m != nil && m.LockTime != nil { - return *m.LockTime - } - return Default_SignTx_LockTime -} - -// * -// Request: Simplified transaction signing -// This method doesn't support streaming, so there are hardware limits in number of inputs and outputs. -// In case of success, the result is returned using TxRequest message. -// @next PassphraseRequest -// @next PinMatrixRequest -// @next TxRequest -// @next Failure -type SimpleSignTx struct { - Inputs []*TxInputType `protobuf:"bytes,1,rep,name=inputs" json:"inputs,omitempty"` - Outputs []*TxOutputType `protobuf:"bytes,2,rep,name=outputs" json:"outputs,omitempty"` - Transactions []*TransactionType `protobuf:"bytes,3,rep,name=transactions" json:"transactions,omitempty"` - CoinName *string `protobuf:"bytes,4,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` - Version *uint32 `protobuf:"varint,5,opt,name=version,def=1" json:"version,omitempty"` - LockTime *uint32 `protobuf:"varint,6,opt,name=lock_time,json=lockTime,def=0" json:"lock_time,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SimpleSignTx) Reset() { *m = SimpleSignTx{} } -func (m *SimpleSignTx) String() string { return proto.CompactTextString(m) } -func (*SimpleSignTx) ProtoMessage() {} -func (*SimpleSignTx) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{46} } - -const Default_SimpleSignTx_CoinName string = "Bitcoin" -const Default_SimpleSignTx_Version uint32 = 1 -const Default_SimpleSignTx_LockTime uint32 = 0 - -func (m *SimpleSignTx) GetInputs() []*TxInputType { - if m != nil { - return m.Inputs - } - return nil -} - -func (m *SimpleSignTx) GetOutputs() []*TxOutputType { - if m != nil { - return m.Outputs - } - return nil -} - -func (m *SimpleSignTx) GetTransactions() []*TransactionType { - if m != nil { - return m.Transactions - } - return nil -} - -func (m *SimpleSignTx) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return Default_SimpleSignTx_CoinName -} - -func (m *SimpleSignTx) GetVersion() uint32 { - if m != nil && m.Version != nil { - return *m.Version - } - return Default_SimpleSignTx_Version -} - -func (m *SimpleSignTx) GetLockTime() uint32 { - if m != nil && m.LockTime != nil { - return *m.LockTime - } - return Default_SimpleSignTx_LockTime -} - -// * -// Response: Device asks for information for signing transaction or returns the last result -// If request_index is set, device awaits TxAck message (with fields filled in according to request_type) -// If signature_index is set, 'signature' contains signed input of signature_index's input -// @prev SignTx -// @prev SimpleSignTx -// @prev TxAck -type TxRequest struct { - RequestType *RequestType `protobuf:"varint,1,opt,name=request_type,json=requestType,enum=RequestType" json:"request_type,omitempty"` - Details *TxRequestDetailsType `protobuf:"bytes,2,opt,name=details" json:"details,omitempty"` - Serialized *TxRequestSerializedType `protobuf:"bytes,3,opt,name=serialized" json:"serialized,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxRequest) Reset() { *m = TxRequest{} } -func (m *TxRequest) String() string { return proto.CompactTextString(m) } -func (*TxRequest) ProtoMessage() {} -func (*TxRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{47} } - -func (m *TxRequest) GetRequestType() RequestType { - if m != nil && m.RequestType != nil { - return *m.RequestType - } - return RequestType_TXINPUT -} - -func (m *TxRequest) GetDetails() *TxRequestDetailsType { - if m != nil { - return m.Details - } - return nil -} - -func (m *TxRequest) GetSerialized() *TxRequestSerializedType { - if m != nil { - return m.Serialized - } - return nil -} - -// * -// Request: Reported transaction data -// @prev TxRequest -// @next TxRequest -type TxAck struct { - Tx *TransactionType `protobuf:"bytes,1,opt,name=tx" json:"tx,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxAck) Reset() { *m = TxAck{} } -func (m *TxAck) String() string { return proto.CompactTextString(m) } -func (*TxAck) ProtoMessage() {} -func (*TxAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{48} } - -func (m *TxAck) GetTx() *TransactionType { - if m != nil { - return m.Tx - } - return nil -} - -// * -// Request: Ask device to sign transaction -// All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing. -// Note: the first at most 1024 bytes of data MUST be transmitted as part of this message. -// @next PassphraseRequest -// @next PinMatrixRequest -// @next EthereumTxRequest -// @next Failure -type EthereumSignTx struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` - GasPrice []byte `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice" json:"gas_price,omitempty"` - GasLimit []byte `protobuf:"bytes,4,opt,name=gas_limit,json=gasLimit" json:"gas_limit,omitempty"` - To []byte `protobuf:"bytes,5,opt,name=to" json:"to,omitempty"` - Value []byte `protobuf:"bytes,6,opt,name=value" json:"value,omitempty"` - DataInitialChunk []byte `protobuf:"bytes,7,opt,name=data_initial_chunk,json=dataInitialChunk" json:"data_initial_chunk,omitempty"` - DataLength *uint32 `protobuf:"varint,8,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` - ChainId *uint32 `protobuf:"varint,9,opt,name=chain_id,json=chainId" json:"chain_id,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumSignTx) Reset() { *m = EthereumSignTx{} } -func (m *EthereumSignTx) String() string { return proto.CompactTextString(m) } -func (*EthereumSignTx) ProtoMessage() {} -func (*EthereumSignTx) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{49} } - -func (m *EthereumSignTx) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *EthereumSignTx) GetNonce() []byte { - if m != nil { - return m.Nonce - } - return nil -} - -func (m *EthereumSignTx) GetGasPrice() []byte { - if m != nil { - return m.GasPrice - } - return nil -} - -func (m *EthereumSignTx) GetGasLimit() []byte { - if m != nil { - return m.GasLimit - } - return nil -} - -func (m *EthereumSignTx) GetTo() []byte { - if m != nil { - return m.To - } - return nil -} - -func (m *EthereumSignTx) GetValue() []byte { - if m != nil { - return m.Value - } - return nil -} - -func (m *EthereumSignTx) GetDataInitialChunk() []byte { - if m != nil { - return m.DataInitialChunk - } - return nil -} - -func (m *EthereumSignTx) GetDataLength() uint32 { - if m != nil && m.DataLength != nil { - return *m.DataLength - } - return 0 -} - -func (m *EthereumSignTx) GetChainId() uint32 { - if m != nil && m.ChainId != nil { - return *m.ChainId - } - return 0 -} - -// * -// Response: Device asks for more data from transaction payload, or returns the signature. -// If data_length is set, device awaits that many more bytes of payload. -// Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present. -// @prev EthereumSignTx -// @next EthereumTxAck -type EthereumTxRequest struct { - DataLength *uint32 `protobuf:"varint,1,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` - SignatureV *uint32 `protobuf:"varint,2,opt,name=signature_v,json=signatureV" json:"signature_v,omitempty"` - SignatureR []byte `protobuf:"bytes,3,opt,name=signature_r,json=signatureR" json:"signature_r,omitempty"` - SignatureS []byte `protobuf:"bytes,4,opt,name=signature_s,json=signatureS" json:"signature_s,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumTxRequest) Reset() { *m = EthereumTxRequest{} } -func (m *EthereumTxRequest) String() string { return proto.CompactTextString(m) } -func (*EthereumTxRequest) ProtoMessage() {} -func (*EthereumTxRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{50} } - -func (m *EthereumTxRequest) GetDataLength() uint32 { - if m != nil && m.DataLength != nil { - return *m.DataLength - } - return 0 -} - -func (m *EthereumTxRequest) GetSignatureV() uint32 { - if m != nil && m.SignatureV != nil { - return *m.SignatureV - } - return 0 -} - -func (m *EthereumTxRequest) GetSignatureR() []byte { - if m != nil { - return m.SignatureR - } - return nil -} - -func (m *EthereumTxRequest) GetSignatureS() []byte { - if m != nil { - return m.SignatureS - } - return nil -} - -// * -// Request: Transaction payload data. -// @prev EthereumTxRequest -// @next EthereumTxRequest -type EthereumTxAck struct { - DataChunk []byte `protobuf:"bytes,1,opt,name=data_chunk,json=dataChunk" json:"data_chunk,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumTxAck) Reset() { *m = EthereumTxAck{} } -func (m *EthereumTxAck) String() string { return proto.CompactTextString(m) } -func (*EthereumTxAck) ProtoMessage() {} -func (*EthereumTxAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{51} } - -func (m *EthereumTxAck) GetDataChunk() []byte { - if m != nil { - return m.DataChunk - } - return nil -} - -// * -// Request: Ask device to sign message -// @next EthereumMessageSignature -// @next Failure -type EthereumSignMessage struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Message []byte `protobuf:"bytes,2,req,name=message" json:"message,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumSignMessage) Reset() { *m = EthereumSignMessage{} } -func (m *EthereumSignMessage) String() string { return proto.CompactTextString(m) } -func (*EthereumSignMessage) ProtoMessage() {} -func (*EthereumSignMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{52} } - -func (m *EthereumSignMessage) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *EthereumSignMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -// * -// Request: Ask device to verify message -// @next Success -// @next Failure -type EthereumVerifyMessage struct { - Address []byte `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumVerifyMessage) Reset() { *m = EthereumVerifyMessage{} } -func (m *EthereumVerifyMessage) String() string { return proto.CompactTextString(m) } -func (*EthereumVerifyMessage) ProtoMessage() {} -func (*EthereumVerifyMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{53} } - -func (m *EthereumVerifyMessage) GetAddress() []byte { - if m != nil { - return m.Address - } - return nil -} - -func (m *EthereumVerifyMessage) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -func (m *EthereumVerifyMessage) GetMessage() []byte { - if m != nil { - return m.Message - } - return nil -} - -// * -// Response: Signed message -// @prev EthereumSignMessage -type EthereumMessageSignature struct { - Address []byte `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *EthereumMessageSignature) Reset() { *m = EthereumMessageSignature{} } -func (m *EthereumMessageSignature) String() string { return proto.CompactTextString(m) } -func (*EthereumMessageSignature) ProtoMessage() {} -func (*EthereumMessageSignature) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{54} } - -func (m *EthereumMessageSignature) GetAddress() []byte { - if m != nil { - return m.Address - } - return nil -} - -func (m *EthereumMessageSignature) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -// * -// Request: Ask device to sign identity -// @next SignedIdentity -// @next Failure -type SignIdentity struct { - Identity *IdentityType `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"` - ChallengeHidden []byte `protobuf:"bytes,2,opt,name=challenge_hidden,json=challengeHidden" json:"challenge_hidden,omitempty"` - ChallengeVisual *string `protobuf:"bytes,3,opt,name=challenge_visual,json=challengeVisual" json:"challenge_visual,omitempty"` - EcdsaCurveName *string `protobuf:"bytes,4,opt,name=ecdsa_curve_name,json=ecdsaCurveName" json:"ecdsa_curve_name,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SignIdentity) Reset() { *m = SignIdentity{} } -func (m *SignIdentity) String() string { return proto.CompactTextString(m) } -func (*SignIdentity) ProtoMessage() {} -func (*SignIdentity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{55} } - -func (m *SignIdentity) GetIdentity() *IdentityType { - if m != nil { - return m.Identity - } - return nil -} - -func (m *SignIdentity) GetChallengeHidden() []byte { - if m != nil { - return m.ChallengeHidden - } - return nil -} - -func (m *SignIdentity) GetChallengeVisual() string { - if m != nil && m.ChallengeVisual != nil { - return *m.ChallengeVisual - } - return "" -} - -func (m *SignIdentity) GetEcdsaCurveName() string { - if m != nil && m.EcdsaCurveName != nil { - return *m.EcdsaCurveName - } - return "" -} - -// * -// Response: Device provides signed identity -// @prev SignIdentity -type SignedIdentity struct { - Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey" json:"public_key,omitempty"` - Signature []byte `protobuf:"bytes,3,opt,name=signature" json:"signature,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SignedIdentity) Reset() { *m = SignedIdentity{} } -func (m *SignedIdentity) String() string { return proto.CompactTextString(m) } -func (*SignedIdentity) ProtoMessage() {} -func (*SignedIdentity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{56} } - -func (m *SignedIdentity) GetAddress() string { - if m != nil && m.Address != nil { - return *m.Address - } - return "" -} - -func (m *SignedIdentity) GetPublicKey() []byte { - if m != nil { - return m.PublicKey - } - return nil -} - -func (m *SignedIdentity) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -// * -// Request: Ask device to generate ECDH session key -// @next ECDHSessionKey -// @next Failure -type GetECDHSessionKey struct { - Identity *IdentityType `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"` - PeerPublicKey []byte `protobuf:"bytes,2,opt,name=peer_public_key,json=peerPublicKey" json:"peer_public_key,omitempty"` - EcdsaCurveName *string `protobuf:"bytes,3,opt,name=ecdsa_curve_name,json=ecdsaCurveName" json:"ecdsa_curve_name,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GetECDHSessionKey) Reset() { *m = GetECDHSessionKey{} } -func (m *GetECDHSessionKey) String() string { return proto.CompactTextString(m) } -func (*GetECDHSessionKey) ProtoMessage() {} -func (*GetECDHSessionKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{57} } - -func (m *GetECDHSessionKey) GetIdentity() *IdentityType { - if m != nil { - return m.Identity - } - return nil -} - -func (m *GetECDHSessionKey) GetPeerPublicKey() []byte { - if m != nil { - return m.PeerPublicKey - } - return nil -} - -func (m *GetECDHSessionKey) GetEcdsaCurveName() string { - if m != nil && m.EcdsaCurveName != nil { - return *m.EcdsaCurveName - } - return "" -} - -// * -// Response: Device provides ECDH session key -// @prev GetECDHSessionKey -type ECDHSessionKey struct { - SessionKey []byte `protobuf:"bytes,1,opt,name=session_key,json=sessionKey" json:"session_key,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ECDHSessionKey) Reset() { *m = ECDHSessionKey{} } -func (m *ECDHSessionKey) String() string { return proto.CompactTextString(m) } -func (*ECDHSessionKey) ProtoMessage() {} -func (*ECDHSessionKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{58} } - -func (m *ECDHSessionKey) GetSessionKey() []byte { - if m != nil { - return m.SessionKey - } - return nil -} - -// * -// Request: Set U2F counter -// @next Success -type SetU2FCounter struct { - U2FCounter *uint32 `protobuf:"varint,1,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SetU2FCounter) Reset() { *m = SetU2FCounter{} } -func (m *SetU2FCounter) String() string { return proto.CompactTextString(m) } -func (*SetU2FCounter) ProtoMessage() {} -func (*SetU2FCounter) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{59} } - -func (m *SetU2FCounter) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter - } - return 0 -} - -// * -// Request: Ask device to erase its firmware (so it can be replaced via FirmwareUpload) -// @next Success -// @next FirmwareRequest -// @next Failure -type FirmwareErase struct { - Length *uint32 `protobuf:"varint,1,opt,name=length" json:"length,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *FirmwareErase) Reset() { *m = FirmwareErase{} } -func (m *FirmwareErase) String() string { return proto.CompactTextString(m) } -func (*FirmwareErase) ProtoMessage() {} -func (*FirmwareErase) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{60} } - -func (m *FirmwareErase) GetLength() uint32 { - if m != nil && m.Length != nil { - return *m.Length - } - return 0 -} - -// * -// Response: Ask for firmware chunk -// @next FirmwareUpload -type FirmwareRequest struct { - Offset *uint32 `protobuf:"varint,1,opt,name=offset" json:"offset,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *FirmwareRequest) Reset() { *m = FirmwareRequest{} } -func (m *FirmwareRequest) String() string { return proto.CompactTextString(m) } -func (*FirmwareRequest) ProtoMessage() {} -func (*FirmwareRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{61} } - -func (m *FirmwareRequest) GetOffset() uint32 { - if m != nil && m.Offset != nil { - return *m.Offset - } - return 0 -} - -func (m *FirmwareRequest) GetLength() uint32 { - if m != nil && m.Length != nil { - return *m.Length - } - return 0 -} - -// * -// Request: Send firmware in binary form to the device -// @next Success -// @next Failure -type FirmwareUpload struct { - Payload []byte `protobuf:"bytes,1,req,name=payload" json:"payload,omitempty"` - Hash []byte `protobuf:"bytes,2,opt,name=hash" json:"hash,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *FirmwareUpload) Reset() { *m = FirmwareUpload{} } -func (m *FirmwareUpload) String() string { return proto.CompactTextString(m) } -func (*FirmwareUpload) ProtoMessage() {} -func (*FirmwareUpload) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{62} } - -func (m *FirmwareUpload) GetPayload() []byte { - if m != nil { - return m.Payload - } - return nil -} - -func (m *FirmwareUpload) GetHash() []byte { - if m != nil { - return m.Hash - } - return nil -} - -// * -// Request: Perform a device self-test -// @next Success -// @next Failure -type SelfTest struct { - Payload []byte `protobuf:"bytes,1,opt,name=payload" json:"payload,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *SelfTest) Reset() { *m = SelfTest{} } -func (m *SelfTest) String() string { return proto.CompactTextString(m) } -func (*SelfTest) ProtoMessage() {} -func (*SelfTest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{63} } - -func (m *SelfTest) GetPayload() []byte { - if m != nil { - return m.Payload - } - return nil -} - -// * -// Request: "Press" the button on the device -// @next Success -type DebugLinkDecision struct { - YesNo *bool `protobuf:"varint,1,req,name=yes_no,json=yesNo" json:"yes_no,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkDecision) Reset() { *m = DebugLinkDecision{} } -func (m *DebugLinkDecision) String() string { return proto.CompactTextString(m) } -func (*DebugLinkDecision) ProtoMessage() {} -func (*DebugLinkDecision) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{64} } - -func (m *DebugLinkDecision) GetYesNo() bool { - if m != nil && m.YesNo != nil { - return *m.YesNo - } - return false -} - -// * -// Request: Computer asks for device state -// @next DebugLinkState -type DebugLinkGetState struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkGetState) Reset() { *m = DebugLinkGetState{} } -func (m *DebugLinkGetState) String() string { return proto.CompactTextString(m) } -func (*DebugLinkGetState) ProtoMessage() {} -func (*DebugLinkGetState) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{65} } - -// * -// Response: Device current state -// @prev DebugLinkGetState -type DebugLinkState struct { - Layout []byte `protobuf:"bytes,1,opt,name=layout" json:"layout,omitempty"` - Pin *string `protobuf:"bytes,2,opt,name=pin" json:"pin,omitempty"` - Matrix *string `protobuf:"bytes,3,opt,name=matrix" json:"matrix,omitempty"` - Mnemonic *string `protobuf:"bytes,4,opt,name=mnemonic" json:"mnemonic,omitempty"` - Node *HDNodeType `protobuf:"bytes,5,opt,name=node" json:"node,omitempty"` - PassphraseProtection *bool `protobuf:"varint,6,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - ResetWord *string `protobuf:"bytes,7,opt,name=reset_word,json=resetWord" json:"reset_word,omitempty"` - ResetEntropy []byte `protobuf:"bytes,8,opt,name=reset_entropy,json=resetEntropy" json:"reset_entropy,omitempty"` - RecoveryFakeWord *string `protobuf:"bytes,9,opt,name=recovery_fake_word,json=recoveryFakeWord" json:"recovery_fake_word,omitempty"` - RecoveryWordPos *uint32 `protobuf:"varint,10,opt,name=recovery_word_pos,json=recoveryWordPos" json:"recovery_word_pos,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkState) Reset() { *m = DebugLinkState{} } -func (m *DebugLinkState) String() string { return proto.CompactTextString(m) } -func (*DebugLinkState) ProtoMessage() {} -func (*DebugLinkState) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{66} } - -func (m *DebugLinkState) GetLayout() []byte { - if m != nil { - return m.Layout - } - return nil -} - -func (m *DebugLinkState) GetPin() string { - if m != nil && m.Pin != nil { - return *m.Pin - } - return "" -} - -func (m *DebugLinkState) GetMatrix() string { - if m != nil && m.Matrix != nil { - return *m.Matrix - } - return "" -} - -func (m *DebugLinkState) GetMnemonic() string { - if m != nil && m.Mnemonic != nil { - return *m.Mnemonic - } - return "" -} - -func (m *DebugLinkState) GetNode() *HDNodeType { - if m != nil { - return m.Node - } - return nil -} - -func (m *DebugLinkState) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection - } - return false -} - -func (m *DebugLinkState) GetResetWord() string { - if m != nil && m.ResetWord != nil { - return *m.ResetWord - } - return "" -} - -func (m *DebugLinkState) GetResetEntropy() []byte { - if m != nil { - return m.ResetEntropy - } - return nil -} - -func (m *DebugLinkState) GetRecoveryFakeWord() string { - if m != nil && m.RecoveryFakeWord != nil { - return *m.RecoveryFakeWord - } - return "" -} - -func (m *DebugLinkState) GetRecoveryWordPos() uint32 { - if m != nil && m.RecoveryWordPos != nil { - return *m.RecoveryWordPos - } - return 0 -} - -// * -// Request: Ask device to restart -type DebugLinkStop struct { - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkStop) Reset() { *m = DebugLinkStop{} } -func (m *DebugLinkStop) String() string { return proto.CompactTextString(m) } -func (*DebugLinkStop) ProtoMessage() {} -func (*DebugLinkStop) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{67} } - -// * -// Response: Device wants host to log event -type DebugLinkLog struct { - Level *uint32 `protobuf:"varint,1,opt,name=level" json:"level,omitempty"` - Bucket *string `protobuf:"bytes,2,opt,name=bucket" json:"bucket,omitempty"` - Text *string `protobuf:"bytes,3,opt,name=text" json:"text,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkLog) Reset() { *m = DebugLinkLog{} } -func (m *DebugLinkLog) String() string { return proto.CompactTextString(m) } -func (*DebugLinkLog) ProtoMessage() {} -func (*DebugLinkLog) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{68} } - -func (m *DebugLinkLog) GetLevel() uint32 { - if m != nil && m.Level != nil { - return *m.Level - } - return 0 -} - -func (m *DebugLinkLog) GetBucket() string { - if m != nil && m.Bucket != nil { - return *m.Bucket - } - return "" -} - -func (m *DebugLinkLog) GetText() string { - if m != nil && m.Text != nil { - return *m.Text - } - return "" -} - -// * -// Request: Read memory from device -// @next DebugLinkMemory -type DebugLinkMemoryRead struct { - Address *uint32 `protobuf:"varint,1,opt,name=address" json:"address,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkMemoryRead) Reset() { *m = DebugLinkMemoryRead{} } -func (m *DebugLinkMemoryRead) String() string { return proto.CompactTextString(m) } -func (*DebugLinkMemoryRead) ProtoMessage() {} -func (*DebugLinkMemoryRead) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{69} } - -func (m *DebugLinkMemoryRead) GetAddress() uint32 { - if m != nil && m.Address != nil { - return *m.Address - } - return 0 -} - -func (m *DebugLinkMemoryRead) GetLength() uint32 { - if m != nil && m.Length != nil { - return *m.Length - } - return 0 -} - -// * -// Response: Device sends memory back -// @prev DebugLinkMemoryRead -type DebugLinkMemory struct { - Memory []byte `protobuf:"bytes,1,opt,name=memory" json:"memory,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkMemory) Reset() { *m = DebugLinkMemory{} } -func (m *DebugLinkMemory) String() string { return proto.CompactTextString(m) } -func (*DebugLinkMemory) ProtoMessage() {} -func (*DebugLinkMemory) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{70} } - -func (m *DebugLinkMemory) GetMemory() []byte { - if m != nil { - return m.Memory - } - return nil -} - -// * -// Request: Write memory to device. -// WARNING: Writing to the wrong location can irreparably break the device. -type DebugLinkMemoryWrite struct { - Address *uint32 `protobuf:"varint,1,opt,name=address" json:"address,omitempty"` - Memory []byte `protobuf:"bytes,2,opt,name=memory" json:"memory,omitempty"` - Flash *bool `protobuf:"varint,3,opt,name=flash" json:"flash,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkMemoryWrite) Reset() { *m = DebugLinkMemoryWrite{} } -func (m *DebugLinkMemoryWrite) String() string { return proto.CompactTextString(m) } -func (*DebugLinkMemoryWrite) ProtoMessage() {} -func (*DebugLinkMemoryWrite) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{71} } - -func (m *DebugLinkMemoryWrite) GetAddress() uint32 { - if m != nil && m.Address != nil { - return *m.Address - } - return 0 -} - -func (m *DebugLinkMemoryWrite) GetMemory() []byte { - if m != nil { - return m.Memory - } - return nil -} - -func (m *DebugLinkMemoryWrite) GetFlash() bool { - if m != nil && m.Flash != nil { - return *m.Flash - } - return false -} - -// * -// Request: Erase block of flash on device -// WARNING: Writing to the wrong location can irreparably break the device. -type DebugLinkFlashErase struct { - Sector *uint32 `protobuf:"varint,1,opt,name=sector" json:"sector,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DebugLinkFlashErase) Reset() { *m = DebugLinkFlashErase{} } -func (m *DebugLinkFlashErase) String() string { return proto.CompactTextString(m) } -func (*DebugLinkFlashErase) ProtoMessage() {} -func (*DebugLinkFlashErase) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{72} } - -func (m *DebugLinkFlashErase) GetSector() uint32 { - if m != nil && m.Sector != nil { - return *m.Sector - } - return 0 +func (MessageType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_4dc296cbfe5ffcd5, []int{0} +} + +var E_WireIn = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50002, + Name: "hw.trezor.messages.wire_in", + Tag: "varint,50002,opt,name=wire_in", + Filename: "messages.proto", +} + +var E_WireOut = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50003, + Name: "hw.trezor.messages.wire_out", + Tag: "varint,50003,opt,name=wire_out", + Filename: "messages.proto", +} + +var E_WireDebugIn = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50004, + Name: "hw.trezor.messages.wire_debug_in", + Tag: "varint,50004,opt,name=wire_debug_in", + Filename: "messages.proto", +} + +var E_WireDebugOut = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50005, + Name: "hw.trezor.messages.wire_debug_out", + Tag: "varint,50005,opt,name=wire_debug_out", + Filename: "messages.proto", +} + +var E_WireTiny = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50006, + Name: "hw.trezor.messages.wire_tiny", + Tag: "varint,50006,opt,name=wire_tiny", + Filename: "messages.proto", +} + +var E_WireBootloader = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50007, + Name: "hw.trezor.messages.wire_bootloader", + Tag: "varint,50007,opt,name=wire_bootloader", + Filename: "messages.proto", +} + +var E_WireNoFsm = &proto.ExtensionDesc{ + ExtendedType: (*descriptor.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50008, + Name: "hw.trezor.messages.wire_no_fsm", + Tag: "varint,50008,opt,name=wire_no_fsm", + Filename: "messages.proto", } func init() { - proto.RegisterType((*Initialize)(nil), "Initialize") - proto.RegisterType((*GetFeatures)(nil), "GetFeatures") - proto.RegisterType((*Features)(nil), "Features") - proto.RegisterType((*ClearSession)(nil), "ClearSession") - proto.RegisterType((*ApplySettings)(nil), "ApplySettings") - proto.RegisterType((*ApplyFlags)(nil), "ApplyFlags") - proto.RegisterType((*ChangePin)(nil), "ChangePin") - proto.RegisterType((*Ping)(nil), "Ping") - proto.RegisterType((*Success)(nil), "Success") - proto.RegisterType((*Failure)(nil), "Failure") - proto.RegisterType((*ButtonRequest)(nil), "ButtonRequest") - proto.RegisterType((*ButtonAck)(nil), "ButtonAck") - proto.RegisterType((*PinMatrixRequest)(nil), "PinMatrixRequest") - proto.RegisterType((*PinMatrixAck)(nil), "PinMatrixAck") - proto.RegisterType((*Cancel)(nil), "Cancel") - proto.RegisterType((*PassphraseRequest)(nil), "PassphraseRequest") - proto.RegisterType((*PassphraseAck)(nil), "PassphraseAck") - proto.RegisterType((*GetEntropy)(nil), "GetEntropy") - proto.RegisterType((*Entropy)(nil), "Entropy") - proto.RegisterType((*GetPublicKey)(nil), "GetPublicKey") - proto.RegisterType((*PublicKey)(nil), "PublicKey") - proto.RegisterType((*GetAddress)(nil), "GetAddress") - proto.RegisterType((*EthereumGetAddress)(nil), "EthereumGetAddress") - proto.RegisterType((*Address)(nil), "Address") - proto.RegisterType((*EthereumAddress)(nil), "EthereumAddress") - proto.RegisterType((*WipeDevice)(nil), "WipeDevice") - proto.RegisterType((*LoadDevice)(nil), "LoadDevice") - proto.RegisterType((*ResetDevice)(nil), "ResetDevice") - proto.RegisterType((*BackupDevice)(nil), "BackupDevice") - proto.RegisterType((*EntropyRequest)(nil), "EntropyRequest") - proto.RegisterType((*EntropyAck)(nil), "EntropyAck") - proto.RegisterType((*RecoveryDevice)(nil), "RecoveryDevice") - proto.RegisterType((*WordRequest)(nil), "WordRequest") - proto.RegisterType((*WordAck)(nil), "WordAck") - proto.RegisterType((*SignMessage)(nil), "SignMessage") - proto.RegisterType((*VerifyMessage)(nil), "VerifyMessage") - proto.RegisterType((*MessageSignature)(nil), "MessageSignature") - proto.RegisterType((*EncryptMessage)(nil), "EncryptMessage") - proto.RegisterType((*EncryptedMessage)(nil), "EncryptedMessage") - proto.RegisterType((*DecryptMessage)(nil), "DecryptMessage") - proto.RegisterType((*DecryptedMessage)(nil), "DecryptedMessage") - proto.RegisterType((*CipherKeyValue)(nil), "CipherKeyValue") - proto.RegisterType((*CipheredKeyValue)(nil), "CipheredKeyValue") - proto.RegisterType((*EstimateTxSize)(nil), "EstimateTxSize") - proto.RegisterType((*TxSize)(nil), "TxSize") - proto.RegisterType((*SignTx)(nil), "SignTx") - proto.RegisterType((*SimpleSignTx)(nil), "SimpleSignTx") - proto.RegisterType((*TxRequest)(nil), "TxRequest") - proto.RegisterType((*TxAck)(nil), "TxAck") - proto.RegisterType((*EthereumSignTx)(nil), "EthereumSignTx") - proto.RegisterType((*EthereumTxRequest)(nil), "EthereumTxRequest") - proto.RegisterType((*EthereumTxAck)(nil), "EthereumTxAck") - proto.RegisterType((*EthereumSignMessage)(nil), "EthereumSignMessage") - proto.RegisterType((*EthereumVerifyMessage)(nil), "EthereumVerifyMessage") - proto.RegisterType((*EthereumMessageSignature)(nil), "EthereumMessageSignature") - proto.RegisterType((*SignIdentity)(nil), "SignIdentity") - proto.RegisterType((*SignedIdentity)(nil), "SignedIdentity") - proto.RegisterType((*GetECDHSessionKey)(nil), "GetECDHSessionKey") - proto.RegisterType((*ECDHSessionKey)(nil), "ECDHSessionKey") - proto.RegisterType((*SetU2FCounter)(nil), "SetU2FCounter") - proto.RegisterType((*FirmwareErase)(nil), "FirmwareErase") - proto.RegisterType((*FirmwareRequest)(nil), "FirmwareRequest") - proto.RegisterType((*FirmwareUpload)(nil), "FirmwareUpload") - proto.RegisterType((*SelfTest)(nil), "SelfTest") - proto.RegisterType((*DebugLinkDecision)(nil), "DebugLinkDecision") - proto.RegisterType((*DebugLinkGetState)(nil), "DebugLinkGetState") - proto.RegisterType((*DebugLinkState)(nil), "DebugLinkState") - proto.RegisterType((*DebugLinkStop)(nil), "DebugLinkStop") - proto.RegisterType((*DebugLinkLog)(nil), "DebugLinkLog") - proto.RegisterType((*DebugLinkMemoryRead)(nil), "DebugLinkMemoryRead") - proto.RegisterType((*DebugLinkMemory)(nil), "DebugLinkMemory") - proto.RegisterType((*DebugLinkMemoryWrite)(nil), "DebugLinkMemoryWrite") - proto.RegisterType((*DebugLinkFlashErase)(nil), "DebugLinkFlashErase") - proto.RegisterEnum("MessageType", MessageType_name, MessageType_value) + proto.RegisterEnum("hw.trezor.messages.MessageType", MessageType_name, MessageType_value) + proto.RegisterExtension(E_WireIn) + proto.RegisterExtension(E_WireOut) + proto.RegisterExtension(E_WireDebugIn) + proto.RegisterExtension(E_WireDebugOut) + proto.RegisterExtension(E_WireTiny) + proto.RegisterExtension(E_WireBootloader) + proto.RegisterExtension(E_WireNoFsm) } -func init() { proto.RegisterFile("messages.proto", fileDescriptor1) } +func init() { proto.RegisterFile("messages.proto", fileDescriptor_4dc296cbfe5ffcd5) } -var fileDescriptor1 = []byte{ - // 3424 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5a, 0xcb, 0x6f, 0xdc, 0x46, - 0x9a, 0x5f, 0x76, 0xb7, 0xfa, 0xf1, 0x35, 0xbb, 0x55, 0xa2, 0x2d, 0xbb, 0x2d, 0x5b, 0xb6, 0x4c, - 0xc9, 0xb6, 0x64, 0x27, 0xed, 0x44, 0x79, 0x6c, 0xd6, 0xbb, 0x79, 0xc8, 0x7a, 0xd8, 0xde, 0xd8, - 0x8e, 0xc0, 0x56, 0x9c, 0xdb, 0x12, 0x14, 0x59, 0xea, 0xae, 0x55, 0x37, 0xc9, 0xf0, 0xa1, 0xa8, - 0x7d, 0xd8, 0xeb, 0xee, 0x65, 0x81, 0xec, 0x69, 0x73, 0x1a, 0xe4, 0x36, 0x19, 0x04, 0x18, 0x0c, - 0x30, 0x18, 0x60, 0x72, 0x9a, 0x3f, 0x60, 0xfe, 0x8b, 0x39, 0xce, 0x1f, 0x30, 0xe7, 0x41, 0x3d, - 0x48, 0x16, 0x29, 0xb6, 0x6c, 0x27, 0xc0, 0x5c, 0x04, 0xd6, 0x57, 0xbf, 0xfe, 0xea, 0x7b, 0xd5, - 0x57, 0x5f, 0x7d, 0x25, 0xe8, 0x4e, 0x70, 0x18, 0x5a, 0x43, 0x1c, 0xf6, 0xfd, 0xc0, 0x8b, 0xbc, - 0xa5, 0x76, 0x34, 0xf5, 0x93, 0x81, 0xae, 0x02, 0x3c, 0x71, 0x49, 0x44, 0xac, 0x31, 0x79, 0x89, - 0xf5, 0x0e, 0xb4, 0x1f, 0xe1, 0x68, 0x0f, 0x5b, 0x51, 0x1c, 0xe0, 0x50, 0xff, 0x69, 0x0e, 0x9a, - 0xc9, 0x40, 0xbb, 0x04, 0xf5, 0x13, 0xec, 0x3a, 0x5e, 0xd0, 0x53, 0x56, 0x94, 0xf5, 0x96, 0x21, - 0x46, 0xda, 0x2a, 0x74, 0x26, 0xd6, 0x7f, 0x7a, 0x81, 0x79, 0x82, 0x83, 0x90, 0x78, 0x6e, 0xaf, - 0xb2, 0xa2, 0xac, 0x77, 0x0c, 0x95, 0x11, 0x5f, 0x70, 0x1a, 0x03, 0x11, 0x57, 0x02, 0x55, 0x05, - 0x88, 0x12, 0x25, 0x90, 0x6f, 0x45, 0xf6, 0x28, 0x05, 0xd5, 0x38, 0x88, 0x11, 0x13, 0xd0, 0x1d, - 0x98, 0x3f, 0xf4, 0xbc, 0x68, 0xec, 0x59, 0x0e, 0x0e, 0xcc, 0x89, 0xe7, 0xe0, 0xde, 0xdc, 0x8a, - 0xb2, 0xde, 0x34, 0xba, 0x19, 0xf9, 0x99, 0xe7, 0x60, 0xed, 0x2a, 0xb4, 0x1c, 0x7c, 0x42, 0x6c, - 0x6c, 0x12, 0xa7, 0x57, 0x67, 0x22, 0x37, 0x39, 0xe1, 0x89, 0xa3, 0xdd, 0x82, 0xae, 0x4f, 0x5c, - 0x93, 0xda, 0x00, 0xdb, 0x11, 0x5d, 0xab, 0xc1, 0x98, 0x74, 0x7c, 0xe2, 0xee, 0xa7, 0x44, 0xed, - 0x3d, 0x58, 0xf4, 0xad, 0x30, 0xf4, 0x47, 0x81, 0x15, 0x62, 0x19, 0xdd, 0x64, 0xe8, 0x8b, 0xd9, - 0xa4, 0xf4, 0xa3, 0x25, 0x68, 0x8e, 0x2d, 0x77, 0x18, 0x5b, 0x43, 0xdc, 0x6b, 0xf1, 0x75, 0x93, - 0xb1, 0x76, 0x11, 0xe6, 0xc6, 0xd6, 0x21, 0x1e, 0xf7, 0x80, 0x4d, 0xf0, 0x81, 0x76, 0x03, 0xe6, - 0x6c, 0x8f, 0xb8, 0x61, 0xaf, 0xbd, 0x52, 0x5d, 0x6f, 0x6f, 0xb6, 0xfa, 0xdb, 0x1e, 0x71, 0x0f, - 0xa6, 0x3e, 0x36, 0x38, 0x5d, 0x5b, 0x81, 0x36, 0x49, 0xbd, 0xe4, 0xf4, 0x54, 0xb6, 0xba, 0x4c, - 0xa2, 0x8b, 0x06, 0xf8, 0x84, 0x30, 0xb3, 0x75, 0x56, 0x94, 0x75, 0xd5, 0x48, 0xc7, 0x05, 0x93, - 0x8d, 0xac, 0x70, 0xd4, 0xeb, 0x32, 0x88, 0x64, 0xb2, 0xc7, 0x56, 0x38, 0xa2, 0x4c, 0xc8, 0xc4, - 0xf7, 0x82, 0x08, 0x3b, 0xbd, 0x79, 0xb6, 0x46, 0x3a, 0xd6, 0x96, 0x01, 0xa8, 0xc5, 0x6c, 0xcb, - 0x1e, 0x61, 0xa7, 0x87, 0xd8, 0x6c, 0xcb, 0x27, 0xee, 0x36, 0x23, 0x68, 0xf7, 0x60, 0x41, 0xb2, - 0x94, 0x40, 0x2d, 0x30, 0x14, 0xca, 0x26, 0x04, 0x78, 0x03, 0xd0, 0x11, 0x09, 0x26, 0xdf, 0x58, - 0x01, 0x35, 0x2a, 0x0e, 0xb1, 0x1b, 0xf5, 0x34, 0x86, 0x9d, 0x4f, 0xe8, 0xfb, 0x9c, 0xac, 0xdd, - 0x04, 0xd5, 0xc5, 0xd8, 0x09, 0xcd, 0x43, 0xcb, 0x3e, 0x8e, 0xfd, 0xde, 0x05, 0xae, 0x3a, 0xa3, - 0x3d, 0x64, 0x24, 0x6a, 0xd3, 0xa3, 0xb1, 0x35, 0x0c, 0x7b, 0x17, 0x59, 0xb8, 0xf0, 0x81, 0xde, - 0x05, 0x75, 0x7b, 0x8c, 0xad, 0x60, 0x80, 0x43, 0x6a, 0x04, 0xfd, 0x7f, 0x14, 0xe8, 0x6c, 0xf9, - 0xfe, 0x78, 0x3a, 0xc0, 0x51, 0x44, 0xdc, 0x61, 0x98, 0xf3, 0x93, 0x32, 0xcb, 0x4f, 0x15, 0xd9, - 0x4f, 0xb7, 0xa0, 0x1b, 0xd3, 0x38, 0x48, 0xf5, 0x61, 0x61, 0xdc, 0x34, 0x3a, 0x71, 0x88, 0xf7, - 0x53, 0xa2, 0x76, 0x1d, 0x60, 0xe4, 0x4d, 0x70, 0x68, 0x07, 0x18, 0xf3, 0x20, 0x56, 0x0d, 0x89, - 0xa2, 0xeb, 0x00, 0x4c, 0x92, 0x3d, 0x2a, 0x68, 0x26, 0xbe, 0x22, 0x8b, 0xbf, 0x0a, 0xad, 0xed, - 0x91, 0xe5, 0x0e, 0xf1, 0x3e, 0x71, 0xe9, 0xd6, 0x0b, 0xf0, 0xc4, 0x3b, 0xe1, 0x72, 0x36, 0x0d, - 0x31, 0xd2, 0x7f, 0xa3, 0x40, 0x6d, 0x9f, 0xb8, 0x43, 0xad, 0x07, 0x0d, 0xb1, 0xc9, 0x85, 0x26, - 0xc9, 0x90, 0xfa, 0xe5, 0x30, 0x8e, 0x22, 0x2f, 0x17, 0xeb, 0x15, 0xee, 0x17, 0x3e, 0x21, 0x45, - 0xee, 0xd9, 0x5d, 0x51, 0x7d, 0xa3, 0x5d, 0x51, 0x9b, 0xbd, 0x2b, 0xf4, 0x55, 0x68, 0x0c, 0x62, - 0xdb, 0xc6, 0x61, 0x38, 0x5b, 0x5a, 0x7d, 0x17, 0x1a, 0x7b, 0x16, 0x19, 0xc7, 0x01, 0xd6, 0x56, - 0xa0, 0x66, 0xd3, 0xcd, 0x4d, 0x11, 0xdd, 0x4d, 0xb5, 0x2f, 0xe8, 0x6c, 0x57, 0xb0, 0x19, 0x99, - 0x4d, 0x25, 0xcf, 0xe6, 0x73, 0xe8, 0x3c, 0x64, 0xba, 0x19, 0xf8, 0xeb, 0x18, 0x87, 0x91, 0x76, - 0x3b, 0xc7, 0x4c, 0xeb, 0xe7, 0x66, 0x25, 0x96, 0x1a, 0xd4, 0x1c, 0x2b, 0xb2, 0x04, 0x3f, 0xf6, - 0xad, 0xb7, 0xa1, 0xc5, 0xe1, 0x5b, 0xf6, 0xb1, 0xfe, 0x31, 0xa0, 0x7d, 0xe2, 0x3e, 0xb3, 0xa2, - 0x80, 0x9c, 0x26, 0xcc, 0x37, 0xa0, 0x46, 0x33, 0xaa, 0x60, 0xbe, 0xd8, 0x2f, 0x02, 0x38, 0x7f, - 0x0a, 0xd1, 0x57, 0x40, 0x4d, 0x67, 0xb7, 0xec, 0x63, 0x0d, 0x41, 0xd5, 0x27, 0x6e, 0x4f, 0x59, - 0xa9, 0xac, 0xb7, 0x0c, 0xfa, 0xa9, 0x37, 0xa1, 0xbe, 0x6d, 0xb9, 0x36, 0x1e, 0xeb, 0x17, 0x60, - 0x21, 0x8b, 0x29, 0xc1, 0x4a, 0xbf, 0x0f, 0x9d, 0x8c, 0x48, 0x39, 0x5c, 0x07, 0x90, 0xc2, 0x91, - 0x33, 0x92, 0x28, 0xfa, 0x0a, 0xc0, 0x23, 0x1c, 0xed, 0xba, 0x51, 0xe0, 0xf9, 0x53, 0xaa, 0x5f, - 0x48, 0x5e, 0x72, 0x5c, 0xc7, 0x60, 0xdf, 0xd4, 0x31, 0xc9, 0x74, 0x0f, 0x1a, 0x98, 0x7f, 0x32, - 0x84, 0x6a, 0x24, 0x43, 0xfd, 0x57, 0x0a, 0xa8, 0x8f, 0x70, 0xb4, 0x1f, 0x1f, 0x8e, 0x89, 0xfd, - 0x39, 0x9e, 0xd2, 0xec, 0x6a, 0x39, 0x4e, 0x80, 0xc3, 0xd0, 0xa4, 0xf2, 0x57, 0xd7, 0x3b, 0x46, - 0x53, 0x10, 0x9e, 0x6b, 0xeb, 0x80, 0xb0, 0xed, 0x84, 0x96, 0x69, 0xc7, 0xc1, 0x09, 0x36, 0x5d, - 0x6b, 0x92, 0xb8, 0xa8, 0xcb, 0xe8, 0xdb, 0x94, 0xfc, 0xdc, 0x9a, 0x60, 0xba, 0xbd, 0xc3, 0x91, - 0xf7, 0x8d, 0xe9, 0x90, 0xd0, 0x1f, 0x5b, 0x53, 0x11, 0x6f, 0x6d, 0x4a, 0xdb, 0xe1, 0x24, 0x6d, - 0x0d, 0x5a, 0x34, 0x09, 0x72, 0x2e, 0x34, 0xc2, 0x5a, 0x0f, 0x1a, 0x0f, 0x49, 0x44, 0x69, 0x46, - 0x93, 0xfe, 0xa5, 0x8c, 0xf4, 0xcf, 0xa0, 0x95, 0x09, 0x77, 0x03, 0x6a, 0x2e, 0x77, 0x77, 0x65, - 0xbd, 0xbd, 0xd9, 0xee, 0x3f, 0xde, 0x79, 0xee, 0x39, 0x22, 0x74, 0x5c, 0xe1, 0xe7, 0x53, 0x3f, - 0x3e, 0x4c, 0xfc, 0x4c, 0xbf, 0xf5, 0xbf, 0x2a, 0xcc, 0x54, 0x5b, 0x5c, 0x89, 0xf3, 0x15, 0xcc, - 0xc9, 0x54, 0x99, 0x21, 0xd3, 0xeb, 0x28, 0xf7, 0x01, 0x34, 0x27, 0xf1, 0x38, 0x22, 0x21, 0x19, - 0x32, 0xdd, 0xda, 0x9b, 0x57, 0xfa, 0xcf, 0x04, 0xc1, 0xc0, 0x0e, 0xc6, 0x93, 0x81, 0x1d, 0x10, - 0x9f, 0xc7, 0x50, 0x0a, 0xd5, 0x3e, 0x85, 0x76, 0xc8, 0xe8, 0x26, 0x8b, 0xbc, 0x39, 0x16, 0x79, - 0xa8, 0xff, 0xc4, 0xf5, 0xe3, 0x28, 0xfb, 0xc1, 0x03, 0x75, 0xb0, 0xbf, 0xfb, 0x7c, 0x67, 0x6b, - 0x67, 0xc7, 0xd8, 0x1d, 0x0c, 0x0c, 0x08, 0xd3, 0x19, 0xfd, 0x00, 0xb4, 0xdd, 0x68, 0x84, 0x03, - 0x1c, 0x4f, 0x5e, 0x57, 0xe7, 0xa2, 0x36, 0x95, 0x33, 0xda, 0xd0, 0x50, 0x4a, 0x58, 0xf5, 0xa0, - 0x21, 0x7e, 0x29, 0x82, 0x32, 0x19, 0xea, 0xf7, 0x60, 0x3e, 0x59, 0x7a, 0x06, 0x58, 0xcd, 0xc0, - 0x2a, 0xc0, 0x57, 0xc4, 0xc7, 0x3b, 0xec, 0xdc, 0xd6, 0xff, 0xaf, 0x02, 0xf0, 0xd4, 0xb3, 0x1c, - 0x3e, 0xa4, 0x09, 0x7c, 0xe2, 0xe2, 0x89, 0xe7, 0x12, 0x3b, 0x49, 0xe0, 0xc9, 0x38, 0x0d, 0x81, - 0x0a, 0x33, 0x6a, 0x49, 0x08, 0x88, 0xad, 0x57, 0x65, 0xbf, 0xa3, 0x9f, 0x3f, 0x2b, 0xad, 0x69, - 0xab, 0xd2, 0x21, 0x32, 0xc7, 0x03, 0x01, 0xbb, 0xc3, 0x31, 0x09, 0x47, 0x65, 0xa7, 0x49, 0x5d, - 0x3e, 0x4d, 0x56, 0xa1, 0x13, 0x1e, 0x13, 0xdf, 0xb4, 0x47, 0xd8, 0x3e, 0x0e, 0xe3, 0x89, 0x28, - 0x41, 0x54, 0x4a, 0xdc, 0x16, 0x34, 0xed, 0x06, 0xb4, 0xe3, 0xcd, 0x23, 0xd3, 0xf6, 0x62, 0x37, - 0xc2, 0x01, 0xab, 0x3b, 0x3a, 0x06, 0xc4, 0x9b, 0x47, 0xdb, 0x9c, 0xa2, 0xff, 0xb6, 0x02, 0x6d, - 0x03, 0x87, 0x38, 0x12, 0x46, 0xb9, 0x05, 0x5d, 0xe1, 0x21, 0x33, 0xb0, 0x5c, 0xc7, 0x9b, 0x88, - 0x33, 0xa3, 0x23, 0xa8, 0x06, 0x23, 0x6a, 0x37, 0xa0, 0x19, 0x46, 0x01, 0x76, 0x87, 0xd1, 0x88, - 0x17, 0x6c, 0x0f, 0xaa, 0x9b, 0x1f, 0x7c, 0x68, 0xa4, 0xc4, 0xd9, 0xd6, 0xa8, 0x9e, 0x63, 0x8d, - 0xb3, 0x07, 0x48, 0xad, 0xec, 0x00, 0xf9, 0x05, 0x46, 0x2b, 0xd8, 0xa3, 0x51, 0xb4, 0x07, 0x05, - 0x30, 0xab, 0x8a, 0x7a, 0x81, 0x17, 0x6a, 0x40, 0x49, 0xbc, 0x5c, 0xa0, 0x85, 0x01, 0xff, 0x12, - 0x41, 0x85, 0xa0, 0x2b, 0xf2, 0x5f, 0x92, 0x64, 0x6f, 0x03, 0x08, 0x0a, 0xcd, 0xb0, 0xb9, 0xa4, - 0xa8, 0xc8, 0x49, 0xf1, 0x4f, 0x15, 0xe8, 0x1a, 0xd8, 0xf6, 0x4e, 0x70, 0x30, 0x15, 0xd6, 0x5f, - 0x06, 0xf8, 0xc6, 0x0b, 0x1c, 0x2e, 0x9f, 0x38, 0xd1, 0x5b, 0x94, 0xc2, 0xc4, 0x9b, 0x6d, 0xd4, - 0xca, 0x1b, 0x19, 0xb5, 0xfa, 0x2a, 0xa3, 0xd6, 0x5e, 0x69, 0xd4, 0x39, 0xd9, 0xa8, 0x1b, 0x80, - 0xb0, 0x7b, 0xe4, 0x05, 0x36, 0x36, 0xa9, 0xac, 0x63, 0x12, 0x46, 0xcc, 0xea, 0x4d, 0x63, 0x5e, - 0xd0, 0xbf, 0x12, 0x64, 0x9a, 0x39, 0x59, 0xca, 0xe1, 0x81, 0xc8, 0xbe, 0x8b, 0x3e, 0x69, 0x9d, - 0xf1, 0xc9, 0x65, 0x68, 0x38, 0xc1, 0xd4, 0x0c, 0x62, 0x97, 0xd5, 0xbd, 0x4d, 0xa3, 0xee, 0x04, - 0x53, 0x23, 0x76, 0xf5, 0xf7, 0xa0, 0x4d, 0x39, 0x27, 0x27, 0xe9, 0x5a, 0xee, 0x24, 0x45, 0x7d, - 0x69, 0x4e, 0x3a, 0x44, 0x97, 0xa1, 0x41, 0x27, 0xa8, 0x6f, 0x34, 0xa8, 0x51, 0x81, 0x45, 0x8a, - 0x61, 0xdf, 0xfa, 0x8f, 0x0a, 0xb4, 0x07, 0x64, 0xe8, 0x3e, 0x13, 0x15, 0xd0, 0xb9, 0x49, 0x2d, - 0x57, 0x43, 0xb0, 0xcc, 0x93, 0x14, 0x4e, 0xb9, 0x14, 0x5f, 0x9d, 0x95, 0xe2, 0x0b, 0x89, 0xb8, - 0xf6, 0xc6, 0x89, 0xf8, 0xbf, 0x15, 0xe8, 0xbc, 0xc0, 0x01, 0x39, 0x9a, 0x26, 0xf2, 0xe6, 0x92, - 0xa1, 0x22, 0x65, 0x4e, 0xed, 0x1a, 0xb4, 0x42, 0x32, 0x74, 0xd9, 0x7d, 0x8c, 0x45, 0x8c, 0x6a, - 0x64, 0x04, 0x59, 0x95, 0x2a, 0x8f, 0xd3, 0x52, 0x55, 0x66, 0x9e, 0xa0, 0xff, 0x0e, 0x48, 0x88, - 0x30, 0x90, 0x79, 0xfe, 0x1c, 0x59, 0xf4, 0x1f, 0x14, 0xba, 0xa9, 0xec, 0x60, 0xea, 0x47, 0x89, - 0x5a, 0x97, 0xa0, 0xee, 0xc7, 0x87, 0xc7, 0x38, 0xd9, 0x45, 0x62, 0x54, 0xac, 0xe2, 0x24, 0xb1, - 0x6f, 0x82, 0x9a, 0x64, 0x32, 0xcf, 0x1d, 0xa7, 0xc7, 0xa7, 0xa0, 0x7d, 0xe1, 0x8e, 0x0b, 0x55, - 0x48, 0xed, 0xbc, 0x43, 0x7a, 0x6e, 0x96, 0xda, 0x2f, 0x00, 0x09, 0x49, 0xb1, 0x93, 0xc8, 0x7a, - 0x11, 0xe6, 0x5c, 0xcf, 0xb5, 0xb1, 0x10, 0x95, 0x0f, 0xce, 0x91, 0x54, 0x83, 0xda, 0x68, 0x62, - 0xd9, 0xc2, 0xee, 0xec, 0x5b, 0xff, 0x1a, 0xba, 0x3b, 0x38, 0x67, 0x81, 0x73, 0x03, 0x31, 0x5d, - 0xb2, 0x32, 0x63, 0xc9, 0x6a, 0xf9, 0x92, 0x35, 0x69, 0xc9, 0x3d, 0x40, 0x62, 0xc9, 0x4c, 0x95, - 0x42, 0xad, 0x2d, 0x71, 0x90, 0x7c, 0x5b, 0xc9, 0xf9, 0x56, 0xff, 0xb3, 0x02, 0xdd, 0x6d, 0xe2, - 0x8f, 0x70, 0xf0, 0x39, 0x9e, 0xbe, 0xb0, 0xc6, 0xf1, 0x2b, 0x64, 0x47, 0x50, 0xa5, 0x7e, 0xe5, - 0x5c, 0xe8, 0x27, 0xd5, 0xe6, 0x84, 0xfe, 0x4e, 0x48, 0xcd, 0x07, 0x3c, 0x93, 0x32, 0xf9, 0xc4, - 0xb1, 0x90, 0x0c, 0xb5, 0x35, 0xe8, 0x5a, 0xe1, 0xb1, 0xe9, 0xb9, 0x66, 0x02, 0xe0, 0x77, 0x7a, - 0xd5, 0x0a, 0x8f, 0xbf, 0x70, 0x77, 0xcf, 0xa0, 0x1c, 0xae, 0xa6, 0x48, 0x52, 0x1c, 0x25, 0x54, - 0xd7, 0xba, 0x50, 0x21, 0x27, 0xec, 0x60, 0x50, 0x8d, 0x0a, 0x39, 0xd1, 0xd7, 0x01, 0x71, 0x65, - 0xb0, 0x93, 0xaa, 0x93, 0xca, 0xa7, 0x48, 0xf2, 0xe9, 0xff, 0x05, 0xdd, 0xdd, 0x30, 0x22, 0x13, - 0x2b, 0xc2, 0x07, 0xa7, 0x03, 0xf2, 0x12, 0xd3, 0x23, 0xda, 0x8b, 0x23, 0x3f, 0x8e, 0xc2, 0x34, - 0xa3, 0xd3, 0xc2, 0x59, 0x15, 0x44, 0x9e, 0xd4, 0x6f, 0x82, 0x4a, 0x5c, 0x09, 0x53, 0x61, 0x98, - 0x36, 0xa7, 0x71, 0xc8, 0x6b, 0x25, 0x13, 0xfd, 0x26, 0xd4, 0xc5, 0xba, 0x97, 0xa1, 0x11, 0x9d, - 0x9a, 0xa2, 0x54, 0xa7, 0xd9, 0xb4, 0x1e, 0xb1, 0x09, 0xfd, 0xf7, 0x0a, 0xd4, 0xe9, 0xf6, 0x3c, - 0x38, 0xfd, 0xc7, 0xca, 0xa6, 0x5d, 0x85, 0x46, 0xae, 0x2b, 0xf3, 0x40, 0x79, 0xd7, 0x48, 0x28, - 0xda, 0x75, 0x68, 0x8d, 0x3d, 0xfb, 0xd8, 0x8c, 0x88, 0xd8, 0x69, 0x9d, 0x07, 0xca, 0x3b, 0x46, - 0x93, 0xd2, 0x0e, 0xc8, 0x04, 0xeb, 0x7f, 0x53, 0x40, 0x1d, 0x90, 0x89, 0x3f, 0xc6, 0x42, 0xf6, - 0x35, 0xa8, 0x73, 0x11, 0x58, 0x2c, 0xb5, 0x37, 0xd5, 0xfe, 0xc1, 0x29, 0xcb, 0x99, 0x2c, 0xcd, - 0x8b, 0x39, 0xed, 0x0e, 0x34, 0x84, 0x32, 0xbd, 0x0a, 0x83, 0x75, 0xfa, 0x07, 0xa7, 0x5f, 0x30, - 0x0a, 0xc3, 0x25, 0xb3, 0xda, 0xfb, 0xa0, 0x46, 0x81, 0xe5, 0x86, 0x16, 0x3b, 0x09, 0xc3, 0x5e, - 0x95, 0xa1, 0x51, 0xff, 0x20, 0x23, 0xb2, 0x1f, 0xe4, 0x50, 0xaf, 0x97, 0x16, 0x65, 0xc5, 0xe7, - 0xce, 0x57, 0xbc, 0x7e, 0x56, 0xf1, 0x5f, 0x2b, 0xd0, 0x3a, 0x48, 0x2f, 0x8a, 0xf7, 0x41, 0x0d, - 0xf8, 0xa7, 0x29, 0x1d, 0x73, 0x6a, 0x5f, 0x3e, 0xe2, 0xda, 0x41, 0x36, 0xd0, 0xee, 0x43, 0xc3, - 0xc1, 0x91, 0x45, 0xc6, 0xa1, 0xa8, 0x63, 0x17, 0xfb, 0x29, 0xb7, 0x1d, 0x3e, 0xc1, 0x0d, 0x21, - 0x50, 0xda, 0x47, 0x00, 0x21, 0x0e, 0x92, 0x36, 0x51, 0x95, 0xfd, 0xa6, 0x97, 0xfd, 0x66, 0x90, - 0xce, 0xb1, 0x9f, 0x49, 0x58, 0x7d, 0x03, 0xe6, 0x0e, 0xd8, 0x95, 0x74, 0x05, 0x2a, 0xd1, 0x29, - 0x13, 0xad, 0xcc, 0x82, 0x95, 0xe8, 0x54, 0xff, 0xdf, 0x0a, 0x74, 0x93, 0x0a, 0x5e, 0xf8, 0xf3, - 0x67, 0xa4, 0xb6, 0xab, 0xd0, 0x1a, 0x5a, 0xa1, 0xe9, 0x07, 0xc4, 0x4e, 0xd2, 0x44, 0x73, 0x68, - 0x85, 0xfb, 0x74, 0x9c, 0x4c, 0x8e, 0xc9, 0x84, 0x44, 0x22, 0xc5, 0xd1, 0xc9, 0xa7, 0x74, 0x4c, - 0x37, 0x78, 0xe4, 0x31, 0x67, 0xa8, 0x46, 0x25, 0xf2, 0xb2, 0xcd, 0x5c, 0x97, 0x93, 0xcd, 0x5b, - 0xa0, 0xd1, 0xeb, 0xbb, 0x29, 0x9a, 0x64, 0xa6, 0x3d, 0x8a, 0xdd, 0x63, 0x91, 0x16, 0x10, 0x9d, - 0x11, 0x6d, 0xcf, 0x6d, 0x4a, 0xa7, 0x25, 0x0c, 0x43, 0x8f, 0x79, 0x45, 0x2c, 0xca, 0x6c, 0x4a, - 0x7a, 0xca, 0xcb, 0xe1, 0x2b, 0xd0, 0xb4, 0x47, 0x16, 0x71, 0x4d, 0xe2, 0x88, 0x02, 0xa7, 0xc1, - 0xc6, 0x4f, 0x1c, 0xfd, 0xff, 0x15, 0x58, 0x48, 0xec, 0x91, 0x39, 0xbb, 0xc0, 0x51, 0x39, 0xc3, - 0x91, 0x16, 0xaa, 0xc9, 0x81, 0x69, 0x9e, 0x88, 0xae, 0x29, 0xa4, 0xa4, 0x17, 0x79, 0x40, 0x20, - 0x6c, 0x94, 0x01, 0x8c, 0x3c, 0x20, 0x4c, 0x1a, 0x4d, 0x29, 0x69, 0xa0, 0xf7, 0xa1, 0x93, 0x09, - 0x46, 0x9d, 0xbb, 0x0c, 0x4c, 0x02, 0x61, 0x0c, 0x9e, 0xfc, 0x5a, 0x94, 0xc2, 0xac, 0xa0, 0x3f, - 0x85, 0x0b, 0xb2, 0x63, 0x7f, 0x59, 0x05, 0xa5, 0x13, 0x58, 0x4c, 0xb8, 0x9d, 0x5b, 0xe1, 0xa8, - 0xbf, 0xb8, 0xc2, 0xd1, 0x0d, 0xe8, 0x25, 0x4b, 0xbd, 0xaa, 0x86, 0x79, 0xdd, 0xd5, 0xf4, 0x9f, - 0x58, 0xd2, 0x1a, 0xba, 0x4f, 0x1c, 0xec, 0x46, 0x24, 0x9a, 0x6a, 0x1b, 0xd0, 0x24, 0xe2, 0x5b, - 0xec, 0x8f, 0x4e, 0x3f, 0x99, 0xe4, 0xf7, 0x73, 0x92, 0x41, 0x91, 0x3d, 0xb2, 0xc6, 0xd4, 0xf7, - 0xd8, 0x1c, 0x11, 0xc7, 0xc1, 0xae, 0x58, 0x60, 0x3e, 0xa5, 0x3f, 0x66, 0xe4, 0x3c, 0xf4, 0x84, - 0x84, 0xb1, 0x35, 0x16, 0x97, 0xd2, 0x0c, 0xfa, 0x82, 0x91, 0x4b, 0xdb, 0x2a, 0xb5, 0xb2, 0xb6, - 0x8a, 0x3e, 0x84, 0x2e, 0x15, 0x1d, 0x3b, 0xa9, 0xf0, 0xb3, 0x2b, 0xb9, 0x65, 0x00, 0x9f, 0x75, - 0x4e, 0xcc, 0xe4, 0x10, 0x57, 0x8d, 0x96, 0x9f, 0xf6, 0x52, 0x72, 0x46, 0xaa, 0x16, 0x8d, 0xf4, - 0xad, 0x02, 0x0b, 0x8f, 0x70, 0xb4, 0xbb, 0xbd, 0xf3, 0x58, 0x34, 0x5a, 0xe9, 0x6f, 0xde, 0xc0, - 0x52, 0xb7, 0x61, 0xde, 0xc7, 0x38, 0x30, 0xcf, 0x88, 0xd0, 0xa1, 0xe4, 0xac, 0xa5, 0x53, 0xa6, - 0x7b, 0xb5, 0x54, 0xf7, 0x77, 0xa1, 0x5b, 0x10, 0x87, 0xee, 0x13, 0x3e, 0x32, 0xb3, 0xfa, 0x13, - 0xc2, 0x14, 0xa0, 0xbf, 0x03, 0x9d, 0x01, 0x8e, 0xbe, 0xdc, 0xdc, 0x93, 0x2e, 0x91, 0xf2, 0x8d, - 0x46, 0x39, 0x73, 0xeb, 0xbe, 0x03, 0x9d, 0x3d, 0xd1, 0xa9, 0xde, 0x65, 0x3d, 0xdf, 0x4b, 0x50, - 0xcf, 0xed, 0x74, 0x31, 0xd2, 0xb7, 0x60, 0x3e, 0x01, 0x26, 0x99, 0xe1, 0x12, 0xd4, 0xbd, 0xa3, - 0xa3, 0x10, 0x27, 0xf7, 0x43, 0x31, 0x92, 0x58, 0x54, 0x72, 0x2c, 0x3e, 0x81, 0x6e, 0xc2, 0xe2, - 0x4b, 0x7f, 0xec, 0x59, 0x0e, 0x75, 0xa6, 0x6f, 0x4d, 0xe9, 0x67, 0xd2, 0x2f, 0x11, 0x43, 0x56, - 0x16, 0x5a, 0xe1, 0x48, 0xd8, 0x90, 0x7d, 0xeb, 0x6b, 0xd0, 0x1c, 0xe0, 0xf1, 0xd1, 0x01, 0x5d, - 0x3b, 0xf7, 0x4b, 0x45, 0xfa, 0xa5, 0x7e, 0x17, 0x16, 0x76, 0xf0, 0x61, 0x3c, 0x7c, 0x4a, 0xdc, - 0xe3, 0x1d, 0x6c, 0xf3, 0x97, 0x83, 0x45, 0xa8, 0x4f, 0x71, 0x68, 0xba, 0x1e, 0x5b, 0xa7, 0x69, - 0xcc, 0x4d, 0x71, 0xf8, 0xdc, 0xd3, 0x2f, 0x48, 0xd8, 0x47, 0x38, 0x1a, 0x44, 0x56, 0x84, 0xf5, - 0xbf, 0x54, 0x68, 0xc5, 0x2b, 0xa8, 0x8c, 0xc4, 0x34, 0xb2, 0xa6, 0x5e, 0x1c, 0x25, 0x35, 0x3f, - 0x1f, 0x25, 0xbd, 0x97, 0x4a, 0xd6, 0x7b, 0xb9, 0x04, 0xf5, 0x09, 0xeb, 0x8a, 0x0a, 0xa7, 0x8a, - 0x51, 0xae, 0xc5, 0x53, 0x9b, 0xd1, 0xe2, 0x99, 0x9b, 0xd5, 0xe2, 0x99, 0x79, 0xdb, 0xae, 0x9f, - 0x73, 0xdb, 0x5e, 0x06, 0x08, 0x70, 0x88, 0x23, 0x76, 0x13, 0x66, 0xe7, 0x45, 0xcb, 0x68, 0x31, - 0x0a, 0xbd, 0x74, 0xd2, 0xaa, 0x8b, 0x4f, 0x27, 0x3d, 0x81, 0x26, 0xd3, 0x4c, 0x65, 0xc4, 0xa4, - 0x8f, 0xfa, 0x16, 0x68, 0x81, 0xe8, 0x0b, 0x98, 0x47, 0xd6, 0x31, 0xbf, 0x55, 0x8b, 0xb7, 0x20, - 0x94, 0xcc, 0xec, 0x59, 0xc7, 0xec, 0x5a, 0xad, 0xdd, 0x85, 0x85, 0x14, 0xcd, 0x9a, 0x07, 0xbe, - 0x17, 0xb2, 0x7b, 0x72, 0xc7, 0x98, 0x4f, 0x26, 0x28, 0x70, 0xdf, 0x0b, 0xf5, 0x79, 0xe8, 0x48, - 0x36, 0xf6, 0x7c, 0x7d, 0x1f, 0xd4, 0x94, 0xf0, 0xd4, 0x1b, 0xb2, 0x0b, 0x3e, 0x3e, 0xc1, 0xe3, - 0xe4, 0x35, 0x81, 0x0d, 0xa8, 0x79, 0x0f, 0x63, 0xfb, 0x18, 0x47, 0xc2, 0xe6, 0x62, 0xc4, 0x6e, - 0xf3, 0xf8, 0x34, 0x12, 0x46, 0x67, 0xdf, 0xfa, 0x23, 0xb8, 0x90, 0x72, 0x7c, 0x86, 0x27, 0x5e, - 0x30, 0x35, 0x30, 0x8f, 0x39, 0x39, 0x81, 0x74, 0xb2, 0x04, 0x32, 0x2b, 0x6e, 0x37, 0x60, 0xbe, - 0xc0, 0x88, 0xb9, 0x99, 0x7d, 0x25, 0x01, 0xc1, 0x47, 0xfa, 0x7f, 0xc0, 0xc5, 0x02, 0xf4, 0xab, - 0x80, 0x44, 0xf8, 0xfc, 0x45, 0x05, 0xa7, 0x8a, 0xcc, 0x49, 0xbc, 0xa6, 0x84, 0x23, 0x71, 0x5b, - 0xe4, 0x03, 0xfd, 0x6d, 0x49, 0xa7, 0x3d, 0x4a, 0x49, 0x37, 0x6d, 0x88, 0xed, 0xc8, 0x4b, 0x76, - 0xb8, 0x18, 0xdd, 0xfd, 0x71, 0x11, 0xda, 0xe2, 0x1c, 0x61, 0x75, 0xd8, 0x0a, 0x5c, 0x92, 0x86, - 0x66, 0xf6, 0x60, 0x8a, 0xfe, 0x69, 0xa9, 0xf6, 0xed, 0x1f, 0x7a, 0x8a, 0xb6, 0x94, 0x5e, 0x9e, - 0x19, 0x62, 0x9f, 0xb8, 0x43, 0xa4, 0x88, 0xb9, 0x65, 0xb8, 0x20, 0xcf, 0x89, 0x57, 0x10, 0x54, - 0x59, 0xaa, 0x7d, 0x57, 0x32, 0x2d, 0xde, 0x39, 0x50, 0x55, 0x4c, 0xdf, 0x80, 0x45, 0x79, 0x3a, - 0x7d, 0x14, 0x42, 0x35, 0xc1, 0xbe, 0x20, 0x5c, 0xd6, 0x2e, 0x45, 0x73, 0x02, 0x71, 0x07, 0xae, - 0xe4, 0x56, 0x90, 0x13, 0x17, 0xaa, 0x2f, 0x35, 0x29, 0xe8, 0x8f, 0x14, 0xb8, 0x0e, 0x4b, 0x65, - 0x40, 0x9e, 0x75, 0x50, 0x43, 0x42, 0x6e, 0xc0, 0xd5, 0x32, 0xa4, 0x48, 0x71, 0xa8, 0xb9, 0xd4, - 0xfc, 0x2e, 0x81, 0x16, 0xe4, 0xcb, 0x5e, 0x23, 0x50, 0xab, 0xdc, 0x40, 0xc9, 0x34, 0x08, 0x0b, - 0xe8, 0xd0, 0x2b, 0x30, 0x48, 0x8f, 0x05, 0xd4, 0x16, 0x2c, 0x0a, 0x56, 0xca, 0x00, 0xaa, 0x60, - 0x52, 0x90, 0x22, 0xeb, 0x22, 0xa3, 0x8e, 0x60, 0x71, 0x13, 0x2e, 0xcb, 0x08, 0xa9, 0xa7, 0x8a, - 0xba, 0x02, 0x72, 0x0d, 0xb4, 0x9c, 0x27, 0x59, 0xf1, 0x8b, 0xe6, 0xc5, 0xec, 0x5a, 0x5e, 0x4e, - 0xf9, 0xc2, 0x83, 0xd0, 0x52, 0x9d, 0x62, 0x9a, 0x8a, 0x76, 0x1d, 0x2e, 0xe6, 0x2c, 0x27, 0x9e, - 0xd7, 0xd1, 0x82, 0x10, 0xf4, 0x36, 0x5c, 0x2b, 0x44, 0x52, 0xee, 0x31, 0x09, 0x69, 0x29, 0xae, - 0x57, 0x8a, 0xdb, 0xb2, 0x8f, 0xd1, 0x05, 0xee, 0xa9, 0xdf, 0x95, 0xc8, 0xcc, 0x1f, 0x97, 0xd0, - 0xc5, 0x72, 0xbb, 0xa5, 0xe5, 0x2b, 0x5a, 0x14, 0xcb, 0x5c, 0x85, 0x85, 0x3c, 0x80, 0xf2, 0xbf, - 0x94, 0x6a, 0x9c, 0x8b, 0x97, 0x7c, 0xcf, 0x00, 0x5d, 0x16, 0xa8, 0x82, 0xff, 0xe4, 0x57, 0x59, - 0xd4, 0x13, 0x98, 0xd5, 0x7c, 0x88, 0xe6, 0x1e, 0x6a, 0xd1, 0x95, 0x72, 0x50, 0xee, 0x11, 0x0f, - 0x2d, 0x09, 0x81, 0x57, 0xf3, 0x1a, 0xa5, 0x4f, 0x77, 0xe8, 0xaa, 0x64, 0x94, 0x42, 0x34, 0x64, - 0xaf, 0xb1, 0xe8, 0x5a, 0xf9, 0xae, 0xca, 0x1e, 0x49, 0xd0, 0x72, 0x79, 0xd4, 0x26, 0xd3, 0xd7, - 0xd3, 0xa8, 0xcd, 0xf9, 0x39, 0x39, 0x81, 0xd1, 0x8a, 0xb4, 0x8b, 0x0a, 0x96, 0x91, 0xdb, 0xd2, - 0x48, 0x2f, 0xb7, 0x71, 0xbe, 0x55, 0x8d, 0x56, 0xcb, 0xc3, 0x3b, 0x6b, 0x5f, 0xa3, 0xb5, 0xf2, - 0xf0, 0x96, 0xea, 0x7b, 0x74, 0xbb, 0xdc, 0xbe, 0xb9, 0xa2, 0x1d, 0xdd, 0x11, 0xa0, 0x42, 0x7c, - 0x16, 0xcb, 0x6d, 0xb4, 0x2e, 0x24, 0xba, 0x03, 0xcb, 0xb9, 0xf8, 0x2c, 0x3e, 0x65, 0xa2, 0x8d, - 0x14, 0x78, 0xa5, 0x1c, 0x48, 0xa5, 0xbf, 0x2b, 0x39, 0xed, 0x76, 0xc1, 0x12, 0xb9, 0x56, 0x0d, - 0xba, 0x27, 0xed, 0x30, 0x2d, 0x1f, 0xb2, 0x6c, 0xfe, 0xad, 0xa5, 0xfa, 0x77, 0x7c, 0xbe, 0x60, - 0xd1, 0x7c, 0x07, 0x1f, 0xbd, 0x5d, 0x6e, 0x2f, 0xa9, 0x15, 0x8d, 0xfa, 0xe5, 0x99, 0x5b, 0x34, - 0xa5, 0xd1, 0xfd, 0x72, 0x4b, 0x15, 0x9b, 0x50, 0xe8, 0x9d, 0x74, 0x27, 0x17, 0x3c, 0x2c, 0x77, - 0x0d, 0xd1, 0xbb, 0xa9, 0x5e, 0xeb, 0x79, 0x7e, 0xc5, 0xae, 0x25, 0xda, 0x4c, 0x35, 0x2c, 0x70, - 0xcc, 0xf7, 0x21, 0xd1, 0x7b, 0xb3, 0x38, 0x16, 0x9b, 0x87, 0xe8, 0xfd, 0x94, 0xa3, 0x5e, 0xcc, - 0x6d, 0xd9, 0xbd, 0x08, 0x7d, 0x50, 0x1e, 0xa9, 0xf9, 0x0b, 0x08, 0xfa, 0x50, 0x68, 0x5b, 0xb0, - 0xab, 0xf4, 0xef, 0x46, 0xe8, 0x9f, 0x05, 0xa3, 0x75, 0xb8, 0x9e, 0x53, 0xf4, 0xcc, 0x43, 0x25, - 0xfa, 0x48, 0x20, 0x6f, 0xe5, 0x8f, 0xa1, 0xc2, 0xbb, 0x22, 0xfa, 0x17, 0xb1, 0x66, 0x71, 0x0f, - 0xe5, 0x9a, 0x17, 0xe8, 0x41, 0x7a, 0x4c, 0x2e, 0x97, 0xa1, 0xb2, 0x9c, 0xf8, 0xaf, 0x69, 0x8a, - 0xb9, 0x52, 0x0e, 0xa4, 0xde, 0xff, 0xb7, 0x72, 0x6e, 0x67, 0x2e, 0x49, 0xe8, 0xe3, 0x19, 0x1b, - 0x3c, 0x8f, 0xfa, 0xa4, 0x7c, 0xcd, 0xdc, 0x75, 0x05, 0x7d, 0x2a, 0x58, 0x6d, 0xc0, 0x8d, 0x59, - 0x7a, 0x26, 0x2e, 0xfd, 0x4c, 0x40, 0xef, 0xc1, 0xcd, 0x32, 0x68, 0x7e, 0xcf, 0x6f, 0x09, 0x70, - 0x1f, 0xd6, 0xca, 0xc0, 0x67, 0xf6, 0xfe, 0x43, 0x21, 0xec, 0xbd, 0xbc, 0xee, 0x67, 0xee, 0x15, - 0xc8, 0x59, 0x6a, 0x7e, 0x9f, 0x6c, 0xeb, 0x3b, 0x33, 0xc0, 0xc9, 0xc5, 0x02, 0xe1, 0xa5, 0xda, - 0xf7, 0x25, 0x86, 0xca, 0xdf, 0x35, 0xd0, 0xd1, 0x52, 0xed, 0x87, 0x12, 0x43, 0xe5, 0xaa, 0x65, - 0x34, 0x14, 0xac, 0x0a, 0xe1, 0x2c, 0x57, 0xd0, 0x68, 0x24, 0x18, 0x15, 0x8c, 0x59, 0x52, 0x13, - 0x23, 0x57, 0xb0, 0x2b, 0x84, 0x61, 0x01, 0x8a, 0x3c, 0xc1, 0xf1, 0x2e, 0xac, 0x9c, 0x03, 0x63, - 0x15, 0x2f, 0xf2, 0x05, 0xcb, 0x59, 0xab, 0x67, 0xd5, 0x2b, 0xfa, 0x9a, 0x43, 0x1f, 0xbe, 0x0f, - 0xab, 0xb6, 0x37, 0xe9, 0x87, 0x56, 0xe4, 0x85, 0x23, 0x32, 0xb6, 0x0e, 0xc3, 0x7e, 0x14, 0xe0, - 0x97, 0x5e, 0xd0, 0x1f, 0x93, 0x43, 0xfe, 0x6f, 0x7e, 0x87, 0xf1, 0xd1, 0xc3, 0xce, 0x01, 0x23, - 0x0a, 0xae, 0x7f, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x2a, 0xe4, 0xc0, 0x85, 0x16, 0x28, 0x00, 0x00, +var fileDescriptor_4dc296cbfe5ffcd5 = []byte{ + // 2430 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x9a, 0xd9, 0x73, 0x1c, 0xc5, + 0x1d, 0xc7, 0xb3, 0xab, 0x11, 0x88, 0xf6, 0x41, 0x23, 0xb0, 0x2d, 0xaf, 0x2f, 0xf9, 0xc0, 0x96, + 0x2f, 0xd9, 0x10, 0x0c, 0x44, 0x38, 0x60, 0x69, 0xb5, 0x12, 0x8a, 0xb5, 0x5a, 0x97, 0x76, 0xb1, + 0x1f, 0x5d, 0xa3, 0x9d, 0xd6, 0x6e, 0x97, 0x67, 0x67, 0x86, 0x9e, 0x1e, 0x49, 0xeb, 0xa7, 0x9c, + 0x3c, 0x13, 0x48, 0xc0, 0xb9, 0xa9, 0xa4, 0x2a, 0x21, 0x57, 0x85, 0x1c, 0x4e, 0x25, 0x55, 0x39, + 0x08, 0x24, 0x2f, 0xc9, 0x43, 0x52, 0x9c, 0x86, 0x40, 0xee, 0x90, 0xe4, 0x0f, 0xc8, 0xc5, 0x91, + 0xa4, 0x7a, 0xa6, 0xbb, 0xe7, 0xd8, 0xdf, 0xae, 0x36, 0x6f, 0x58, 0xf3, 0xf9, 0x7d, 0x7f, 0x47, + 0xff, 0xfa, 0x37, 0xdd, 0xb3, 0xa0, 0xcd, 0x2d, 0xe2, 0xfb, 0x66, 0x83, 0xf8, 0xe3, 0x1e, 0x73, + 0xb9, 0x3b, 0x3c, 0xdc, 0x5c, 0x1d, 0xe7, 0x8c, 0x5c, 0x76, 0xd9, 0xb8, 0x7a, 0x52, 0x18, 0x6d, + 0xb8, 0x6e, 0xc3, 0x26, 0x27, 0x42, 0x62, 0x29, 0x58, 0x3e, 0x61, 0x11, 0xbf, 0xce, 0xa8, 0xc7, + 0x5d, 0x16, 0x59, 0x1d, 0xf9, 0xfe, 0x7d, 0x68, 0x43, 0x39, 0xc2, 0x6b, 0x6d, 0x8f, 0x0c, 0x1f, + 0x40, 0x5b, 0x13, 0xff, 0xbc, 0x38, 0xe7, 0x50, 0x4e, 0x4d, 0x9b, 0x5e, 0x26, 0xf8, 0x5d, 0x85, + 0xa1, 0x87, 0xaf, 0x8e, 0xe4, 0x9e, 0xba, 0x3a, 0x92, 0x1b, 0x2e, 0x20, 0x9c, 0xa4, 0xce, 0x51, + 0xa7, 0x81, 0x73, 0x05, 0x43, 0x3c, 0x1f, 0xde, 0x85, 0x6e, 0x4e, 0x3e, 0xab, 0x06, 0xf5, 0x3a, + 0xf1, 0x7d, 0x9c, 0x2f, 0x18, 0x57, 0x80, 0xc7, 0x33, 0x26, 0xb5, 0x03, 0x46, 0xf0, 0x80, 0x7c, + 0xbc, 0x07, 0x6d, 0x49, 0x3e, 0x2e, 0x36, 0x4d, 0xa7, 0x41, 0xce, 0x51, 0x07, 0x1b, 0x52, 0x7e, + 0x34, 0x1d, 0xe0, 0x05, 0xea, 0x91, 0x69, 0xb2, 0x42, 0xeb, 0x04, 0x0f, 0xc2, 0xc4, 0x2c, 0xe1, + 0x25, 0x87, 0x33, 0xd7, 0x6b, 0xe3, 0x1b, 0xe0, 0x10, 0xd5, 0x63, 0x24, 0x63, 0xc8, 0x08, 0xcc, + 0xbb, 0xa6, 0x25, 0x5d, 0x6c, 0x92, 0x02, 0x7b, 0xd1, 0xb6, 0x24, 0xb1, 0x48, 0x7c, 0xc2, 0x25, + 0xb2, 0x59, 0x22, 0xbb, 0xd1, 0x2d, 0xa9, 0x3c, 0x89, 0xc9, 0x03, 0x46, 0x7c, 0x7c, 0x93, 0x74, + 0x72, 0x10, 0xed, 0xcc, 0x94, 0xb0, 0x6c, 0x72, 0x46, 0xd7, 0x16, 0xc9, 0x83, 0x01, 0xf1, 0x39, + 0x1e, 0x96, 0xdc, 0x11, 0x34, 0x02, 0x72, 0x93, 0xf5, 0x4b, 0xf8, 0xe6, 0xc2, 0x46, 0xb5, 0x24, + 0x4f, 0x47, 0x81, 0x0f, 0xa7, 0x8a, 0x67, 0x3a, 0x75, 0x62, 0xe3, 0x5b, 0x12, 0x0b, 0xb7, 0x2f, + 0xad, 0x56, 0xb4, 0x89, 0xc9, 0xaa, 0xc4, 0xf7, 0xa9, 0xeb, 0xe0, 0x11, 0x19, 0xf9, 0x7e, 0xb4, + 0x3d, 0xc9, 0x4c, 0x7a, 0x9e, 0xdd, 0xae, 0x12, 0xce, 0xa9, 0xd3, 0xf0, 0xf1, 0x76, 0x18, 0x9a, + 0x0a, 0x38, 0x77, 0x1d, 0x15, 0x7b, 0x41, 0xc6, 0x7e, 0x28, 0xbd, 0x98, 0x11, 0x24, 0x02, 0xdf, + 0xd1, 0x11, 0xf8, 0xd6, 0x0e, 0x97, 0x33, 0xb6, 0xd9, 0xf0, 0xf1, 0x4e, 0xe9, 0x2f, 0x13, 0xf8, + 0x94, 0x59, 0xbf, 0x14, 0x78, 0xb2, 0xe4, 0xfb, 0x24, 0x73, 0x00, 0x15, 0x80, 0x65, 0x55, 0x41, + 0xed, 0x87, 0x57, 0x57, 0x52, 0x22, 0xaa, 0x03, 0x52, 0xe7, 0x10, 0xda, 0x95, 0x2a, 0xb9, 0xe9, + 0xfb, 0x5e, 0x93, 0x99, 0x3e, 0x51, 0x52, 0x87, 0xa5, 0xd4, 0xd1, 0x74, 0x11, 0x62, 0x50, 0xa8, + 0x1d, 0xc9, 0xe4, 0x78, 0x0c, 0xed, 0x83, 0xe1, 0x2a, 0x37, 0xb9, 0x96, 0x2e, 0x4b, 0xe9, 0x93, + 0x68, 0x77, 0x0f, 0x5a, 0xe8, 0x2f, 0x64, 0xf4, 0x33, 0xd9, 0x2f, 0x92, 0xba, 0xbb, 0x42, 0x58, + 0x5b, 0xd6, 0xe8, 0x38, 0xdc, 0xb9, 0x17, 0x5c, 0x66, 0x29, 0xd7, 0xe3, 0xf0, 0x0e, 0x15, 0x88, + 0xf0, 0x77, 0x02, 0x56, 0x98, 0x25, 0x5c, 0xf7, 0xf6, 0x5d, 0x70, 0x73, 0x54, 0x09, 0x7f, 0xe0, + 0xf6, 0x99, 0xa2, 0x1b, 0x38, 0x9c, 0x30, 0x7c, 0x9f, 0xae, 0x72, 0x0a, 0x9a, 0xa1, 0xac, 0xb5, + 0x6a, 0x32, 0x52, 0x12, 0x49, 0xe2, 0xeb, 0xa2, 0x9e, 0xfd, 0x9e, 0x00, 0xc7, 0xd2, 0x89, 0x29, + 0xf0, 0x01, 0xcf, 0x76, 0x4d, 0x0b, 0x5f, 0x9f, 0x20, 0x0f, 0xa3, 0x1d, 0x10, 0xa9, 0x12, 0x1c, + 0x2a, 0x0c, 0x5d, 0x51, 0xe8, 0xbe, 0xf4, 0xf6, 0xac, 0x12, 0x7b, 0xb9, 0x26, 0x98, 0xd1, 0x84, + 0x5c, 0xa6, 0xe7, 0x66, 0x09, 0x3f, 0x17, 0x2c, 0xd9, 0xb4, 0x7e, 0x96, 0xb4, 0xf1, 0x06, 0x99, + 0x45, 0x66, 0x5e, 0xc5, 0xc0, 0x46, 0x59, 0xcd, 0x9d, 0xe9, 0x3d, 0x59, 0xa5, 0x0d, 0xa7, 0xb6, + 0x86, 0x6f, 0x84, 0xcd, 0x6b, 0x7a, 0xfb, 0x6f, 0x91, 0xe6, 0x3b, 0xd0, 0x4d, 0x69, 0x40, 0x2c, + 0xc5, 0xd6, 0xae, 0x93, 0x6e, 0xd2, 0xb2, 0x98, 0x98, 0xb6, 0xbb, 0xe0, 0x49, 0xa7, 0x1e, 0xef, + 0x96, 0xea, 0x99, 0xb5, 0x14, 0xc1, 0xc9, 0x7f, 0xe3, 0x83, 0xf0, 0x5a, 0x9e, 0x27, 0x8c, 0x2e, + 0xb7, 0x15, 0x74, 0x48, 0x42, 0x99, 0x61, 0x26, 0xff, 0x5b, 0xc8, 0x85, 0x9d, 0x81, 0xc7, 0xa4, + 0xbf, 0x4c, 0x8f, 0x16, 0xa9, 0xd7, 0x24, 0xec, 0x2c, 0x69, 0x9f, 0x37, 0xed, 0x80, 0xe0, 0x6d, + 0xb0, 0x5a, 0x44, 0x11, 0x4b, 0x73, 0x27, 0xa5, 0x5a, 0x66, 0x7d, 0x84, 0xbb, 0x39, 0x8b, 0x38, + 0x9c, 0xf2, 0x36, 0x3e, 0x05, 0xcf, 0x04, 0xc1, 0x10, 0x4b, 0x53, 0x77, 0xea, 0x41, 0xb5, 0x2b, + 0xfb, 0xca, 0x28, 0x4e, 0xdf, 0x2f, 0x07, 0xa3, 0x58, 0xcd, 0xf7, 0x76, 0x19, 0x31, 0x69, 0xea, + 0x5e, 0x78, 0xc4, 0x14, 0x5d, 0x9f, 0x16, 0xdd, 0x56, 0x8b, 0x72, 0x3c, 0x0b, 0xeb, 0xc4, 0x44, + 0x8b, 0x38, 0x1c, 0xdf, 0x2f, 0x75, 0x32, 0xef, 0x10, 0x41, 0x89, 0x04, 0xf0, 0x1c, 0xbc, 0x36, + 0xea, 0x79, 0x54, 0xf3, 0xf7, 0x49, 0x91, 0x13, 0xe9, 0xdc, 0xa6, 0xc9, 0x52, 0xd0, 0x98, 0xa7, + 0xce, 0xa5, 0x69, 0x52, 0xa7, 0xe1, 0xdc, 0xb7, 0x0a, 0x1b, 0x9f, 0x48, 0x0e, 0x92, 0xa3, 0x5d, + 0x0c, 0x66, 0x09, 0x0f, 0x87, 0x0f, 0x26, 0x85, 0x21, 0x65, 0x90, 0x4d, 0x44, 0xc3, 0x11, 0xb9, + 0x5c, 0x30, 0x9e, 0x04, 0x02, 0x4d, 0x50, 0xae, 0x87, 0x1b, 0x05, 0xe3, 0x09, 0x60, 0x39, 0x35, + 0x34, 0xef, 0x36, 0x70, 0x53, 0x0a, 0x1d, 0x46, 0x7b, 0x40, 0xa6, 0x4c, 0x5a, 0x2e, 0x6b, 0x2f, + 0x12, 0xd3, 0xc2, 0x8e, 0x94, 0xbb, 0x35, 0x3d, 0x0c, 0x32, 0x28, 0x76, 0xa5, 0xe2, 0x11, 0x34, + 0xda, 0x03, 0xbb, 0xc0, 0x28, 0x27, 0xd8, 0x93, 0x92, 0xdd, 0xbc, 0xcf, 0xd8, 0xa6, 0xdf, 0x8c, + 0x06, 0xd7, 0x83, 0x12, 0x3d, 0x9a, 0x96, 0x2d, 0x71, 0xd1, 0xc2, 0x41, 0x2b, 0x35, 0x43, 0x9e, + 0x19, 0x90, 0xeb, 0x38, 0x96, 0xae, 0xb8, 0x82, 0x63, 0xf2, 0x59, 0x75, 0x3c, 0x1a, 0x4b, 0xbf, + 0x16, 0x12, 0xb2, 0x6a, 0x6b, 0xdf, 0x2d, 0x35, 0x33, 0xe9, 0x2b, 0x52, 0x61, 0xef, 0x81, 0x77, + 0xa4, 0xc2, 0xe4, 0x98, 0x9a, 0x80, 0xdf, 0x88, 0x8a, 0x8a, 0xc7, 0xd5, 0x3d, 0x52, 0x2e, 0xb3, + 0xd0, 0x31, 0x28, 0xc6, 0xd6, 0x69, 0xa9, 0x96, 0x29, 0x63, 0xd2, 0xa7, 0x1a, 0x2c, 0x67, 0x24, + 0x7a, 0x14, 0xed, 0x85, 0xd0, 0xf4, 0x14, 0x9a, 0x94, 0xf0, 0x38, 0x3a, 0x00, 0xc1, 0x1d, 0xd3, + 0x68, 0x0a, 0x0e, 0x76, 0xa1, 0x54, 0x4e, 0xd4, 0xb1, 0x08, 0xcf, 0xd8, 0x85, 0x52, 0x59, 0x11, + 0xd3, 0xf0, 0x91, 0x75, 0xa1, 0x54, 0x96, 0xd5, 0x2b, 0xc1, 0x6f, 0x4c, 0x09, 0x10, 0xab, 0xb6, + 0x86, 0x67, 0xe0, 0x01, 0xb4, 0x50, 0x2a, 0x4f, 0x93, 0x3a, 0x6b, 0x7b, 0x5c, 0xe5, 0x78, 0x16, + 0xae, 0x5d, 0x0c, 0x12, 0x4b, 0xa1, 0xf3, 0xf0, 0xd2, 0xce, 0x53, 0xff, 0x52, 0x22, 0x3f, 0x06, + 0x07, 0x27, 0x28, 0x85, 0xf8, 0x5d, 0xce, 0xc3, 0xd4, 0xbf, 0x24, 0x33, 0xe4, 0xf0, 0xe9, 0x4c, + 0x11, 0x61, 0x8a, 0x81, 0x54, 0xc9, 0x34, 0xa4, 0x62, 0x54, 0xd4, 0x2b, 0x52, 0x2a, 0xb3, 0x1f, + 0x05, 0xd6, 0xb1, 0x80, 0xab, 0x70, 0xd5, 0x04, 0x9b, 0xee, 0x8c, 0x35, 0xf8, 0x8d, 0x22, 0x4b, + 0x11, 0xef, 0xaf, 0x36, 0x3c, 0x50, 0x05, 0x17, 0x43, 0x97, 0xf5, 0xc9, 0x3d, 0x95, 0x48, 0x8d, + 0x5c, 0x76, 0xfd, 0x44, 0x61, 0x1f, 0xcb, 0x69, 0xb1, 0x91, 0x0e, 0x4e, 0x41, 0x8f, 0xe7, 0xf4, + 0x3b, 0x6c, 0x5b, 0x07, 0x24, 0x8b, 0x7b, 0x25, 0xa7, 0x5f, 0x16, 0xdb, 0x41, 0x26, 0x2c, 0xef, + 0x27, 0x72, 0x7a, 0x34, 0xec, 0x82, 0xc2, 0x8a, 0xe3, 0xff, 0x64, 0x4e, 0x8f, 0x86, 0x42, 0x07, + 0x19, 0x63, 0x9f, 0xca, 0xe9, 0xfe, 0x49, 0x9f, 0xe2, 0x38, 0xb1, 0x6d, 0x93, 0xc9, 0xe0, 0x7e, + 0x9e, 0xd3, 0x0d, 0xb9, 0x1b, 0xa0, 0x6a, 0x6b, 0x15, 0x4f, 0xcd, 0x86, 0x5f, 0x74, 0x89, 0x50, + 0xa2, 0x89, 0xd2, 0xfd, 0xb2, 0x4b, 0x84, 0x92, 0x54, 0xd8, 0xaf, 0x94, 0xe0, 0xf1, 0xf4, 0x91, + 0x5a, 0x62, 0x45, 0x46, 0xc2, 0x23, 0x72, 0x5d, 0x1c, 0x38, 0x2b, 0x1e, 0x7e, 0x2e, 0xa7, 0xa7, + 0xd8, 0x4e, 0x00, 0x3f, 0x67, 0xb6, 0xc5, 0x4b, 0xb7, 0xe2, 0xe1, 0xe7, 0x73, 0x7a, 0xea, 0x8c, + 0x82, 0x20, 0x6f, 0xc6, 0xf0, 0x0b, 0xbd, 0xe1, 0xb2, 0xe9, 0x98, 0x0d, 0x52, 0x59, 0x5e, 0x26, + 0xac, 0xe2, 0xe1, 0x17, 0x15, 0x7c, 0x3b, 0x3a, 0xd4, 0x35, 0x62, 0x71, 0xc6, 0xa7, 0x2b, 0xda, + 0xe6, 0xa5, 0x9c, 0xde, 0x11, 0x7b, 0xa0, 0x75, 0x20, 0xbc, 0xe2, 0x71, 0xea, 0x3a, 0x7e, 0xc5, + 0xc3, 0x2f, 0xf7, 0x0e, 0x26, 0xba, 0x45, 0xd7, 0x58, 0xe0, 0x8b, 0xc8, 0xaf, 0xf5, 0x16, 0x9e, + 0xb4, 0x6d, 0x77, 0x55, 0xb1, 0xaf, 0x28, 0xf6, 0x58, 0x7a, 0x10, 0x2b, 0x36, 0x2a, 0x72, 0x99, + 0xb0, 0x06, 0xa9, 0x78, 0xf8, 0xd5, 0xde, 0xca, 0x51, 0x4d, 0xa6, 0x4d, 0x6e, 0x56, 0x3c, 0xfc, + 0x5a, 0x6f, 0xe5, 0xa9, 0xa0, 0xe5, 0x55, 0x45, 0x03, 0x39, 0x75, 0xa1, 0xfc, 0x7a, 0x4e, 0xef, + 0xe4, 0x1d, 0x5d, 0x9a, 0x32, 0xdc, 0x0d, 0x6f, 0xe4, 0xf4, 0xb4, 0x49, 0xf7, 0x38, 0x73, 0x9d, + 0x44, 0xa3, 0xbd, 0x99, 0xd3, 0x83, 0x6b, 0x5b, 0x16, 0x53, 0xcc, 0x5b, 0x39, 0x7d, 0x48, 0xde, + 0x9a, 0x65, 0xe4, 0x26, 0x78, 0xbb, 0xdb, 0x56, 0x97, 0x48, 0x18, 0xd2, 0x3b, 0x5d, 0xf6, 0x53, + 0xd1, 0x64, 0x96, 0xe9, 0xb8, 0x52, 0xea, 0x1b, 0x79, 0xb8, 0x49, 0x25, 0x15, 0xbf, 0x69, 0x9f, + 0xca, 0xeb, 0x0f, 0x03, 0x7b, 0x00, 0x30, 0xb5, 0xe3, 0xbf, 0xd9, 0x5b, 0x34, 0x06, 0xbf, 0x95, + 0x87, 0xb7, 0x68, 0x2c, 0xaa, 0xaa, 0xf2, 0xed, 0x3c, 0xbc, 0x45, 0x25, 0xa9, 0xb0, 0xef, 0xe4, + 0xf5, 0x3b, 0x76, 0x04, 0x4c, 0x47, 0x9c, 0x07, 0xae, 0xe6, 0xe1, 0x45, 0x4d, 0x54, 0x26, 0xac, + 0xe0, 0x77, 0x95, 0x58, 0x66, 0xd6, 0x54, 0x1c, 0xee, 0xda, 0x6e, 0xa3, 0x9d, 0x08, 0xef, 0x37, + 0x5d, 0x24, 0x15, 0xaa, 0xb8, 0xdf, 0xe6, 0xf5, 0x15, 0x7e, 0xb4, 0x8b, 0x64, 0x5c, 0x9d, 0xdf, + 0xe5, 0xe1, 0x73, 0x9a, 0x82, 0x63, 0xf2, 0xf7, 0xeb, 0xc8, 0x86, 0x8b, 0xcd, 0x4c, 0xc7, 0x5f, + 0x26, 0x0c, 0xff, 0x41, 0xc9, 0x66, 0xc6, 0x58, 0x12, 0x26, 0x96, 0xc6, 0xff, 0xa8, 0xb4, 0xc7, + 0xd1, 0xfe, 0x6e, 0xf8, 0x05, 0xca, 0x9b, 0x16, 0x33, 0x57, 0x2b, 0x4e, 0x03, 0xff, 0x49, 0xc9, + 0x9f, 0x44, 0xb7, 0x76, 0x97, 0x4f, 0x5a, 0xfc, 0x39, 0xaf, 0x3f, 0x3e, 0x74, 0xb5, 0xa8, 0x38, + 0x7c, 0xce, 0x5a, 0x24, 0x0d, 0xea, 0x8b, 0xbb, 0xfc, 0x1b, 0x79, 0x78, 0xae, 0xa5, 0x7d, 0xa4, + 0x6d, 0xfe, 0xa2, 0xbc, 0x9c, 0x42, 0x47, 0x7a, 0x7a, 0x99, 0xb4, 0xac, 0x49, 0xce, 0x19, 0x5d, + 0x0a, 0x38, 0xf1, 0xf1, 0x5f, 0x95, 0xab, 0xbb, 0xd0, 0xb1, 0x75, 0x5c, 0xa5, 0x0d, 0xff, 0x96, + 0xd7, 0xa7, 0x85, 0xd4, 0x26, 0x58, 0xa4, 0x9e, 0x67, 0x93, 0x44, 0xef, 0x3c, 0x3c, 0x00, 0xbf, + 0x6f, 0x23, 0x50, 0x51, 0x1f, 0x1d, 0x80, 0x3b, 0x3b, 0xa2, 0xe4, 0x6e, 0x7e, 0x64, 0x00, 0xde, + 0x25, 0x31, 0x14, 0x36, 0xf6, 0xa3, 0x0a, 0x7b, 0x37, 0x1a, 0x4b, 0xdd, 0x9f, 0x5d, 0x87, 0x30, + 0x37, 0x5c, 0x79, 0xb3, 0x2e, 0x66, 0xfc, 0x9c, 0x43, 0xb9, 0x1a, 0x00, 0x7f, 0x1f, 0xd0, 0x17, + 0xbb, 0x03, 0xeb, 0x1a, 0x89, 0x6d, 0xf6, 0x0f, 0x65, 0x90, 0xa9, 0x5c, 0x87, 0x41, 0x95, 0xf0, + 0x39, 0xc7, 0x0b, 0xb4, 0xa7, 0x7f, 0x2a, 0xc3, 0xf5, 0xc2, 0x53, 0x86, 0xc2, 0xdb, 0xbf, 0x94, + 0xd1, 0x19, 0x74, 0x6a, 0x9d, 0xf0, 0xbc, 0x80, 0xfb, 0xe7, 0x08, 0x6b, 0x05, 0xdc, 0x14, 0x7f, + 0x50, 0x6e, 0xff, 0xad, 0x14, 0x4e, 0xa3, 0xdb, 0xfe, 0x3f, 0x05, 0xe1, 0xff, 0x4d, 0x65, 0x7d, + 0x37, 0x3a, 0xbe, 0xbe, 0xf5, 0x79, 0xea, 0x50, 0xe5, 0xf7, 0x2d, 0x65, 0x79, 0x07, 0x3a, 0xdc, + 0x9f, 0xa5, 0xf0, 0xf7, 0xb6, 0xb2, 0xba, 0x07, 0x9d, 0xec, 0x69, 0x35, 0x69, 0xdb, 0x51, 0xc0, + 0x55, 0xa2, 0x2b, 0xfc, 0x4e, 0xbf, 0x4b, 0x93, 0x34, 0x16, 0x5e, 0xff, 0xd3, 0x6f, 0x96, 0xe2, + 0x98, 0x10, 0xf0, 0xc4, 0xa2, 0xfe, 0xb7, 0xdf, 0x2c, 0xb5, 0xa5, 0xf0, 0xf7, 0x7e, 0xa3, 0x4f, + 0x7f, 0x93, 0xb6, 0x5d, 0x09, 0x78, 0x22, 0xc5, 0x0f, 0x18, 0x7d, 0xfa, 0xd3, 0x96, 0xc2, 0xdf, + 0x07, 0xfb, 0xf5, 0x17, 0x7e, 0xf4, 0x49, 0x36, 0xed, 0x87, 0xfa, 0xf5, 0xa7, 0x2d, 0x85, 0xbf, + 0x0f, 0xf7, 0x6b, 0x35, 0x43, 0x1d, 0xd3, 0x56, 0xbe, 0x3e, 0x62, 0xc0, 0x03, 0x13, 0xb6, 0x12, + 0x7e, 0x1e, 0x52, 0x16, 0x77, 0xa2, 0xa3, 0x9d, 0x16, 0x67, 0x49, 0x7b, 0xae, 0x65, 0x36, 0x48, + 0x69, 0xcd, 0x73, 0x19, 0x4f, 0x6e, 0xfa, 0x47, 0x94, 0x5d, 0x66, 0xd0, 0x76, 0xb3, 0x13, 0xbe, + 0x1e, 0xed, 0x99, 0x93, 0xb2, 0xa9, 0xb6, 0x9d, 0x7a, 0x95, 0x13, 0x7d, 0x5a, 0xff, 0x58, 0xcf, + 0x9c, 0xb2, 0x56, 0xc2, 0xcf, 0xc7, 0x0d, 0x78, 0xa0, 0x77, 0x5a, 0xa4, 0x8a, 0xf7, 0x98, 0x32, + 0xbb, 0x0d, 0x1d, 0xec, 0xc3, 0x4c, 0x78, 0x7a, 0xdc, 0x80, 0x47, 0x79, 0x64, 0x92, 0x18, 0xe5, + 0x9f, 0x36, 0xe0, 0x51, 0x1e, 0x81, 0x8a, 0xfa, 0x8c, 0x01, 0x9f, 0x7a, 0xb4, 0xdc, 0x05, 0x93, + 0xd7, 0x9b, 0xe2, 0xbd, 0xfe, 0x59, 0x03, 0x9e, 0xe7, 0x11, 0xa9, 0xb1, 0xcf, 0x19, 0xf0, 0xc5, + 0x24, 0xfc, 0x50, 0x14, 0xb1, 0xd3, 0xd4, 0x6c, 0xa8, 0x0a, 0x7c, 0xde, 0x80, 0xef, 0x50, 0x19, + 0x5c, 0x64, 0xfe, 0x05, 0xa5, 0x9c, 0x39, 0x2d, 0xeb, 0x50, 0x6b, 0x6b, 0x67, 0x89, 0xfe, 0xa9, + 0xe3, 0x8b, 0x06, 0x7c, 0x60, 0x49, 0xd3, 0x42, 0xf7, 0x4b, 0x3d, 0x7b, 0x64, 0x9e, 0xae, 0x90, + 0x45, 0xb2, 0xcc, 0x88, 0xdf, 0xac, 0x72, 0x93, 0xe9, 0x6e, 0x7c, 0xd2, 0x80, 0x8f, 0x16, 0xb0, + 0x95, 0xf0, 0xf3, 0x65, 0xa3, 0xd7, 0xab, 0x24, 0x65, 0x11, 0xb7, 0xe2, 0x57, 0x94, 0x1b, 0xf0, + 0x4d, 0x97, 0x31, 0x12, 0x5e, 0xbe, 0xda, 0x6f, 0x36, 0xa9, 0x46, 0xfc, 0x5a, 0xbf, 0xd9, 0xe8, + 0x3e, 0xfc, 0xba, 0x01, 0x7f, 0x0a, 0x28, 0x65, 0x6e, 0xdc, 0xd7, 0x0c, 0xf8, 0x7e, 0x50, 0x4a, + 0xde, 0xb7, 0x5f, 0x31, 0xf4, 0x67, 0x96, 0x2d, 0x19, 0x48, 0x9e, 0x26, 0x5e, 0xed, 0xd2, 0x27, + 0x25, 0xd7, 0x17, 0x07, 0xe9, 0xe4, 0xbb, 0xf3, 0xd7, 0x06, 0x7c, 0xff, 0x49, 0xa0, 0x22, 0x81, + 0xd7, 0x0c, 0xf8, 0xfe, 0x53, 0x4a, 0x7c, 0x58, 0x78, 0xbd, 0xcb, 0xee, 0x98, 0xa2, 0x8e, 0xe9, + 0xd4, 0x93, 0x07, 0xa7, 0x1f, 0x0c, 0xc2, 0xbb, 0x43, 0x92, 0x0a, 0xfb, 0xe1, 0x20, 0x7c, 0x73, + 0x89, 0x05, 0xe3, 0xa2, 0xfc, 0x68, 0x10, 0xbe, 0xb9, 0x48, 0x36, 0x06, 0x7f, 0x3c, 0x08, 0xdf, + 0xae, 0x24, 0x28, 0x2b, 0xf8, 0x74, 0x6f, 0xb9, 0xf8, 0x76, 0xf5, 0x93, 0x41, 0xf8, 0xaa, 0xa1, + 0x40, 0x79, 0x18, 0x2f, 0xfb, 0x0d, 0xfc, 0xcc, 0x20, 0x7c, 0xd5, 0x90, 0x68, 0x85, 0x59, 0x11, + 0xf7, 0x6c, 0x6f, 0xdf, 0xd1, 0x8f, 0xb4, 0x02, 0xfc, 0x69, 0x6f, 0x41, 0xbd, 0x30, 0x3f, 0x93, + 0x31, 0x4e, 0x9c, 0x46, 0xd7, 0xaf, 0x52, 0x46, 0x2e, 0x52, 0x67, 0x78, 0xef, 0x78, 0xf4, 0x4b, + 0xff, 0xb8, 0xfa, 0xa5, 0x7f, 0xbc, 0xe4, 0x04, 0xad, 0xf0, 0xe7, 0x12, 0xf9, 0x95, 0x60, 0xe4, + 0xb9, 0x87, 0x06, 0x46, 0x73, 0x63, 0x43, 0x8b, 0xd7, 0x09, 0x9b, 0x39, 0x67, 0xe2, 0x5e, 0x34, + 0x14, 0x5a, 0xbb, 0x01, 0xef, 0xc7, 0xfc, 0x79, 0x69, 0x1e, 0xba, 0xac, 0x04, 0x7c, 0x62, 0x16, + 0x6d, 0x0a, 0xed, 0x2d, 0x31, 0xad, 0xfa, 0x8c, 0xe1, 0x05, 0x29, 0xb2, 0x41, 0x58, 0x86, 0x63, + 0x6e, 0xce, 0x99, 0x98, 0x43, 0x9b, 0x13, 0x42, 0x7d, 0x86, 0xf3, 0xa2, 0x54, 0xda, 0xa8, 0x95, + 0x44, 0x4c, 0x67, 0xd0, 0x0d, 0xa1, 0x14, 0xa7, 0x4e, 0xbb, 0x1f, 0x95, 0x97, 0xa4, 0x4a, 0x58, + 0x89, 0x1a, 0x75, 0xda, 0x13, 0xf3, 0xe8, 0xc6, 0x50, 0x61, 0xc9, 0x75, 0xb9, 0xed, 0x9a, 0x16, + 0x61, 0xfd, 0xe8, 0xbc, 0x2c, 0x75, 0xc2, 0x44, 0xa6, 0xb4, 0xe9, 0x44, 0x11, 0x85, 0x99, 0x5e, + 0x74, 0xdc, 0x8b, 0xcb, 0x7e, 0xab, 0x1f, 0xa5, 0x6b, 0x52, 0x29, 0xcc, 0x63, 0xc1, 0x9d, 0xf1, + 0x5b, 0x53, 0x77, 0xa0, 0xfd, 0x75, 0xb7, 0x35, 0xee, 0x9b, 0xdc, 0xf5, 0x9b, 0xd4, 0x36, 0x97, + 0x7c, 0xf5, 0xff, 0x79, 0xd8, 0x74, 0x49, 0x4b, 0x4d, 0x6d, 0xaa, 0x85, 0x7f, 0x94, 0x9d, 0xf3, + 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x69, 0x67, 0x5d, 0x1f, 0x22, 0x00, 0x00, } diff --git a/accounts/usbwallet/trezor/messages.proto b/accounts/usbwallet/trezor/messages.proto index 8cb9c8cc25..3e0482e344 100644 --- a/accounts/usbwallet/trezor/messages.proto +++ b/accounts/usbwallet/trezor/messages.proto @@ -1,8 +1,9 @@ // This file originates from the SatoshiLabs Trezor `common` repository at: // https://github.com/trezor/trezor-common/blob/master/protob/messages.proto -// dated 28.07.2017, commit dd8ec3231fb5f7992360aff9bdfe30bb58130f4b. +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. syntax = "proto2"; +package hw.trezor.messages; /** * Messages for TREZOR communication @@ -12,894 +13,252 @@ syntax = "proto2"; option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessage"; -import "types.proto"; +import "google/protobuf/descriptor.proto"; /** - * Mapping between Trezor wire identifier (uint) and a protobuf message + * Options for specifying message direction and type of wire (normal/debug) + */ +extend google.protobuf.EnumValueOptions { + optional bool wire_in = 50002; // message can be transmitted via wire from PC to TREZOR + optional bool wire_out = 50003; // message can be transmitted via wire from TREZOR to PC + optional bool wire_debug_in = 50004; // message can be transmitted via debug wire from PC to TREZOR + optional bool wire_debug_out = 50005; // message can be transmitted via debug wire from TREZOR to PC + optional bool wire_tiny = 50006; // message is handled by TREZOR when the USB stack is in tiny mode + optional bool wire_bootloader = 50007; // message is only handled by TREZOR Bootloader + optional bool wire_no_fsm = 50008; // message is not handled by TREZOR unless the USB stack is in tiny mode +} + +/** + * Mapping between TREZOR wire identifier (uint) and a protobuf message */ enum MessageType { - MessageType_Initialize = 0 [(wire_in) = true]; - MessageType_Ping = 1 [(wire_in) = true]; - MessageType_Success = 2 [(wire_out) = true]; - MessageType_Failure = 3 [(wire_out) = true]; - MessageType_ChangePin = 4 [(wire_in) = true]; - MessageType_WipeDevice = 5 [(wire_in) = true]; - MessageType_FirmwareErase = 6 [(wire_in) = true, (wire_bootloader) = true]; - MessageType_FirmwareUpload = 7 [(wire_in) = true, (wire_bootloader) = true]; - MessageType_FirmwareRequest = 8 [(wire_out) = true, (wire_bootloader) = true]; - MessageType_GetEntropy = 9 [(wire_in) = true]; - MessageType_Entropy = 10 [(wire_out) = true]; - MessageType_GetPublicKey = 11 [(wire_in) = true]; - MessageType_PublicKey = 12 [(wire_out) = true]; - MessageType_LoadDevice = 13 [(wire_in) = true]; - MessageType_ResetDevice = 14 [(wire_in) = true]; - MessageType_SignTx = 15 [(wire_in) = true]; - MessageType_SimpleSignTx = 16 [(wire_in) = true, deprecated = true]; - MessageType_Features = 17 [(wire_out) = true]; - MessageType_PinMatrixRequest = 18 [(wire_out) = true]; - MessageType_PinMatrixAck = 19 [(wire_in) = true, (wire_tiny) = true]; - MessageType_Cancel = 20 [(wire_in) = true]; - MessageType_TxRequest = 21 [(wire_out) = true]; - MessageType_TxAck = 22 [(wire_in) = true]; - MessageType_CipherKeyValue = 23 [(wire_in) = true]; - MessageType_ClearSession = 24 [(wire_in) = true]; - MessageType_ApplySettings = 25 [(wire_in) = true]; - MessageType_ButtonRequest = 26 [(wire_out) = true]; - MessageType_ButtonAck = 27 [(wire_in) = true, (wire_tiny) = true]; - MessageType_ApplyFlags = 28 [(wire_in) = true]; - MessageType_GetAddress = 29 [(wire_in) = true]; - MessageType_Address = 30 [(wire_out) = true]; - MessageType_SelfTest = 32 [(wire_in) = true, (wire_bootloader) = true]; - MessageType_BackupDevice = 34 [(wire_in) = true]; - MessageType_EntropyRequest = 35 [(wire_out) = true]; - MessageType_EntropyAck = 36 [(wire_in) = true]; - MessageType_SignMessage = 38 [(wire_in) = true]; - MessageType_VerifyMessage = 39 [(wire_in) = true]; - MessageType_MessageSignature = 40 [(wire_out) = true]; - MessageType_PassphraseRequest = 41 [(wire_out) = true]; - MessageType_PassphraseAck = 42 [(wire_in) = true, (wire_tiny) = true]; - MessageType_EstimateTxSize = 43 [(wire_in) = true, deprecated = true]; - MessageType_TxSize = 44 [(wire_out) = true, deprecated = true]; - MessageType_RecoveryDevice = 45 [(wire_in) = true]; - MessageType_WordRequest = 46 [(wire_out) = true]; - MessageType_WordAck = 47 [(wire_in) = true]; - MessageType_CipheredKeyValue = 48 [(wire_out) = true]; - MessageType_EncryptMessage = 49 [(wire_in) = true, deprecated = true]; - MessageType_EncryptedMessage = 50 [(wire_out) = true, deprecated = true]; - MessageType_DecryptMessage = 51 [(wire_in) = true, deprecated = true]; - MessageType_DecryptedMessage = 52 [(wire_out) = true, deprecated = true]; - MessageType_SignIdentity = 53 [(wire_in) = true]; - MessageType_SignedIdentity = 54 [(wire_out) = true]; - MessageType_GetFeatures = 55 [(wire_in) = true]; - MessageType_EthereumGetAddress = 56 [(wire_in) = true]; - MessageType_EthereumAddress = 57 [(wire_out) = true]; - MessageType_EthereumSignTx = 58 [(wire_in) = true]; - MessageType_EthereumTxRequest = 59 [(wire_out) = true]; - MessageType_EthereumTxAck = 60 [(wire_in) = true]; - MessageType_GetECDHSessionKey = 61 [(wire_in) = true]; - MessageType_ECDHSessionKey = 62 [(wire_out) = true]; - MessageType_SetU2FCounter = 63 [(wire_in) = true]; - MessageType_EthereumSignMessage = 64 [(wire_in) = true]; - MessageType_EthereumVerifyMessage = 65 [(wire_in) = true]; - MessageType_EthereumMessageSignature = 66 [(wire_out) = true]; - MessageType_DebugLinkDecision = 100 [(wire_debug_in) = true, (wire_tiny) = true]; - MessageType_DebugLinkGetState = 101 [(wire_debug_in) = true]; - MessageType_DebugLinkState = 102 [(wire_debug_out) = true]; - MessageType_DebugLinkStop = 103 [(wire_debug_in) = true]; - MessageType_DebugLinkLog = 104 [(wire_debug_out) = true]; - MessageType_DebugLinkMemoryRead = 110 [(wire_debug_in) = true]; - MessageType_DebugLinkMemory = 111 [(wire_debug_out) = true]; - MessageType_DebugLinkMemoryWrite = 112 [(wire_debug_in) = true]; - MessageType_DebugLinkFlashErase = 113 [(wire_debug_in) = true]; -} - -//////////////////// -// Basic messages // -//////////////////// - -/** - * Request: Reset device to default state and ask for device details - * @next Features - */ -message Initialize { -} - -/** - * Request: Ask for device details (no device reset) - * @next Features - */ -message GetFeatures { -} - -/** - * Response: Reports various information about the device - * @prev Initialize - * @prev GetFeatures - */ -message Features { - optional string vendor = 1; // name of the manufacturer, e.g. "bitcointrezor.com" - optional uint32 major_version = 2; // major version of the device, e.g. 1 - optional uint32 minor_version = 3; // minor version of the device, e.g. 0 - optional uint32 patch_version = 4; // patch version of the device, e.g. 0 - optional bool bootloader_mode = 5; // is device in bootloader mode? - optional string device_id = 6; // device's unique identifier - optional bool pin_protection = 7; // is device protected by PIN? - optional bool passphrase_protection = 8; // is node/mnemonic encrypted using passphrase? - optional string language = 9; // device language - optional string label = 10; // device description label - repeated CoinType coins = 11; // supported coins - optional bool initialized = 12; // does device contain seed? - optional bytes revision = 13; // SCM revision of firmware - optional bytes bootloader_hash = 14; // hash of the bootloader - optional bool imported = 15; // was storage imported from an external source? - optional bool pin_cached = 16; // is PIN already cached in session? - optional bool passphrase_cached = 17; // is passphrase already cached in session? - optional bool firmware_present = 18; // is valid firmware loaded? - optional bool needs_backup = 19; // does storage need backup? (equals to Storage.needs_backup) - optional uint32 flags = 20; // device flags (equals to Storage.flags) -} - -/** - * Request: clear session (removes cached PIN, passphrase, etc). - * @next Success - */ -message ClearSession { -} - -/** - * Request: change language and/or label of the device - * @next Success - * @next Failure - * @next ButtonRequest - * @next PinMatrixRequest - */ -message ApplySettings { - optional string language = 1; - optional string label = 2; - optional bool use_passphrase = 3; - optional bytes homescreen = 4; -} - -/** - * Request: set flags of the device - * @next Success - * @next Failure - */ -message ApplyFlags { - optional uint32 flags = 1; // bitmask, can only set bits, not unset -} - -/** - * Request: Starts workflow for setting/changing/removing the PIN - * @next ButtonRequest - * @next PinMatrixRequest - */ -message ChangePin { - optional bool remove = 1; // is PIN removal requested? -} - -/** - * Request: Test if the device is alive, device sends back the message in Success response - * @next Success - */ -message Ping { - optional string message = 1; // message to send back in Success message - optional bool button_protection = 2; // ask for button press - optional bool pin_protection = 3; // ask for PIN if set in device - optional bool passphrase_protection = 4; // ask for passphrase if set in device -} - -/** - * Response: Success of the previous request - */ -message Success { - optional string message = 1; // human readable description of action or request-specific payload -} - -/** - * Response: Failure of the previous request - */ -message Failure { - optional FailureType code = 1; // computer-readable definition of the error state - optional string message = 2; // human-readable message of the error state -} - -/** - * Response: Device is waiting for HW button press. - * @next ButtonAck - * @next Cancel - */ -message ButtonRequest { - optional ButtonRequestType code = 1; - optional string data = 2; -} - -/** - * Request: Computer agrees to wait for HW button press - * @prev ButtonRequest - */ -message ButtonAck { -} - -/** - * Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme - * @next PinMatrixAck - * @next Cancel - */ -message PinMatrixRequest { - optional PinMatrixRequestType type = 1; -} - -/** - * Request: Computer responds with encoded PIN - * @prev PinMatrixRequest - */ -message PinMatrixAck { - required string pin = 1; // matrix encoded PIN entered by user -} - -/** - * Request: Abort last operation that required user interaction - * @prev ButtonRequest - * @prev PinMatrixRequest - * @prev PassphraseRequest - */ -message Cancel { -} - -/** - * Response: Device awaits encryption passphrase - * @next PassphraseAck - * @next Cancel - */ -message PassphraseRequest { -} - -/** - * Request: Send passphrase back - * @prev PassphraseRequest - */ -message PassphraseAck { - required string passphrase = 1; -} - -/** - * Request: Request a sample of random data generated by hardware RNG. May be used for testing. - * @next ButtonRequest - * @next Entropy - * @next Failure - */ -message GetEntropy { - required uint32 size = 1; // size of requested entropy -} - -/** - * Response: Reply with random data generated by internal RNG - * @prev GetEntropy - */ -message Entropy { - required bytes entropy = 1; // stream of random generated bytes -} - -/** - * Request: Ask device for public key corresponding to address_n path - * @next PassphraseRequest - * @next PublicKey - * @next Failure - */ -message GetPublicKey { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional string ecdsa_curve_name = 2; // ECDSA curve name to use - optional bool show_display = 3; // optionally show on display before sending the result - optional string coin_name = 4 [default='Bitcoin']; -} - -/** - * Response: Contains public key derived from device private seed - * @prev GetPublicKey - */ -message PublicKey { - required HDNodeType node = 1; // BIP32 public node - optional string xpub = 2; // serialized form of public node -} - -/** - * Request: Ask device for address corresponding to address_n path - * @next PassphraseRequest - * @next Address - * @next Failure - */ -message GetAddress { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional string coin_name = 2 [default='Bitcoin']; - optional bool show_display = 3 ; // optionally show on display before sending the result - optional MultisigRedeemScriptType multisig = 4; // filled if we are showing a multisig address - optional InputScriptType script_type = 5 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.) -} - -/** - * Request: Ask device for Ethereum address corresponding to address_n path - * @next PassphraseRequest - * @next EthereumAddress - * @next Failure - */ -message EthereumGetAddress { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional bool show_display = 2; // optionally show on display before sending the result -} - -/** - * Response: Contains address derived from device private seed - * @prev GetAddress - */ -message Address { - required string address = 1; // Coin address in Base58 encoding -} - -/** - * Response: Contains an Ethereum address derived from device private seed - * @prev EthereumGetAddress - */ -message EthereumAddress { - required bytes address = 1; // Coin address as an Ethereum 160 bit hash -} - -/** - * Request: Request device to wipe all sensitive data and settings - * @next ButtonRequest - */ -message WipeDevice { -} - -/** - * Request: Load seed and related internal settings from the computer - * @next ButtonRequest - * @next Success - * @next Failure - */ -message LoadDevice { - optional string mnemonic = 1; // seed encoded as BIP-39 mnemonic (12, 18 or 24 words) - optional HDNodeType node = 2; // BIP-32 node - optional string pin = 3; // set PIN protection - optional bool passphrase_protection = 4; // enable master node encryption using passphrase - optional string language = 5 [default='english']; // device language - optional string label = 6; // device label - optional bool skip_checksum = 7; // do not test mnemonic for valid BIP-39 checksum - optional uint32 u2f_counter = 8; // U2F counter -} - -/** - * Request: Ask device to do initialization involving user interaction - * @next EntropyRequest - * @next Failure - */ -message ResetDevice { - optional bool display_random = 1; // display entropy generated by the device before asking for additional entropy - optional uint32 strength = 2 [default=256]; // strength of seed in bits - optional bool passphrase_protection = 3; // enable master node encryption using passphrase - optional bool pin_protection = 4; // enable PIN protection - optional string language = 5 [default='english']; // device language - optional string label = 6; // device label - optional uint32 u2f_counter = 7; // U2F counter - optional bool skip_backup = 8; // postpone seed backup to BackupDevice workflow -} - -/** - * Request: Perform backup of the device seed if not backed up using ResetDevice - * @next ButtonRequest - */ -message BackupDevice { -} - -/** - * Response: Ask for additional entropy from host computer - * @prev ResetDevice - * @next EntropyAck - */ -message EntropyRequest { -} - -/** - * Request: Provide additional entropy for seed generation function - * @prev EntropyRequest - * @next ButtonRequest - */ -message EntropyAck { - optional bytes entropy = 1; // 256 bits (32 bytes) of random data -} - -/** - * Request: Start recovery workflow asking user for specific words of mnemonic - * Used to recovery device safely even on untrusted computer. - * @next WordRequest - */ -message RecoveryDevice { - optional uint32 word_count = 1; // number of words in BIP-39 mnemonic - optional bool passphrase_protection = 2; // enable master node encryption using passphrase - optional bool pin_protection = 3; // enable PIN protection - optional string language = 4 [default='english']; // device language - optional string label = 5; // device label - optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process - // 7 reserved for unused recovery method - optional uint32 type = 8; // supported recovery type (see RecoveryType) - optional uint32 u2f_counter = 9; // U2F counter - optional bool dry_run = 10; // perform dry-run recovery workflow (for safe mnemonic validation) -} - -/** - * Response: Device is waiting for user to enter word of the mnemonic - * Its position is shown only on device's internal display. - * @prev RecoveryDevice - * @prev WordAck - */ -message WordRequest { - optional WordRequestType type = 1; -} - -/** - * Request: Computer replies with word from the mnemonic - * @prev WordRequest - * @next WordRequest - * @next Success - * @next Failure - */ -message WordAck { - required string word = 1; // one word of mnemonic on asked position -} - -////////////////////////////// -// Message signing messages // -////////////////////////////// - -/** - * Request: Ask device to sign message - * @next MessageSignature - * @next Failure - */ -message SignMessage { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - required bytes message = 2; // message to be signed - optional string coin_name = 3 [default='Bitcoin']; // coin to use for signing - optional InputScriptType script_type = 4 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.) -} - -/** - * Request: Ask device to verify message - * @next Success - * @next Failure - */ -message VerifyMessage { - optional string address = 1; // address to verify - optional bytes signature = 2; // signature to verify - optional bytes message = 3; // message to verify - optional string coin_name = 4 [default='Bitcoin']; // coin to use for verifying -} - -/** - * Response: Signed message - * @prev SignMessage - */ -message MessageSignature { - optional string address = 1; // address used to sign the message - optional bytes signature = 2; // signature of the message -} - -/////////////////////////// -// Encryption/decryption // -/////////////////////////// - -/** - * Request: Ask device to encrypt message - * @next EncryptedMessage - * @next Failure - */ -message EncryptMessage { - optional bytes pubkey = 1; // public key - optional bytes message = 2; // message to encrypt - optional bool display_only = 3; // show just on display? (don't send back via wire) - repeated uint32 address_n = 4; // BIP-32 path to derive the signing key from master node - optional string coin_name = 5 [default='Bitcoin']; // coin to use for signing -} - -/** - * Response: Encrypted message - * @prev EncryptMessage - */ -message EncryptedMessage { - optional bytes nonce = 1; // nonce used during encryption - optional bytes message = 2; // encrypted message - optional bytes hmac = 3; // message hmac -} - -/** - * Request: Ask device to decrypt message - * @next Success - * @next Failure - */ -message DecryptMessage { - repeated uint32 address_n = 1; // BIP-32 path to derive the decryption key from master node - optional bytes nonce = 2; // nonce used during encryption - optional bytes message = 3; // message to decrypt - optional bytes hmac = 4; // message hmac -} - -/** - * Response: Decrypted message - * @prev DecryptedMessage - */ -message DecryptedMessage { - optional bytes message = 1; // decrypted message - optional string address = 2; // address used to sign the message (if used) -} - -/** - * Request: Ask device to encrypt or decrypt value of given key - * @next CipheredKeyValue - * @next Failure - */ -message CipherKeyValue { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional string key = 2; // key component of key:value - optional bytes value = 3; // value component of key:value - optional bool encrypt = 4; // are we encrypting (True) or decrypting (False)? - optional bool ask_on_encrypt = 5; // should we ask on encrypt operation? - optional bool ask_on_decrypt = 6; // should we ask on decrypt operation? - optional bytes iv = 7; // initialization vector (will be computed if not set) -} - -/** - * Response: Return ciphered/deciphered value - * @prev CipherKeyValue - */ -message CipheredKeyValue { - optional bytes value = 1; // ciphered/deciphered value -} - -////////////////////////////////// -// Transaction signing messages // -////////////////////////////////// - -/** - * Request: Estimated size of the transaction - * This behaves exactly like SignTx, which means that it can ask using TxRequest - * This call is non-blocking (except possible PassphraseRequest to unlock the seed) - * @next TxSize - * @next Failure - */ -message EstimateTxSize { - required uint32 outputs_count = 1; // number of transaction outputs - required uint32 inputs_count = 2; // number of transaction inputs - optional string coin_name = 3 [default='Bitcoin']; // coin to use -} - -/** - * Response: Estimated size of the transaction - * @prev EstimateTxSize - */ -message TxSize { - optional uint32 tx_size = 1; // estimated size of transaction in bytes -} - -/** - * Request: Ask device to sign transaction - * @next PassphraseRequest - * @next PinMatrixRequest - * @next TxRequest - * @next Failure - */ -message SignTx { - required uint32 outputs_count = 1; // number of transaction outputs - required uint32 inputs_count = 2; // number of transaction inputs - optional string coin_name = 3 [default='Bitcoin']; // coin to use - optional uint32 version = 4 [default=1]; // transaction version - optional uint32 lock_time = 5 [default=0]; // transaction lock_time -} - -/** - * Request: Simplified transaction signing - * This method doesn't support streaming, so there are hardware limits in number of inputs and outputs. - * In case of success, the result is returned using TxRequest message. - * @next PassphraseRequest - * @next PinMatrixRequest - * @next TxRequest - * @next Failure - */ -message SimpleSignTx { - repeated TxInputType inputs = 1; // transaction inputs - repeated TxOutputType outputs = 2; // transaction outputs - repeated TransactionType transactions = 3; // transactions whose outputs are used to build current inputs - optional string coin_name = 4 [default='Bitcoin']; // coin to use - optional uint32 version = 5 [default=1]; // transaction version - optional uint32 lock_time = 6 [default=0]; // transaction lock_time -} - -/** - * Response: Device asks for information for signing transaction or returns the last result - * If request_index is set, device awaits TxAck message (with fields filled in according to request_type) - * If signature_index is set, 'signature' contains signed input of signature_index's input - * @prev SignTx - * @prev SimpleSignTx - * @prev TxAck - */ -message TxRequest { - optional RequestType request_type = 1; // what should be filled in TxAck message? - optional TxRequestDetailsType details = 2; // request for tx details - optional TxRequestSerializedType serialized = 3; // serialized data and request for next -} - -/** - * Request: Reported transaction data - * @prev TxRequest - * @next TxRequest - */ -message TxAck { - optional TransactionType tx = 1; -} - -/** - * Request: Ask device to sign transaction - * All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing. - * Note: the first at most 1024 bytes of data MUST be transmitted as part of this message. - * @next PassphraseRequest - * @next PinMatrixRequest - * @next EthereumTxRequest - * @next Failure - */ -message EthereumSignTx { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional bytes nonce = 2; // <=256 bit unsigned big endian - optional bytes gas_price = 3; // <=256 bit unsigned big endian (in wei) - optional bytes gas_limit = 4; // <=256 bit unsigned big endian - optional bytes to = 5; // 160 bit address hash - optional bytes value = 6; // <=256 bit unsigned big endian (in wei) - optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes) - optional uint32 data_length = 8; // Length of transaction payload - optional uint32 chain_id = 9; // Chain Id for EIP 155 -} - -/** - * Response: Device asks for more data from transaction payload, or returns the signature. - * If data_length is set, device awaits that many more bytes of payload. - * Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present. - * @prev EthereumSignTx - * @next EthereumTxAck - */ -message EthereumTxRequest { - optional uint32 data_length = 1; // Number of bytes being requested (<= 1024) - optional uint32 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28) - optional bytes signature_r = 3; // Computed signature R component (256 bit) - optional bytes signature_s = 4; // Computed signature S component (256 bit) -} - -/** - * Request: Transaction payload data. - * @prev EthereumTxRequest - * @next EthereumTxRequest - */ -message EthereumTxAck { - optional bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes) -} - -//////////////////////////////////////// -// Ethereum: Message signing messages // -//////////////////////////////////////// - -/** - * Request: Ask device to sign message - * @next EthereumMessageSignature - * @next Failure - */ -message EthereumSignMessage { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - required bytes message = 2; // message to be signed -} - -/** - * Request: Ask device to verify message - * @next Success - * @next Failure - */ -message EthereumVerifyMessage { - optional bytes address = 1; // address to verify - optional bytes signature = 2; // signature to verify - optional bytes message = 3; // message to verify -} - -/** - * Response: Signed message - * @prev EthereumSignMessage - */ -message EthereumMessageSignature { - optional bytes address = 1; // address used to sign the message - optional bytes signature = 2; // signature of the message -} - -/////////////////////// -// Identity messages // -/////////////////////// - -/** - * Request: Ask device to sign identity - * @next SignedIdentity - * @next Failure - */ -message SignIdentity { - optional IdentityType identity = 1; // identity - optional bytes challenge_hidden = 2; // non-visible challenge - optional string challenge_visual = 3; // challenge shown on display (e.g. date+time) - optional string ecdsa_curve_name = 4; // ECDSA curve name to use -} - -/** - * Response: Device provides signed identity - * @prev SignIdentity - */ -message SignedIdentity { - optional string address = 1; // identity address - optional bytes public_key = 2; // identity public key - optional bytes signature = 3; // signature of the identity data -} - -/////////////////// -// ECDH messages // -/////////////////// - -/** - * Request: Ask device to generate ECDH session key - * @next ECDHSessionKey - * @next Failure - */ -message GetECDHSessionKey { - optional IdentityType identity = 1; // identity - optional bytes peer_public_key = 2; // peer's public key - optional string ecdsa_curve_name = 3; // ECDSA curve name to use -} - -/** - * Response: Device provides ECDH session key - * @prev GetECDHSessionKey - */ -message ECDHSessionKey { - optional bytes session_key = 1; // ECDH session key -} - -/////////////////// -// U2F messages // -/////////////////// - -/** - * Request: Set U2F counter - * @next Success - */ -message SetU2FCounter { - optional uint32 u2f_counter = 1; // counter -} - -///////////////////////// -// Bootloader messages // -///////////////////////// - -/** - * Request: Ask device to erase its firmware (so it can be replaced via FirmwareUpload) - * @next Success - * @next FirmwareRequest - * @next Failure - */ -message FirmwareErase { - optional uint32 length = 1; // length of new firmware -} - -/** - * Response: Ask for firmware chunk - * @next FirmwareUpload - */ -message FirmwareRequest { - optional uint32 offset = 1; // offset of requested firmware chunk - optional uint32 length = 2; // length of requested firmware chunk -} - -/** - * Request: Send firmware in binary form to the device - * @next Success - * @next Failure - */ -message FirmwareUpload { - required bytes payload = 1; // firmware to be loaded into device - optional bytes hash = 2; // hash of the payload -} - - -/** - * Request: Perform a device self-test - * @next Success - * @next Failure - */ -message SelfTest { - optional bytes payload = 1; // payload to be used in self-test -} - -///////////////////////////////////////////////////////////// -// Debug messages (only available if DebugLink is enabled) // -///////////////////////////////////////////////////////////// - -/** - * Request: "Press" the button on the device - * @next Success - */ -message DebugLinkDecision { - required bool yes_no = 1; // true for "Confirm", false for "Cancel" -} - -/** - * Request: Computer asks for device state - * @next DebugLinkState - */ -message DebugLinkGetState { -} - -/** - * Response: Device current state - * @prev DebugLinkGetState - */ -message DebugLinkState { - optional bytes layout = 1; // raw buffer of display - optional string pin = 2; // current PIN, blank if PIN is not set/enabled - optional string matrix = 3; // current PIN matrix - optional string mnemonic = 4; // current BIP-39 mnemonic - optional HDNodeType node = 5; // current BIP-32 node - optional bool passphrase_protection = 6; // is node/mnemonic encrypted using passphrase? - optional string reset_word = 7; // word on device display during ResetDevice workflow - optional bytes reset_entropy = 8; // current entropy during ResetDevice workflow - optional string recovery_fake_word = 9; // (fake) word on display during RecoveryDevice workflow - optional uint32 recovery_word_pos = 10; // index of mnemonic word the device is expecting during RecoveryDevice workflow -} - -/** - * Request: Ask device to restart - */ -message DebugLinkStop { -} - -/** - * Response: Device wants host to log event - */ -message DebugLinkLog { - optional uint32 level = 1; - optional string bucket = 2; - optional string text = 3; -} - -/** - * Request: Read memory from device - * @next DebugLinkMemory - */ -message DebugLinkMemoryRead { - optional uint32 address = 1; - optional uint32 length = 2; -} - -/** - * Response: Device sends memory back - * @prev DebugLinkMemoryRead - */ -message DebugLinkMemory { - optional bytes memory = 1; -} - -/** - * Request: Write memory to device. - * WARNING: Writing to the wrong location can irreparably break the device. - */ -message DebugLinkMemoryWrite { - optional uint32 address = 1; - optional bytes memory = 2; - optional bool flash = 3; -} -/** - * Request: Erase block of flash on device - * WARNING: Writing to the wrong location can irreparably break the device. - */ -message DebugLinkFlashErase { - optional uint32 sector = 1; + // Management + MessageType_Initialize = 0 [(wire_in) = true, (wire_tiny) = true]; + MessageType_Ping = 1 [(wire_in) = true]; + MessageType_Success = 2 [(wire_out) = true]; + MessageType_Failure = 3 [(wire_out) = true]; + MessageType_ChangePin = 4 [(wire_in) = true]; + MessageType_WipeDevice = 5 [(wire_in) = true]; + MessageType_GetEntropy = 9 [(wire_in) = true]; + MessageType_Entropy = 10 [(wire_out) = true]; + MessageType_LoadDevice = 13 [(wire_in) = true]; + MessageType_ResetDevice = 14 [(wire_in) = true]; + MessageType_Features = 17 [(wire_out) = true]; + MessageType_PinMatrixRequest = 18 [(wire_out) = true]; + MessageType_PinMatrixAck = 19 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true]; + MessageType_Cancel = 20 [(wire_in) = true, (wire_tiny) = true]; + MessageType_ClearSession = 24 [(wire_in) = true]; + MessageType_ApplySettings = 25 [(wire_in) = true]; + MessageType_ButtonRequest = 26 [(wire_out) = true]; + MessageType_ButtonAck = 27 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true]; + MessageType_ApplyFlags = 28 [(wire_in) = true]; + MessageType_BackupDevice = 34 [(wire_in) = true]; + MessageType_EntropyRequest = 35 [(wire_out) = true]; + MessageType_EntropyAck = 36 [(wire_in) = true]; + MessageType_PassphraseRequest = 41 [(wire_out) = true]; + MessageType_PassphraseAck = 42 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true]; + MessageType_PassphraseStateRequest = 77 [(wire_out) = true]; + MessageType_PassphraseStateAck = 78 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true]; + MessageType_RecoveryDevice = 45 [(wire_in) = true]; + MessageType_WordRequest = 46 [(wire_out) = true]; + MessageType_WordAck = 47 [(wire_in) = true]; + MessageType_GetFeatures = 55 [(wire_in) = true]; + MessageType_SetU2FCounter = 63 [(wire_in) = true]; + + // Bootloader + MessageType_FirmwareErase = 6 [(wire_in) = true, (wire_bootloader) = true]; + MessageType_FirmwareUpload = 7 [(wire_in) = true, (wire_bootloader) = true]; + MessageType_FirmwareRequest = 8 [(wire_out) = true, (wire_bootloader) = true]; + MessageType_SelfTest = 32 [(wire_in) = true, (wire_bootloader) = true]; + + // Bitcoin + MessageType_GetPublicKey = 11 [(wire_in) = true]; + MessageType_PublicKey = 12 [(wire_out) = true]; + MessageType_SignTx = 15 [(wire_in) = true]; + MessageType_TxRequest = 21 [(wire_out) = true]; + MessageType_TxAck = 22 [(wire_in) = true]; + MessageType_GetAddress = 29 [(wire_in) = true]; + MessageType_Address = 30 [(wire_out) = true]; + MessageType_SignMessage = 38 [(wire_in) = true]; + MessageType_VerifyMessage = 39 [(wire_in) = true]; + MessageType_MessageSignature = 40 [(wire_out) = true]; + + // Crypto + MessageType_CipherKeyValue = 23 [(wire_in) = true]; + MessageType_CipheredKeyValue = 48 [(wire_out) = true]; + MessageType_SignIdentity = 53 [(wire_in) = true]; + MessageType_SignedIdentity = 54 [(wire_out) = true]; + MessageType_GetECDHSessionKey = 61 [(wire_in) = true]; + MessageType_ECDHSessionKey = 62 [(wire_out) = true]; + MessageType_CosiCommit = 71 [(wire_in) = true]; + MessageType_CosiCommitment = 72 [(wire_out) = true]; + MessageType_CosiSign = 73 [(wire_in) = true]; + MessageType_CosiSignature = 74 [(wire_out) = true]; + + // Debug + MessageType_DebugLinkDecision = 100 [(wire_debug_in) = true, (wire_tiny) = true, (wire_no_fsm) = true]; + MessageType_DebugLinkGetState = 101 [(wire_debug_in) = true, (wire_tiny) = true]; + MessageType_DebugLinkState = 102 [(wire_debug_out) = true]; + MessageType_DebugLinkStop = 103 [(wire_debug_in) = true]; + MessageType_DebugLinkLog = 104 [(wire_debug_out) = true]; + MessageType_DebugLinkMemoryRead = 110 [(wire_debug_in) = true]; + MessageType_DebugLinkMemory = 111 [(wire_debug_out) = true]; + MessageType_DebugLinkMemoryWrite = 112 [(wire_debug_in) = true]; + MessageType_DebugLinkFlashErase = 113 [(wire_debug_in) = true]; + + // Ethereum + MessageType_EthereumGetPublicKey = 450 [(wire_in) = true]; + MessageType_EthereumPublicKey = 451 [(wire_out) = true]; + MessageType_EthereumGetAddress = 56 [(wire_in) = true]; + MessageType_EthereumAddress = 57 [(wire_out) = true]; + MessageType_EthereumSignTx = 58 [(wire_in) = true]; + MessageType_EthereumTxRequest = 59 [(wire_out) = true]; + MessageType_EthereumTxAck = 60 [(wire_in) = true]; + MessageType_EthereumSignMessage = 64 [(wire_in) = true]; + MessageType_EthereumVerifyMessage = 65 [(wire_in) = true]; + MessageType_EthereumMessageSignature = 66 [(wire_out) = true]; + + // NEM + MessageType_NEMGetAddress = 67 [(wire_in) = true]; + MessageType_NEMAddress = 68 [(wire_out) = true]; + MessageType_NEMSignTx = 69 [(wire_in) = true]; + MessageType_NEMSignedTx = 70 [(wire_out) = true]; + MessageType_NEMDecryptMessage = 75 [(wire_in) = true]; + MessageType_NEMDecryptedMessage = 76 [(wire_out) = true]; + + // Lisk + MessageType_LiskGetAddress = 114 [(wire_in) = true]; + MessageType_LiskAddress = 115 [(wire_out) = true]; + MessageType_LiskSignTx = 116 [(wire_in) = true]; + MessageType_LiskSignedTx = 117 [(wire_out) = true]; + MessageType_LiskSignMessage = 118 [(wire_in) = true]; + MessageType_LiskMessageSignature = 119 [(wire_out) = true]; + MessageType_LiskVerifyMessage = 120 [(wire_in) = true]; + MessageType_LiskGetPublicKey = 121 [(wire_in) = true]; + MessageType_LiskPublicKey = 122 [(wire_out) = true]; + + // Tezos + MessageType_TezosGetAddress = 150 [(wire_in) = true]; + MessageType_TezosAddress = 151 [(wire_out) = true]; + MessageType_TezosSignTx = 152 [(wire_in) = true]; + MessageType_TezosSignedTx = 153 [(wire_out) = true]; + MessageType_TezosGetPublicKey = 154 [(wire_in) = true]; + MessageType_TezosPublicKey = 155 [(wire_out) = true]; + + // Stellar + MessageType_StellarSignTx = 202 [(wire_in) = true]; + MessageType_StellarTxOpRequest = 203 [(wire_out) = true]; + MessageType_StellarGetAddress = 207 [(wire_in) = true]; + MessageType_StellarAddress = 208 [(wire_out) = true]; + MessageType_StellarCreateAccountOp = 210 [(wire_in) = true]; + MessageType_StellarPaymentOp = 211 [(wire_in) = true]; + MessageType_StellarPathPaymentOp = 212 [(wire_in) = true]; + MessageType_StellarManageOfferOp = 213 [(wire_in) = true]; + MessageType_StellarCreatePassiveOfferOp = 214 [(wire_in) = true]; + MessageType_StellarSetOptionsOp = 215 [(wire_in) = true]; + MessageType_StellarChangeTrustOp = 216 [(wire_in) = true]; + MessageType_StellarAllowTrustOp = 217 [(wire_in) = true]; + MessageType_StellarAccountMergeOp = 218 [(wire_in) = true]; + // omitted: StellarInflationOp is not a supported operation, would be 219 + MessageType_StellarManageDataOp = 220 [(wire_in) = true]; + MessageType_StellarBumpSequenceOp = 221 [(wire_in) = true]; + MessageType_StellarSignedTx = 230 [(wire_out) = true]; + + // TRON + MessageType_TronGetAddress = 250 [(wire_in) = true]; + MessageType_TronAddress = 251 [(wire_out) = true]; + MessageType_TronSignTx = 252 [(wire_in) = true]; + MessageType_TronSignedTx = 253 [(wire_out) = true]; + + // Cardano + // dropped Sign/VerifyMessage ids 300-302 + MessageType_CardanoSignTx = 303 [(wire_in) = true]; + MessageType_CardanoTxRequest = 304 [(wire_out) = true]; + MessageType_CardanoGetPublicKey = 305 [(wire_in) = true]; + MessageType_CardanoPublicKey = 306 [(wire_out) = true]; + MessageType_CardanoGetAddress = 307 [(wire_in) = true]; + MessageType_CardanoAddress = 308 [(wire_out) = true]; + MessageType_CardanoTxAck = 309 [(wire_in) = true]; + MessageType_CardanoSignedTx = 310 [(wire_out) = true]; + + // Ontology + MessageType_OntologyGetAddress = 350 [(wire_in) = true]; + MessageType_OntologyAddress = 351 [(wire_out) = true]; + MessageType_OntologyGetPublicKey = 352 [(wire_in) = true]; + MessageType_OntologyPublicKey = 353 [(wire_out) = true]; + MessageType_OntologySignTransfer = 354 [(wire_in) = true]; + MessageType_OntologySignedTransfer = 355 [(wire_out) = true]; + MessageType_OntologySignWithdrawOng = 356 [(wire_in) = true]; + MessageType_OntologySignedWithdrawOng = 357 [(wire_out) = true]; + MessageType_OntologySignOntIdRegister = 358 [(wire_in) = true]; + MessageType_OntologySignedOntIdRegister = 359 [(wire_out) = true]; + MessageType_OntologySignOntIdAddAttributes = 360 [(wire_in) = true]; + MessageType_OntologySignedOntIdAddAttributes = 361 [(wire_out) = true]; + + // Ripple + MessageType_RippleGetAddress = 400 [(wire_in) = true]; + MessageType_RippleAddress = 401 [(wire_out) = true]; + MessageType_RippleSignTx = 402 [(wire_in) = true]; + MessageType_RippleSignedTx = 403 [(wire_in) = true]; + + // Monero + MessageType_MoneroTransactionInitRequest = 501 [(wire_out) = true]; + MessageType_MoneroTransactionInitAck = 502 [(wire_out) = true]; + MessageType_MoneroTransactionSetInputRequest = 503 [(wire_out) = true]; + MessageType_MoneroTransactionSetInputAck = 504 [(wire_out) = true]; + MessageType_MoneroTransactionInputsPermutationRequest = 505 [(wire_out) = true]; + MessageType_MoneroTransactionInputsPermutationAck = 506 [(wire_out) = true]; + MessageType_MoneroTransactionInputViniRequest = 507 [(wire_out) = true]; + MessageType_MoneroTransactionInputViniAck = 508 [(wire_out) = true]; + MessageType_MoneroTransactionAllInputsSetRequest = 509 [(wire_out) = true]; + MessageType_MoneroTransactionAllInputsSetAck = 510 [(wire_out) = true]; + MessageType_MoneroTransactionSetOutputRequest = 511 [(wire_out) = true]; + MessageType_MoneroTransactionSetOutputAck = 512 [(wire_out) = true]; + MessageType_MoneroTransactionAllOutSetRequest = 513 [(wire_out) = true]; + MessageType_MoneroTransactionAllOutSetAck = 514 [(wire_out) = true]; + MessageType_MoneroTransactionSignInputRequest = 515 [(wire_out) = true]; + MessageType_MoneroTransactionSignInputAck = 516 [(wire_out) = true]; + MessageType_MoneroTransactionFinalRequest = 517 [(wire_out) = true]; + MessageType_MoneroTransactionFinalAck = 518 [(wire_out) = true]; + MessageType_MoneroKeyImageExportInitRequest = 530 [(wire_out) = true]; + MessageType_MoneroKeyImageExportInitAck = 531 [(wire_out) = true]; + MessageType_MoneroKeyImageSyncStepRequest = 532 [(wire_out) = true]; + MessageType_MoneroKeyImageSyncStepAck = 533 [(wire_out) = true]; + MessageType_MoneroKeyImageSyncFinalRequest = 534 [(wire_out) = true]; + MessageType_MoneroKeyImageSyncFinalAck = 535 [(wire_out) = true]; + MessageType_MoneroGetAddress = 540 [(wire_in) = true]; + MessageType_MoneroAddress = 541 [(wire_out) = true]; + MessageType_MoneroGetWatchKey = 542 [(wire_in) = true]; + MessageType_MoneroWatchKey = 543 [(wire_out) = true]; + MessageType_DebugMoneroDiagRequest = 546 [(wire_in) = true]; + MessageType_DebugMoneroDiagAck = 547 [(wire_out) = true]; + MessageType_MoneroGetTxKeyRequest = 550 [(wire_in) = true]; + MessageType_MoneroGetTxKeyAck = 551 [(wire_out) = true]; + MessageType_MoneroLiveRefreshStartRequest = 552 [(wire_in) = true]; + MessageType_MoneroLiveRefreshStartAck = 553 [(wire_out) = true]; + MessageType_MoneroLiveRefreshStepRequest = 554 [(wire_in) = true]; + MessageType_MoneroLiveRefreshStepAck = 555 [(wire_out) = true]; + MessageType_MoneroLiveRefreshFinalRequest = 556 [(wire_in) = true]; + MessageType_MoneroLiveRefreshFinalAck = 557 [(wire_out) = true]; + + // EOS + MessageType_EosGetPublicKey = 600 [(wire_in) = true]; + MessageType_EosPublicKey = 601 [(wire_out) = true]; + MessageType_EosSignTx = 602 [(wire_in) = true]; + MessageType_EosTxActionRequest = 603 [(wire_out) = true]; + MessageType_EosTxActionAck = 604 [(wire_in) = true]; + MessageType_EosSignedTx = 605 [(wire_out) = true]; + + // Binance + MessageType_BinanceGetAddress = 700 [(wire_in) = true]; + MessageType_BinanceAddress = 701 [(wire_out) = true]; + MessageType_BinanceGetPublicKey = 702 [(wire_in) = true]; + MessageType_BinancePublicKey = 703 [(wire_out) = true]; + MessageType_BinanceSignTx = 704 [(wire_in) = true]; + MessageType_BinanceTxRequest = 705 [(wire_out) = true]; + MessageType_BinanceTransferMsg = 706 [(wire_in) = true]; + MessageType_BinanceOrderMsg = 707 [(wire_in) = true]; + MessageType_BinanceCancelMsg = 708 [(wire_in) = true]; + MessageType_BinanceSignedTx = 709 [(wire_out) = true]; } diff --git a/accounts/usbwallet/trezor/trezor.go b/accounts/usbwallet/trezor/trezor.go index 80cc75efc4..a259c1dce9 100644 --- a/accounts/usbwallet/trezor/trezor.go +++ b/accounts/usbwallet/trezor/trezor.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// Copyright 2019 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -16,11 +16,35 @@ // This file contains the implementation for interacting with the Trezor hardware // wallets. The wire protocol spec can be found on the SatoshiLabs website: -// https://doc.satoshilabs.com/trezor-tech/api-protobuf.html +// https://wiki.trezor.io/Developers_guide-Message_Workflows -//go:generate protoc --go_out=import_path=trezor:. types.proto messages.proto +// !!! STAHP !!! +// +// Before you touch the protocol files, you need to be aware of a breaking change +// that occurred between firmware versions 1.7.3->1.8.0 (Model One) and 2.0.10-> +// 2.1.0 (Model T). The Ethereum address representation was changed from the 20 +// byte binary blob to a 42 byte hex string. The upstream protocol buffer files +// only support the new format, so blindly pulling in a new spec will break old +// devices! +// +// The Trezor devs had the foresight to add the string version as a new message +// code instead of replacing the binary one. This means that the proto file can +// actually define both the old and the new versions as optional. Please ensure +// that you add back the old addresses everywhere (to avoid name clash. use the +// addressBin and addressHex names). +// +// If in doubt, reach out to @karalabe. -// Package trezor contains the wire protocol wrapper in Go. +// To regenerate the protocol files in this package: +// - Download the latest protoc https://github.com/protocolbuffers/protobuf/releases +// - Build with the usual `./configure && make` and ensure it's on your $PATH +// - Delete all the .proto and .pb.go files, pull in fresh ones from Trezor +// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go` +// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...` + +//go:generate protoc -I/usr/local/include:. --go_out=import_path=trezor:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto + +// Package trezor contains the wire protocol. package trezor import ( diff --git a/accounts/usbwallet/trezor/types.pb.go b/accounts/usbwallet/trezor/types.pb.go deleted file mode 100644 index 25b7672d23..0000000000 --- a/accounts/usbwallet/trezor/types.pb.go +++ /dev/null @@ -1,1333 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: types.proto - -/* -Package trezor is a generated protocol buffer package. - -It is generated from these files: - types.proto - messages.proto - -It has these top-level messages: - HDNodeType - HDNodePathType - CoinType - MultisigRedeemScriptType - TxInputType - TxOutputType - TxOutputBinType - TransactionType - TxRequestDetailsType - TxRequestSerializedType - IdentityType - Initialize - GetFeatures - Features - ClearSession - ApplySettings - ApplyFlags - ChangePin - Ping - Success - Failure - ButtonRequest - ButtonAck - PinMatrixRequest - PinMatrixAck - Cancel - PassphraseRequest - PassphraseAck - GetEntropy - Entropy - GetPublicKey - PublicKey - GetAddress - EthereumGetAddress - Address - EthereumAddress - WipeDevice - LoadDevice - ResetDevice - BackupDevice - EntropyRequest - EntropyAck - RecoveryDevice - WordRequest - WordAck - SignMessage - VerifyMessage - MessageSignature - EncryptMessage - EncryptedMessage - DecryptMessage - DecryptedMessage - CipherKeyValue - CipheredKeyValue - EstimateTxSize - TxSize - SignTx - SimpleSignTx - TxRequest - TxAck - EthereumSignTx - EthereumTxRequest - EthereumTxAck - EthereumSignMessage - EthereumVerifyMessage - EthereumMessageSignature - SignIdentity - SignedIdentity - GetECDHSessionKey - ECDHSessionKey - SetU2FCounter - FirmwareErase - FirmwareRequest - FirmwareUpload - SelfTest - DebugLinkDecision - DebugLinkGetState - DebugLinkState - DebugLinkStop - DebugLinkLog - DebugLinkMemoryRead - DebugLinkMemory - DebugLinkMemoryWrite - DebugLinkFlashErase -*/ -package trezor - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/golang/protobuf/protoc-gen-go/descriptor" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -// * -// Type of failures returned by Failure message -// @used_in Failure -type FailureType int32 - -const ( - FailureType_Failure_UnexpectedMessage FailureType = 1 - FailureType_Failure_ButtonExpected FailureType = 2 - FailureType_Failure_DataError FailureType = 3 - FailureType_Failure_ActionCancelled FailureType = 4 - FailureType_Failure_PinExpected FailureType = 5 - FailureType_Failure_PinCancelled FailureType = 6 - FailureType_Failure_PinInvalid FailureType = 7 - FailureType_Failure_InvalidSignature FailureType = 8 - FailureType_Failure_ProcessError FailureType = 9 - FailureType_Failure_NotEnoughFunds FailureType = 10 - FailureType_Failure_NotInitialized FailureType = 11 - FailureType_Failure_FirmwareError FailureType = 99 -) - -var FailureType_name = map[int32]string{ - 1: "Failure_UnexpectedMessage", - 2: "Failure_ButtonExpected", - 3: "Failure_DataError", - 4: "Failure_ActionCancelled", - 5: "Failure_PinExpected", - 6: "Failure_PinCancelled", - 7: "Failure_PinInvalid", - 8: "Failure_InvalidSignature", - 9: "Failure_ProcessError", - 10: "Failure_NotEnoughFunds", - 11: "Failure_NotInitialized", - 99: "Failure_FirmwareError", -} -var FailureType_value = map[string]int32{ - "Failure_UnexpectedMessage": 1, - "Failure_ButtonExpected": 2, - "Failure_DataError": 3, - "Failure_ActionCancelled": 4, - "Failure_PinExpected": 5, - "Failure_PinCancelled": 6, - "Failure_PinInvalid": 7, - "Failure_InvalidSignature": 8, - "Failure_ProcessError": 9, - "Failure_NotEnoughFunds": 10, - "Failure_NotInitialized": 11, - "Failure_FirmwareError": 99, -} - -func (x FailureType) Enum() *FailureType { - p := new(FailureType) - *p = x - return p -} -func (x FailureType) String() string { - return proto.EnumName(FailureType_name, int32(x)) -} -func (x *FailureType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FailureType_value, data, "FailureType") - if err != nil { - return err - } - *x = FailureType(value) - return nil -} -func (FailureType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -// * -// Type of script which will be used for transaction output -// @used_in TxOutputType -type OutputScriptType int32 - -const ( - OutputScriptType_PAYTOADDRESS OutputScriptType = 0 - OutputScriptType_PAYTOSCRIPTHASH OutputScriptType = 1 - OutputScriptType_PAYTOMULTISIG OutputScriptType = 2 - OutputScriptType_PAYTOOPRETURN OutputScriptType = 3 - OutputScriptType_PAYTOWITNESS OutputScriptType = 4 - OutputScriptType_PAYTOP2SHWITNESS OutputScriptType = 5 -) - -var OutputScriptType_name = map[int32]string{ - 0: "PAYTOADDRESS", - 1: "PAYTOSCRIPTHASH", - 2: "PAYTOMULTISIG", - 3: "PAYTOOPRETURN", - 4: "PAYTOWITNESS", - 5: "PAYTOP2SHWITNESS", -} -var OutputScriptType_value = map[string]int32{ - "PAYTOADDRESS": 0, - "PAYTOSCRIPTHASH": 1, - "PAYTOMULTISIG": 2, - "PAYTOOPRETURN": 3, - "PAYTOWITNESS": 4, - "PAYTOP2SHWITNESS": 5, -} - -func (x OutputScriptType) Enum() *OutputScriptType { - p := new(OutputScriptType) - *p = x - return p -} -func (x OutputScriptType) String() string { - return proto.EnumName(OutputScriptType_name, int32(x)) -} -func (x *OutputScriptType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(OutputScriptType_value, data, "OutputScriptType") - if err != nil { - return err - } - *x = OutputScriptType(value) - return nil -} -func (OutputScriptType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -// * -// Type of script which will be used for transaction output -// @used_in TxInputType -type InputScriptType int32 - -const ( - InputScriptType_SPENDADDRESS InputScriptType = 0 - InputScriptType_SPENDMULTISIG InputScriptType = 1 - InputScriptType_EXTERNAL InputScriptType = 2 - InputScriptType_SPENDWITNESS InputScriptType = 3 - InputScriptType_SPENDP2SHWITNESS InputScriptType = 4 -) - -var InputScriptType_name = map[int32]string{ - 0: "SPENDADDRESS", - 1: "SPENDMULTISIG", - 2: "EXTERNAL", - 3: "SPENDWITNESS", - 4: "SPENDP2SHWITNESS", -} -var InputScriptType_value = map[string]int32{ - "SPENDADDRESS": 0, - "SPENDMULTISIG": 1, - "EXTERNAL": 2, - "SPENDWITNESS": 3, - "SPENDP2SHWITNESS": 4, -} - -func (x InputScriptType) Enum() *InputScriptType { - p := new(InputScriptType) - *p = x - return p -} -func (x InputScriptType) String() string { - return proto.EnumName(InputScriptType_name, int32(x)) -} -func (x *InputScriptType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(InputScriptType_value, data, "InputScriptType") - if err != nil { - return err - } - *x = InputScriptType(value) - return nil -} -func (InputScriptType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -// * -// Type of information required by transaction signing process -// @used_in TxRequest -type RequestType int32 - -const ( - RequestType_TXINPUT RequestType = 0 - RequestType_TXOUTPUT RequestType = 1 - RequestType_TXMETA RequestType = 2 - RequestType_TXFINISHED RequestType = 3 - RequestType_TXEXTRADATA RequestType = 4 -) - -var RequestType_name = map[int32]string{ - 0: "TXINPUT", - 1: "TXOUTPUT", - 2: "TXMETA", - 3: "TXFINISHED", - 4: "TXEXTRADATA", -} -var RequestType_value = map[string]int32{ - "TXINPUT": 0, - "TXOUTPUT": 1, - "TXMETA": 2, - "TXFINISHED": 3, - "TXEXTRADATA": 4, -} - -func (x RequestType) Enum() *RequestType { - p := new(RequestType) - *p = x - return p -} -func (x RequestType) String() string { - return proto.EnumName(RequestType_name, int32(x)) -} -func (x *RequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(RequestType_value, data, "RequestType") - if err != nil { - return err - } - *x = RequestType(value) - return nil -} -func (RequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -// * -// Type of button request -// @used_in ButtonRequest -type ButtonRequestType int32 - -const ( - ButtonRequestType_ButtonRequest_Other ButtonRequestType = 1 - ButtonRequestType_ButtonRequest_FeeOverThreshold ButtonRequestType = 2 - ButtonRequestType_ButtonRequest_ConfirmOutput ButtonRequestType = 3 - ButtonRequestType_ButtonRequest_ResetDevice ButtonRequestType = 4 - ButtonRequestType_ButtonRequest_ConfirmWord ButtonRequestType = 5 - ButtonRequestType_ButtonRequest_WipeDevice ButtonRequestType = 6 - ButtonRequestType_ButtonRequest_ProtectCall ButtonRequestType = 7 - ButtonRequestType_ButtonRequest_SignTx ButtonRequestType = 8 - ButtonRequestType_ButtonRequest_FirmwareCheck ButtonRequestType = 9 - ButtonRequestType_ButtonRequest_Address ButtonRequestType = 10 - ButtonRequestType_ButtonRequest_PublicKey ButtonRequestType = 11 -) - -var ButtonRequestType_name = map[int32]string{ - 1: "ButtonRequest_Other", - 2: "ButtonRequest_FeeOverThreshold", - 3: "ButtonRequest_ConfirmOutput", - 4: "ButtonRequest_ResetDevice", - 5: "ButtonRequest_ConfirmWord", - 6: "ButtonRequest_WipeDevice", - 7: "ButtonRequest_ProtectCall", - 8: "ButtonRequest_SignTx", - 9: "ButtonRequest_FirmwareCheck", - 10: "ButtonRequest_Address", - 11: "ButtonRequest_PublicKey", -} -var ButtonRequestType_value = map[string]int32{ - "ButtonRequest_Other": 1, - "ButtonRequest_FeeOverThreshold": 2, - "ButtonRequest_ConfirmOutput": 3, - "ButtonRequest_ResetDevice": 4, - "ButtonRequest_ConfirmWord": 5, - "ButtonRequest_WipeDevice": 6, - "ButtonRequest_ProtectCall": 7, - "ButtonRequest_SignTx": 8, - "ButtonRequest_FirmwareCheck": 9, - "ButtonRequest_Address": 10, - "ButtonRequest_PublicKey": 11, -} - -func (x ButtonRequestType) Enum() *ButtonRequestType { - p := new(ButtonRequestType) - *p = x - return p -} -func (x ButtonRequestType) String() string { - return proto.EnumName(ButtonRequestType_name, int32(x)) -} -func (x *ButtonRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(ButtonRequestType_value, data, "ButtonRequestType") - if err != nil { - return err - } - *x = ButtonRequestType(value) - return nil -} -func (ButtonRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } - -// * -// Type of PIN request -// @used_in PinMatrixRequest -type PinMatrixRequestType int32 - -const ( - PinMatrixRequestType_PinMatrixRequestType_Current PinMatrixRequestType = 1 - PinMatrixRequestType_PinMatrixRequestType_NewFirst PinMatrixRequestType = 2 - PinMatrixRequestType_PinMatrixRequestType_NewSecond PinMatrixRequestType = 3 -) - -var PinMatrixRequestType_name = map[int32]string{ - 1: "PinMatrixRequestType_Current", - 2: "PinMatrixRequestType_NewFirst", - 3: "PinMatrixRequestType_NewSecond", -} -var PinMatrixRequestType_value = map[string]int32{ - "PinMatrixRequestType_Current": 1, - "PinMatrixRequestType_NewFirst": 2, - "PinMatrixRequestType_NewSecond": 3, -} - -func (x PinMatrixRequestType) Enum() *PinMatrixRequestType { - p := new(PinMatrixRequestType) - *p = x - return p -} -func (x PinMatrixRequestType) String() string { - return proto.EnumName(PinMatrixRequestType_name, int32(x)) -} -func (x *PinMatrixRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(PinMatrixRequestType_value, data, "PinMatrixRequestType") - if err != nil { - return err - } - *x = PinMatrixRequestType(value) - return nil -} -func (PinMatrixRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } - -// * -// Type of recovery procedure. These should be used as bitmask, e.g., -// `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` -// listing every method supported by the host computer. -// -// Note that ScrambledWords must be supported by every implementation -// for backward compatibility; there is no way to not support it. -// -// @used_in RecoveryDevice -type RecoveryDeviceType int32 - -const ( - // use powers of two when extending this field - RecoveryDeviceType_RecoveryDeviceType_ScrambledWords RecoveryDeviceType = 0 - RecoveryDeviceType_RecoveryDeviceType_Matrix RecoveryDeviceType = 1 -) - -var RecoveryDeviceType_name = map[int32]string{ - 0: "RecoveryDeviceType_ScrambledWords", - 1: "RecoveryDeviceType_Matrix", -} -var RecoveryDeviceType_value = map[string]int32{ - "RecoveryDeviceType_ScrambledWords": 0, - "RecoveryDeviceType_Matrix": 1, -} - -func (x RecoveryDeviceType) Enum() *RecoveryDeviceType { - p := new(RecoveryDeviceType) - *p = x - return p -} -func (x RecoveryDeviceType) String() string { - return proto.EnumName(RecoveryDeviceType_name, int32(x)) -} -func (x *RecoveryDeviceType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(RecoveryDeviceType_value, data, "RecoveryDeviceType") - if err != nil { - return err - } - *x = RecoveryDeviceType(value) - return nil -} -func (RecoveryDeviceType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } - -// * -// Type of Recovery Word request -// @used_in WordRequest -type WordRequestType int32 - -const ( - WordRequestType_WordRequestType_Plain WordRequestType = 0 - WordRequestType_WordRequestType_Matrix9 WordRequestType = 1 - WordRequestType_WordRequestType_Matrix6 WordRequestType = 2 -) - -var WordRequestType_name = map[int32]string{ - 0: "WordRequestType_Plain", - 1: "WordRequestType_Matrix9", - 2: "WordRequestType_Matrix6", -} -var WordRequestType_value = map[string]int32{ - "WordRequestType_Plain": 0, - "WordRequestType_Matrix9": 1, - "WordRequestType_Matrix6": 2, -} - -func (x WordRequestType) Enum() *WordRequestType { - p := new(WordRequestType) - *p = x - return p -} -func (x WordRequestType) String() string { - return proto.EnumName(WordRequestType_name, int32(x)) -} -func (x *WordRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(WordRequestType_value, data, "WordRequestType") - if err != nil { - return err - } - *x = WordRequestType(value) - return nil -} -func (WordRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } - -// * -// Structure representing BIP32 (hierarchical deterministic) node -// Used for imports of private key into the device and exporting public key out of device -// @used_in PublicKey -// @used_in LoadDevice -// @used_in DebugLinkState -// @used_in Storage -type HDNodeType struct { - Depth *uint32 `protobuf:"varint,1,req,name=depth" json:"depth,omitempty"` - Fingerprint *uint32 `protobuf:"varint,2,req,name=fingerprint" json:"fingerprint,omitempty"` - ChildNum *uint32 `protobuf:"varint,3,req,name=child_num,json=childNum" json:"child_num,omitempty"` - ChainCode []byte `protobuf:"bytes,4,req,name=chain_code,json=chainCode" json:"chain_code,omitempty"` - PrivateKey []byte `protobuf:"bytes,5,opt,name=private_key,json=privateKey" json:"private_key,omitempty"` - PublicKey []byte `protobuf:"bytes,6,opt,name=public_key,json=publicKey" json:"public_key,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *HDNodeType) Reset() { *m = HDNodeType{} } -func (m *HDNodeType) String() string { return proto.CompactTextString(m) } -func (*HDNodeType) ProtoMessage() {} -func (*HDNodeType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func (m *HDNodeType) GetDepth() uint32 { - if m != nil && m.Depth != nil { - return *m.Depth - } - return 0 -} - -func (m *HDNodeType) GetFingerprint() uint32 { - if m != nil && m.Fingerprint != nil { - return *m.Fingerprint - } - return 0 -} - -func (m *HDNodeType) GetChildNum() uint32 { - if m != nil && m.ChildNum != nil { - return *m.ChildNum - } - return 0 -} - -func (m *HDNodeType) GetChainCode() []byte { - if m != nil { - return m.ChainCode - } - return nil -} - -func (m *HDNodeType) GetPrivateKey() []byte { - if m != nil { - return m.PrivateKey - } - return nil -} - -func (m *HDNodeType) GetPublicKey() []byte { - if m != nil { - return m.PublicKey - } - return nil -} - -type HDNodePathType struct { - Node *HDNodeType `protobuf:"bytes,1,req,name=node" json:"node,omitempty"` - AddressN []uint32 `protobuf:"varint,2,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *HDNodePathType) Reset() { *m = HDNodePathType{} } -func (m *HDNodePathType) String() string { return proto.CompactTextString(m) } -func (*HDNodePathType) ProtoMessage() {} -func (*HDNodePathType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *HDNodePathType) GetNode() *HDNodeType { - if m != nil { - return m.Node - } - return nil -} - -func (m *HDNodePathType) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -// * -// Structure representing Coin -// @used_in Features -type CoinType struct { - CoinName *string `protobuf:"bytes,1,opt,name=coin_name,json=coinName" json:"coin_name,omitempty"` - CoinShortcut *string `protobuf:"bytes,2,opt,name=coin_shortcut,json=coinShortcut" json:"coin_shortcut,omitempty"` - AddressType *uint32 `protobuf:"varint,3,opt,name=address_type,json=addressType,def=0" json:"address_type,omitempty"` - MaxfeeKb *uint64 `protobuf:"varint,4,opt,name=maxfee_kb,json=maxfeeKb" json:"maxfee_kb,omitempty"` - AddressTypeP2Sh *uint32 `protobuf:"varint,5,opt,name=address_type_p2sh,json=addressTypeP2sh,def=5" json:"address_type_p2sh,omitempty"` - SignedMessageHeader *string `protobuf:"bytes,8,opt,name=signed_message_header,json=signedMessageHeader" json:"signed_message_header,omitempty"` - XpubMagic *uint32 `protobuf:"varint,9,opt,name=xpub_magic,json=xpubMagic,def=76067358" json:"xpub_magic,omitempty"` - XprvMagic *uint32 `protobuf:"varint,10,opt,name=xprv_magic,json=xprvMagic,def=76066276" json:"xprv_magic,omitempty"` - Segwit *bool `protobuf:"varint,11,opt,name=segwit" json:"segwit,omitempty"` - Forkid *uint32 `protobuf:"varint,12,opt,name=forkid" json:"forkid,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *CoinType) Reset() { *m = CoinType{} } -func (m *CoinType) String() string { return proto.CompactTextString(m) } -func (*CoinType) ProtoMessage() {} -func (*CoinType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -const Default_CoinType_AddressType uint32 = 0 -const Default_CoinType_AddressTypeP2Sh uint32 = 5 -const Default_CoinType_XpubMagic uint32 = 76067358 -const Default_CoinType_XprvMagic uint32 = 76066276 - -func (m *CoinType) GetCoinName() string { - if m != nil && m.CoinName != nil { - return *m.CoinName - } - return "" -} - -func (m *CoinType) GetCoinShortcut() string { - if m != nil && m.CoinShortcut != nil { - return *m.CoinShortcut - } - return "" -} - -func (m *CoinType) GetAddressType() uint32 { - if m != nil && m.AddressType != nil { - return *m.AddressType - } - return Default_CoinType_AddressType -} - -func (m *CoinType) GetMaxfeeKb() uint64 { - if m != nil && m.MaxfeeKb != nil { - return *m.MaxfeeKb - } - return 0 -} - -func (m *CoinType) GetAddressTypeP2Sh() uint32 { - if m != nil && m.AddressTypeP2Sh != nil { - return *m.AddressTypeP2Sh - } - return Default_CoinType_AddressTypeP2Sh -} - -func (m *CoinType) GetSignedMessageHeader() string { - if m != nil && m.SignedMessageHeader != nil { - return *m.SignedMessageHeader - } - return "" -} - -func (m *CoinType) GetXpubMagic() uint32 { - if m != nil && m.XpubMagic != nil { - return *m.XpubMagic - } - return Default_CoinType_XpubMagic -} - -func (m *CoinType) GetXprvMagic() uint32 { - if m != nil && m.XprvMagic != nil { - return *m.XprvMagic - } - return Default_CoinType_XprvMagic -} - -func (m *CoinType) GetSegwit() bool { - if m != nil && m.Segwit != nil { - return *m.Segwit - } - return false -} - -func (m *CoinType) GetForkid() uint32 { - if m != nil && m.Forkid != nil { - return *m.Forkid - } - return 0 -} - -// * -// Type of redeem script used in input -// @used_in TxInputType -type MultisigRedeemScriptType struct { - Pubkeys []*HDNodePathType `protobuf:"bytes,1,rep,name=pubkeys" json:"pubkeys,omitempty"` - Signatures [][]byte `protobuf:"bytes,2,rep,name=signatures" json:"signatures,omitempty"` - M *uint32 `protobuf:"varint,3,opt,name=m" json:"m,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *MultisigRedeemScriptType) Reset() { *m = MultisigRedeemScriptType{} } -func (m *MultisigRedeemScriptType) String() string { return proto.CompactTextString(m) } -func (*MultisigRedeemScriptType) ProtoMessage() {} -func (*MultisigRedeemScriptType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -func (m *MultisigRedeemScriptType) GetPubkeys() []*HDNodePathType { - if m != nil { - return m.Pubkeys - } - return nil -} - -func (m *MultisigRedeemScriptType) GetSignatures() [][]byte { - if m != nil { - return m.Signatures - } - return nil -} - -func (m *MultisigRedeemScriptType) GetM() uint32 { - if m != nil && m.M != nil { - return *m.M - } - return 0 -} - -// * -// Structure representing transaction input -// @used_in SimpleSignTx -// @used_in TransactionType -type TxInputType struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - PrevHash []byte `protobuf:"bytes,2,req,name=prev_hash,json=prevHash" json:"prev_hash,omitempty"` - PrevIndex *uint32 `protobuf:"varint,3,req,name=prev_index,json=prevIndex" json:"prev_index,omitempty"` - ScriptSig []byte `protobuf:"bytes,4,opt,name=script_sig,json=scriptSig" json:"script_sig,omitempty"` - Sequence *uint32 `protobuf:"varint,5,opt,name=sequence,def=4294967295" json:"sequence,omitempty"` - ScriptType *InputScriptType `protobuf:"varint,6,opt,name=script_type,json=scriptType,enum=InputScriptType,def=0" json:"script_type,omitempty"` - Multisig *MultisigRedeemScriptType `protobuf:"bytes,7,opt,name=multisig" json:"multisig,omitempty"` - Amount *uint64 `protobuf:"varint,8,opt,name=amount" json:"amount,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxInputType) Reset() { *m = TxInputType{} } -func (m *TxInputType) String() string { return proto.CompactTextString(m) } -func (*TxInputType) ProtoMessage() {} -func (*TxInputType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } - -const Default_TxInputType_Sequence uint32 = 4294967295 -const Default_TxInputType_ScriptType InputScriptType = InputScriptType_SPENDADDRESS - -func (m *TxInputType) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *TxInputType) GetPrevHash() []byte { - if m != nil { - return m.PrevHash - } - return nil -} - -func (m *TxInputType) GetPrevIndex() uint32 { - if m != nil && m.PrevIndex != nil { - return *m.PrevIndex - } - return 0 -} - -func (m *TxInputType) GetScriptSig() []byte { - if m != nil { - return m.ScriptSig - } - return nil -} - -func (m *TxInputType) GetSequence() uint32 { - if m != nil && m.Sequence != nil { - return *m.Sequence - } - return Default_TxInputType_Sequence -} - -func (m *TxInputType) GetScriptType() InputScriptType { - if m != nil && m.ScriptType != nil { - return *m.ScriptType - } - return Default_TxInputType_ScriptType -} - -func (m *TxInputType) GetMultisig() *MultisigRedeemScriptType { - if m != nil { - return m.Multisig - } - return nil -} - -func (m *TxInputType) GetAmount() uint64 { - if m != nil && m.Amount != nil { - return *m.Amount - } - return 0 -} - -// * -// Structure representing transaction output -// @used_in SimpleSignTx -// @used_in TransactionType -type TxOutputType struct { - Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - AddressN []uint32 `protobuf:"varint,2,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Amount *uint64 `protobuf:"varint,3,req,name=amount" json:"amount,omitempty"` - ScriptType *OutputScriptType `protobuf:"varint,4,req,name=script_type,json=scriptType,enum=OutputScriptType" json:"script_type,omitempty"` - Multisig *MultisigRedeemScriptType `protobuf:"bytes,5,opt,name=multisig" json:"multisig,omitempty"` - OpReturnData []byte `protobuf:"bytes,6,opt,name=op_return_data,json=opReturnData" json:"op_return_data,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxOutputType) Reset() { *m = TxOutputType{} } -func (m *TxOutputType) String() string { return proto.CompactTextString(m) } -func (*TxOutputType) ProtoMessage() {} -func (*TxOutputType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } - -func (m *TxOutputType) GetAddress() string { - if m != nil && m.Address != nil { - return *m.Address - } - return "" -} - -func (m *TxOutputType) GetAddressN() []uint32 { - if m != nil { - return m.AddressN - } - return nil -} - -func (m *TxOutputType) GetAmount() uint64 { - if m != nil && m.Amount != nil { - return *m.Amount - } - return 0 -} - -func (m *TxOutputType) GetScriptType() OutputScriptType { - if m != nil && m.ScriptType != nil { - return *m.ScriptType - } - return OutputScriptType_PAYTOADDRESS -} - -func (m *TxOutputType) GetMultisig() *MultisigRedeemScriptType { - if m != nil { - return m.Multisig - } - return nil -} - -func (m *TxOutputType) GetOpReturnData() []byte { - if m != nil { - return m.OpReturnData - } - return nil -} - -// * -// Structure representing compiled transaction output -// @used_in TransactionType -type TxOutputBinType struct { - Amount *uint64 `protobuf:"varint,1,req,name=amount" json:"amount,omitempty"` - ScriptPubkey []byte `protobuf:"bytes,2,req,name=script_pubkey,json=scriptPubkey" json:"script_pubkey,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxOutputBinType) Reset() { *m = TxOutputBinType{} } -func (m *TxOutputBinType) String() string { return proto.CompactTextString(m) } -func (*TxOutputBinType) ProtoMessage() {} -func (*TxOutputBinType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } - -func (m *TxOutputBinType) GetAmount() uint64 { - if m != nil && m.Amount != nil { - return *m.Amount - } - return 0 -} - -func (m *TxOutputBinType) GetScriptPubkey() []byte { - if m != nil { - return m.ScriptPubkey - } - return nil -} - -// * -// Structure representing transaction -// @used_in SimpleSignTx -type TransactionType struct { - Version *uint32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` - Inputs []*TxInputType `protobuf:"bytes,2,rep,name=inputs" json:"inputs,omitempty"` - BinOutputs []*TxOutputBinType `protobuf:"bytes,3,rep,name=bin_outputs,json=binOutputs" json:"bin_outputs,omitempty"` - Outputs []*TxOutputType `protobuf:"bytes,5,rep,name=outputs" json:"outputs,omitempty"` - LockTime *uint32 `protobuf:"varint,4,opt,name=lock_time,json=lockTime" json:"lock_time,omitempty"` - InputsCnt *uint32 `protobuf:"varint,6,opt,name=inputs_cnt,json=inputsCnt" json:"inputs_cnt,omitempty"` - OutputsCnt *uint32 `protobuf:"varint,7,opt,name=outputs_cnt,json=outputsCnt" json:"outputs_cnt,omitempty"` - ExtraData []byte `protobuf:"bytes,8,opt,name=extra_data,json=extraData" json:"extra_data,omitempty"` - ExtraDataLen *uint32 `protobuf:"varint,9,opt,name=extra_data_len,json=extraDataLen" json:"extra_data_len,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TransactionType) Reset() { *m = TransactionType{} } -func (m *TransactionType) String() string { return proto.CompactTextString(m) } -func (*TransactionType) ProtoMessage() {} -func (*TransactionType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } - -func (m *TransactionType) GetVersion() uint32 { - if m != nil && m.Version != nil { - return *m.Version - } - return 0 -} - -func (m *TransactionType) GetInputs() []*TxInputType { - if m != nil { - return m.Inputs - } - return nil -} - -func (m *TransactionType) GetBinOutputs() []*TxOutputBinType { - if m != nil { - return m.BinOutputs - } - return nil -} - -func (m *TransactionType) GetOutputs() []*TxOutputType { - if m != nil { - return m.Outputs - } - return nil -} - -func (m *TransactionType) GetLockTime() uint32 { - if m != nil && m.LockTime != nil { - return *m.LockTime - } - return 0 -} - -func (m *TransactionType) GetInputsCnt() uint32 { - if m != nil && m.InputsCnt != nil { - return *m.InputsCnt - } - return 0 -} - -func (m *TransactionType) GetOutputsCnt() uint32 { - if m != nil && m.OutputsCnt != nil { - return *m.OutputsCnt - } - return 0 -} - -func (m *TransactionType) GetExtraData() []byte { - if m != nil { - return m.ExtraData - } - return nil -} - -func (m *TransactionType) GetExtraDataLen() uint32 { - if m != nil && m.ExtraDataLen != nil { - return *m.ExtraDataLen - } - return 0 -} - -// * -// Structure representing request details -// @used_in TxRequest -type TxRequestDetailsType struct { - RequestIndex *uint32 `protobuf:"varint,1,opt,name=request_index,json=requestIndex" json:"request_index,omitempty"` - TxHash []byte `protobuf:"bytes,2,opt,name=tx_hash,json=txHash" json:"tx_hash,omitempty"` - ExtraDataLen *uint32 `protobuf:"varint,3,opt,name=extra_data_len,json=extraDataLen" json:"extra_data_len,omitempty"` - ExtraDataOffset *uint32 `protobuf:"varint,4,opt,name=extra_data_offset,json=extraDataOffset" json:"extra_data_offset,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxRequestDetailsType) Reset() { *m = TxRequestDetailsType{} } -func (m *TxRequestDetailsType) String() string { return proto.CompactTextString(m) } -func (*TxRequestDetailsType) ProtoMessage() {} -func (*TxRequestDetailsType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } - -func (m *TxRequestDetailsType) GetRequestIndex() uint32 { - if m != nil && m.RequestIndex != nil { - return *m.RequestIndex - } - return 0 -} - -func (m *TxRequestDetailsType) GetTxHash() []byte { - if m != nil { - return m.TxHash - } - return nil -} - -func (m *TxRequestDetailsType) GetExtraDataLen() uint32 { - if m != nil && m.ExtraDataLen != nil { - return *m.ExtraDataLen - } - return 0 -} - -func (m *TxRequestDetailsType) GetExtraDataOffset() uint32 { - if m != nil && m.ExtraDataOffset != nil { - return *m.ExtraDataOffset - } - return 0 -} - -// * -// Structure representing serialized data -// @used_in TxRequest -type TxRequestSerializedType struct { - SignatureIndex *uint32 `protobuf:"varint,1,opt,name=signature_index,json=signatureIndex" json:"signature_index,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - SerializedTx []byte `protobuf:"bytes,3,opt,name=serialized_tx,json=serializedTx" json:"serialized_tx,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TxRequestSerializedType) Reset() { *m = TxRequestSerializedType{} } -func (m *TxRequestSerializedType) String() string { return proto.CompactTextString(m) } -func (*TxRequestSerializedType) ProtoMessage() {} -func (*TxRequestSerializedType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } - -func (m *TxRequestSerializedType) GetSignatureIndex() uint32 { - if m != nil && m.SignatureIndex != nil { - return *m.SignatureIndex - } - return 0 -} - -func (m *TxRequestSerializedType) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -func (m *TxRequestSerializedType) GetSerializedTx() []byte { - if m != nil { - return m.SerializedTx - } - return nil -} - -// * -// Structure representing identity data -// @used_in IdentityType -type IdentityType struct { - Proto *string `protobuf:"bytes,1,opt,name=proto" json:"proto,omitempty"` - User *string `protobuf:"bytes,2,opt,name=user" json:"user,omitempty"` - Host *string `protobuf:"bytes,3,opt,name=host" json:"host,omitempty"` - Port *string `protobuf:"bytes,4,opt,name=port" json:"port,omitempty"` - Path *string `protobuf:"bytes,5,opt,name=path" json:"path,omitempty"` - Index *uint32 `protobuf:"varint,6,opt,name=index,def=0" json:"index,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *IdentityType) Reset() { *m = IdentityType{} } -func (m *IdentityType) String() string { return proto.CompactTextString(m) } -func (*IdentityType) ProtoMessage() {} -func (*IdentityType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } - -const Default_IdentityType_Index uint32 = 0 - -func (m *IdentityType) GetProto() string { - if m != nil && m.Proto != nil { - return *m.Proto - } - return "" -} - -func (m *IdentityType) GetUser() string { - if m != nil && m.User != nil { - return *m.User - } - return "" -} - -func (m *IdentityType) GetHost() string { - if m != nil && m.Host != nil { - return *m.Host - } - return "" -} - -func (m *IdentityType) GetPort() string { - if m != nil && m.Port != nil { - return *m.Port - } - return "" -} - -func (m *IdentityType) GetPath() string { - if m != nil && m.Path != nil { - return *m.Path - } - return "" -} - -func (m *IdentityType) GetIndex() uint32 { - if m != nil && m.Index != nil { - return *m.Index - } - return Default_IdentityType_Index -} - -var E_WireIn = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50002, - Name: "wire_in", - Tag: "varint,50002,opt,name=wire_in,json=wireIn", - Filename: "types.proto", -} - -var E_WireOut = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50003, - Name: "wire_out", - Tag: "varint,50003,opt,name=wire_out,json=wireOut", - Filename: "types.proto", -} - -var E_WireDebugIn = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50004, - Name: "wire_debug_in", - Tag: "varint,50004,opt,name=wire_debug_in,json=wireDebugIn", - Filename: "types.proto", -} - -var E_WireDebugOut = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50005, - Name: "wire_debug_out", - Tag: "varint,50005,opt,name=wire_debug_out,json=wireDebugOut", - Filename: "types.proto", -} - -var E_WireTiny = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50006, - Name: "wire_tiny", - Tag: "varint,50006,opt,name=wire_tiny,json=wireTiny", - Filename: "types.proto", -} - -var E_WireBootloader = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50007, - Name: "wire_bootloader", - Tag: "varint,50007,opt,name=wire_bootloader,json=wireBootloader", - Filename: "types.proto", -} - -func init() { - proto.RegisterType((*HDNodeType)(nil), "HDNodeType") - proto.RegisterType((*HDNodePathType)(nil), "HDNodePathType") - proto.RegisterType((*CoinType)(nil), "CoinType") - proto.RegisterType((*MultisigRedeemScriptType)(nil), "MultisigRedeemScriptType") - proto.RegisterType((*TxInputType)(nil), "TxInputType") - proto.RegisterType((*TxOutputType)(nil), "TxOutputType") - proto.RegisterType((*TxOutputBinType)(nil), "TxOutputBinType") - proto.RegisterType((*TransactionType)(nil), "TransactionType") - proto.RegisterType((*TxRequestDetailsType)(nil), "TxRequestDetailsType") - proto.RegisterType((*TxRequestSerializedType)(nil), "TxRequestSerializedType") - proto.RegisterType((*IdentityType)(nil), "IdentityType") - proto.RegisterEnum("FailureType", FailureType_name, FailureType_value) - proto.RegisterEnum("OutputScriptType", OutputScriptType_name, OutputScriptType_value) - proto.RegisterEnum("InputScriptType", InputScriptType_name, InputScriptType_value) - proto.RegisterEnum("RequestType", RequestType_name, RequestType_value) - proto.RegisterEnum("ButtonRequestType", ButtonRequestType_name, ButtonRequestType_value) - proto.RegisterEnum("PinMatrixRequestType", PinMatrixRequestType_name, PinMatrixRequestType_value) - proto.RegisterEnum("RecoveryDeviceType", RecoveryDeviceType_name, RecoveryDeviceType_value) - proto.RegisterEnum("WordRequestType", WordRequestType_name, WordRequestType_value) - proto.RegisterExtension(E_WireIn) - proto.RegisterExtension(E_WireOut) - proto.RegisterExtension(E_WireDebugIn) - proto.RegisterExtension(E_WireDebugOut) - proto.RegisterExtension(E_WireTiny) - proto.RegisterExtension(E_WireBootloader) -} - -func init() { proto.RegisterFile("types.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 1899 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xdb, 0x72, 0x1a, 0xc9, - 0x19, 0xf6, 0x00, 0x92, 0xe0, 0x07, 0xc4, 0xa8, 0x7d, 0xd0, 0x78, 0x6d, 0xaf, 0x31, 0x76, 0x62, - 0x45, 0x55, 0x61, 0x77, 0xc9, 0x5a, 0x8e, 0x55, 0xa9, 0x24, 0x3a, 0xa0, 0x15, 0x65, 0x0b, 0x51, - 0xc3, 0x28, 0x56, 0x72, 0x33, 0x35, 0xcc, 0xb4, 0xa0, 0x4b, 0x43, 0x37, 0xe9, 0xe9, 0x91, 0xd1, - 0xde, 0xe4, 0x2a, 0xc9, 0x55, 0x5e, 0x23, 0x6f, 0x91, 0xaa, 0xbc, 0x41, 0xaa, 0x36, 0xa7, 0xcb, - 0xbc, 0x41, 0xae, 0xf2, 0x00, 0xa9, 0x3e, 0x0c, 0x02, 0xc9, 0xde, 0xd2, 0x1d, 0xfd, 0x7d, 0xff, - 0xf9, 0xd0, 0x3d, 0x40, 0x59, 0x5c, 0x4e, 0x70, 0xd2, 0x9c, 0x70, 0x26, 0xd8, 0x67, 0xf5, 0x21, - 0x63, 0xc3, 0x18, 0x7f, 0xa1, 0x4e, 0x83, 0xf4, 0xec, 0x8b, 0x08, 0x27, 0x21, 0x27, 0x13, 0xc1, - 0xb8, 0x96, 0x68, 0xfc, 0xd5, 0x02, 0x38, 0xdc, 0xef, 0xb2, 0x08, 0x7b, 0x97, 0x13, 0x8c, 0xee, - 0xc1, 0x52, 0x84, 0x27, 0x62, 0xe4, 0x58, 0xf5, 0xdc, 0x46, 0xd5, 0xd5, 0x07, 0x54, 0x87, 0xf2, - 0x19, 0xa1, 0x43, 0xcc, 0x27, 0x9c, 0x50, 0xe1, 0xe4, 0x14, 0x37, 0x0f, 0xa1, 0x47, 0x50, 0x0a, - 0x47, 0x24, 0x8e, 0x7c, 0x9a, 0x8e, 0x9d, 0xbc, 0xe2, 0x8b, 0x0a, 0xe8, 0xa6, 0x63, 0xf4, 0x04, - 0x20, 0x1c, 0x05, 0x84, 0xfa, 0x21, 0x8b, 0xb0, 0x53, 0xa8, 0xe7, 0x36, 0x2a, 0x6e, 0x49, 0x21, - 0x7b, 0x2c, 0xc2, 0xe8, 0x29, 0x94, 0x27, 0x9c, 0x5c, 0x04, 0x02, 0xfb, 0xe7, 0xf8, 0xd2, 0x59, - 0xaa, 0x5b, 0x1b, 0x15, 0x17, 0x0c, 0xf4, 0x16, 0x5f, 0x4a, 0xfd, 0x49, 0x3a, 0x88, 0x49, 0xa8, - 0xf8, 0x65, 0xc5, 0x97, 0x34, 0xf2, 0x16, 0x5f, 0x36, 0xba, 0xb0, 0xaa, 0x33, 0xe8, 0x05, 0x62, - 0xa4, 0xb2, 0x78, 0x0a, 0x05, 0x2a, 0x5d, 0xc9, 0x24, 0xca, 0xad, 0x72, 0xf3, 0x2a, 0x41, 0x57, - 0x11, 0x32, 0xdc, 0x20, 0x8a, 0x38, 0x4e, 0x12, 0x9f, 0x3a, 0xb9, 0x7a, 0x5e, 0x86, 0x6b, 0x80, - 0x6e, 0xe3, 0x7f, 0x39, 0x28, 0xee, 0x31, 0x42, 0x95, 0x29, 0x99, 0x18, 0x23, 0xd4, 0xa7, 0xc1, - 0x58, 0xda, 0xb3, 0x36, 0x4a, 0x6e, 0x51, 0x02, 0xdd, 0x60, 0x8c, 0xd1, 0x73, 0xa8, 0x2a, 0x32, - 0x19, 0x31, 0x2e, 0xc2, 0x54, 0x56, 0x46, 0x0a, 0x54, 0x24, 0xd8, 0x37, 0x18, 0x7a, 0x01, 0x95, - 0xcc, 0x97, 0x6c, 0x8d, 0x93, 0xaf, 0x5b, 0x1b, 0xd5, 0x6d, 0xeb, 0x4b, 0xb7, 0x6c, 0xe0, 0xcc, - 0xcf, 0x38, 0x98, 0x9e, 0x61, 0xec, 0x9f, 0x0f, 0x9c, 0x42, 0xdd, 0xda, 0x28, 0xb8, 0x45, 0x0d, - 0xbc, 0x1d, 0xa0, 0x1f, 0xc3, 0xda, 0xbc, 0x09, 0x7f, 0xd2, 0x4a, 0x46, 0xaa, 0x4e, 0xd5, 0x6d, - 0xeb, 0x95, 0x5b, 0x9b, 0xb3, 0xd3, 0x6b, 0x25, 0x23, 0xd4, 0x82, 0xfb, 0x09, 0x19, 0x52, 0x1c, - 0xf9, 0x63, 0x9c, 0x24, 0xc1, 0x10, 0xfb, 0x23, 0x1c, 0x44, 0x98, 0x3b, 0x45, 0x15, 0xde, 0x5d, - 0x4d, 0x1e, 0x69, 0xee, 0x50, 0x51, 0xe8, 0x25, 0xc0, 0x74, 0x92, 0x0e, 0xfc, 0x71, 0x30, 0x24, - 0xa1, 0x53, 0x52, 0xb6, 0x8b, 0xaf, 0xb7, 0xbe, 0xdc, 0x7a, 0xfd, 0x93, 0x57, 0x3f, 0x75, 0x4b, - 0x92, 0x3b, 0x92, 0x94, 0x16, 0xe4, 0x17, 0x46, 0x10, 0xae, 0x04, 0xb7, 0x5a, 0xaf, 0xb7, 0xa4, - 0x20, 0xbf, 0xd0, 0x82, 0x0f, 0x60, 0x39, 0xc1, 0xc3, 0x0f, 0x44, 0x38, 0xe5, 0xba, 0xb5, 0x51, - 0x74, 0xcd, 0x49, 0xe2, 0x67, 0x8c, 0x9f, 0x93, 0xc8, 0xa9, 0x48, 0x65, 0xd7, 0x9c, 0x1a, 0x09, - 0x38, 0x47, 0x69, 0x2c, 0x48, 0x42, 0x86, 0x2e, 0x8e, 0x30, 0x1e, 0xf7, 0xd5, 0xa4, 0xaa, 0xea, - 0xfc, 0x08, 0x56, 0x26, 0xe9, 0xe0, 0x1c, 0x5f, 0x26, 0x8e, 0x55, 0xcf, 0x6f, 0x94, 0x5b, 0xb5, - 0xe6, 0x62, 0xcb, 0xdd, 0x8c, 0x47, 0x9f, 0x03, 0xc8, 0xfc, 0x02, 0x91, 0x72, 0x9c, 0xa8, 0xde, - 0x56, 0xdc, 0x39, 0x04, 0x55, 0xc0, 0x1a, 0xeb, 0x1e, 0xb8, 0xd6, 0xb8, 0xf1, 0x97, 0x1c, 0x94, - 0xbd, 0x69, 0x87, 0x4e, 0x52, 0x91, 0xb5, 0xe1, 0x6a, 0x30, 0xac, 0xc5, 0xc1, 0x90, 0xe4, 0x84, - 0xe3, 0x0b, 0x7f, 0x14, 0x24, 0x23, 0xb5, 0x04, 0x15, 0xb7, 0x28, 0x81, 0xc3, 0x20, 0x19, 0xa9, - 0x21, 0x95, 0x24, 0xa1, 0x11, 0x9e, 0x9a, 0x15, 0x50, 0xe2, 0x1d, 0x09, 0x48, 0x5a, 0x6f, 0x9e, - 0x9f, 0x90, 0xa1, 0x6a, 0x70, 0xc5, 0x2d, 0x69, 0xa4, 0x4f, 0x86, 0xe8, 0x87, 0x50, 0x4c, 0xf0, - 0x6f, 0x53, 0x4c, 0x43, 0x6c, 0x1a, 0x0b, 0x5f, 0xb7, 0xde, 0x7c, 0xfd, 0x66, 0xeb, 0x75, 0xeb, - 0xcd, 0x2b, 0x77, 0xc6, 0xa1, 0x5f, 0x40, 0xd9, 0x98, 0x51, 0xb3, 0x24, 0x77, 0x61, 0xb5, 0x65, - 0x37, 0x55, 0x02, 0x57, 0xf5, 0xda, 0xae, 0xf4, 0x7b, 0xed, 0xee, 0xfe, 0xce, 0xfe, 0xbe, 0xdb, - 0xee, 0xf7, 0x5d, 0xe3, 0x59, 0x25, 0xf8, 0x0a, 0x8a, 0x63, 0x53, 0x65, 0x67, 0xa5, 0x6e, 0x6d, - 0x94, 0x5b, 0x0f, 0x9b, 0x9f, 0x2a, 0xbb, 0x3b, 0x13, 0x95, 0x4d, 0x0b, 0xc6, 0x2c, 0xa5, 0x42, - 0xcd, 0x50, 0xc1, 0x35, 0xa7, 0xc6, 0x7f, 0x2d, 0xa8, 0x78, 0xd3, 0xe3, 0x54, 0x64, 0x05, 0x74, - 0x60, 0xc5, 0xd4, 0xcb, 0x6c, 0x4b, 0x76, 0xfc, 0xde, 0x9d, 0x9b, 0xb3, 0x2f, 0x2b, 0x37, 0xb3, - 0x8f, 0x5a, 0x8b, 0xf9, 0xca, 0xbb, 0x63, 0xb5, 0xb5, 0xd6, 0xd4, 0x0e, 0xe7, 0x22, 0xfd, 0x54, - 0x8a, 0x4b, 0xb7, 0x4f, 0xf1, 0x05, 0xac, 0xb2, 0x89, 0xcf, 0xb1, 0x48, 0x39, 0xf5, 0xa3, 0x40, - 0x04, 0xe6, 0xa6, 0xa9, 0xb0, 0x89, 0xab, 0xc0, 0xfd, 0x40, 0x04, 0x8d, 0x2e, 0xd4, 0xb2, 0x7c, - 0x77, 0xcd, 0x15, 0x71, 0x15, 0xbb, 0xb5, 0x10, 0xfb, 0x73, 0xa8, 0x9a, 0xd8, 0xf5, 0x6c, 0x9a, - 0x91, 0xa9, 0x68, 0xb0, 0xa7, 0xb0, 0xc6, 0xdf, 0x72, 0x50, 0xf3, 0x78, 0x40, 0x93, 0x20, 0x14, - 0x84, 0xd1, 0xac, 0x86, 0x17, 0x98, 0x27, 0x84, 0x51, 0x55, 0xc3, 0xaa, 0x9b, 0x1d, 0xd1, 0x0b, - 0x58, 0x26, 0xb2, 0xd5, 0x7a, 0xb0, 0xcb, 0xad, 0x4a, 0x73, 0x6e, 0x78, 0x5d, 0xc3, 0xa1, 0xaf, - 0xa0, 0x3c, 0x20, 0xd4, 0x67, 0x2a, 0xca, 0xc4, 0xc9, 0x2b, 0x51, 0xbb, 0x79, 0x2d, 0x6e, 0x17, - 0x06, 0x84, 0x6a, 0x24, 0x41, 0x2f, 0x61, 0x25, 0x13, 0x5f, 0x52, 0xe2, 0xd5, 0xe6, 0x7c, 0x5b, - 0xdd, 0x8c, 0x95, 0x5d, 0x8c, 0x59, 0x78, 0xee, 0x0b, 0x32, 0xc6, 0x6a, 0x8c, 0xab, 0x6e, 0x51, - 0x02, 0x1e, 0x19, 0x63, 0x39, 0xe4, 0x3a, 0x04, 0x3f, 0xa4, 0x42, 0x95, 0xaf, 0xea, 0x96, 0x34, - 0xb2, 0x47, 0x85, 0xbc, 0xe8, 0x8d, 0x19, 0xc5, 0xaf, 0x28, 0x1e, 0x0c, 0x24, 0x05, 0x9e, 0x00, - 0xe0, 0xa9, 0xe0, 0x81, 0x2e, 0x7f, 0x51, 0x2f, 0x89, 0x42, 0x64, 0xed, 0x65, 0x87, 0xae, 0x68, - 0x3f, 0xc6, 0x54, 0xdf, 0x53, 0x6e, 0x65, 0x26, 0xf2, 0x0e, 0xd3, 0xc6, 0x9f, 0x2d, 0xb8, 0xe7, - 0x4d, 0x5d, 0xb9, 0x31, 0x89, 0xd8, 0xc7, 0x22, 0x20, 0xb1, 0xbe, 0x62, 0x9f, 0x43, 0x95, 0x6b, - 0xd4, 0x2c, 0xa9, 0x2e, 0x6e, 0xc5, 0x80, 0x7a, 0x4f, 0xd7, 0x61, 0x45, 0x4c, 0xb3, 0x0d, 0x97, - 0xfe, 0x97, 0xc5, 0x54, 0xed, 0xf7, 0x4d, 0xe7, 0xf9, 0x9b, 0xce, 0xd1, 0x26, 0xac, 0xcd, 0x49, - 0xb1, 0xb3, 0xb3, 0x04, 0x0b, 0x53, 0xa6, 0xda, 0x4c, 0xf0, 0x58, 0xc1, 0x8d, 0xdf, 0x5b, 0xb0, - 0x3e, 0x0b, 0xb4, 0x8f, 0x39, 0x09, 0x62, 0xf2, 0x2d, 0x8e, 0x54, 0xac, 0x2f, 0xa1, 0x36, 0xbb, - 0xb3, 0x16, 0xa2, 0x5d, 0x9d, 0xc1, 0x3a, 0xde, 0xc7, 0x50, 0x9a, 0x21, 0x26, 0xe2, 0x2b, 0x40, - 0x8d, 0xe0, 0xcc, 0xb0, 0x2f, 0xa6, 0x2a, 0x66, 0x39, 0x82, 0x57, 0xde, 0xa6, 0x8d, 0x3f, 0x59, - 0x50, 0xe9, 0x44, 0x98, 0x0a, 0x22, 0x2e, 0xb3, 0x8f, 0x00, 0xf5, 0x71, 0x60, 0x36, 0x58, 0x1f, - 0x10, 0x82, 0x42, 0x9a, 0x60, 0x6e, 0xde, 0x38, 0xf5, 0x5b, 0x62, 0x23, 0x96, 0x08, 0x65, 0xb6, - 0xe4, 0xaa, 0xdf, 0x12, 0x9b, 0x30, 0xae, 0xb3, 0x2e, 0xb9, 0xea, 0xb7, 0xc2, 0x02, 0xa1, 0xdf, - 0x2c, 0x89, 0x05, 0x62, 0x84, 0xd6, 0x61, 0x49, 0x27, 0xb6, 0x9c, 0x3d, 0x88, 0xfa, 0xbc, 0xf9, - 0x5d, 0x0e, 0xca, 0x07, 0x01, 0x89, 0x53, 0xae, 0xbf, 0x49, 0x9e, 0xc0, 0x43, 0x73, 0xf4, 0x4f, - 0x28, 0x9e, 0x4e, 0x70, 0x28, 0x66, 0xaf, 0x97, 0x6d, 0xa1, 0xcf, 0xe0, 0x41, 0x46, 0xef, 0xa6, - 0x42, 0x30, 0xda, 0x36, 0x22, 0x76, 0x0e, 0xdd, 0x87, 0xb5, 0x8c, 0x93, 0x85, 0x6f, 0x73, 0xce, - 0xb8, 0x9d, 0x47, 0x8f, 0x60, 0x3d, 0x83, 0x77, 0xd4, 0xda, 0xed, 0x05, 0x34, 0xc4, 0x71, 0x8c, - 0x23, 0xbb, 0x80, 0xd6, 0xe1, 0x6e, 0x46, 0xf6, 0xc8, 0x95, 0xb1, 0x25, 0xe4, 0xc0, 0xbd, 0x39, - 0xe2, 0x4a, 0x65, 0x19, 0x3d, 0x00, 0x34, 0xc7, 0x74, 0xe8, 0x45, 0x10, 0x93, 0xc8, 0x5e, 0x41, - 0x8f, 0xc1, 0xc9, 0x70, 0x03, 0xf6, 0xb3, 0xd6, 0xd8, 0xc5, 0x05, 0x7b, 0x9c, 0x85, 0x38, 0x49, - 0x74, 0x7c, 0xa5, 0xf9, 0x94, 0xba, 0x4c, 0xb4, 0x29, 0x4b, 0x87, 0xa3, 0x83, 0x94, 0x46, 0x89, - 0x0d, 0xd7, 0xb8, 0x0e, 0x25, 0xc2, 0x74, 0xd2, 0x2e, 0xa3, 0x87, 0x70, 0x3f, 0xe3, 0x0e, 0x08, - 0x1f, 0x7f, 0x08, 0x38, 0xd6, 0x26, 0xc3, 0xcd, 0x3f, 0x5a, 0x60, 0x5f, 0xbf, 0x35, 0x91, 0x0d, - 0x95, 0xde, 0xce, 0xaf, 0xbd, 0x63, 0xf3, 0x50, 0xd8, 0x77, 0xd0, 0x5d, 0xa8, 0x29, 0xa4, 0xbf, - 0xe7, 0x76, 0x7a, 0xde, 0xe1, 0x4e, 0xff, 0xd0, 0xb6, 0xd0, 0x1a, 0x54, 0x15, 0x78, 0x74, 0xf2, - 0xce, 0xeb, 0xf4, 0x3b, 0xdf, 0xd8, 0xb9, 0x19, 0x74, 0xdc, 0x73, 0xdb, 0xde, 0x89, 0xdb, 0xb5, - 0xf3, 0x33, 0x63, 0xef, 0x3b, 0x5e, 0x57, 0x1a, 0x2b, 0xa0, 0x7b, 0x60, 0x2b, 0xa4, 0xd7, 0xea, - 0x1f, 0x66, 0xe8, 0xd2, 0x66, 0x0c, 0xb5, 0x6b, 0xcf, 0x95, 0x54, 0x9d, 0x7f, 0xb0, 0xec, 0x3b, - 0xd2, 0xbe, 0x42, 0x66, 0x2e, 0x2d, 0x54, 0x81, 0x62, 0xfb, 0xd4, 0x6b, 0xbb, 0xdd, 0x9d, 0x77, - 0x76, 0x6e, 0xa6, 0x92, 0xd9, 0xcd, 0x4b, 0x6f, 0x0a, 0x99, 0xf7, 0x56, 0xd8, 0x3c, 0x81, 0xb2, - 0xd9, 0x30, 0xe5, 0xa9, 0x0c, 0x2b, 0xde, 0x69, 0xa7, 0xdb, 0x3b, 0xf1, 0xec, 0x3b, 0xd2, 0xa2, - 0x77, 0x7a, 0x7c, 0xe2, 0xc9, 0x93, 0x85, 0x00, 0x96, 0xbd, 0xd3, 0xa3, 0xb6, 0xb7, 0x63, 0xe7, - 0xd0, 0x2a, 0x80, 0x77, 0x7a, 0xd0, 0xe9, 0x76, 0xfa, 0x87, 0xed, 0x7d, 0x3b, 0x8f, 0x6a, 0x50, - 0xf6, 0x4e, 0xdb, 0xa7, 0x9e, 0xbb, 0xb3, 0xbf, 0xe3, 0xed, 0xd8, 0x85, 0xcd, 0xff, 0xe4, 0x60, - 0x4d, 0x4f, 0xdb, 0xbc, 0xf5, 0x75, 0xb8, 0xbb, 0x00, 0xfa, 0xc7, 0x62, 0x84, 0xb9, 0x6d, 0xa1, - 0x06, 0x7c, 0xbe, 0x48, 0x1c, 0x60, 0x7c, 0x7c, 0x81, 0xb9, 0x37, 0xe2, 0x38, 0x19, 0xb1, 0x58, - 0xce, 0xea, 0x53, 0x78, 0xb4, 0x28, 0xb3, 0xc7, 0xe8, 0x19, 0xe1, 0x63, 0xdd, 0x35, 0x3b, 0x2f, - 0xf7, 0x60, 0x51, 0xc0, 0xc5, 0x09, 0x16, 0xfb, 0xf8, 0x82, 0x84, 0xd8, 0x2e, 0xdc, 0xa4, 0x8d, - 0xfe, 0x7b, 0xc6, 0xe5, 0xf4, 0x3e, 0x06, 0x67, 0x91, 0x7e, 0x4f, 0x26, 0xd8, 0x28, 0x2f, 0xdf, - 0x54, 0xee, 0x71, 0x26, 0x70, 0x28, 0xf6, 0x82, 0x38, 0xb6, 0x57, 0xe4, 0xa8, 0x2e, 0xd2, 0x72, - 0x8e, 0xbd, 0xa9, 0x5d, 0xbc, 0x19, 0x75, 0x36, 0x78, 0x7b, 0x23, 0x1c, 0x9e, 0xdb, 0x25, 0x39, - 0x93, 0x8b, 0x02, 0x3b, 0xfa, 0xcd, 0xb7, 0x41, 0xae, 0xe1, 0x35, 0xa7, 0xd9, 0x37, 0xbd, 0x5d, - 0xde, 0xfc, 0x1d, 0xdc, 0xeb, 0x11, 0x7a, 0x14, 0x08, 0x4e, 0xa6, 0xf3, 0x35, 0xae, 0xc3, 0xe3, - 0x8f, 0xe1, 0xfe, 0x5e, 0xca, 0x39, 0xa6, 0xc2, 0xb6, 0xd0, 0x33, 0x78, 0xf2, 0x51, 0x89, 0x2e, - 0xfe, 0x70, 0x40, 0x78, 0x22, 0xec, 0x9c, 0xec, 0xc7, 0xa7, 0x44, 0xfa, 0x38, 0x64, 0x34, 0xb2, - 0xf3, 0x9b, 0xbf, 0x01, 0xe4, 0xe2, 0x90, 0x5d, 0x60, 0x7e, 0xa9, 0xcb, 0xa4, 0xdc, 0xff, 0x00, - 0x9e, 0xdd, 0x44, 0xfd, 0x7e, 0xc8, 0x83, 0xf1, 0x20, 0xc6, 0x91, 0x2c, 0x76, 0x62, 0xdf, 0x91, - 0xf5, 0xfc, 0x88, 0x98, 0x76, 0x68, 0x5b, 0x9b, 0x67, 0x50, 0x93, 0x92, 0xf3, 0x79, 0x3d, 0x84, - 0xfb, 0xd7, 0x20, 0xbf, 0x17, 0x07, 0x84, 0xda, 0x77, 0x64, 0x9d, 0xae, 0x53, 0xda, 0xd2, 0x1b, - 0xdb, 0xfa, 0x34, 0xb9, 0x65, 0xe7, 0xb6, 0x7f, 0x06, 0x2b, 0x1f, 0x88, 0x7a, 0x41, 0xd0, 0xb3, - 0xa6, 0xfe, 0x2f, 0xd8, 0xcc, 0xfe, 0x0b, 0x36, 0xdb, 0x34, 0x1d, 0xff, 0x2a, 0x88, 0x53, 0x7c, - 0x3c, 0x91, 0x77, 0x60, 0xe2, 0x7c, 0xf7, 0x87, 0xbc, 0xfe, 0x52, 0x97, 0x3a, 0x1d, 0xba, 0xfd, - 0x73, 0x28, 0x2a, 0x6d, 0x96, 0x8a, 0xdb, 0xa8, 0xff, 0xdd, 0xa8, 0x2b, 0x97, 0xc7, 0xa9, 0xd8, - 0xfe, 0x06, 0xaa, 0x4a, 0x3f, 0xc2, 0x83, 0x74, 0x78, 0xcb, 0x18, 0xfe, 0x61, 0x8c, 0x94, 0xa5, - 0xe6, 0xbe, 0x54, 0xec, 0xd0, 0xed, 0x0e, 0xac, 0xce, 0x19, 0xba, 0x65, 0x38, 0xff, 0x34, 0x96, - 0x2a, 0x33, 0x4b, 0x32, 0xa6, 0x5f, 0x42, 0x49, 0x99, 0x12, 0x84, 0x5e, 0xde, 0xc6, 0xca, 0xbf, - 0x8c, 0x15, 0x55, 0x09, 0x8f, 0xd0, 0xcb, 0xed, 0x77, 0x50, 0x53, 0x16, 0x06, 0x8c, 0x89, 0x98, - 0xa9, 0x3f, 0x4f, 0xb7, 0xb0, 0xf3, 0x6f, 0x63, 0x47, 0x25, 0xb2, 0x3b, 0x53, 0xdd, 0xfd, 0x0a, - 0x9e, 0x87, 0x6c, 0xdc, 0x4c, 0x02, 0xc1, 0x92, 0x11, 0x89, 0x83, 0x41, 0xd2, 0x14, 0x1c, 0x7f, - 0xcb, 0x78, 0x33, 0x26, 0x83, 0x99, 0xbd, 0x5d, 0xf0, 0x14, 0x28, 0xdb, 0xfb, 0xff, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x70, 0x88, 0xcd, 0x71, 0xe2, 0x0f, 0x00, 0x00, -} diff --git a/accounts/usbwallet/trezor/types.proto b/accounts/usbwallet/trezor/types.proto deleted file mode 100644 index acbe79e3ff..0000000000 --- a/accounts/usbwallet/trezor/types.proto +++ /dev/null @@ -1,278 +0,0 @@ -// This file originates from the SatoshiLabs Trezor `common` repository at: -// https://github.com/trezor/trezor-common/blob/master/protob/types.proto -// dated 28.07.2017, commit dd8ec3231fb5f7992360aff9bdfe30bb58130f4b. - -syntax = "proto2"; - -/** - * Types for TREZOR communication - * - * @author Marek Palatinus - * @version 1.2 - */ - -// Sugar for easier handling in Java -option java_package = "com.satoshilabs.trezor.lib.protobuf"; -option java_outer_classname = "TrezorType"; - -import "google/protobuf/descriptor.proto"; - -/** - * Options for specifying message direction and type of wire (normal/debug) - */ -extend google.protobuf.EnumValueOptions { - optional bool wire_in = 50002; // message can be transmitted via wire from PC to TREZOR - optional bool wire_out = 50003; // message can be transmitted via wire from TREZOR to PC - optional bool wire_debug_in = 50004; // message can be transmitted via debug wire from PC to TREZOR - optional bool wire_debug_out = 50005; // message can be transmitted via debug wire from TREZOR to PC - optional bool wire_tiny = 50006; // message is handled by TREZOR when the USB stack is in tiny mode - optional bool wire_bootloader = 50007; // message is only handled by TREZOR Bootloader -} - -/** - * Type of failures returned by Failure message - * @used_in Failure - */ -enum FailureType { - Failure_UnexpectedMessage = 1; - Failure_ButtonExpected = 2; - Failure_DataError = 3; - Failure_ActionCancelled = 4; - Failure_PinExpected = 5; - Failure_PinCancelled = 6; - Failure_PinInvalid = 7; - Failure_InvalidSignature = 8; - Failure_ProcessError = 9; - Failure_NotEnoughFunds = 10; - Failure_NotInitialized = 11; - Failure_FirmwareError = 99; -} - -/** - * Type of script which will be used for transaction output - * @used_in TxOutputType - */ -enum OutputScriptType { - PAYTOADDRESS = 0; // used for all addresses (bitcoin, p2sh, witness) - PAYTOSCRIPTHASH = 1; // p2sh address (deprecated; use PAYTOADDRESS) - PAYTOMULTISIG = 2; // only for change output - PAYTOOPRETURN = 3; // op_return - PAYTOWITNESS = 4; // only for change output - PAYTOP2SHWITNESS = 5; // only for change output -} - -/** - * Type of script which will be used for transaction output - * @used_in TxInputType - */ -enum InputScriptType { - SPENDADDRESS = 0; // standard p2pkh address - SPENDMULTISIG = 1; // p2sh multisig address - EXTERNAL = 2; // reserved for external inputs (coinjoin) - SPENDWITNESS = 3; // native segwit - SPENDP2SHWITNESS = 4; // segwit over p2sh (backward compatible) -} - -/** - * Type of information required by transaction signing process - * @used_in TxRequest - */ -enum RequestType { - TXINPUT = 0; - TXOUTPUT = 1; - TXMETA = 2; - TXFINISHED = 3; - TXEXTRADATA = 4; -} - -/** - * Type of button request - * @used_in ButtonRequest - */ -enum ButtonRequestType { - ButtonRequest_Other = 1; - ButtonRequest_FeeOverThreshold = 2; - ButtonRequest_ConfirmOutput = 3; - ButtonRequest_ResetDevice = 4; - ButtonRequest_ConfirmWord = 5; - ButtonRequest_WipeDevice = 6; - ButtonRequest_ProtectCall = 7; - ButtonRequest_SignTx = 8; - ButtonRequest_FirmwareCheck = 9; - ButtonRequest_Address = 10; - ButtonRequest_PublicKey = 11; -} - -/** - * Type of PIN request - * @used_in PinMatrixRequest - */ -enum PinMatrixRequestType { - PinMatrixRequestType_Current = 1; - PinMatrixRequestType_NewFirst = 2; - PinMatrixRequestType_NewSecond = 3; -} - -/** - * Type of recovery procedure. These should be used as bitmask, e.g., - * `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` - * listing every method supported by the host computer. - * - * Note that ScrambledWords must be supported by every implementation - * for backward compatibility; there is no way to not support it. - * - * @used_in RecoveryDevice - */ -enum RecoveryDeviceType { - // use powers of two when extending this field - RecoveryDeviceType_ScrambledWords = 0; // words in scrambled order - RecoveryDeviceType_Matrix = 1; // matrix recovery type -} - -/** - * Type of Recovery Word request - * @used_in WordRequest - */ -enum WordRequestType { - WordRequestType_Plain = 0; - WordRequestType_Matrix9 = 1; - WordRequestType_Matrix6 = 2; -} - -/** - * Structure representing BIP32 (hierarchical deterministic) node - * Used for imports of private key into the device and exporting public key out of device - * @used_in PublicKey - * @used_in LoadDevice - * @used_in DebugLinkState - * @used_in Storage - */ -message HDNodeType { - required uint32 depth = 1; - required uint32 fingerprint = 2; - required uint32 child_num = 3; - required bytes chain_code = 4; - optional bytes private_key = 5; - optional bytes public_key = 6; -} - -message HDNodePathType { - required HDNodeType node = 1; // BIP-32 node in deserialized form - repeated uint32 address_n = 2; // BIP-32 path to derive the key from node -} - -/** - * Structure representing Coin - * @used_in Features - */ -message CoinType { - optional string coin_name = 1; - optional string coin_shortcut = 2; - optional uint32 address_type = 3 [default=0]; - optional uint64 maxfee_kb = 4; - optional uint32 address_type_p2sh = 5 [default=5]; - optional string signed_message_header = 8; - optional uint32 xpub_magic = 9 [default=76067358]; // default=0x0488b21e - optional uint32 xprv_magic = 10 [default=76066276]; // default=0x0488ade4 - optional bool segwit = 11; - optional uint32 forkid = 12; -} - -/** - * Type of redeem script used in input - * @used_in TxInputType - */ -message MultisigRedeemScriptType { - repeated HDNodePathType pubkeys = 1; // pubkeys from multisig address (sorted lexicographically) - repeated bytes signatures = 2; // existing signatures for partially signed input - optional uint32 m = 3; // "m" from n, how many valid signatures is necessary for spending -} - -/** - * Structure representing transaction input - * @used_in SimpleSignTx - * @used_in TransactionType - */ -message TxInputType { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - required bytes prev_hash = 2; // hash of previous transaction output to spend by this input - required uint32 prev_index = 3; // index of previous output to spend - optional bytes script_sig = 4; // script signature, unset for tx to sign - optional uint32 sequence = 5 [default=4294967295]; // sequence (default=0xffffffff) - optional InputScriptType script_type = 6 [default=SPENDADDRESS]; // defines template of input script - optional MultisigRedeemScriptType multisig = 7; // Filled if input is going to spend multisig tx - optional uint64 amount = 8; // amount of previous transaction output (for segwit only) -} - -/** - * Structure representing transaction output - * @used_in SimpleSignTx - * @used_in TransactionType - */ -message TxOutputType { - optional string address = 1; // target coin address in Base58 encoding - repeated uint32 address_n = 2; // BIP-32 path to derive the key from master node; has higher priority than "address" - required uint64 amount = 3; // amount to spend in satoshis - required OutputScriptType script_type = 4; // output script type - optional MultisigRedeemScriptType multisig = 5; // defines multisig address; script_type must be PAYTOMULTISIG - optional bytes op_return_data = 6; // defines op_return data; script_type must be PAYTOOPRETURN, amount must be 0 -} - -/** - * Structure representing compiled transaction output - * @used_in TransactionType - */ -message TxOutputBinType { - required uint64 amount = 1; - required bytes script_pubkey = 2; -} - -/** - * Structure representing transaction - * @used_in SimpleSignTx - */ -message TransactionType { - optional uint32 version = 1; - repeated TxInputType inputs = 2; - repeated TxOutputBinType bin_outputs = 3; - repeated TxOutputType outputs = 5; - optional uint32 lock_time = 4; - optional uint32 inputs_cnt = 6; - optional uint32 outputs_cnt = 7; - optional bytes extra_data = 8; - optional uint32 extra_data_len = 9; -} - -/** - * Structure representing request details - * @used_in TxRequest - */ -message TxRequestDetailsType { - optional uint32 request_index = 1; // device expects TxAck message from the computer - optional bytes tx_hash = 2; // tx_hash of requested transaction - optional uint32 extra_data_len = 3; // length of requested extra data - optional uint32 extra_data_offset = 4; // offset of requested extra data -} - -/** - * Structure representing serialized data - * @used_in TxRequest - */ -message TxRequestSerializedType { - optional uint32 signature_index = 1; // 'signature' field contains signed input of this index - optional bytes signature = 2; // signature of the signature_index input - optional bytes serialized_tx = 3; // part of serialized and signed transaction -} - -/** - * Structure representing identity data - * @used_in IdentityType - */ -message IdentityType { - optional string proto = 1; // proto part of URI - optional string user = 2; // user part of URI - optional string host = 3; // host part of URI - optional string port = 4; // port part of URI - optional string path = 5; // path part of URI - optional uint32 index = 6 [default=0]; // identity index -} diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE index 1b1b1921ef..0f646931a4 100644 --- a/vendor/github.com/golang/protobuf/LICENSE +++ b/vendor/github.com/golang/protobuf/LICENSE @@ -1,7 +1,4 @@ -Go support for Protocol Buffers - Google's data interchange format - Copyright 2010 The Go Authors. All rights reserved. -https://github.com/golang/protobuf Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/github.com/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile deleted file mode 100644 index e2e0651a93..0000000000 --- a/vendor/github.com/golang/protobuf/proto/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -install: - go install - -test: install generate-test-pbs - go test - - -generate-test-pbs: - make install - make -C testdata - protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto - make diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go index e392575b35..3cd3249f70 100644 --- a/vendor/github.com/golang/protobuf/proto/clone.go +++ b/vendor/github.com/golang/protobuf/proto/clone.go @@ -35,22 +35,39 @@ package proto import ( + "fmt" "log" "reflect" "strings" ) // Clone returns a deep copy of a protocol buffer. -func Clone(pb Message) Message { - in := reflect.ValueOf(pb) +func Clone(src Message) Message { + in := reflect.ValueOf(src) if in.IsNil() { - return pb + return src } - out := reflect.New(in.Type().Elem()) - // out is empty so a merge is a deep copy. - mergeStruct(out.Elem(), in.Elem()) - return out.Interface().(Message) + dst := out.Interface().(Message) + Merge(dst, src) + return dst +} + +// Merger is the interface representing objects that can merge messages of the same type. +type Merger interface { + // Merge merges src into this message. + // Required and optional fields that are set in src will be set to that value in dst. + // Elements of repeated fields will be appended. + // + // Merge may panic if called with a different argument type than the receiver. + Merge(src Message) +} + +// generatedMerger is the custom merge method that generated protos will have. +// We must add this method since a generate Merge method will conflict with +// many existing protos that have a Merge data field already defined. +type generatedMerger interface { + XXX_Merge(src Message) } // Merge merges src into dst. @@ -58,17 +75,24 @@ func Clone(pb Message) Message { // Elements of repeated fields will be appended. // Merge panics if src and dst are not the same type, or if dst is nil. func Merge(dst, src Message) { + if m, ok := dst.(Merger); ok { + m.Merge(src) + return + } + in := reflect.ValueOf(src) out := reflect.ValueOf(dst) if out.IsNil() { panic("proto: nil destination") } if in.Type() != out.Type() { - // Explicit test prior to mergeStruct so that mistyped nils will fail - panic("proto: type mismatch") + panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) } if in.IsNil() { - // Merging nil into non-nil is a quiet no-op + return // Merge from nil src is a noop + } + if m, ok := dst.(generatedMerger); ok { + m.XXX_Merge(src) return } mergeStruct(out.Elem(), in.Elem()) @@ -84,7 +108,7 @@ func mergeStruct(out, in reflect.Value) { mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) } - if emIn, ok := extendable(in.Addr().Interface()); ok { + if emIn, err := extendable(in.Addr().Interface()); err == nil { emOut, _ := extendable(out.Addr().Interface()) mIn, muIn := emIn.extensionsRead() if mIn != nil { diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go index aa207298f9..63b0f08bef 100644 --- a/vendor/github.com/golang/protobuf/proto/decode.go +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -39,8 +39,6 @@ import ( "errors" "fmt" "io" - "os" - "reflect" ) // errOverflow is returned when an integer is too large to be represented. @@ -50,10 +48,6 @@ var errOverflow = errors.New("proto: integer overflow") // wire type is encountered. It does not get returned to user code. var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") -// The fundamental decoders that interpret bytes on the wire. -// Those that take integer types all return uint64 and are -// therefore of type valueDecoder. - // DecodeVarint reads a varint-encoded integer from the slice. // It returns the integer and the number of bytes consumed, or // zero if there is not enough. @@ -192,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) { if b&0x80 == 0 { goto done } - // x -= 0x80 << 63 // Always zero. return 0, errOverflow @@ -267,9 +260,6 @@ func (p *Buffer) DecodeZigzag32() (x uint64, err error) { return } -// These are not ValueDecoders: they produce an array of bytes or a string. -// bytes, embedded messages - // DecodeRawBytes reads a count-delimited byte buffer from the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. @@ -311,81 +301,29 @@ func (p *Buffer) DecodeStringBytes() (s string, err error) { return string(buf), nil } -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -// If the protocol buffer has extensions, and the field matches, add it as an extension. -// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. -func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { - oi := o.index - - err := o.skip(t, tag, wire) - if err != nil { - return err - } - - if !unrecField.IsValid() { - return nil - } - - ptr := structPointer_Bytes(base, unrecField) - - // Add the skipped field to struct field - obuf := o.buf - - o.buf = *ptr - o.EncodeVarint(uint64(tag<<3 | wire)) - *ptr = append(o.buf, obuf[oi:o.index]...) - - o.buf = obuf - - return nil -} - -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -func (o *Buffer) skip(t reflect.Type, tag, wire int) error { - - var u uint64 - var err error - - switch wire { - case WireVarint: - _, err = o.DecodeVarint() - case WireFixed64: - _, err = o.DecodeFixed64() - case WireBytes: - _, err = o.DecodeRawBytes(false) - case WireFixed32: - _, err = o.DecodeFixed32() - case WireStartGroup: - for { - u, err = o.DecodeVarint() - if err != nil { - break - } - fwire := int(u & 0x7) - if fwire == WireEndGroup { - break - } - ftag := int(u >> 3) - err = o.skip(t, ftag, fwire) - if err != nil { - break - } - } - default: - err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) - } - return err -} - // Unmarshaler is the interface representing objects that can -// unmarshal themselves. The method should reset the receiver before -// decoding starts. The argument points to data that may be +// unmarshal themselves. The argument points to data that may be // overwritten, so implementations should not keep references to the // buffer. +// Unmarshal implementations should not clear the receiver. +// Any unmarshaled data should be merged into the receiver. +// Callers of Unmarshal that do not want to retain existing data +// should Reset the receiver before calling Unmarshal. type Unmarshaler interface { Unmarshal([]byte) error } +// newUnmarshaler is the interface representing objects that can +// unmarshal themselves. The semantics are identical to Unmarshaler. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newUnmarshaler interface { + XXX_Unmarshal([]byte) error +} + // Unmarshal parses the protocol buffer representation in buf and places the // decoded result in pb. If the struct underlying pb does not match // the data in buf, the results can be unpredictable. @@ -395,7 +333,13 @@ type Unmarshaler interface { // to preserve and append to existing data. func Unmarshal(buf []byte, pb Message) error { pb.Reset() - return UnmarshalMerge(buf, pb) + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) } // UnmarshalMerge parses the protocol buffer representation in buf and @@ -405,8 +349,16 @@ func Unmarshal(buf []byte, pb Message) error { // UnmarshalMerge merges into existing data in pb. // Most code should use Unmarshal instead. func UnmarshalMerge(buf []byte, pb Message) error { - // If the object can unmarshal itself, let it. + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 return u.Unmarshal(buf) } return NewBuffer(buf).Unmarshal(pb) @@ -422,12 +374,17 @@ func (p *Buffer) DecodeMessage(pb Message) error { } // DecodeGroup reads a tag-delimited group from the Buffer. +// StartGroup tag is already consumed. This function consumes +// EndGroup tag. func (p *Buffer) DecodeGroup(pb Message) error { - typ, base, err := getbase(pb) - if err != nil { - return err + b := p.buf[p.index:] + x, y := findEndGroup(b) + if x < 0 { + return io.ErrUnexpectedEOF } - return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) + err := Unmarshal(b[:x], pb) + p.index += y + return err } // Unmarshal parses the protocol buffer representation in the @@ -438,533 +395,33 @@ func (p *Buffer) DecodeGroup(pb Message) error { // Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. func (p *Buffer) Unmarshal(pb Message) error { // If the object can unmarshal itself, let it. + if u, ok := pb.(newUnmarshaler); ok { + err := u.XXX_Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 err := u.Unmarshal(p.buf[p.index:]) p.index = len(p.buf) return err } - typ, base, err := getbase(pb) - if err != nil { - return err - } - - err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) - - if collectStats { - stats.Decode++ - } - - return err -} - -// unmarshalType does the work of unmarshaling a structure. -func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { - var state errorState - required, reqFields := prop.reqCount, uint64(0) - - var err error - for err == nil && o.index < len(o.buf) { - oi := o.index - var u uint64 - u, err = o.DecodeVarint() - if err != nil { - break - } - wire := int(u & 0x7) - if wire == WireEndGroup { - if is_group { - if required > 0 { - // Not enough information to determine the exact field. - // (See below.) - return &RequiredNotSetError{"{Unknown}"} - } - return nil // input is satisfied - } - return fmt.Errorf("proto: %s: wiretype end group for non-group", st) - } - tag := int(u >> 3) - if tag <= 0 { - return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) - } - fieldnum, ok := prop.decoderTags.get(tag) - if !ok { - // Maybe it's an extension? - if prop.extendable { - if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { - if err = o.skip(st, tag, wire); err == nil { - extmap := e.extensionsWrite() - ext := extmap[int32(tag)] // may be missing - ext.enc = append(ext.enc, o.buf[oi:o.index]...) - extmap[int32(tag)] = ext - } - continue - } - } - // Maybe it's a oneof? - if prop.oneofUnmarshaler != nil { - m := structPointer_Interface(base, st).(Message) - // First return value indicates whether tag is a oneof field. - ok, err = prop.oneofUnmarshaler(m, tag, wire, o) - if err == ErrInternalBadWireType { - // Map the error to something more descriptive. - // Do the formatting here to save generated code space. - err = fmt.Errorf("bad wiretype for oneof field in %T", m) - } - if ok { - continue - } - } - err = o.skipAndSave(st, tag, wire, base, prop.unrecField) - continue - } - p := prop.Prop[fieldnum] - - if p.dec == nil { - fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) - continue - } - dec := p.dec - if wire != WireStartGroup && wire != p.WireType { - if wire == WireBytes && p.packedDec != nil { - // a packable field - dec = p.packedDec - } else { - err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) - continue - } - } - decErr := dec(o, p, base) - if decErr != nil && !state.shouldContinue(decErr, p) { - err = decErr - } - if err == nil && p.Required { - // Successfully decoded a required field. - if tag <= 64 { - // use bitmap for fields 1-64 to catch field reuse. - var mask uint64 = 1 << uint64(tag-1) - if reqFields&mask == 0 { - // new required field - reqFields |= mask - required-- - } - } else { - // This is imprecise. It can be fooled by a required field - // with a tag > 64 that is encoded twice; that's very rare. - // A fully correct implementation would require allocating - // a data structure, which we would like to avoid. - required-- - } - } - } - if err == nil { - if is_group { - return io.ErrUnexpectedEOF - } - if state.err != nil { - return state.err - } - if required > 0 { - // Not enough information to determine the exact field. If we use extra - // CPU, we could determine the field only if the missing required field - // has a tag <= 64 and we check reqFields. - return &RequiredNotSetError{"{Unknown}"} - } - } - return err -} - -// Individual type decoders -// For each, -// u is the decoded value, -// v is a pointer to the field (pointer) in the struct - -// Sizes of the pools to allocate inside the Buffer. -// The goal is modest amortization and allocation -// on at least 16-byte boundaries. -const ( - boolPoolSize = 16 - uint32PoolSize = 8 - uint64PoolSize = 4 -) - -// Decode a bool. -func (o *Buffer) dec_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - if len(o.bools) == 0 { - o.bools = make([]bool, boolPoolSize) - } - o.bools[0] = u != 0 - *structPointer_Bool(base, p.field) = &o.bools[0] - o.bools = o.bools[1:] - return nil -} - -func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - *structPointer_BoolVal(base, p.field) = u != 0 - return nil -} - -// Decode an int32. -func (o *Buffer) dec_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) - return nil -} - -func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) - return nil -} - -// Decode an int64. -func (o *Buffer) dec_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64_Set(structPointer_Word64(base, p.field), o, u) - return nil -} - -func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64Val_Set(structPointer_Word64Val(base, p.field), o, u) - return nil -} - -// Decode a string. -func (o *Buffer) dec_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_String(base, p.field) = &s - return nil -} - -func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_StringVal(base, p.field) = s - return nil -} - -// Decode a slice of bytes ([]byte). -func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - *structPointer_Bytes(base, p.field) = b - return nil -} - -// Decode a slice of bools ([]bool). -func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - v := structPointer_BoolSlice(base, p.field) - *v = append(*v, u != 0) - return nil -} - -// Decode a slice of bools ([]bool) in packed format. -func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { - v := structPointer_BoolSlice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded bools - fin := o.index + nb - if fin < o.index { - return errOverflow - } - - y := *v - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - y = append(y, u != 0) - } - - *v = y - return nil -} - -// Decode a slice of int32s ([]int32). -func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - structPointer_Word32Slice(base, p.field).Append(uint32(u)) - return nil -} - -// Decode a slice of int32s ([]int32) in packed format. -func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int32s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(uint32(u)) - } - return nil -} - -// Decode a slice of int64s ([]int64). -func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - - structPointer_Word64Slice(base, p.field).Append(u) - return nil -} - -// Decode a slice of int64s ([]int64) in packed format. -func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int64s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(u) - } - return nil -} - -// Decode a slice of strings ([]string). -func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - v := structPointer_StringSlice(base, p.field) - *v = append(*v, s) - return nil -} - -// Decode a slice of slice of bytes ([][]byte). -func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - v := structPointer_BytesSlice(base, p.field) - *v = append(*v, b) - return nil -} - -// Decode a map field. -func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - oi := o.index // index at the end of this map entry - o.index -= len(raw) // move buffer back to start of map entry - - mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V - if mptr.Elem().IsNil() { - mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) - } - v := mptr.Elem() // map[K]V - - // Prepare addressable doubly-indirect placeholders for the key and value types. - // See enc_new_map for why. - keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K - keybase := toStructPointer(keyptr.Addr()) // **K - - var valbase structPointer - var valptr reflect.Value - switch p.mtype.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valptr = reflect.ValueOf(&dummy) // *[]byte - valbase = toStructPointer(valptr) // *[]byte - case reflect.Ptr: - // message; valptr is **Msg; need to allocate the intermediate pointer - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valptr.Set(reflect.New(valptr.Type().Elem())) - valbase = toStructPointer(valptr) - default: - // everything else - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valbase = toStructPointer(valptr.Addr()) // **V - } - - // Decode. - // This parses a restricted wire format, namely the encoding of a message - // with two fields. See enc_new_map for the format. - for o.index < oi { - // tagcode for key and value properties are always a single byte - // because they have tags 1 and 2. - tagcode := o.buf[o.index] - o.index++ - switch tagcode { - case p.mkeyprop.tagcode[0]: - if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { - return err - } - case p.mvalprop.tagcode[0]: - if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { - return err - } - default: - // TODO: Should we silently skip this instead? - return fmt.Errorf("proto: bad map data tag %d", raw[0]) - } - } - keyelem, valelem := keyptr.Elem(), valptr.Elem() - if !keyelem.IsValid() { - keyelem = reflect.Zero(p.mtype.Key()) - } - if !valelem.IsValid() { - valelem = reflect.Zero(p.mtype.Elem()) - } - - v.SetMapIndex(keyelem, valelem) - return nil -} - -// Decode a group. -func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - return o.unmarshalType(p.stype, p.sprop, true, bas) -} - -// Decode an embedded message. -func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { - raw, e := o.DecodeRawBytes(false) - if e != nil { - return e - } - - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := structPointer_Interface(bas, p.stype) - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, false, bas) - o.buf = obuf - o.index = oi - - return err -} - -// Decode a slice of embedded messages. -func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, false, base) -} - -// Decode a slice of embedded groups. -func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, true, base) -} - -// Decode a slice of structs ([]*struct). -func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { - v := reflect.New(p.stype) - bas := toStructPointer(v) - structPointer_StructPointerSlice(base, p.field).Append(bas) - - if is_group { - err := o.unmarshalType(p.stype, p.sprop, is_group, bas) - return err - } - - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := v.Interface() - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, is_group, bas) - - o.buf = obuf - o.index = oi - + // Slow workaround for messages that aren't Unmarshalers. + // This includes some hand-coded .pb.go files and + // bootstrap protos. + // TODO: fix all of those and then add Unmarshal to + // the Message interface. Then: + // The cast above and code below can be deleted. + // The old unmarshaler can be deleted. + // Clients can call Unmarshal directly (can already do that, actually). + var info InternalMessageInfo + err := info.Unmarshal(pb, p.buf[p.index:]) + p.index = len(p.buf) return err } diff --git a/vendor/github.com/golang/protobuf/proto/deprecated.go b/vendor/github.com/golang/protobuf/proto/deprecated.go new file mode 100644 index 0000000000..35b882c09a --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/deprecated.go @@ -0,0 +1,63 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import "errors" + +// Deprecated: do not use. +type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } + +// Deprecated: do not use. +func GetStats() Stats { return Stats{} } + +// Deprecated: do not use. +func MarshalMessageSet(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSet([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func MarshalMessageSetJSON(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSetJSON([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func RegisterMessageSetType(Message, int32, string) {} diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go new file mode 100644 index 0000000000..dea2617ced --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/discard.go @@ -0,0 +1,350 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +type generatedDiscarder interface { + XXX_DiscardUnknown() +} + +// DiscardUnknown recursively discards all unknown fields from this message +// and all embedded messages. +// +// When unmarshaling a message with unrecognized fields, the tags and values +// of such fields are preserved in the Message. This allows a later call to +// marshal to be able to produce a message that continues to have those +// unrecognized fields. To avoid this, DiscardUnknown is used to +// explicitly clear the unknown fields after unmarshaling. +// +// For proto2 messages, the unknown fields of message extensions are only +// discarded from messages that have been accessed via GetExtension. +func DiscardUnknown(m Message) { + if m, ok := m.(generatedDiscarder); ok { + m.XXX_DiscardUnknown() + return + } + // TODO: Dynamically populate a InternalMessageInfo for legacy messages, + // but the master branch has no implementation for InternalMessageInfo, + // so it would be more work to replicate that approach. + discardLegacy(m) +} + +// DiscardUnknown recursively discards all unknown fields. +func (a *InternalMessageInfo) DiscardUnknown(m Message) { + di := atomicLoadDiscardInfo(&a.discard) + if di == nil { + di = getDiscardInfo(reflect.TypeOf(m).Elem()) + atomicStoreDiscardInfo(&a.discard, di) + } + di.discard(toPointer(&m)) +} + +type discardInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []discardFieldInfo + unrecognized field +} + +type discardFieldInfo struct { + field field // Offset of field, guaranteed to be valid + discard func(src pointer) +} + +var ( + discardInfoMap = map[reflect.Type]*discardInfo{} + discardInfoLock sync.Mutex +) + +func getDiscardInfo(t reflect.Type) *discardInfo { + discardInfoLock.Lock() + defer discardInfoLock.Unlock() + di := discardInfoMap[t] + if di == nil { + di = &discardInfo{typ: t} + discardInfoMap[t] = di + } + return di +} + +func (di *discardInfo) discard(src pointer) { + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&di.initialized) == 0 { + di.computeDiscardInfo() + } + + for _, fi := range di.fields { + sfp := src.offset(fi.field) + fi.discard(sfp) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil { + // Ignore lock since DiscardUnknown is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + DiscardUnknown(m) + } + } + } + + if di.unrecognized.IsValid() { + *src.offset(di.unrecognized).toBytes() = nil + } +} + +func (di *discardInfo) computeDiscardInfo() { + di.lock.Lock() + defer di.lock.Unlock() + if di.initialized != 0 { + return + } + t := di.typ + n := t.NumField() + + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + dfi := discardFieldInfo{field: toField(&f)} + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name)) + case isSlice: // E.g., []*pb.T + di := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sps := src.getPointerSlice() + for _, sp := range sps { + if !sp.isNil() { + di.discard(sp) + } + } + } + default: // E.g., *pb.T + di := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sp := src.getPointer() + if !sp.isNil() { + di.discard(sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name)) + default: // E.g., map[K]V + if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T) + dfi.discard = func(src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + DiscardUnknown(val.Interface().(Message)) + } + } + } else { + dfi.discard = func(pointer) {} // Noop + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name)) + default: // E.g., interface{} + // TODO: Make this faster? + dfi.discard = func(src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + DiscardUnknown(sv.Interface().(Message)) + } + } + } + } + default: + continue + } + di.fields = append(di.fields, dfi) + } + + di.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + di.unrecognized = toField(&f) + } + + atomic.StoreInt32(&di.initialized, 1) +} + +func discardLegacy(m Message) { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if v.Kind() != reflect.Struct { + return + } + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + vf := v.Field(i) + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) + case isSlice: // E.g., []*pb.T + for j := 0; j < vf.Len(); j++ { + discardLegacy(vf.Index(j).Interface().(Message)) + } + default: // E.g., *pb.T + discardLegacy(vf.Interface().(Message)) + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) + default: // E.g., map[K]V + tv := vf.Type().Elem() + if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) + for _, key := range vf.MapKeys() { + val := vf.MapIndex(key) + discardLegacy(val.Interface().(Message)) + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) + default: // E.g., test_proto.isCommunique_Union interface + if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { + vf = vf.Elem() // E.g., *test_proto.Communique_Msg + if !vf.IsNil() { + vf = vf.Elem() // E.g., test_proto.Communique_Msg + vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value + if vf.Kind() == reflect.Ptr { + discardLegacy(vf.Interface().(Message)) + } + } + } + } + } + } + + if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { + if vf.Type() != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + vf.Set(reflect.ValueOf([]byte(nil))) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(m); err == nil { + // Ignore lock since discardLegacy is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + discardLegacy(m) + } + } + } +} diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go index 8b84d1b22d..3abfed2cff 100644 --- a/vendor/github.com/golang/protobuf/proto/encode.go +++ b/vendor/github.com/golang/protobuf/proto/encode.go @@ -37,28 +37,9 @@ package proto import ( "errors" - "fmt" "reflect" - "sort" ) -// RequiredNotSetError is the error returned if Marshal is called with -// a protocol buffer struct whose required fields have not -// all been initialized. It is also the error returned if Unmarshal is -// called with an encoded protocol buffer that does not include all the -// required fields. -// -// When printed, RequiredNotSetError reports the first unset required field in a -// message. If the field cannot be precisely determined, it is reported as -// "{Unknown}". -type RequiredNotSetError struct { - field string -} - -func (e *RequiredNotSetError) Error() string { - return fmt.Sprintf("proto: required field %q not set", e.field) -} - var ( // errRepeatedHasNil is the error returned if Marshal is called with // a struct with a repeated field containing a nil element. @@ -82,10 +63,6 @@ var ( const maxVarintBytes = 10 // maximum length of a varint -// maxMarshalSize is the largest allowed size of an encoded protobuf, -// since C++ and Java use signed int32s for the size. -const maxMarshalSize = 1<<31 - 1 - // EncodeVarint returns the varint encoding of x. // This is the format for the // int32, int64, uint32, uint64, bool, and enum @@ -119,18 +96,27 @@ func (p *Buffer) EncodeVarint(x uint64) error { // SizeVarint returns the varint encoding size of an integer. func SizeVarint(x uint64) int { - return sizeVarint(x) -} - -func sizeVarint(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } + switch { + case x < 1<<7: + return 1 + case x < 1<<14: + return 2 + case x < 1<<21: + return 3 + case x < 1<<28: + return 4 + case x < 1<<35: + return 5 + case x < 1<<42: + return 6 + case x < 1<<49: + return 7 + case x < 1<<56: + return 8 + case x < 1<<63: + return 9 } - return n + return 10 } // EncodeFixed64 writes a 64-bit integer to the Buffer. @@ -149,10 +135,6 @@ func (p *Buffer) EncodeFixed64(x uint64) error { return nil } -func sizeFixed64(x uint64) int { - return 8 -} - // EncodeFixed32 writes a 32-bit integer to the Buffer. // This is the format for the // fixed32, sfixed32, and float protocol buffer types. @@ -165,20 +147,12 @@ func (p *Buffer) EncodeFixed32(x uint64) error { return nil } -func sizeFixed32(x uint64) int { - return 4 -} - // EncodeZigzag64 writes a zigzag-encoded 64-bit integer // to the Buffer. // This is the format used for the sint64 protocol buffer type. func (p *Buffer) EncodeZigzag64(x uint64) error { // use signed number to get arithmetic right shift. - return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63))) -} - -func sizeZigzag64(x uint64) int { - return sizeVarint((x << 1) ^ uint64((int64(x) >> 63))) + return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } // EncodeZigzag32 writes a zigzag-encoded 32-bit integer @@ -189,10 +163,6 @@ func (p *Buffer) EncodeZigzag32(x uint64) error { return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) } -func sizeZigzag32(x uint64) int { - return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - // EncodeRawBytes writes a count-delimited byte buffer to the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. @@ -202,11 +172,6 @@ func (p *Buffer) EncodeRawBytes(b []byte) error { return nil } -func sizeRawBytes(b []byte) int { - return sizeVarint(uint64(len(b))) + - len(b) -} - // EncodeStringBytes writes an encoded string to the Buffer. // This is the format used for the proto2 string type. func (p *Buffer) EncodeStringBytes(s string) error { @@ -215,319 +180,17 @@ func (p *Buffer) EncodeStringBytes(s string) error { return nil } -func sizeStringBytes(s string) int { - return sizeVarint(uint64(len(s))) + - len(s) -} - // Marshaler is the interface representing objects that can marshal themselves. type Marshaler interface { Marshal() ([]byte, error) } -// Marshal takes the protocol buffer -// and encodes it into the wire format, returning the data. -func Marshal(pb Message) ([]byte, error) { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - return m.Marshal() - } - p := NewBuffer(nil) - err := p.Marshal(pb) - if p.buf == nil && err == nil { - // Return a non-nil slice on success. - return []byte{}, nil - } - return p.buf, err -} - // EncodeMessage writes the protocol buffer to the Buffer, // prefixed by a varint-encoded length. func (p *Buffer) EncodeMessage(pb Message) error { - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return ErrNil - } - if err == nil { - var state errorState - err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) - } - return err -} - -// Marshal takes the protocol buffer -// and encodes it into the wire format, writing the result to the -// Buffer. -func (p *Buffer) Marshal(pb Message) error { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - data, err := m.Marshal() - p.buf = append(p.buf, data...) - return err - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return ErrNil - } - if err == nil { - err = p.enc_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - (stats).Encode++ // Parens are to work around a goimports bug. - } - - if len(p.buf) > maxMarshalSize { - return ErrTooLarge - } - return err -} - -// Size returns the encoded size of a protocol buffer. -func Size(pb Message) (n int) { - // Can the object marshal itself? If so, Size is slow. - // TODO: add Size to Marshaler, or add a Sizer interface. - if m, ok := pb.(Marshaler); ok { - b, _ := m.Marshal() - return len(b) - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return 0 - } - if err == nil { - n = size_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - (stats).Size++ // Parens are to work around a goimports bug. - } - - return -} - -// Individual type encoders. - -// Encode a bool. -func (o *Buffer) enc_bool(p *Properties, base structPointer) error { - v := *structPointer_Bool(base, p.field) - if v == nil { - return ErrNil - } - x := 0 - if *v { - x = 1 - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { - v := *structPointer_BoolVal(base, p.field) - if !v { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, 1) - return nil -} - -func size_bool(p *Properties, base structPointer) int { - v := *structPointer_Bool(base, p.field) - if v == nil { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -func size_proto3_bool(p *Properties, base structPointer) int { - v := *structPointer_BoolVal(base, p.field) - if !v && !p.oneof { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -// Encode an int32. -func (o *Buffer) enc_int32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode a uint32. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := word32_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := word32_Get(v) - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode an int64. -func (o *Buffer) enc_int64(p *Properties, base structPointer) error { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return ErrNil - } - x := word64_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func size_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return 0 - } - x := word64_Get(v) - n += len(p.tagcode) - n += p.valSize(x) - return -} - -func size_proto3_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += p.valSize(x) - return -} - -// Encode a string. -func (o *Buffer) enc_string(p *Properties, base structPointer) error { - v := *structPointer_String(base, p.field) - if v == nil { - return ErrNil - } - x := *v - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(x) - return nil -} - -func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { - v := *structPointer_StringVal(base, p.field) - if v == "" { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(v) - return nil -} - -func size_string(p *Properties, base structPointer) (n int) { - v := *structPointer_String(base, p.field) - if v == nil { - return 0 - } - x := *v - n += len(p.tagcode) - n += sizeStringBytes(x) - return -} - -func size_proto3_string(p *Properties, base structPointer) (n int) { - v := *structPointer_StringVal(base, p.field) - if v == "" && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeStringBytes(v) - return + siz := Size(pb) + p.EncodeVarint(uint64(siz)) + return p.Marshal(pb) } // All protocol buffer fields are nillable, but be careful. @@ -538,825 +201,3 @@ func isNil(v reflect.Value) bool { } return false } - -// Encode a message struct. -func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { - var state errorState - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return ErrNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - return state.err - } - - o.buf = append(o.buf, p.tagcode...) - return o.enc_len_struct(p.sprop, structp, &state) -} - -func size_struct_message(p *Properties, base structPointer) int { - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return 0 - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n0 := len(p.tagcode) - n1 := sizeRawBytes(data) - return n0 + n1 - } - - n0 := len(p.tagcode) - n1 := size_struct(p.sprop, structp) - n2 := sizeVarint(uint64(n1)) // size of encoded length - return n0 + n1 + n2 -} - -// Encode a group struct. -func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { - var state errorState - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return ErrNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - err := o.enc_struct(p.sprop, b) - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return state.err -} - -func size_struct_group(p *Properties, base structPointer) (n int) { - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return 0 - } - - n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) - n += size_struct(p.sprop, b) - n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return -} - -// Encode a slice of bools ([]bool). -func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - for _, x := range s { - o.buf = append(o.buf, p.tagcode...) - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_bool(p *Properties, base structPointer) int { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - return l * (len(p.tagcode) + 1) // each bool takes exactly one byte -} - -// Encode a slice of bools ([]bool) in packed format. -func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(l)) // each bool takes exactly one byte - for _, x := range s { - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_packed_bool(p *Properties, base structPointer) (n int) { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - n += len(p.tagcode) - n += sizeVarint(uint64(l)) - n += l // each bool takes exactly one byte - return -} - -// Encode a slice of bytes ([]byte). -func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if s == nil { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func size_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if s == nil && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 && !p.oneof { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -// Encode a slice of int32s ([]int32). -func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of int32s ([]int32) in packed format. -func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(buf, uint64(x)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - bufSize += p.valSize(uint64(x)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of uint32s ([]uint32). -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := s.Index(i) - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := s.Index(i) - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of uint32s ([]uint32) in packed format. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, uint64(s.Index(i))) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(uint64(s.Index(i))) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of int64s ([]int64). -func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, s.Index(i)) - } - return nil -} - -func size_slice_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - n += p.valSize(s.Index(i)) - } - return -} - -// Encode a slice of int64s ([]int64) in packed format. -func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, s.Index(i)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(s.Index(i)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of slice of bytes ([][]byte). -func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(ss[i]) - } - return nil -} - -func size_slice_slice_byte(p *Properties, base structPointer) (n int) { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return 0 - } - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeRawBytes(ss[i]) - } - return -} - -// Encode a slice of strings ([]string). -func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(ss[i]) - } - return nil -} - -func size_slice_string(p *Properties, base structPointer) (n int) { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeStringBytes(ss[i]) - } - return -} - -// Encode a slice of message structs ([]*struct). -func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return errRepeatedHasNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - continue - } - - o.buf = append(o.buf, p.tagcode...) - err := o.enc_len_struct(p.sprop, structp, &state) - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - } - return state.err -} - -func size_slice_struct_message(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return // return the size up to this point - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n += sizeRawBytes(data) - continue - } - - n0 := size_struct(p.sprop, structp) - n1 := sizeVarint(uint64(n0)) // size of encoded length - n += n0 + n1 - } - return -} - -// Encode a slice of group structs ([]*struct). -func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return errRepeatedHasNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - - err := o.enc_struct(p.sprop, b) - - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - } - return state.err -} - -func size_slice_struct_group(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) - n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return // return size up to this point - } - - n += size_struct(p.sprop, b) - } - return -} - -// Encode an extension map. -func (o *Buffer) enc_map(p *Properties, base structPointer) error { - exts := structPointer_ExtMap(base, p.field) - if err := encodeExtensionsMap(*exts); err != nil { - return err - } - - return o.enc_map_body(*exts) -} - -func (o *Buffer) enc_exts(p *Properties, base structPointer) error { - exts := structPointer_Extensions(base, p.field) - - v, mu := exts.extensionsRead() - if v == nil { - return nil - } - - mu.Lock() - defer mu.Unlock() - if err := encodeExtensionsMap(v); err != nil { - return err - } - - return o.enc_map_body(v) -} - -func (o *Buffer) enc_map_body(v map[int32]Extension) error { - // Fast-path for common cases: zero or one extensions. - if len(v) <= 1 { - for _, e := range v { - o.buf = append(o.buf, e.enc...) - } - return nil - } - - // Sort keys to provide a deterministic encoding. - keys := make([]int, 0, len(v)) - for k := range v { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, k := range keys { - o.buf = append(o.buf, v[int32(k)].enc...) - } - return nil -} - -func size_map(p *Properties, base structPointer) int { - v := structPointer_ExtMap(base, p.field) - return extensionsMapSize(*v) -} - -func size_exts(p *Properties, base structPointer) int { - v := structPointer_Extensions(base, p.field) - return extensionsSize(v) -} - -// Encode a map field. -func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { - var state errorState // XXX: or do we need to plumb this through? - - /* - A map defined as - map map_field = N; - is encoded in the same way as - message MapFieldEntry { - key_type key = 1; - value_type value = 2; - } - repeated MapFieldEntry map_field = N; - */ - - v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V - if v.Len() == 0 { - return nil - } - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - enc := func() error { - if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { - return err - } - if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { - return err - } - return nil - } - - // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. - for _, key := range v.MapKeys() { - val := v.MapIndex(key) - - keycopy.Set(key) - valcopy.Set(val) - - o.buf = append(o.buf, p.tagcode...) - if err := o.enc_len_thing(enc, &state); err != nil { - return err - } - } - return nil -} - -func size_new_map(p *Properties, base structPointer) int { - v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - n := 0 - for _, key := range v.MapKeys() { - val := v.MapIndex(key) - keycopy.Set(key) - valcopy.Set(val) - - // Tag codes for key and val are the responsibility of the sub-sizer. - keysize := p.mkeyprop.size(p.mkeyprop, keybase) - valsize := p.mvalprop.size(p.mvalprop, valbase) - entry := keysize + valsize - // Add on tag code and length of map entry itself. - n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry - } - return n -} - -// mapEncodeScratch returns a new reflect.Value matching the map's value type, -// and a structPointer suitable for passing to an encoder or sizer. -func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { - // Prepare addressable doubly-indirect placeholders for the key and value types. - // This is needed because the element-type encoders expect **T, but the map iteration produces T. - - keycopy = reflect.New(mapType.Key()).Elem() // addressable K - keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K - keyptr.Set(keycopy.Addr()) // - keybase = toStructPointer(keyptr.Addr()) // **K - - // Value types are more varied and require special handling. - switch mapType.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte - valbase = toStructPointer(valcopy.Addr()) - case reflect.Ptr: - // message; the generated field type is map[K]*Msg (so V is *Msg), - // so we only need one level of indirection. - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valbase = toStructPointer(valcopy.Addr()) - default: - // everything else - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V - valptr.Set(valcopy.Addr()) // - valbase = toStructPointer(valptr.Addr()) // **V - } - return -} - -// Encode a struct. -func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { - var state errorState - // Encode fields in tag order so that decoders may use optimizations - // that depend on the ordering. - // https://developers.google.com/protocol-buffers/docs/encoding#order - for _, i := range prop.order { - p := prop.Prop[i] - if p.enc != nil { - err := p.enc(o, p, base) - if err != nil { - if err == ErrNil { - if p.Required && state.err == nil { - state.err = &RequiredNotSetError{p.Name} - } - } else if err == errRepeatedHasNil { - // Give more context to nil values in repeated fields. - return errors.New("repeated field " + p.OrigName + " has nil element") - } else if !state.shouldContinue(err, p) { - return err - } - } - if len(o.buf) > maxMarshalSize { - return ErrTooLarge - } - } - } - - // Do oneof fields. - if prop.oneofMarshaler != nil { - m := structPointer_Interface(base, prop.stype).(Message) - if err := prop.oneofMarshaler(m, o); err == ErrNil { - return errOneofHasNil - } else if err != nil { - return err - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - if len(o.buf)+len(v) > maxMarshalSize { - return ErrTooLarge - } - if len(v) > 0 { - o.buf = append(o.buf, v...) - } - } - - return state.err -} - -func size_struct(prop *StructProperties, base structPointer) (n int) { - for _, i := range prop.order { - p := prop.Prop[i] - if p.size != nil { - n += p.size(p, base) - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - n += len(v) - } - - // Factor in any oneof fields. - if prop.oneofSizer != nil { - m := structPointer_Interface(base, prop.stype).(Message) - n += prop.oneofSizer(m) - } - - return -} - -var zeroes [20]byte // longer than any conceivable sizeVarint - -// Encode a struct, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { - return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) -} - -// Encode something, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { - iLen := len(o.buf) - o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length - iMsg := len(o.buf) - err := enc() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - lMsg := len(o.buf) - iMsg - lLen := sizeVarint(uint64(lMsg)) - switch x := lLen - (iMsg - iLen); { - case x > 0: // actual length is x bytes larger than the space we reserved - // Move msg x bytes right. - o.buf = append(o.buf, zeroes[:x]...) - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - case x < 0: // actual length is x bytes smaller than the space we reserved - // Move msg x bytes left. - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - o.buf = o.buf[:len(o.buf)+x] // x is negative - } - // Encode the length in the reserved space. - o.buf = o.buf[:iLen] - o.EncodeVarint(uint64(lMsg)) - o.buf = o.buf[:len(o.buf)+lMsg] - return state.err -} - -// errorState maintains the first error that occurs and updates that error -// with additional context. -type errorState struct { - err error -} - -// shouldContinue reports whether encoding should continue upon encountering the -// given error. If the error is RequiredNotSetError, shouldContinue returns true -// and, if this is the first appearance of that error, remembers it for future -// reporting. -// -// If prop is not nil, it may update any error with additional context about the -// field with the error. -func (s *errorState) shouldContinue(err error, prop *Properties) bool { - // Ignore unset required fields. - reqNotSet, ok := err.(*RequiredNotSetError) - if !ok { - return false - } - if s.err == nil { - if prop != nil { - err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} - } - s.err = err - } - return true -} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go index 2ed1cf5966..f9b6e41b3c 100644 --- a/vendor/github.com/golang/protobuf/proto/equal.go +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -109,15 +109,6 @@ func equalStruct(v1, v2 reflect.Value) bool { // set/unset mismatch return false } - b1, ok := f1.Interface().(raw) - if ok { - b2 := f2.Interface().(raw) - // RawMessage - if !bytes.Equal(b1.Bytes(), b2.Bytes()) { - return false - } - continue - } f1, f2 = f1.Elem(), f2.Elem() } if !equalAny(f1, f2, sprop.Prop[i]) { @@ -146,11 +137,7 @@ func equalStruct(v1, v2 reflect.Value) bool { u1 := uf.Bytes() u2 := v2.FieldByName("XXX_unrecognized").Bytes() - if !bytes.Equal(u1, u2) { - return false - } - - return true + return bytes.Equal(u1, u2) } // v1 and v2 are known to have the same type. @@ -259,7 +246,17 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { return false } - m1, m2 := e1.value, e2.value + m1 := extensionAsLegacyType(e1.value) + m2 := extensionAsLegacyType(e2.value) + + if m1 == nil && m2 == nil { + // Both have only encoded form. + if bytes.Equal(e1.enc, e2.enc) { + continue + } + // The bytes are different, but the extensions might still be + // equal. We need to decode them to compare. + } if m1 != nil && m2 != nil { // Both are unencoded. @@ -276,8 +273,12 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { desc = m[extNum] } if desc == nil { + // If both have only encoded form and the bytes are the same, + // it is handled above. We get here when the bytes are different. + // We don't know how to decode it, so just compare them as byte + // slices. log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) - continue + return false } var err error if m1 == nil { diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go index eaad218312..fa88add30a 100644 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -38,6 +38,7 @@ package proto import ( "errors" "fmt" + "io" "reflect" "strconv" "sync" @@ -91,14 +92,29 @@ func (n notLocker) Unlock() {} // extendable returns the extendableProto interface for the given generated proto message. // If the proto message has the old extension format, it returns a wrapper that implements // the extendableProto interface. -func extendable(p interface{}) (extendableProto, bool) { - if ep, ok := p.(extendableProto); ok { - return ep, ok +func extendable(p interface{}) (extendableProto, error) { + switch p := p.(type) { + case extendableProto: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return p, nil + case extendableProtoV1: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return extensionAdapter{p}, nil } - if ep, ok := p.(extendableProtoV1); ok { - return extensionAdapter{ep}, ok - } - return nil, false + // Don't allocate a specific error containing %T: + // this is the hot path for Clone and MarshalText. + return nil, errNotExtendable +} + +var errNotExtendable = errors.New("proto: not an extendable proto.Message") + +func isNilPtr(x interface{}) bool { + v := reflect.ValueOf(x) + return v.Kind() == reflect.Ptr && v.IsNil() } // XXX_InternalExtensions is an internal representation of proto extensions. @@ -143,9 +159,6 @@ func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Loc return e.p.extensionMap, &e.p.mu } -var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() -var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() - // ExtensionDesc represents an extension specification. // Used in generated code from the protocol compiler. type ExtensionDesc struct { @@ -172,15 +185,31 @@ type Extension struct { // extension will have only enc set. When such an extension is // accessed using GetExtension (or GetExtensions) desc and value // will be set. - desc *ExtensionDesc + desc *ExtensionDesc + + // value is a concrete value for the extension field. Let the type of + // desc.ExtensionType be the "API type" and the type of Extension.value + // be the "storage type". The API type and storage type are the same except: + // * For scalars (except []byte), the API type uses *T, + // while the storage type uses T. + // * For repeated fields, the API type uses []T, while the storage type + // uses *[]T. + // + // The reason for the divergence is so that the storage type more naturally + // matches what is expected of when retrieving the values through the + // protobuf reflection APIs. + // + // The value may only be populated if desc is also populated. value interface{} - enc []byte + + // enc is the raw bytes for the extension field. + enc []byte } // SetRawExtension is for testing only. func SetRawExtension(base Message, id int32, b []byte) { - epb, ok := extendable(base) - if !ok { + epb, err := extendable(base) + if err != nil { return } extmap := epb.extensionsWrite() @@ -205,7 +234,7 @@ func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { pbi = ea.extendableProtoV1 } if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { - return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) + return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) } // Check the range. if !isExtensionField(pb, extension.Field) { @@ -250,85 +279,11 @@ func extensionProperties(ed *ExtensionDesc) *Properties { return prop } -// encode encodes any unmarshaled (unencoded) extensions in e. -func encodeExtensions(e *XXX_InternalExtensions) error { - m, mu := e.extensionsRead() - if m == nil { - return nil // fast path - } - mu.Lock() - defer mu.Unlock() - return encodeExtensionsMap(m) -} - -// encode encodes any unmarshaled (unencoded) extensions in e. -func encodeExtensionsMap(m map[int32]Extension) error { - for k, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - p := NewBuffer(nil) - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - if err := props.enc(p, props, toStructPointer(x)); err != nil { - return err - } - e.enc = p.buf - m[k] = e - } - return nil -} - -func extensionsSize(e *XXX_InternalExtensions) (n int) { - m, mu := e.extensionsRead() - if m == nil { - return 0 - } - mu.Lock() - defer mu.Unlock() - return extensionsMapSize(m) -} - -func extensionsMapSize(m map[int32]Extension) (n int) { - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - n += props.size(props, toStructPointer(x)) - } - return -} - // HasExtension returns whether the given extension is present in pb. func HasExtension(pb Message, extension *ExtensionDesc) bool { // TODO: Check types, field numbers, etc.? - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return false } extmap, mu := epb.extensionsRead() @@ -336,15 +291,15 @@ func HasExtension(pb Message, extension *ExtensionDesc) bool { return false } mu.Lock() - _, ok = extmap[extension.Field] + _, ok := extmap[extension.Field] mu.Unlock() return ok } // ClearExtension removes the given extension from pb. func ClearExtension(pb Message, extension *ExtensionDesc) { - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return } // TODO: Check types, field numbers, etc.? @@ -352,16 +307,26 @@ func ClearExtension(pb Message, extension *ExtensionDesc) { delete(extmap, extension.Field) } -// GetExtension parses and returns the given extension of pb. -// If the extension is not present and has no default value it returns ErrMissingExtension. +// GetExtension retrieves a proto2 extended field from pb. +// +// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), +// then GetExtension parses the encoded field and returns a Go value of the specified type. +// If the field is not present, then the default value is returned (if one is specified), +// otherwise ErrMissingExtension is reported. +// +// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil), +// then GetExtension returns the raw encoded bytes of the field extension. func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { - epb, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return nil, err } - if err := checkExtensionTypes(epb, extension); err != nil { - return nil, err + if extension.ExtendedType != nil { + // can only check type if this is a complete descriptor + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } } emap, mu := epb.extensionsRead() @@ -385,7 +350,12 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { // descriptors with the same field number. return nil, errors.New("proto: descriptor conflict") } - return e.value, nil + return extensionAsLegacyType(e.value), nil + } + + if extension.ExtensionType == nil { + // incomplete descriptor + return e.enc, nil } v, err := decodeExtension(e.enc, extension) @@ -395,16 +365,21 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { // Remember the decoded version and drop the encoded version. // That way it is safe to mutate what we return. - e.value = v + e.value = extensionAsStorageType(v) e.desc = extension e.enc = nil emap[extension.Field] = e - return e.value, nil + return extensionAsLegacyType(e.value), nil } // defaultExtensionValue returns the default value for extension. // If no default for an extension is defined ErrMissingExtension is returned. func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + if extension.ExtensionType == nil { + // incomplete descriptor, so no default + return nil, ErrMissingExtension + } + t := reflect.TypeOf(extension.ExtensionType) props := extensionProperties(extension) @@ -439,31 +414,28 @@ func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { // decodeExtension decodes an extension encoded in b. func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { - o := NewBuffer(b) - t := reflect.TypeOf(extension.ExtensionType) - - props := extensionProperties(extension) + unmarshal := typeUnmarshaler(t, extension.Tag) // t is a pointer to a struct, pointer to basic type or a slice. - // Allocate a "field" to store the pointer/slice itself; the - // pointer/slice will be stored here. We pass - // the address of this field to props.dec. - // This passes a zero field and a *t and lets props.dec - // interpret it as a *struct{ x t }. + // Allocate space to store the pointer/slice. value := reflect.New(t).Elem() + var err error for { - // Discard wire type and field number varint. It isn't needed. - if _, err := o.DecodeVarint(); err != nil { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + wire := int(x) & 7 + + b, err = unmarshal(b, valToPointer(value.Addr()), wire) + if err != nil { return nil, err } - if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { - return nil, err - } - - if o.index >= len(o.buf) { + if len(b) == 0 { break } } @@ -473,9 +445,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { // GetExtensions returns a slice of the extensions present in pb that are also listed in es. // The returned slice has the same length as es; missing extensions will appear as nil elements. func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return nil, err } extensions = make([]interface{}, len(es)) for i, e := range es { @@ -494,9 +466,9 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e // For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing // just the Field field, which defines the extension's field number. func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { - epb, ok := extendable(pb) - if !ok { - return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + epb, err := extendable(pb) + if err != nil { + return nil, err } registeredExtensions := RegisteredExtensions(pb) @@ -523,16 +495,16 @@ func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { // SetExtension sets the specified extension of pb to the specified value. func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { - epb, ok := extendable(pb) - if !ok { - return errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return err } if err := checkExtensionTypes(epb, extension); err != nil { return err } typ := reflect.TypeOf(extension.ExtensionType) if typ != reflect.TypeOf(value) { - return errors.New("proto: bad extension value type") + return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) } // nil extension values need to be caught early, because the // encoder can't distinguish an ErrNil due to a nil extension @@ -544,14 +516,14 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error } extmap := epb.extensionsWrite() - extmap[extension.Field] = Extension{desc: extension, value: value} + extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)} return nil } // ClearAllExtensions clears all extensions from pb. func ClearAllExtensions(pb Message) { - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return } m := epb.extensionsWrite() @@ -585,3 +557,51 @@ func RegisterExtension(desc *ExtensionDesc) { func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { return extensionMaps[reflect.TypeOf(pb).Elem()] } + +// extensionAsLegacyType converts an value in the storage type as the API type. +// See Extension.value. +func extensionAsLegacyType(v interface{}) interface{} { + switch rv := reflect.ValueOf(v); rv.Kind() { + case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: + // Represent primitive types as a pointer to the value. + rv2 := reflect.New(rv.Type()) + rv2.Elem().Set(rv) + v = rv2.Interface() + case reflect.Ptr: + // Represent slice types as the value itself. + switch rv.Type().Elem().Kind() { + case reflect.Slice: + if rv.IsNil() { + v = reflect.Zero(rv.Type().Elem()).Interface() + } else { + v = rv.Elem().Interface() + } + } + } + return v +} + +// extensionAsStorageType converts an value in the API type as the storage type. +// See Extension.value. +func extensionAsStorageType(v interface{}) interface{} { + switch rv := reflect.ValueOf(v); rv.Kind() { + case reflect.Ptr: + // Represent slice types as the value itself. + switch rv.Type().Elem().Kind() { + case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: + if rv.IsNil() { + v = reflect.Zero(rv.Type().Elem()).Interface() + } else { + v = rv.Elem().Interface() + } + } + case reflect.Slice: + // Represent slice types as a pointer to the value. + if rv.Type().Elem().Kind() != reflect.Uint8 { + rv2 := reflect.New(rv.Type()) + rv2.Elem().Set(rv) + v = rv2.Interface() + } + } + return v +} diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go index 1c225504a0..fdd328bb7f 100644 --- a/vendor/github.com/golang/protobuf/proto/lib.go +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -273,6 +273,67 @@ import ( "sync" ) +// RequiredNotSetError is an error type returned by either Marshal or Unmarshal. +// Marshal reports this when a required field is not initialized. +// Unmarshal reports this when a required field is missing from the wire data. +type RequiredNotSetError struct{ field string } + +func (e *RequiredNotSetError) Error() string { + if e.field == "" { + return fmt.Sprintf("proto: required field not set") + } + return fmt.Sprintf("proto: required field %q not set", e.field) +} +func (e *RequiredNotSetError) RequiredNotSet() bool { + return true +} + +type invalidUTF8Error struct{ field string } + +func (e *invalidUTF8Error) Error() string { + if e.field == "" { + return "proto: invalid UTF-8 detected" + } + return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) +} +func (e *invalidUTF8Error) InvalidUTF8() bool { + return true +} + +// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8. +// This error should not be exposed to the external API as such errors should +// be recreated with the field information. +var errInvalidUTF8 = &invalidUTF8Error{} + +// isNonFatal reports whether the error is either a RequiredNotSet error +// or a InvalidUTF8 error. +func isNonFatal(err error) bool { + if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { + return true + } + if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { + return true + } + return false +} + +type nonFatal struct{ E error } + +// Merge merges err into nf and reports whether it was successful. +// Otherwise it returns false for any fatal non-nil errors. +func (nf *nonFatal) Merge(err error) (ok bool) { + if err == nil { + return true // not an error + } + if !isNonFatal(err) { + return false // fatal error + } + if nf.E == nil { + nf.E = err // store first instance of non-fatal error + } + return true +} + // Message is implemented by generated protocol buffer messages. type Message interface { Reset() @@ -280,26 +341,6 @@ type Message interface { ProtoMessage() } -// Stats records allocation details about the protocol buffer encoders -// and decoders. Useful for tuning the library itself. -type Stats struct { - Emalloc uint64 // mallocs in encode - Dmalloc uint64 // mallocs in decode - Encode uint64 // number of encodes - Decode uint64 // number of decodes - Chit uint64 // number of cache hits - Cmiss uint64 // number of cache misses - Size uint64 // number of sizes -} - -// Set to true to enable stats collection. -const collectStats = false - -var stats Stats - -// GetStats returns a copy of the global Stats structure. -func GetStats() Stats { return stats } - // A Buffer is a buffer manager for marshaling and unmarshaling // protocol buffers. It may be reused between invocations to // reduce memory usage. It is not necessary to use a Buffer; @@ -309,16 +350,7 @@ type Buffer struct { buf []byte // encode/decode byte stream index int // read point - // pools of basic types to amortize allocation. - bools []bool - uint32s []uint32 - uint64s []uint64 - - // extra pools, only used with pointer_reflect.go - int32s []int32 - int64s []int64 - float32s []float32 - float64s []float64 + deterministic bool } // NewBuffer allocates a new Buffer and initializes its internal data to @@ -343,6 +375,30 @@ func (p *Buffer) SetBuf(s []byte) { // Bytes returns the contents of the Buffer. func (p *Buffer) Bytes() []byte { return p.buf } +// SetDeterministic sets whether to use deterministic serialization. +// +// Deterministic serialization guarantees that for a given binary, equal +// messages will always be serialized to the same bytes. This implies: +// +// - Repeated serialization of a message will return the same bytes. +// - Different processes of the same binary (which may be executing on +// different machines) will serialize equal messages to the same bytes. +// +// Note that the deterministic serialization is NOT canonical across +// languages. It is not guaranteed to remain stable over time. It is unstable +// across different builds with schema changes due to unknown fields. +// Users who need canonical serialization (e.g., persistent storage in a +// canonical form, fingerprinting, etc.) should define their own +// canonicalization specification and implement their own serializer rather +// than relying on this API. +// +// If deterministic serialization is requested, map entries will be sorted +// by keys in lexographical order. This is an implementation detail and +// subject to change. +func (p *Buffer) SetDeterministic(deterministic bool) { + p.deterministic = deterministic +} + /* * Helper routines for simplifying the creation of optional fields of basic type. */ @@ -831,22 +887,12 @@ func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMes return sf, false, nil } +// mapKeys returns a sort.Interface to be used for sorting the map keys. // Map fields may have key types of non-float scalars, strings and enums. -// The easiest way to sort them in some deterministic order is to use fmt. -// If this turns out to be inefficient we can always consider other options, -// such as doing a Schwartzian transform. - func mapKeys(vs []reflect.Value) sort.Interface { - s := mapKeySorter{ - vs: vs, - // default Less function: textual comparison - less: func(a, b reflect.Value) bool { - return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) - }, - } + s := mapKeySorter{vs: vs} - // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; - // numeric keys are sorted numerically. + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. if len(vs) == 0 { return s } @@ -855,6 +901,12 @@ func mapKeys(vs []reflect.Value) sort.Interface { s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } case reflect.Uint32, reflect.Uint64: s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + case reflect.Bool: + s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true + case reflect.String: + s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } + default: + panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) } return s @@ -888,10 +940,26 @@ func isProto3Zero(v reflect.Value) bool { return false } -// ProtoPackageIsVersion2 is referenced from generated protocol buffer files -// to assert that that code is compatible with this version of the proto package. -const ProtoPackageIsVersion2 = true +const ( + // ProtoPackageIsVersion3 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + ProtoPackageIsVersion3 = true -// ProtoPackageIsVersion1 is referenced from generated protocol buffer files -// to assert that that code is compatible with this version of the proto package. -const ProtoPackageIsVersion1 = true + // ProtoPackageIsVersion2 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + ProtoPackageIsVersion2 = true + + // ProtoPackageIsVersion1 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + ProtoPackageIsVersion1 = true +) + +// InternalMessageInfo is a type used internally by generated .pb.go files. +// This type is not intended to be used by non-generated code. +// This type is not subject to any compatibility guarantee. +type InternalMessageInfo struct { + marshal *marshalInfo + unmarshal *unmarshalInfo + merge *mergeInfo + discard *discardInfo +} diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go index fd982decd6..f48a756761 100644 --- a/vendor/github.com/golang/protobuf/proto/message_set.go +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -36,12 +36,7 @@ package proto */ import ( - "bytes" - "encoding/json" "errors" - "fmt" - "reflect" - "sort" ) // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. @@ -94,10 +89,7 @@ func (ms *messageSet) find(pb Message) *_MessageSet_Item { } func (ms *messageSet) Has(pb Message) bool { - if ms.find(pb) != nil { - return true - } - return false + return ms.find(pb) != nil } func (ms *messageSet) Unmarshal(pb Message) error { @@ -147,50 +139,9 @@ func skipVarint(buf []byte) []byte { return buf[i+1:] } -// MarshalMessageSet encodes the extension map represented by m in the message set wire format. -// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSet(exts interface{}) ([]byte, error) { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - if err := encodeExtensions(exts); err != nil { - return nil, err - } - m, _ = exts.extensionsRead() - case map[int32]Extension: - if err := encodeExtensionsMap(exts); err != nil { - return nil, err - } - m = exts - default: - return nil, errors.New("proto: not an extension map") - } - - // Sort extension IDs to provide a deterministic encoding. - // See also enc_map in encode.go. - ids := make([]int, 0, len(m)) - for id := range m { - ids = append(ids, int(id)) - } - sort.Ints(ids) - - ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} - for _, id := range ids { - e := m[int32(id)] - // Remove the wire type and field number varint, as well as the length varint. - msg := skipVarint(skipVarint(e.enc)) - - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: Int32(int32(id)), - Message: msg, - }) - } - return Marshal(ms) -} - -// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. -// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSet(buf []byte, exts interface{}) error { +// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func unmarshalMessageSet(buf []byte, exts interface{}) error { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: @@ -228,84 +179,3 @@ func UnmarshalMessageSet(buf []byte, exts interface{}) error { } return nil } - -// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. -// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - m, _ = exts.extensionsRead() - case map[int32]Extension: - m = exts - default: - return nil, errors.New("proto: not an extension map") - } - var b bytes.Buffer - b.WriteByte('{') - - // Process the map in key order for deterministic output. - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) // int32Slice defined in text.go - - for i, id := range ids { - ext := m[id] - if i > 0 { - b.WriteByte(',') - } - - msd, ok := messageSetMap[id] - if !ok { - // Unknown type; we can't render it, so skip it. - continue - } - fmt.Fprintf(&b, `"[%s]":`, msd.name) - - x := ext.value - if x == nil { - x = reflect.New(msd.t.Elem()).Interface() - if err := Unmarshal(ext.enc, x.(Message)); err != nil { - return nil, err - } - } - d, err := json.Marshal(x) - if err != nil { - return nil, err - } - b.Write(d) - } - b.WriteByte('}') - return b.Bytes(), nil -} - -// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. -// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { - // Common-case fast path. - if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { - return nil - } - - // This is fairly tricky, and it's not clear that it is needed. - return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") -} - -// A global registry of types that can be used in a MessageSet. - -var messageSetMap = make(map[int32]messageSetDesc) - -type messageSetDesc struct { - t reflect.Type // pointer to struct - name string -} - -// RegisterMessageSetType is called from the generated code. -func RegisterMessageSetType(m Message, fieldNum int32, name string) { - messageSetMap[fieldNum] = messageSetDesc{ - t: reflect.TypeOf(m), - name: name, - } -} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go index fb512e2e16..94fa9194a8 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build appengine js +// +build purego appengine js // This file contains an implementation of proto field accesses using package reflect. // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can @@ -38,32 +38,13 @@ package proto import ( - "math" "reflect" + "sync" ) -// A structPointer is a pointer to a struct. -type structPointer struct { - v reflect.Value -} +const unsafeAllowed = false -// toStructPointer returns a structPointer equivalent to the given reflect value. -// The reflect value must itself be a pointer to a struct. -func toStructPointer(v reflect.Value) structPointer { - return structPointer{v} -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p.v.IsNil() -} - -// Interface returns the struct pointer as an interface value. -func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { - return p.v.Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. +// A field identifies a field in a struct, accessible from a pointer. // In this implementation, a field is identified by the sequence of field indices // passed to reflect's FieldByIndex. type field []int @@ -76,409 +57,304 @@ func toField(f *reflect.StructField) field { // invalidField is an invalid field identifier. var invalidField = field(nil) +// zeroField is a noop when calling pointer.offset. +var zeroField = field([]int{}) + // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { return f != nil } -// field returns the given field in the struct as a reflect value. -func structPointer_field(p structPointer, f field) reflect.Value { - // Special case: an extension map entry with a value of type T - // passes a *T to the struct-handling code with a zero field, - // expecting that it will be treated as equivalent to *struct{ X T }, - // which has the same memory layout. We have to handle that case - // specially, because reflect will panic if we call FieldByIndex on a - // non-struct. - if f == nil { - return p.v.Elem() +// The pointer type is for the table-driven decoder. +// The implementation here uses a reflect.Value of pointer type to +// create a generic pointer. In pointer_unsafe.go we use unsafe +// instead of reflect to implement the same (but faster) interface. +type pointer struct { + v reflect.Value +} + +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + return pointer{v: reflect.ValueOf(*i)} +} + +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr, deref bool) pointer { + v := reflect.ValueOf(*i) + u := reflect.New(v.Type()) + u.Elem().Set(v) + if deref { + u = u.Elem() } - - return p.v.Elem().FieldByIndex(f) + return pointer{v: u} } -// ifield returns the given field in the struct as an interface value. -func structPointer_ifield(p structPointer, f field) interface{} { - return structPointer_field(p, f).Addr().Interface() +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{v: v} } -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return structPointer_ifield(p, f).(*[]byte) +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} } -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return structPointer_ifield(p, f).(*[][]byte) -} - -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return structPointer_ifield(p, f).(**bool) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return structPointer_ifield(p, f).(*bool) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return structPointer_ifield(p, f).(*[]bool) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return structPointer_ifield(p, f).(**string) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return structPointer_ifield(p, f).(*string) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return structPointer_ifield(p, f).(*[]string) -} - -// Extensions returns the address of an extension map field in the struct. -func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { - return structPointer_ifield(p, f).(*XXX_InternalExtensions) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return structPointer_ifield(p, f).(*map[int32]Extension) -} - -// NewAt returns the reflect.Value for a pointer to a field in the struct. -func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { - return structPointer_field(p, f).Addr() -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - structPointer_field(p, f).Set(q.v) -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return structPointer{structPointer_field(p, f)} -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { - return structPointerSlice{structPointer_field(p, f)} -} - -// A structPointerSlice represents the address of a slice of pointers to structs -// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. -type structPointerSlice struct { - v reflect.Value -} - -func (p structPointerSlice) Len() int { return p.v.Len() } -func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } -func (p structPointerSlice) Append(q structPointer) { - p.v.Set(reflect.Append(p.v, q.v)) -} - -var ( - int32Type = reflect.TypeOf(int32(0)) - uint32Type = reflect.TypeOf(uint32(0)) - float32Type = reflect.TypeOf(float32(0)) - int64Type = reflect.TypeOf(int64(0)) - uint64Type = reflect.TypeOf(uint64(0)) - float64Type = reflect.TypeOf(float64(0)) -) - -// A word32 represents a field of type *int32, *uint32, *float32, or *enum. -// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. -type word32 struct { - v reflect.Value -} - -// IsNil reports whether p is nil. -func word32_IsNil(p word32) bool { +func (p pointer) isNil() bool { return p.v.IsNil() } -// Set sets p to point at a newly allocated word with bits set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - t := p.v.Type().Elem() - switch t { - case int32Type: - if len(o.int32s) == 0 { - o.int32s = make([]int32, uint32PoolSize) - } - o.int32s[0] = int32(x) - p.v.Set(reflect.ValueOf(&o.int32s[0])) - o.int32s = o.int32s[1:] - return - case uint32Type: - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) - } - o.uint32s[0] = x - p.v.Set(reflect.ValueOf(&o.uint32s[0])) - o.uint32s = o.uint32s[1:] - return - case float32Type: - if len(o.float32s) == 0 { - o.float32s = make([]float32, uint32PoolSize) - } - o.float32s[0] = math.Float32frombits(x) - p.v.Set(reflect.ValueOf(&o.float32s[0])) - o.float32s = o.float32s[1:] - return - } - - // must be enum - p.v.Set(reflect.New(t)) - p.v.Elem().SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32_Get(p word32) uint32 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32{structPointer_field(p, f)} -} - -// A word32Val represents a field of type int32, uint32, float32, or enum. -// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. -type word32Val struct { - v reflect.Value -} - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - switch p.v.Type() { - case int32Type: - p.v.SetInt(int64(x)) - return - case uint32Type: - p.v.SetUint(uint64(x)) - return - case float32Type: - p.v.SetFloat(float64(math.Float32frombits(x))) - return - } - - // must be enum - p.v.SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32Val_Get(p word32Val) uint32 { - elem := p.v - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val{structPointer_field(p, f)} -} - -// A word32Slice is a slice of 32-bit values. -// That is, v.Type() is []int32, []uint32, []float32, or []enum. -type word32Slice struct { - v reflect.Value -} - -func (p word32Slice) Append(x uint32) { - n, m := p.v.Len(), p.v.Cap() +// grow updates the slice s in place to make it one element longer. +// s must be addressable. +// Returns the (addressable) new element. +func grow(s reflect.Value) reflect.Value { + n, m := s.Len(), s.Cap() if n < m { - p.v.SetLen(n + 1) + s.SetLen(n + 1) } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int32: - elem.SetInt(int64(int32(x))) - case reflect.Uint32: - elem.SetUint(uint64(x)) - case reflect.Float32: - elem.SetFloat(float64(math.Float32frombits(x))) + return s.Index(n) +} + +func (p pointer) toInt64() *int64 { + return p.v.Interface().(*int64) +} +func (p pointer) toInt64Ptr() **int64 { + return p.v.Interface().(**int64) +} +func (p pointer) toInt64Slice() *[]int64 { + return p.v.Interface().(*[]int64) +} + +var int32ptr = reflect.TypeOf((*int32)(nil)) + +func (p pointer) toInt32() *int32 { + return p.v.Convert(int32ptr).Interface().(*int32) +} + +// The toInt32Ptr/Slice methods don't work because of enums. +// Instead, we must use set/get methods for the int32ptr/slice case. +/* + func (p pointer) toInt32Ptr() **int32 { + return p.v.Interface().(**int32) +} + func (p pointer) toInt32Slice() *[]int32 { + return p.v.Interface().(*[]int32) +} +*/ +func (p pointer) getInt32Ptr() *int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().(*int32) } + // an enum + return p.v.Elem().Convert(int32PtrType).Interface().(*int32) +} +func (p pointer) setInt32Ptr(v int32) { + // Allocate value in a *int32. Possibly convert that to a *enum. + // Then assign it to a **int32 or **enum. + // Note: we can convert *int32 to *enum, but we can't convert + // **int32 to **enum! + p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) } -func (p word32Slice) Len() int { - return p.v.Len() -} - -func (p word32Slice) Index(i int) uint32 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) +// getInt32Slice copies []int32 from p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getInt32Slice() []int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().([]int32) } - panic("unreachable") + // an enum + // Allocate a []int32, then assign []enum's values into it. + // Note: we can't convert []enum to []int32. + slice := p.v.Elem() + s := make([]int32, slice.Len()) + for i := 0; i < slice.Len(); i++ { + s[i] = int32(slice.Index(i).Int()) + } + return s } -// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) word32Slice { - return word32Slice{structPointer_field(p, f)} -} - -// word64 is like word32 but for 64-bit values. -type word64 struct { - v reflect.Value -} - -func word64_Set(p word64, o *Buffer, x uint64) { - t := p.v.Type().Elem() - switch t { - case int64Type: - if len(o.int64s) == 0 { - o.int64s = make([]int64, uint64PoolSize) - } - o.int64s[0] = int64(x) - p.v.Set(reflect.ValueOf(&o.int64s[0])) - o.int64s = o.int64s[1:] - return - case uint64Type: - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) - } - o.uint64s[0] = x - p.v.Set(reflect.ValueOf(&o.uint64s[0])) - o.uint64s = o.uint64s[1:] - return - case float64Type: - if len(o.float64s) == 0 { - o.float64s = make([]float64, uint64PoolSize) - } - o.float64s[0] = math.Float64frombits(x) - p.v.Set(reflect.ValueOf(&o.float64s[0])) - o.float64s = o.float64s[1:] +// setInt32Slice copies []int32 into p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setInt32Slice(v []int32) { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + p.v.Elem().Set(reflect.ValueOf(v)) return } - panic("unreachable") -} - -func word64_IsNil(p word64) bool { - return p.v.IsNil() -} - -func word64_Get(p word64) uint64 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) + // an enum + // Allocate a []enum, then assign []int32's values into it. + // Note: we can't convert []enum to []int32. + slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) + for i, x := range v { + slice.Index(i).SetInt(int64(x)) } - panic("unreachable") + p.v.Elem().Set(slice) +} +func (p pointer) appendInt32Slice(v int32) { + grow(p.v.Elem()).SetInt(int64(v)) } -func structPointer_Word64(p structPointer, f field) word64 { - return word64{structPointer_field(p, f)} +func (p pointer) toUint64() *uint64 { + return p.v.Interface().(*uint64) +} +func (p pointer) toUint64Ptr() **uint64 { + return p.v.Interface().(**uint64) +} +func (p pointer) toUint64Slice() *[]uint64 { + return p.v.Interface().(*[]uint64) +} +func (p pointer) toUint32() *uint32 { + return p.v.Interface().(*uint32) +} +func (p pointer) toUint32Ptr() **uint32 { + return p.v.Interface().(**uint32) +} +func (p pointer) toUint32Slice() *[]uint32 { + return p.v.Interface().(*[]uint32) +} +func (p pointer) toBool() *bool { + return p.v.Interface().(*bool) +} +func (p pointer) toBoolPtr() **bool { + return p.v.Interface().(**bool) +} +func (p pointer) toBoolSlice() *[]bool { + return p.v.Interface().(*[]bool) +} +func (p pointer) toFloat64() *float64 { + return p.v.Interface().(*float64) +} +func (p pointer) toFloat64Ptr() **float64 { + return p.v.Interface().(**float64) +} +func (p pointer) toFloat64Slice() *[]float64 { + return p.v.Interface().(*[]float64) +} +func (p pointer) toFloat32() *float32 { + return p.v.Interface().(*float32) +} +func (p pointer) toFloat32Ptr() **float32 { + return p.v.Interface().(**float32) +} +func (p pointer) toFloat32Slice() *[]float32 { + return p.v.Interface().(*[]float32) +} +func (p pointer) toString() *string { + return p.v.Interface().(*string) +} +func (p pointer) toStringPtr() **string { + return p.v.Interface().(**string) +} +func (p pointer) toStringSlice() *[]string { + return p.v.Interface().(*[]string) +} +func (p pointer) toBytes() *[]byte { + return p.v.Interface().(*[]byte) +} +func (p pointer) toBytesSlice() *[][]byte { + return p.v.Interface().(*[][]byte) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return p.v.Interface().(*XXX_InternalExtensions) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return p.v.Interface().(*map[int32]Extension) +} +func (p pointer) getPointer() pointer { + return pointer{v: p.v.Elem()} +} +func (p pointer) setPointer(q pointer) { + p.v.Elem().Set(q.v) +} +func (p pointer) appendPointer(q pointer) { + grow(p.v.Elem()).Set(q.v) } -// word64Val is like word32Val but for 64-bit values. -type word64Val struct { - v reflect.Value +// getPointerSlice copies []*T from p as a new []pointer. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getPointerSlice() []pointer { + if p.v.IsNil() { + return nil + } + n := p.v.Elem().Len() + s := make([]pointer, n) + for i := 0; i < n; i++ { + s[i] = pointer{v: p.v.Elem().Index(i)} + } + return s } -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - switch p.v.Type() { - case int64Type: - p.v.SetInt(int64(x)) - return - case uint64Type: - p.v.SetUint(x) - return - case float64Type: - p.v.SetFloat(math.Float64frombits(x)) +// setPointerSlice copies []pointer into p as a new []*T. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setPointerSlice(v []pointer) { + if v == nil { + p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) return } - panic("unreachable") -} - -func word64Val_Get(p word64Val) uint64 { - elem := p.v - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) + s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) + for _, p := range v { + s = reflect.Append(s, p.v) } - panic("unreachable") + p.v.Elem().Set(s) } -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val{structPointer_field(p, f)} -} - -type word64Slice struct { - v reflect.Value -} - -func (p word64Slice) Append(x uint64) { - n, m := p.v.Len(), p.v.Cap() - if n < m { - p.v.SetLen(n + 1) - } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) - } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int64: - elem.SetInt(int64(int64(x))) - case reflect.Uint64: - elem.SetUint(uint64(x)) - case reflect.Float64: - elem.SetFloat(float64(math.Float64frombits(x))) +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + if p.v.Elem().IsNil() { + return pointer{v: p.v.Elem()} } + return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct } -func (p word64Slice) Len() int { - return p.v.Len() +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + // TODO: check that p.v.Type().Elem() == t? + return p.v } -func (p word64Slice) Index(i int) uint64 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return uint64(elem.Uint()) - case reflect.Float64: - return math.Float64bits(float64(elem.Float())) - } - panic("unreachable") +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v } -func structPointer_Word64Slice(p structPointer, f field) word64Slice { - return word64Slice{structPointer_field(p, f)} -} +var atomicLock sync.Mutex diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go index 6b5567d47c..dbfffe071b 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -29,7 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build !appengine,!js +// +build !purego,!appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. @@ -37,38 +37,13 @@ package proto import ( "reflect" + "sync/atomic" "unsafe" ) -// NOTE: These type_Foo functions would more idiomatically be methods, -// but Go does not allow methods on pointer types, and we must preserve -// some pointer type for the garbage collector. We use these -// funcs with clunky names as our poor approximation to methods. -// -// An alternative would be -// type structPointer struct { p unsafe.Pointer } -// but that does not registerize as well. +const unsafeAllowed = true -// A structPointer is a pointer to a struct. -type structPointer unsafe.Pointer - -// toStructPointer returns a structPointer equivalent to the given reflect value. -func toStructPointer(v reflect.Value) structPointer { - return structPointer(unsafe.Pointer(v.Pointer())) -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p == nil -} - -// Interface returns the struct pointer, assumed to have element type t, -// as an interface value. -func structPointer_Interface(p structPointer, t reflect.Type) interface{} { - return reflect.NewAt(t, unsafe.Pointer(p)).Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. +// A field identifies a field in a struct, accessible from a pointer. // In this implementation, a field is identified by its byte offset from the start of the struct. type field uintptr @@ -80,191 +55,259 @@ func toField(f *reflect.StructField) field { // invalidField is an invalid field identifier. const invalidField = ^field(0) +// zeroField is a noop when calling pointer.offset. +const zeroField = field(0) + // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { - return f != ^field(0) + return f != invalidField } -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +// The pointer type below is for the new table-driven encoder/decoder. +// The implementation here uses unsafe.Pointer to create a generic pointer. +// In pointer_reflect.go we use reflect instead of unsafe to implement +// the same (but slower) interface. +type pointer struct { + p unsafe.Pointer } -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +// size of pointer +var ptrSize = unsafe.Sizeof(uintptr(0)) + +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + // Super-tricky - read pointer out of data word of interface value. + // Saves ~25ns over the equivalent: + // return valToPointer(reflect.ValueOf(*i)) + return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} } -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { - return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// NewAt returns the reflect.Value for a pointer to a field in the struct. -func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { - return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { - return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). -type structPointerSlice []structPointer - -func (v *structPointerSlice) Len() int { return len(*v) } -func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } -func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } - -// A word32 is the address of a "pointer to 32-bit value" field. -type word32 **uint32 - -// IsNil reports whether *v is nil. -func word32_IsNil(p word32) bool { - return *p == nil -} - -// Set sets *v to point at a newly allocated word set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) { + // Super-tricky - read or get the address of data word of interface value. + if isptr { + // The interface is of pointer type, thus it is a direct interface. + // The data word is the pointer data itself. We take its address. + p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} + } else { + // The interface is not of pointer type. The data word is the pointer + // to the data. + p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} } - o.uint32s[0] = x - *p = &o.uint32s[0] - o.uint32s = o.uint32s[1:] -} - -// Get gets the value pointed at by *v. -func word32_Get(p word32) uint32 { - return **p -} - -// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// A word32Val is the address of a 32-bit value field. -type word32Val *uint32 - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - *p = x -} - -// Get gets the value pointed at by p. -func word32Val_Get(p word32Val) uint32 { - return *p -} - -// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// A word32Slice is a slice of 32-bit values. -type word32Slice []uint32 - -func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } -func (v *word32Slice) Len() int { return len(*v) } -func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } - -// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) *word32Slice { - return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// word64 is like word32 but for 64-bit values. -type word64 **uint64 - -func word64_Set(p word64, o *Buffer, x uint64) { - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) + if deref { + p.p = *(*unsafe.Pointer)(p.p) } - o.uint64s[0] = x - *p = &o.uint64s[0] - o.uint64s = o.uint64s[1:] + return p } -func word64_IsNil(p word64) bool { - return *p == nil +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{p: unsafe.Pointer(v.Pointer())} } -func word64_Get(p word64) uint64 { - return **p +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + // For safety, we should panic if !f.IsValid, however calling panic causes + // this to no longer be inlineable, which is a serious performance cost. + /* + if !f.IsValid() { + panic("invalid field") + } + */ + return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} } -func structPointer_Word64(p structPointer, f field) word64 { - return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +func (p pointer) isNil() bool { + return p.p == nil } -// word64Val is like word32Val but for 64-bit values. -type word64Val *uint64 - -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - *p = x +func (p pointer) toInt64() *int64 { + return (*int64)(p.p) +} +func (p pointer) toInt64Ptr() **int64 { + return (**int64)(p.p) +} +func (p pointer) toInt64Slice() *[]int64 { + return (*[]int64)(p.p) +} +func (p pointer) toInt32() *int32 { + return (*int32)(p.p) } -func word64Val_Get(p word64Val) uint64 { - return *p +// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. +/* + func (p pointer) toInt32Ptr() **int32 { + return (**int32)(p.p) + } + func (p pointer) toInt32Slice() *[]int32 { + return (*[]int32)(p.p) + } +*/ +func (p pointer) getInt32Ptr() *int32 { + return *(**int32)(p.p) +} +func (p pointer) setInt32Ptr(v int32) { + *(**int32)(p.p) = &v } -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +// getInt32Slice loads a []int32 from p. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getInt32Slice() []int32 { + return *(*[]int32)(p.p) } -// word64Slice is like word32Slice but for 64-bit values. -type word64Slice []uint64 - -func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } -func (v *word64Slice) Len() int { return len(*v) } -func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } - -func structPointer_Word64Slice(p structPointer, f field) *word64Slice { - return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +// setInt32Slice stores a []int32 to p. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setInt32Slice(v []int32) { + *(*[]int32)(p.p) = v +} + +// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? +func (p pointer) appendInt32Slice(v int32) { + s := (*[]int32)(p.p) + *s = append(*s, v) +} + +func (p pointer) toUint64() *uint64 { + return (*uint64)(p.p) +} +func (p pointer) toUint64Ptr() **uint64 { + return (**uint64)(p.p) +} +func (p pointer) toUint64Slice() *[]uint64 { + return (*[]uint64)(p.p) +} +func (p pointer) toUint32() *uint32 { + return (*uint32)(p.p) +} +func (p pointer) toUint32Ptr() **uint32 { + return (**uint32)(p.p) +} +func (p pointer) toUint32Slice() *[]uint32 { + return (*[]uint32)(p.p) +} +func (p pointer) toBool() *bool { + return (*bool)(p.p) +} +func (p pointer) toBoolPtr() **bool { + return (**bool)(p.p) +} +func (p pointer) toBoolSlice() *[]bool { + return (*[]bool)(p.p) +} +func (p pointer) toFloat64() *float64 { + return (*float64)(p.p) +} +func (p pointer) toFloat64Ptr() **float64 { + return (**float64)(p.p) +} +func (p pointer) toFloat64Slice() *[]float64 { + return (*[]float64)(p.p) +} +func (p pointer) toFloat32() *float32 { + return (*float32)(p.p) +} +func (p pointer) toFloat32Ptr() **float32 { + return (**float32)(p.p) +} +func (p pointer) toFloat32Slice() *[]float32 { + return (*[]float32)(p.p) +} +func (p pointer) toString() *string { + return (*string)(p.p) +} +func (p pointer) toStringPtr() **string { + return (**string)(p.p) +} +func (p pointer) toStringSlice() *[]string { + return (*[]string)(p.p) +} +func (p pointer) toBytes() *[]byte { + return (*[]byte)(p.p) +} +func (p pointer) toBytesSlice() *[][]byte { + return (*[][]byte)(p.p) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(p.p) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return (*map[int32]Extension)(p.p) +} + +// getPointerSlice loads []*T from p as a []pointer. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getPointerSlice() []pointer { + // Super-tricky - p should point to a []*T where T is a + // message type. We load it as []pointer. + return *(*[]pointer)(p.p) +} + +// setPointerSlice stores []pointer into p as a []*T. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setPointerSlice(v []pointer) { + // Super-tricky - p should point to a []*T where T is a + // message type. We store it as []pointer. + *(*[]pointer)(p.p) = v +} + +// getPointer loads the pointer at p and returns it. +func (p pointer) getPointer() pointer { + return pointer{p: *(*unsafe.Pointer)(p.p)} +} + +// setPointer stores the pointer q at p. +func (p pointer) setPointer(q pointer) { + *(*unsafe.Pointer)(p.p) = q.p +} + +// append q to the slice pointed to by p. +func (p pointer) appendPointer(q pointer) { + s := (*[]unsafe.Pointer)(p.p) + *s = append(*s, q.p) +} + +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + // Super-tricky - read pointer out of data word of interface value. + return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} +} + +// asPointerTo returns a reflect.Value that is a pointer to an +// object of type t stored at p. +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + return reflect.NewAt(t, p.p) +} + +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) } diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go index ec2289c005..a4b8c0cd3a 100644 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -38,7 +38,6 @@ package proto import ( "fmt" "log" - "os" "reflect" "sort" "strconv" @@ -58,42 +57,6 @@ const ( WireFixed32 = 5 ) -const startSize = 10 // initial slice/string sizes - -// Encoders are defined in encode.go -// An encoder outputs the full representation of a field, including its -// tag and encoder type. -type encoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueEncoder encodes a single integer in a particular encoding. -type valueEncoder func(o *Buffer, x uint64) error - -// Sizers are defined in encode.go -// A sizer returns the encoded size of a field, including its tag and encoder -// type. -type sizer func(prop *Properties, base structPointer) int - -// A valueSizer returns the encoded size of a single integer in a particular -// encoding. -type valueSizer func(x uint64) int - -// Decoders are defined in decode.go -// A decoder creates a value from its wire representation. -// Unrecognized subelements are saved in unrec. -type decoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueDecoder decodes a single integer in a particular encoding. -type valueDecoder func(o *Buffer) (x uint64, err error) - -// A oneofMarshaler does the marshaling for all oneof fields in a message. -type oneofMarshaler func(Message, *Buffer) error - -// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. -type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) - -// A oneofSizer does the sizing for all oneof fields in a message. -type oneofSizer func(Message) int - // tagMap is an optimization over map[int]int for typical protocol buffer // use-cases. Encoded protocol buffers are often in tag order with small tag // numbers. @@ -140,13 +103,6 @@ type StructProperties struct { decoderTags tagMap // map from proto tag to struct field number decoderOrigNames map[string]int // map from original name to struct field number order []int // list of struct field numbers in tag order - unrecField field // field id of the XXX_unrecognized []byte field - extendable bool // is this an extendable proto - - oneofMarshaler oneofMarshaler - oneofUnmarshaler oneofUnmarshaler - oneofSizer oneofSizer - stype reflect.Type // OneofTypes contains information about the oneof fields in this message. // It is keyed by the original name of a field. @@ -182,41 +138,24 @@ type Properties struct { Repeated bool Packed bool // relevant for repeated primitives only Enum string // set for enum types only - proto3 bool // whether this is known to be a proto3 field; set for []byte only + proto3 bool // whether this is known to be a proto3 field oneof bool // whether this is a oneof field Default string // default value HasDefault bool // whether an explicit default was provided - def_uint64 uint64 - enc encoder - valEnc valueEncoder // set for bool and numeric types only - field field - tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) - tagbuf [8]byte - stype reflect.Type // set for struct types only - sprop *StructProperties // set for struct types only - isMarshaler bool - isUnmarshaler bool + stype reflect.Type // set for struct types only + sprop *StructProperties // set for struct types only - mtype reflect.Type // set for map types only - mkeyprop *Properties // set for map types only - mvalprop *Properties // set for map types only - - size sizer - valSize valueSizer // set for bool and numeric types only - - dec decoder - valDec valueDecoder // set for bool and numeric types only - - // If this is a packable field, this will be the decoder for the packed version of the field. - packedDec decoder + mtype reflect.Type // set for map types only + MapKeyProp *Properties // set for map types only + MapValProp *Properties // set for map types only } // String formats the properties in the protobuf struct field tag style. func (p *Properties) String() string { s := p.Wire - s = "," + s += "," s += strconv.Itoa(p.Tag) if p.Required { s += ",req" @@ -254,7 +193,7 @@ func (p *Properties) Parse(s string) { // "bytes,49,opt,name=foo,def=hello!" fields := strings.Split(s, ",") // breaks def=, but handled below. if len(fields) < 2 { - fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) + log.Printf("proto: tag has too few fields: %q", s) return } @@ -262,34 +201,19 @@ func (p *Properties) Parse(s string) { switch p.Wire { case "varint": p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeVarint - p.valDec = (*Buffer).DecodeVarint - p.valSize = sizeVarint case "fixed32": p.WireType = WireFixed32 - p.valEnc = (*Buffer).EncodeFixed32 - p.valDec = (*Buffer).DecodeFixed32 - p.valSize = sizeFixed32 case "fixed64": p.WireType = WireFixed64 - p.valEnc = (*Buffer).EncodeFixed64 - p.valDec = (*Buffer).DecodeFixed64 - p.valSize = sizeFixed64 case "zigzag32": p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag32 - p.valDec = (*Buffer).DecodeZigzag32 - p.valSize = sizeZigzag32 case "zigzag64": p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag64 - p.valDec = (*Buffer).DecodeZigzag64 - p.valSize = sizeZigzag64 case "bytes", "group": p.WireType = WireBytes // no numeric converter for non-numeric types default: - fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) + log.Printf("proto: tag has unknown wire type: %q", s) return } @@ -299,6 +223,7 @@ func (p *Properties) Parse(s string) { return } +outer: for i := 2; i < len(fields); i++ { f := fields[i] switch { @@ -326,256 +251,41 @@ func (p *Properties) Parse(s string) { if i+1 < len(fields) { // Commas aren't escaped, and def is always last. p.Default += "," + strings.Join(fields[i+1:], ",") - break + break outer } } } } -func logNoSliceEnc(t1, t2 reflect.Type) { - fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) -} - var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() -// Initialize the fields for encoding and decoding. -func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { - p.enc = nil - p.dec = nil - p.size = nil - +// setFieldProps initializes the field properties for submessages and maps. +func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { switch t1 := typ; t1.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) - - // proto3 scalar types - - case reflect.Bool: - p.enc = (*Buffer).enc_proto3_bool - p.dec = (*Buffer).dec_proto3_bool - p.size = size_proto3_bool - case reflect.Int32: - p.enc = (*Buffer).enc_proto3_int32 - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_proto3_uint32 - p.dec = (*Buffer).dec_proto3_int32 // can reuse - p.size = size_proto3_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_proto3_int64 - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.String: - p.enc = (*Buffer).enc_proto3_string - p.dec = (*Buffer).dec_proto3_string - p.size = size_proto3_string - case reflect.Ptr: - switch t2 := t1.Elem(); t2.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) - break - case reflect.Bool: - p.enc = (*Buffer).enc_bool - p.dec = (*Buffer).dec_bool - p.size = size_bool - case reflect.Int32: - p.enc = (*Buffer).enc_int32 - p.dec = (*Buffer).dec_int32 - p.size = size_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_uint32 - p.dec = (*Buffer).dec_int32 // can reuse - p.size = size_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_int64 - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_int32 - p.size = size_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_int64 // can just treat them as bits - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.String: - p.enc = (*Buffer).enc_string - p.dec = (*Buffer).dec_string - p.size = size_string - case reflect.Struct: + if t1.Elem().Kind() == reflect.Struct { p.stype = t1.Elem() - p.isMarshaler = isMarshaler(t1) - p.isUnmarshaler = isUnmarshaler(t1) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_struct_message - p.dec = (*Buffer).dec_struct_message - p.size = size_struct_message - } else { - p.enc = (*Buffer).enc_struct_group - p.dec = (*Buffer).dec_struct_group - p.size = size_struct_group - } } case reflect.Slice: - switch t2 := t1.Elem(); t2.Kind() { - default: - logNoSliceEnc(t1, t2) - break - case reflect.Bool: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_bool - p.size = size_slice_packed_bool - } else { - p.enc = (*Buffer).enc_slice_bool - p.size = size_slice_bool - } - p.dec = (*Buffer).dec_slice_bool - p.packedDec = (*Buffer).dec_slice_packed_bool - case reflect.Int32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int32 - p.size = size_slice_packed_int32 - } else { - p.enc = (*Buffer).enc_slice_int32 - p.size = size_slice_int32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Uint32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Int64, reflect.Uint64: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - case reflect.Uint8: - p.dec = (*Buffer).dec_slice_byte - if p.proto3 { - p.enc = (*Buffer).enc_proto3_slice_byte - p.size = size_proto3_slice_byte - } else { - p.enc = (*Buffer).enc_slice_byte - p.size = size_slice_byte - } - case reflect.Float32, reflect.Float64: - switch t2.Bits() { - case 32: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case 64: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - default: - logNoSliceEnc(t1, t2) - break - } - case reflect.String: - p.enc = (*Buffer).enc_slice_string - p.dec = (*Buffer).dec_slice_string - p.size = size_slice_string - case reflect.Ptr: - switch t3 := t2.Elem(); t3.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) - break - case reflect.Struct: - p.stype = t2.Elem() - p.isMarshaler = isMarshaler(t2) - p.isUnmarshaler = isUnmarshaler(t2) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_slice_struct_message - p.dec = (*Buffer).dec_slice_struct_message - p.size = size_slice_struct_message - } else { - p.enc = (*Buffer).enc_slice_struct_group - p.dec = (*Buffer).dec_slice_struct_group - p.size = size_slice_struct_group - } - } - case reflect.Slice: - switch t2.Elem().Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) - break - case reflect.Uint8: - p.enc = (*Buffer).enc_slice_slice_byte - p.dec = (*Buffer).dec_slice_slice_byte - p.size = size_slice_slice_byte - } + if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct { + p.stype = t2.Elem() } case reflect.Map: - p.enc = (*Buffer).enc_new_map - p.dec = (*Buffer).dec_new_map - p.size = size_new_map - p.mtype = t1 - p.mkeyprop = &Properties{} - p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) - p.mvalprop = &Properties{} + p.MapKeyProp = &Properties{} + p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.MapValProp = &Properties{} vtype := p.mtype.Elem() if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { // The value type is not a message (*T) or bytes ([]byte), // so we need encoders for the pointer to this type. vtype = reflect.PtrTo(vtype) } - p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) } - // precalculate tag code - wire := p.WireType - if p.Packed { - wire = WireBytes - } - x := uint32(p.Tag)<<3 | uint32(wire) - i := 0 - for i = 0; x > 127; i++ { - p.tagbuf[i] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - p.tagbuf[i] = uint8(x) - p.tagcode = p.tagbuf[0 : i+1] - if p.stype != nil { if lockGetProp { p.sprop = GetProperties(p.stype) @@ -586,32 +296,9 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock } var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() - unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() ) -// isMarshaler reports whether type t implements Marshaler. -func isMarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isMarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isMarshaler") - } - return t.Implements(marshalerType) -} - -// isUnmarshaler reports whether type t implements Unmarshaler. -func isUnmarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isUnmarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isUnmarshaler") - } - return t.Implements(unmarshalerType) -} - // Init populates the properties from a protocol buffer struct tag. func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { p.init(typ, name, tag, f, true) @@ -621,14 +308,11 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF // "bytes,49,opt,def=hello!" p.Name = name p.OrigName = name - if f != nil { - p.field = toField(f) - } if tag == "" { return } p.Parse(tag) - p.setEncAndDec(typ, f, lockGetProp) + p.setFieldProps(typ, f, lockGetProp) } var ( @@ -649,9 +333,6 @@ func GetProperties(t reflect.Type) *StructProperties { sprop, ok := propertiesMap[t] propertiesMu.RUnlock() if ok { - if collectStats { - stats.Chit++ - } return sprop } @@ -661,26 +342,26 @@ func GetProperties(t reflect.Type) *StructProperties { return sprop } +type ( + oneofFuncsIface interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + oneofWrappersIface interface { + XXX_OneofWrappers() []interface{} + } +) + // getPropertiesLocked requires that propertiesMu is held. func getPropertiesLocked(t reflect.Type) *StructProperties { if prop, ok := propertiesMap[t]; ok { - if collectStats { - stats.Chit++ - } return prop } - if collectStats { - stats.Cmiss++ - } prop := new(StructProperties) // in case of recursive protos, fill this in now. propertiesMap[t] = prop // build properties - prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || - reflect.PtrTo(t).Implements(extendableProtoV1Type) - prop.unrecField = invalidField prop.Prop = make([]*Properties, t.NumField()) prop.order = make([]int, t.NumField()) @@ -690,17 +371,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { name := f.Name p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - if f.Name == "XXX_InternalExtensions" { // special case - p.enc = (*Buffer).enc_exts - p.dec = nil // not needed - p.size = size_exts - } else if f.Name == "XXX_extensions" { // special case - p.enc = (*Buffer).enc_map - p.dec = nil // not needed - p.size = size_map - } else if f.Name == "XXX_unrecognized" { // special case - prop.unrecField = toField(&f) - } oneof := f.Tag.Get("protobuf_oneof") // special case if oneof != "" { // Oneof fields don't use the traditional protobuf tag. @@ -715,22 +385,19 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { } print("\n") } - if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { - fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") - } } // Re-order prop.order. sort.Sort(prop) - type oneofMessage interface { - XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + var oots []interface{} + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oots = m.XXX_OneofFuncs() + case oneofWrappersIface: + oots = m.XXX_OneofWrappers() } - if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { - var oots []interface{} - prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() - prop.stype = t - + if len(oots) > 0 { // Interpret oneof metadata. prop.OneofTypes = make(map[string]*OneofProperties) for _, oot := range oots { @@ -779,30 +446,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { return prop } -// Return the Properties object for the x[0]'th field of the structure. -func propByIndex(t reflect.Type, x []int) *Properties { - if len(x) != 1 { - fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) - return nil - } - prop := GetProperties(t) - return prop.Prop[x[0]] -} - -// Get the address and type of a pointer to a struct from an interface. -func getbase(pb Message) (t reflect.Type, b structPointer, err error) { - if pb == nil { - err = ErrNil - return - } - // get the reflect type of the pointer to the struct. - t = reflect.TypeOf(pb) - // get the address of the struct. - value := reflect.ValueOf(pb) - b = toStructPointer(value) - return -} - // A global registry of enum types. // The generated code will register the generated maps by calling RegisterEnum. @@ -826,20 +469,42 @@ func EnumValueMap(enumType string) map[string]int32 { // A registry of all linked message types. // The string is a fully-qualified proto name ("pkg.Message"). var ( - protoTypes = make(map[string]reflect.Type) - revProtoTypes = make(map[reflect.Type]string) + protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers + protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types + revProtoTypes = make(map[reflect.Type]string) ) // RegisterType is called from generated code and maps from the fully qualified // proto name to the type (pointer to struct) of the protocol buffer. func RegisterType(x Message, name string) { - if _, ok := protoTypes[name]; ok { + if _, ok := protoTypedNils[name]; ok { // TODO: Some day, make this a panic. log.Printf("proto: duplicate proto type registered: %s", name) return } t := reflect.TypeOf(x) - protoTypes[name] = t + if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { + // Generated code always calls RegisterType with nil x. + // This check is just for extra safety. + protoTypedNils[name] = x + } else { + protoTypedNils[name] = reflect.Zero(t).Interface().(Message) + } + revProtoTypes[t] = name +} + +// RegisterMapType is called from generated code and maps from the fully qualified +// proto name to the native map type of the proto map definition. +func RegisterMapType(x interface{}, name string) { + if reflect.TypeOf(x).Kind() != reflect.Map { + panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) + } + if _, ok := protoMapTypes[name]; ok { + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoMapTypes[name] = t revProtoTypes[t] = name } @@ -855,7 +520,14 @@ func MessageName(x Message) string { } // MessageType returns the message type (pointer to struct) for a named message. -func MessageType(name string) reflect.Type { return protoTypes[name] } +// The type is not guaranteed to implement proto.Message if the name refers to a +// map entry. +func MessageType(name string) reflect.Type { + if t, ok := protoTypedNils[name]; ok { + return reflect.TypeOf(t) + } + return protoMapTypes[name] +} // A registry of all linked proto files. var ( diff --git a/vendor/github.com/golang/protobuf/proto/table_marshal.go b/vendor/github.com/golang/protobuf/proto/table_marshal.go new file mode 100644 index 0000000000..5cb11fa955 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_marshal.go @@ -0,0 +1,2776 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "errors" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// a sizer takes a pointer to a field and the size of its tag, computes the size of +// the encoded data. +type sizer func(pointer, int) int + +// a marshaler takes a byte slice, a pointer to a field, and its tag (in wire format), +// marshals the field to the end of the slice, returns the slice and error (if any). +type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) + +// marshalInfo is the information used for marshaling a message. +type marshalInfo struct { + typ reflect.Type + fields []*marshalFieldInfo + unrecognized field // offset of XXX_unrecognized + extensions field // offset of XXX_InternalExtensions + v1extensions field // offset of XXX_extensions + sizecache field // offset of XXX_sizecache + initialized int32 // 0 -- only typ is set, 1 -- fully initialized + messageset bool // uses message set wire format + hasmarshaler bool // has custom marshaler + sync.RWMutex // protect extElems map, also for initialization + extElems map[int32]*marshalElemInfo // info of extension elements +} + +// marshalFieldInfo is the information used for marshaling a field of a message. +type marshalFieldInfo struct { + field field + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isPointer bool + required bool // field is required + name string // name of the field, for error reporting + oneofElems map[reflect.Type]*marshalElemInfo // info of oneof elements +} + +// marshalElemInfo is the information used for marshaling an extension or oneof element. +type marshalElemInfo struct { + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) + deref bool // dereference the pointer before operating on it; implies isptr +} + +var ( + marshalInfoMap = map[reflect.Type]*marshalInfo{} + marshalInfoLock sync.Mutex +) + +// getMarshalInfo returns the information to marshal a given type of message. +// The info it returns may not necessarily initialized. +// t is the type of the message (NOT the pointer to it). +func getMarshalInfo(t reflect.Type) *marshalInfo { + marshalInfoLock.Lock() + u, ok := marshalInfoMap[t] + if !ok { + u = &marshalInfo{typ: t} + marshalInfoMap[t] = u + } + marshalInfoLock.Unlock() + return u +} + +// Size is the entry point from generated code, +// and should be ONLY called by generated code. +// It computes the size of encoded data of msg. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Size(msg Message) int { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return 0 + } + return u.size(ptr) +} + +// Marshal is the entry point from generated code, +// and should be ONLY called by generated code. +// It marshals msg to the end of b. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return b, ErrNil + } + return u.marshal(b, ptr, deterministic) +} + +func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo { + // u := a.marshal, but atomically. + // We use an atomic here to ensure memory consistency. + u := atomicLoadMarshalInfo(&a.marshal) + if u == nil { + // Get marshal information from type of message. + t := reflect.ValueOf(msg).Type() + if t.Kind() != reflect.Ptr { + panic(fmt.Sprintf("cannot handle non-pointer message type %v", t)) + } + u = getMarshalInfo(t.Elem()) + // Store it in the cache for later users. + // a.marshal = u, but atomically. + atomicStoreMarshalInfo(&a.marshal, u) + } + return u +} + +// size is the main function to compute the size of the encoded data of a message. +// ptr is the pointer to the message. +func (u *marshalInfo) size(ptr pointer) int { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b, _ := m.Marshal() + return len(b) + } + + n := 0 + for _, f := range u.fields { + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + n += f.sizer(ptr.offset(f.field), f.tagsize) + } + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + n += u.sizeMessageSet(e) + } else { + n += u.sizeExtensions(e) + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + n += u.sizeV1Extensions(m) + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + n += len(s) + } + // cache the result for use in marshal + if u.sizecache.IsValid() { + atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n)) + } + return n +} + +// cachedsize gets the size from cache. If there is no cache (i.e. message is not generated), +// fall back to compute the size. +func (u *marshalInfo) cachedsize(ptr pointer) int { + if u.sizecache.IsValid() { + return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32())) + } + return u.size(ptr) +} + +// marshal is the main function to marshal a message. It takes a byte slice and appends +// the encoded data to the end of the slice, returns the slice and error (if any). +// ptr is the pointer to the message. +// If deterministic is true, map is marshaled in deterministic order. +func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b1, err := m.Marshal() + b = append(b, b1...) + return b, err + } + + var err, errLater error + // The old marshaler encodes extensions at beginning. + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + b, err = u.appendMessageSet(b, e, deterministic) + } else { + b, err = u.appendExtensions(b, e, deterministic) + } + if err != nil { + return b, err + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + b, err = u.appendV1Extensions(b, m, deterministic) + if err != nil { + return b, err + } + } + for _, f := range u.fields { + if f.required { + if ptr.offset(f.field).getPointer().isNil() { + // Required field is not set. + // We record the error but keep going, to give a complete marshaling. + if errLater == nil { + errLater = &RequiredNotSetError{f.name} + } + continue + } + } + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic) + if err != nil { + if err1, ok := err.(*RequiredNotSetError); ok { + // Required field in submessage is not set. + // We record the error but keep going, to give a complete marshaling. + if errLater == nil { + errLater = &RequiredNotSetError{f.name + "." + err1.field} + } + continue + } + if err == errRepeatedHasNil { + err = errors.New("proto: repeated field " + f.name + " has nil element") + } + if err == errInvalidUTF8 { + if errLater == nil { + fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name + errLater = &invalidUTF8Error{fullName} + } + continue + } + return b, err + } + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + b = append(b, s...) + } + return b, errLater +} + +// computeMarshalInfo initializes the marshal info. +func (u *marshalInfo) computeMarshalInfo() { + u.Lock() + defer u.Unlock() + if u.initialized != 0 { // non-atomic read is ok as it is protected by the lock + return + } + + t := u.typ + u.unrecognized = invalidField + u.extensions = invalidField + u.v1extensions = invalidField + u.sizecache = invalidField + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if reflect.PtrTo(t).Implements(marshalerType) { + u.hasmarshaler = true + atomic.StoreInt32(&u.initialized, 1) + return + } + + // get oneof implementers + var oneofImplementers []interface{} + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oneofImplementers = m.XXX_OneofFuncs() + case oneofWrappersIface: + oneofImplementers = m.XXX_OneofWrappers() + } + + n := t.NumField() + + // deal with XXX fields first + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if !strings.HasPrefix(f.Name, "XXX_") { + continue + } + switch f.Name { + case "XXX_sizecache": + u.sizecache = toField(&f) + case "XXX_unrecognized": + u.unrecognized = toField(&f) + case "XXX_InternalExtensions": + u.extensions = toField(&f) + u.messageset = f.Tag.Get("protobuf_messageset") == "1" + case "XXX_extensions": + u.v1extensions = toField(&f) + case "XXX_NoUnkeyedLiteral": + // nothing to do + default: + panic("unknown XXX field: " + f.Name) + } + n-- + } + + // normal fields + fields := make([]marshalFieldInfo, n) // batch allocation + u.fields = make([]*marshalFieldInfo, 0, n) + for i, j := 0, 0; i < t.NumField(); i++ { + f := t.Field(i) + + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + field := &fields[j] + j++ + field.name = f.Name + u.fields = append(u.fields, field) + if f.Tag.Get("protobuf_oneof") != "" { + field.computeOneofFieldInfo(&f, oneofImplementers) + continue + } + if f.Tag.Get("protobuf") == "" { + // field has no tag (not in generated message), ignore it + u.fields = u.fields[:len(u.fields)-1] + j-- + continue + } + field.computeMarshalFieldInfo(&f) + } + + // fields are marshaled in tag order on the wire. + sort.Sort(byTag(u.fields)) + + atomic.StoreInt32(&u.initialized, 1) +} + +// helper for sorting fields by tag +type byTag []*marshalFieldInfo + +func (a byTag) Len() int { return len(a) } +func (a byTag) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag } + +// getExtElemInfo returns the information to marshal an extension element. +// The info it returns is initialized. +func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo { + // get from cache first + u.RLock() + e, ok := u.extElems[desc.Field] + u.RUnlock() + if ok { + return e + } + + t := reflect.TypeOf(desc.ExtensionType) // pointer or slice to basic type or struct + tags := strings.Split(desc.Tag, ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct { + t = t.Elem() + } + sizer, marshaler := typeMarshaler(t, tags, false, false) + var deref bool + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + t = reflect.PtrTo(t) + deref = true + } + e = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizer, + marshaler: marshaler, + isptr: t.Kind() == reflect.Ptr, + deref: deref, + } + + // update cache + u.Lock() + if u.extElems == nil { + u.extElems = make(map[int32]*marshalElemInfo) + } + u.extElems[desc.Field] = e + u.Unlock() + return e +} + +// computeMarshalFieldInfo fills up the information to marshal a field. +func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { + // parse protobuf tag of the field. + // tag has format of "bytes,49,opt,name=foo,def=hello!" + tags := strings.Split(f.Tag.Get("protobuf"), ",") + if tags[0] == "" { + return + } + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + if tags[2] == "req" { + fi.required = true + } + fi.setTag(f, tag, wt) + fi.setMarshaler(f, tags) +} + +func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { + fi.field = toField(f) + fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. + fi.isPointer = true + fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) + fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) + + ityp := f.Type // interface type + for _, o := range oneofImplementers { + t := reflect.TypeOf(o) + if !t.Implements(ityp) { + continue + } + sf := t.Elem().Field(0) // oneof implementer is a struct with a single field + tags := strings.Split(sf.Tag.Get("protobuf"), ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + sizer, marshaler := typeMarshaler(sf.Type, tags, false, true) // oneof should not omit any zero value + fi.oneofElems[t.Elem()] = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizer, + marshaler: marshaler, + } + } +} + +// wiretype returns the wire encoding of the type. +func wiretype(encoding string) uint64 { + switch encoding { + case "fixed32": + return WireFixed32 + case "fixed64": + return WireFixed64 + case "varint", "zigzag32", "zigzag64": + return WireVarint + case "bytes": + return WireBytes + case "group": + return WireStartGroup + } + panic("unknown wire type " + encoding) +} + +// setTag fills up the tag (in wire format) and its size in the info of a field. +func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) { + fi.field = toField(f) + fi.wiretag = uint64(tag)<<3 | wt + fi.tagsize = SizeVarint(uint64(tag) << 3) +} + +// setMarshaler fills up the sizer and marshaler in the info of a field. +func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) { + switch f.Type.Kind() { + case reflect.Map: + // map field + fi.isPointer = true + fi.sizer, fi.marshaler = makeMapMarshaler(f) + return + case reflect.Ptr, reflect.Slice: + fi.isPointer = true + } + fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false) +} + +// typeMarshaler returns the sizer and marshaler of a given field. +// t is the type of the field. +// tags is the generated "protobuf" tag of the field. +// If nozero is true, zero value is not marshaled to the wire. +// If oneof is true, it is a oneof field. +func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) { + encoding := tags[0] + + pointer := false + slice := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + packed := false + proto3 := false + validateUTF8 := true + for i := 2; i < len(tags); i++ { + if tags[i] == "packed" { + packed = true + } + if tags[i] == "proto3" { + proto3 = true + } + } + validateUTF8 = validateUTF8 && proto3 + + switch t.Kind() { + case reflect.Bool: + if pointer { + return sizeBoolPtr, appendBoolPtr + } + if slice { + if packed { + return sizeBoolPackedSlice, appendBoolPackedSlice + } + return sizeBoolSlice, appendBoolSlice + } + if nozero { + return sizeBoolValueNoZero, appendBoolValueNoZero + } + return sizeBoolValue, appendBoolValue + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixed32Ptr, appendFixed32Ptr + } + if slice { + if packed { + return sizeFixed32PackedSlice, appendFixed32PackedSlice + } + return sizeFixed32Slice, appendFixed32Slice + } + if nozero { + return sizeFixed32ValueNoZero, appendFixed32ValueNoZero + } + return sizeFixed32Value, appendFixed32Value + case "varint": + if pointer { + return sizeVarint32Ptr, appendVarint32Ptr + } + if slice { + if packed { + return sizeVarint32PackedSlice, appendVarint32PackedSlice + } + return sizeVarint32Slice, appendVarint32Slice + } + if nozero { + return sizeVarint32ValueNoZero, appendVarint32ValueNoZero + } + return sizeVarint32Value, appendVarint32Value + } + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixedS32Ptr, appendFixedS32Ptr + } + if slice { + if packed { + return sizeFixedS32PackedSlice, appendFixedS32PackedSlice + } + return sizeFixedS32Slice, appendFixedS32Slice + } + if nozero { + return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero + } + return sizeFixedS32Value, appendFixedS32Value + case "varint": + if pointer { + return sizeVarintS32Ptr, appendVarintS32Ptr + } + if slice { + if packed { + return sizeVarintS32PackedSlice, appendVarintS32PackedSlice + } + return sizeVarintS32Slice, appendVarintS32Slice + } + if nozero { + return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero + } + return sizeVarintS32Value, appendVarintS32Value + case "zigzag32": + if pointer { + return sizeZigzag32Ptr, appendZigzag32Ptr + } + if slice { + if packed { + return sizeZigzag32PackedSlice, appendZigzag32PackedSlice + } + return sizeZigzag32Slice, appendZigzag32Slice + } + if nozero { + return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero + } + return sizeZigzag32Value, appendZigzag32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixed64Ptr, appendFixed64Ptr + } + if slice { + if packed { + return sizeFixed64PackedSlice, appendFixed64PackedSlice + } + return sizeFixed64Slice, appendFixed64Slice + } + if nozero { + return sizeFixed64ValueNoZero, appendFixed64ValueNoZero + } + return sizeFixed64Value, appendFixed64Value + case "varint": + if pointer { + return sizeVarint64Ptr, appendVarint64Ptr + } + if slice { + if packed { + return sizeVarint64PackedSlice, appendVarint64PackedSlice + } + return sizeVarint64Slice, appendVarint64Slice + } + if nozero { + return sizeVarint64ValueNoZero, appendVarint64ValueNoZero + } + return sizeVarint64Value, appendVarint64Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixedS64Ptr, appendFixedS64Ptr + } + if slice { + if packed { + return sizeFixedS64PackedSlice, appendFixedS64PackedSlice + } + return sizeFixedS64Slice, appendFixedS64Slice + } + if nozero { + return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero + } + return sizeFixedS64Value, appendFixedS64Value + case "varint": + if pointer { + return sizeVarintS64Ptr, appendVarintS64Ptr + } + if slice { + if packed { + return sizeVarintS64PackedSlice, appendVarintS64PackedSlice + } + return sizeVarintS64Slice, appendVarintS64Slice + } + if nozero { + return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero + } + return sizeVarintS64Value, appendVarintS64Value + case "zigzag64": + if pointer { + return sizeZigzag64Ptr, appendZigzag64Ptr + } + if slice { + if packed { + return sizeZigzag64PackedSlice, appendZigzag64PackedSlice + } + return sizeZigzag64Slice, appendZigzag64Slice + } + if nozero { + return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero + } + return sizeZigzag64Value, appendZigzag64Value + } + case reflect.Float32: + if pointer { + return sizeFloat32Ptr, appendFloat32Ptr + } + if slice { + if packed { + return sizeFloat32PackedSlice, appendFloat32PackedSlice + } + return sizeFloat32Slice, appendFloat32Slice + } + if nozero { + return sizeFloat32ValueNoZero, appendFloat32ValueNoZero + } + return sizeFloat32Value, appendFloat32Value + case reflect.Float64: + if pointer { + return sizeFloat64Ptr, appendFloat64Ptr + } + if slice { + if packed { + return sizeFloat64PackedSlice, appendFloat64PackedSlice + } + return sizeFloat64Slice, appendFloat64Slice + } + if nozero { + return sizeFloat64ValueNoZero, appendFloat64ValueNoZero + } + return sizeFloat64Value, appendFloat64Value + case reflect.String: + if validateUTF8 { + if pointer { + return sizeStringPtr, appendUTF8StringPtr + } + if slice { + return sizeStringSlice, appendUTF8StringSlice + } + if nozero { + return sizeStringValueNoZero, appendUTF8StringValueNoZero + } + return sizeStringValue, appendUTF8StringValue + } + if pointer { + return sizeStringPtr, appendStringPtr + } + if slice { + return sizeStringSlice, appendStringSlice + } + if nozero { + return sizeStringValueNoZero, appendStringValueNoZero + } + return sizeStringValue, appendStringValue + case reflect.Slice: + if slice { + return sizeBytesSlice, appendBytesSlice + } + if oneof { + // Oneof bytes field may also have "proto3" tag. + // We want to marshal it as a oneof field. Do this + // check before the proto3 check. + return sizeBytesOneof, appendBytesOneof + } + if proto3 { + return sizeBytes3, appendBytes3 + } + return sizeBytes, appendBytes + case reflect.Struct: + switch encoding { + case "group": + if slice { + return makeGroupSliceMarshaler(getMarshalInfo(t)) + } + return makeGroupMarshaler(getMarshalInfo(t)) + case "bytes": + if slice { + return makeMessageSliceMarshaler(getMarshalInfo(t)) + } + return makeMessageMarshaler(getMarshalInfo(t)) + } + } + panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding)) +} + +// Below are functions to size/marshal a specific type of a field. +// They are stored in the field's info, and called by function pointers. +// They have type sizer or marshaler. + +func sizeFixed32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixed32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixed32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixedS32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixedS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixedS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFloat32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFloat32ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + return (4 + tagsize) * len(s) +} +func sizeFloat32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixed64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixed64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixed64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFixedS64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixedS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixedS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFloat64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFloat64ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + return (8 + tagsize) * len(s) +} +func sizeFloat64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeVarint32Value(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarint32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarint32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarint64Value(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + return SizeVarint(v) + tagsize +} +func sizeVarint64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return SizeVarint(v) + tagsize +} +func sizeVarint64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return SizeVarint(*p) + tagsize +} +func sizeVarint64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(v) + tagsize + } + return n +} +func sizeVarint64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize + } + return n +} +func sizeZigzag32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize + } + return n +} +func sizeZigzag64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeBoolValue(_ pointer, tagsize int) int { + return 1 + tagsize +} +func sizeBoolValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toBool() + if !v { + return 0 + } + return 1 + tagsize +} +func sizeBoolPtr(ptr pointer, tagsize int) int { + p := *ptr.toBoolPtr() + if p == nil { + return 0 + } + return 1 + tagsize +} +func sizeBoolSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + return (1 + tagsize) * len(s) +} +func sizeBoolPackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return 0 + } + return len(s) + SizeVarint(uint64(len(s))) + tagsize +} +func sizeStringValue(ptr pointer, tagsize int) int { + v := *ptr.toString() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toString() + if v == "" { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringPtr(ptr pointer, tagsize int) int { + p := *ptr.toStringPtr() + if p == nil { + return 0 + } + v := *p + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringSlice(ptr pointer, tagsize int) int { + s := *ptr.toStringSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} +func sizeBytes(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if v == nil { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytes3(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if len(v) == 0 { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesOneof(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesSlice(ptr pointer, tagsize int) int { + s := *ptr.toBytesSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} + +// appendFixed32 appends an encoded fixed32 to b. +func appendFixed32(b []byte, v uint32) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24)) + return b +} + +// appendFixed64 appends an encoded fixed64 to b. +func appendFixed64(b []byte, v uint64) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + byte(v>>32), + byte(v>>40), + byte(v>>48), + byte(v>>56)) + return b +} + +// appendVarint appends an encoded varint to b. +func appendVarint(b []byte, v uint64) []byte { + // TODO: make 1-byte (maybe 2-byte) case inline-able, once we + // have non-leaf inliner. + switch { + case v < 1<<7: + b = append(b, byte(v)) + case v < 1<<14: + b = append(b, + byte(v&0x7f|0x80), + byte(v>>7)) + case v < 1<<21: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte(v>>14)) + case v < 1<<28: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte(v>>21)) + case v < 1<<35: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte(v>>28)) + case v < 1<<42: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte(v>>35)) + case v < 1<<49: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte(v>>42)) + case v < 1<<56: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte(v>>49)) + case v < 1<<63: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte(v>>56)) + default: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte((v>>56)&0x7f|0x80), + 1) + } + return b +} + +func appendFixed32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, *p) + return b, nil +} +func appendFixed32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixed32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixedS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(*p)) + return b, nil +} +func appendFixedS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFixedS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFloat32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(*p)) + return b, nil +} +func appendFloat32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFloat32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFixed64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, *p) + return b, nil +} +func appendFixed64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixed64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixedS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(*p)) + return b, nil +} +func appendFixedS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFixedS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFloat64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(*p)) + return b, nil +} +func appendFloat64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendFloat64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendVarint32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarint32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, *p) + return b, nil +} +func appendVarint64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + } + return b, nil +} +func appendVarint64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, v) + } + return b, nil +} +func appendVarintS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendZigzag32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendZigzag64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendBoolValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + if !v { + return b, nil + } + b = appendVarint(b, wiretag) + b = append(b, 1) + return b, nil +} + +func appendBoolPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toBoolPtr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + if *p { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(len(s))) + for _, v := range s { + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + if v == "" { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toStringPtr() + if p == nil { + return b, nil + } + v := *p + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toStringSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} +func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + v := *ptr.toString() + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + v := *ptr.toString() + if v == "" { + return b, nil + } + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + p := *ptr.toStringPtr() + if p == nil { + return b, nil + } + v := *p + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + s := *ptr.toStringSlice() + for _, v := range s { + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if v == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytes3(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if len(v) == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesOneof(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBytesSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} + +// makeGroupMarshaler returns the sizer and marshaler for a group. +// u is the marshal info of the underlying message. +func makeGroupMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + return u.size(p) + 2*tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + var err error + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, p, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + return b, err + } +} + +// makeGroupSliceMarshaler returns the sizer and marshaler for a group slice. +// u is the marshal info of the underlying message. +func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + n += u.size(v) + 2*tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err error + var nerr nonFatal + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, v, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + if !nerr.Merge(err) { + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, nerr.E + } +} + +// makeMessageMarshaler returns the sizer and marshaler for a message field. +// u is the marshal info of the message. +func makeMessageMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + siz := u.size(p) + return siz + SizeVarint(uint64(siz)) + tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(p) + b = appendVarint(b, uint64(siz)) + return u.marshal(b, p, deterministic) + } +} + +// makeMessageSliceMarshaler returns the sizer and marshaler for a message slice. +// u is the marshal info of the message. +func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + siz := u.size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err error + var nerr nonFatal + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(v) + b = appendVarint(b, uint64(siz)) + b, err = u.marshal(b, v, deterministic) + + if !nerr.Merge(err) { + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, nerr.E + } +} + +// makeMapMarshaler returns the sizer and marshaler for a map field. +// f is the pointer to the reflect data structure of the field. +func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { + // figure out key and value type + t := f.Type + keyType := t.Key() + valType := t.Elem() + keyTags := strings.Split(f.Tag.Get("protobuf_key"), ",") + valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") + keySizer, keyMarshaler := typeMarshaler(keyType, keyTags, false, false) // don't omit zero value in map + valSizer, valMarshaler := typeMarshaler(valType, valTags, false, false) // don't omit zero value in map + keyWireTag := 1<<3 | wiretype(keyTags[0]) + valWireTag := 2<<3 | wiretype(valTags[0]) + + // We create an interface to get the addresses of the map key and value. + // If value is pointer-typed, the interface is a direct interface, the + // idata itself is the value. Otherwise, the idata is the pointer to the + // value. + // Key cannot be pointer-typed. + valIsPtr := valType.Kind() == reflect.Ptr + + // If value is a message with nested maps, calling + // valSizer in marshal may be quadratic. We should use + // cached version in marshal (but not in size). + // If value is not message type, we don't have size cache, + // but it cannot be nested either. Just use valSizer. + valCachedSizer := valSizer + if valIsPtr && valType.Elem().Kind() == reflect.Struct { + u := getMarshalInfo(valType.Elem()) + valCachedSizer = func(ptr pointer, tagsize int) int { + // Same as message sizer, but use cache. + p := ptr.getPointer() + if p.isNil() { + return 0 + } + siz := u.cachedsize(p) + return siz + SizeVarint(uint64(siz)) + tagsize + } + } + return func(ptr pointer, tagsize int) int { + m := ptr.asPointerTo(t).Elem() // the map + n := 0 + for _, k := range m.MapKeys() { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value + siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, tag uint64, deterministic bool) ([]byte, error) { + m := ptr.asPointerTo(t).Elem() // the map + var err error + keys := m.MapKeys() + if len(keys) > 1 && deterministic { + sort.Sort(mapKeys(keys)) + } + + var nerr nonFatal + for _, k := range keys { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value + b = appendVarint(b, tag) + siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + b = appendVarint(b, uint64(siz)) + b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic) + if !nerr.Merge(err) { + return b, err + } + b, err = valMarshaler(b, vaddr, valWireTag, deterministic) + if err != ErrNil && !nerr.Merge(err) { // allow nil value in map + return b, err + } + } + return b, nerr.E + } +} + +// makeOneOfMarshaler returns the sizer and marshaler for a oneof field. +// fi is the marshal info of the field. +// f is the pointer to the reflect data structure of the field. +func makeOneOfMarshaler(fi *marshalFieldInfo, f *reflect.StructField) (sizer, marshaler) { + // Oneof field is an interface. We need to get the actual data type on the fly. + t := f.Type + return func(ptr pointer, _ int) int { + p := ptr.getInterfacePointer() + if p.isNil() { + return 0 + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + e := fi.oneofElems[telem] + return e.sizer(p, e.tagsize) + }, + func(b []byte, ptr pointer, _ uint64, deterministic bool) ([]byte, error) { + p := ptr.getInterfacePointer() + if p.isNil() { + return b, nil + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + if telem.Field(0).Type.Kind() == reflect.Ptr && p.getPointer().isNil() { + return b, errOneofHasNil + } + e := fi.oneofElems[telem] + return e.marshaler(b, p, e.wiretag, deterministic) + } +} + +// sizeExtensions computes the size of encoded data for a XXX_InternalExtensions field. +func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + n += ei.sizer(p, ei.tagsize) + } + mu.Unlock() + return n +} + +// appendExtensions marshals a XXX_InternalExtensions field to the end of byte slice b. +func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + var nerr nonFatal + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E + } + + // Sort the keys to provide a deterministic encoding. + // Not sure this is required, but the old code does it. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// message set format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } + +// sizeMessageSet computes the size of encoded data for a XXX_InternalExtensions field +// in message set format (above). +func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for id, e := range m { + n += 2 // start group, end group. tag = 1 (size=1) + n += SizeVarint(uint64(id)) + 1 // type_id, tag = 2 (size=1) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + siz := len(msgWithLen) + n += siz + 1 // message, tag = 3 (size=1) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + n += ei.sizer(p, 1) // message, tag = 3 (size=1) + } + mu.Unlock() + return n +} + +// appendMessageSet marshals a XXX_InternalExtensions field in message set format (above) +// to the end of byte slice b. +func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + var nerr nonFatal + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for id, e := range m { + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + if !nerr.Merge(err) { + return b, err + } + b = append(b, 1<<3|WireEndGroup) + } + return b, nerr.E + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, id := range keys { + e := m[int32(id)] + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + b = append(b, 1<<3|WireEndGroup) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// sizeV1Extensions computes the size of encoded data for a V1-API extension field. +func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int { + if m == nil { + return 0 + } + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + n += ei.sizer(p, ei.tagsize) + } + return n +} + +// appendV1Extensions marshals a V1-API extension field to the end of byte slice b. +func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, deterministic bool) ([]byte, error) { + if m == nil { + return b, nil + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + var err error + var nerr nonFatal + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr, ei.deref) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// newMarshaler is the interface representing objects that can marshal themselves. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newMarshaler interface { + XXX_Size() int + XXX_Marshal(b []byte, deterministic bool) ([]byte, error) +} + +// Size returns the encoded size of a protocol buffer message. +// This is the main entry point. +func Size(pb Message) int { + if m, ok := pb.(newMarshaler); ok { + return m.XXX_Size() + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + b, _ := m.Marshal() + return len(b) + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return 0 + } + var info InternalMessageInfo + return info.Size(pb) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, returning the data. +// This is the main entry point. +func Marshal(pb Message) ([]byte, error) { + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + b := make([]byte, 0, siz) + return m.XXX_Marshal(b, false) + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + return m.Marshal() + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return nil, ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + b := make([]byte, 0, siz) + return info.Marshal(b, pb, false) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, writing the result to the +// Buffer. +// This is an alternative entry point. It is not necessary to use +// a Buffer for most applications. +func (p *Buffer) Marshal(pb Message) error { + var err error + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + p.grow(siz) // make sure buf has enough capacity + p.buf, err = m.XXX_Marshal(p.buf, p.deterministic) + return err + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + b, err := m.Marshal() + p.buf = append(p.buf, b...) + return err + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + p.grow(siz) // make sure buf has enough capacity + p.buf, err = info.Marshal(p.buf, pb, p.deterministic) + return err +} + +// grow grows the buffer's capacity, if necessary, to guarantee space for +// another n bytes. After grow(n), at least n bytes can be written to the +// buffer without another allocation. +func (p *Buffer) grow(n int) { + need := len(p.buf) + n + if need <= cap(p.buf) { + return + } + newCap := len(p.buf) * 2 + if newCap < need { + newCap = need + } + p.buf = append(make([]byte, 0, newCap), p.buf...) +} diff --git a/vendor/github.com/golang/protobuf/proto/table_merge.go b/vendor/github.com/golang/protobuf/proto/table_merge.go new file mode 100644 index 0000000000..5525def6a5 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_merge.go @@ -0,0 +1,654 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +// Merge merges the src message into dst. +// This assumes that dst and src of the same type and are non-nil. +func (a *InternalMessageInfo) Merge(dst, src Message) { + mi := atomicLoadMergeInfo(&a.merge) + if mi == nil { + mi = getMergeInfo(reflect.TypeOf(dst).Elem()) + atomicStoreMergeInfo(&a.merge, mi) + } + mi.merge(toPointer(&dst), toPointer(&src)) +} + +type mergeInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []mergeFieldInfo + unrecognized field // Offset of XXX_unrecognized +} + +type mergeFieldInfo struct { + field field // Offset of field, guaranteed to be valid + + // isPointer reports whether the value in the field is a pointer. + // This is true for the following situations: + // * Pointer to struct + // * Pointer to basic type (proto2 only) + // * Slice (first value in slice header is a pointer) + // * String (first value in string header is a pointer) + isPointer bool + + // basicWidth reports the width of the field assuming that it is directly + // embedded in the struct (as is the case for basic types in proto3). + // The possible values are: + // 0: invalid + // 1: bool + // 4: int32, uint32, float32 + // 8: int64, uint64, float64 + basicWidth int + + // Where dst and src are pointers to the types being merged. + merge func(dst, src pointer) +} + +var ( + mergeInfoMap = map[reflect.Type]*mergeInfo{} + mergeInfoLock sync.Mutex +) + +func getMergeInfo(t reflect.Type) *mergeInfo { + mergeInfoLock.Lock() + defer mergeInfoLock.Unlock() + mi := mergeInfoMap[t] + if mi == nil { + mi = &mergeInfo{typ: t} + mergeInfoMap[t] = mi + } + return mi +} + +// merge merges src into dst assuming they are both of type *mi.typ. +func (mi *mergeInfo) merge(dst, src pointer) { + if dst.isNil() { + panic("proto: nil destination") + } + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&mi.initialized) == 0 { + mi.computeMergeInfo() + } + + for _, fi := range mi.fields { + sfp := src.offset(fi.field) + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string + continue + } + if fi.basicWidth > 0 { + switch { + case fi.basicWidth == 1 && !*sfp.toBool(): + continue + case fi.basicWidth == 4 && *sfp.toUint32() == 0: + continue + case fi.basicWidth == 8 && *sfp.toUint64() == 0: + continue + } + } + } + + dfp := dst.offset(fi.field) + fi.merge(dfp, sfp) + } + + // TODO: Make this faster? + out := dst.asPointerTo(mi.typ).Elem() + in := src.asPointerTo(mi.typ).Elem() + if emIn, err := extendable(in.Addr().Interface()); err == nil { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + if mi.unrecognized.IsValid() { + if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 { + *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...) + } + } +} + +func (mi *mergeInfo) computeMergeInfo() { + mi.lock.Lock() + defer mi.lock.Unlock() + if mi.initialized != 0 { + return + } + t := mi.typ + n := t.NumField() + + props := GetProperties(t) + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + mfi := mergeFieldInfo{field: toField(&f)} + tf := f.Type + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + switch tf.Kind() { + case reflect.Ptr, reflect.Slice, reflect.String: + // As a special case, we assume slices and strings are pointers + // since we know that the first field in the SliceSlice or + // StringHeader is a data pointer. + mfi.isPointer = true + case reflect.Bool: + mfi.basicWidth = 1 + case reflect.Int32, reflect.Uint32, reflect.Float32: + mfi.basicWidth = 4 + case reflect.Int64, reflect.Uint64, reflect.Float64: + mfi.basicWidth = 8 + } + } + + // Unwrap tf to get at its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + tf.Name()) + } + + switch tf.Kind() { + case reflect.Int32: + switch { + case isSlice: // E.g., []int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Slice is not defined (see pointer_reflect.go). + /* + sfsp := src.toInt32Slice() + if *sfsp != nil { + dfsp := dst.toInt32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + */ + sfs := src.getInt32Slice() + if sfs != nil { + dfs := dst.getInt32Slice() + dfs = append(dfs, sfs...) + if dfs == nil { + dfs = []int32{} + } + dst.setInt32Slice(dfs) + } + } + case isPointer: // E.g., *int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Ptr is not defined (see pointer_reflect.go). + /* + sfpp := src.toInt32Ptr() + if *sfpp != nil { + dfpp := dst.toInt32Ptr() + if *dfpp == nil { + *dfpp = Int32(**sfpp) + } else { + **dfpp = **sfpp + } + } + */ + sfp := src.getInt32Ptr() + if sfp != nil { + dfp := dst.getInt32Ptr() + if dfp == nil { + dst.setInt32Ptr(*sfp) + } else { + *dfp = *sfp + } + } + } + default: // E.g., int32 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt32(); v != 0 { + *dst.toInt32() = v + } + } + } + case reflect.Int64: + switch { + case isSlice: // E.g., []int64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toInt64Slice() + if *sfsp != nil { + dfsp := dst.toInt64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + } + case isPointer: // E.g., *int64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toInt64Ptr() + if *sfpp != nil { + dfpp := dst.toInt64Ptr() + if *dfpp == nil { + *dfpp = Int64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., int64 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt64(); v != 0 { + *dst.toInt64() = v + } + } + } + case reflect.Uint32: + switch { + case isSlice: // E.g., []uint32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint32Slice() + if *sfsp != nil { + dfsp := dst.toUint32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint32{} + } + } + } + case isPointer: // E.g., *uint32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint32Ptr() + if *sfpp != nil { + dfpp := dst.toUint32Ptr() + if *dfpp == nil { + *dfpp = Uint32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint32 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint32(); v != 0 { + *dst.toUint32() = v + } + } + } + case reflect.Uint64: + switch { + case isSlice: // E.g., []uint64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint64Slice() + if *sfsp != nil { + dfsp := dst.toUint64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint64{} + } + } + } + case isPointer: // E.g., *uint64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint64Ptr() + if *sfpp != nil { + dfpp := dst.toUint64Ptr() + if *dfpp == nil { + *dfpp = Uint64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint64 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint64(); v != 0 { + *dst.toUint64() = v + } + } + } + case reflect.Float32: + switch { + case isSlice: // E.g., []float32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat32Slice() + if *sfsp != nil { + dfsp := dst.toFloat32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float32{} + } + } + } + case isPointer: // E.g., *float32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat32Ptr() + if *sfpp != nil { + dfpp := dst.toFloat32Ptr() + if *dfpp == nil { + *dfpp = Float32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float32 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat32(); v != 0 { + *dst.toFloat32() = v + } + } + } + case reflect.Float64: + switch { + case isSlice: // E.g., []float64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat64Slice() + if *sfsp != nil { + dfsp := dst.toFloat64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float64{} + } + } + } + case isPointer: // E.g., *float64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat64Ptr() + if *sfpp != nil { + dfpp := dst.toFloat64Ptr() + if *dfpp == nil { + *dfpp = Float64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float64 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat64(); v != 0 { + *dst.toFloat64() = v + } + } + } + case reflect.Bool: + switch { + case isSlice: // E.g., []bool + mfi.merge = func(dst, src pointer) { + sfsp := src.toBoolSlice() + if *sfsp != nil { + dfsp := dst.toBoolSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []bool{} + } + } + } + case isPointer: // E.g., *bool + mfi.merge = func(dst, src pointer) { + sfpp := src.toBoolPtr() + if *sfpp != nil { + dfpp := dst.toBoolPtr() + if *dfpp == nil { + *dfpp = Bool(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., bool + mfi.merge = func(dst, src pointer) { + if v := *src.toBool(); v { + *dst.toBool() = v + } + } + } + case reflect.String: + switch { + case isSlice: // E.g., []string + mfi.merge = func(dst, src pointer) { + sfsp := src.toStringSlice() + if *sfsp != nil { + dfsp := dst.toStringSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []string{} + } + } + } + case isPointer: // E.g., *string + mfi.merge = func(dst, src pointer) { + sfpp := src.toStringPtr() + if *sfpp != nil { + dfpp := dst.toStringPtr() + if *dfpp == nil { + *dfpp = String(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., string + mfi.merge = func(dst, src pointer) { + if v := *src.toString(); v != "" { + *dst.toString() = v + } + } + } + case reflect.Slice: + isProto3 := props.Prop[i].proto3 + switch { + case isPointer: + panic("bad pointer in byte slice case in " + tf.Name()) + case tf.Elem().Kind() != reflect.Uint8: + panic("bad element kind in byte slice case in " + tf.Name()) + case isSlice: // E.g., [][]byte + mfi.merge = func(dst, src pointer) { + sbsp := src.toBytesSlice() + if *sbsp != nil { + dbsp := dst.toBytesSlice() + for _, sb := range *sbsp { + if sb == nil { + *dbsp = append(*dbsp, nil) + } else { + *dbsp = append(*dbsp, append([]byte{}, sb...)) + } + } + if *dbsp == nil { + *dbsp = [][]byte{} + } + } + } + default: // E.g., []byte + mfi.merge = func(dst, src pointer) { + sbp := src.toBytes() + if *sbp != nil { + dbp := dst.toBytes() + if !isProto3 || len(*sbp) > 0 { + *dbp = append([]byte{}, *sbp...) + } + } + } + } + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("message field %s without pointer", tf)) + case isSlice: // E.g., []*pb.T + mi := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sps := src.getPointerSlice() + if sps != nil { + dps := dst.getPointerSlice() + for _, sp := range sps { + var dp pointer + if !sp.isNil() { + dp = valToPointer(reflect.New(tf)) + mi.merge(dp, sp) + } + dps = append(dps, dp) + } + if dps == nil { + dps = []pointer{} + } + dst.setPointerSlice(dps) + } + } + default: // E.g., *pb.T + mi := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sp := src.getPointer() + if !sp.isNil() { + dp := dst.getPointer() + if dp.isNil() { + dp = valToPointer(reflect.New(tf)) + dst.setPointer(dp) + } + mi.merge(dp, sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic("bad pointer or slice in map case in " + tf.Name()) + default: // E.g., map[K]V + mfi.merge = func(dst, src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + dm := dst.asPointerTo(tf).Elem() + if dm.IsNil() { + dm.Set(reflect.MakeMap(tf)) + } + + switch tf.Elem().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(Clone(val.Interface().(Message))) + dm.SetMapIndex(key, val) + } + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + dm.SetMapIndex(key, val) + } + default: // Basic type (e.g., string) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + dm.SetMapIndex(key, val) + } + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic("bad pointer or slice in interface case in " + tf.Name()) + default: // E.g., interface{} + // TODO: Make this faster? + mfi.merge = func(dst, src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + du := dst.asPointerTo(tf).Elem() + typ := su.Elem().Type() + if du.IsNil() || du.Elem().Type() != typ { + du.Set(reflect.New(typ.Elem())) // Initialize interface if empty + } + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + dv := du.Elem().Elem().Field(0) + if dv.Kind() == reflect.Ptr && dv.IsNil() { + dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + Merge(dv.Interface().(Message), sv.Interface().(Message)) + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...))) + default: // Basic type (e.g., string) + dv.Set(sv) + } + } + } + } + default: + panic(fmt.Sprintf("merger not found for type:%s", tf)) + } + mi.fields = append(mi.fields, mfi) + } + + mi.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + mi.unrecognized = toField(&f) + } + + atomic.StoreInt32(&mi.initialized, 1) +} diff --git a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go new file mode 100644 index 0000000000..acee2fc529 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go @@ -0,0 +1,2053 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "errors" + "fmt" + "io" + "math" + "reflect" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// Unmarshal is the entry point from the generated .pb.go files. +// This function is not intended to be used by non-generated code. +// This function is not subject to any compatibility guarantee. +// msg contains a pointer to a protocol buffer struct. +// b is the data to be unmarshaled into the protocol buffer. +// a is a pointer to a place to store cached unmarshal information. +func (a *InternalMessageInfo) Unmarshal(msg Message, b []byte) error { + // Load the unmarshal information for this message type. + // The atomic load ensures memory consistency. + u := atomicLoadUnmarshalInfo(&a.unmarshal) + if u == nil { + // Slow path: find unmarshal info for msg, update a with it. + u = getUnmarshalInfo(reflect.TypeOf(msg).Elem()) + atomicStoreUnmarshalInfo(&a.unmarshal, u) + } + // Then do the unmarshaling. + err := u.unmarshal(toPointer(&msg), b) + return err +} + +type unmarshalInfo struct { + typ reflect.Type // type of the protobuf struct + + // 0 = only typ field is initialized + // 1 = completely initialized + initialized int32 + lock sync.Mutex // prevents double initialization + dense []unmarshalFieldInfo // fields indexed by tag # + sparse map[uint64]unmarshalFieldInfo // fields indexed by tag # + reqFields []string // names of required fields + reqMask uint64 // 1< 0 { + // Read tag and wire type. + // Special case 1 and 2 byte varints. + var x uint64 + if b[0] < 128 { + x = uint64(b[0]) + b = b[1:] + } else if len(b) >= 2 && b[1] < 128 { + x = uint64(b[0]&0x7f) + uint64(b[1])<<7 + b = b[2:] + } else { + var n int + x, n = decodeVarint(b) + if n == 0 { + return io.ErrUnexpectedEOF + } + b = b[n:] + } + tag := x >> 3 + wire := int(x) & 7 + + // Dispatch on the tag to one of the unmarshal* functions below. + var f unmarshalFieldInfo + if tag < uint64(len(u.dense)) { + f = u.dense[tag] + } else { + f = u.sparse[tag] + } + if fn := f.unmarshal; fn != nil { + var err error + b, err = fn(b, m.offset(f.field), wire) + if err == nil { + reqMask |= f.reqMask + continue + } + if r, ok := err.(*RequiredNotSetError); ok { + // Remember this error, but keep parsing. We need to produce + // a full parse even if a required field is missing. + if errLater == nil { + errLater = r + } + reqMask |= f.reqMask + continue + } + if err != errInternalBadWireType { + if err == errInvalidUTF8 { + if errLater == nil { + fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name + errLater = &invalidUTF8Error{fullName} + } + continue + } + return err + } + // Fragments with bad wire type are treated as unknown fields. + } + + // Unknown tag. + if !u.unrecognized.IsValid() { + // Don't keep unrecognized data; just skip it. + var err error + b, err = skipField(b, wire) + if err != nil { + return err + } + continue + } + // Keep unrecognized data around. + // maybe in extensions, maybe in the unrecognized field. + z := m.offset(u.unrecognized).toBytes() + var emap map[int32]Extension + var e Extension + for _, r := range u.extensionRanges { + if uint64(r.Start) <= tag && tag <= uint64(r.End) { + if u.extensions.IsValid() { + mp := m.offset(u.extensions).toExtensions() + emap = mp.extensionsWrite() + e = emap[int32(tag)] + z = &e.enc + break + } + if u.oldExtensions.IsValid() { + p := m.offset(u.oldExtensions).toOldExtensions() + emap = *p + if emap == nil { + emap = map[int32]Extension{} + *p = emap + } + e = emap[int32(tag)] + z = &e.enc + break + } + panic("no extensions field available") + } + } + + // Use wire type to skip data. + var err error + b0 := b + b, err = skipField(b, wire) + if err != nil { + return err + } + *z = encodeVarint(*z, tag<<3|uint64(wire)) + *z = append(*z, b0[:len(b0)-len(b)]...) + + if emap != nil { + emap[int32(tag)] = e + } + } + if reqMask != u.reqMask && errLater == nil { + // A required field of this message is missing. + for _, n := range u.reqFields { + if reqMask&1 == 0 { + errLater = &RequiredNotSetError{n} + } + reqMask >>= 1 + } + } + return errLater +} + +// computeUnmarshalInfo fills in u with information for use +// in unmarshaling protocol buffers of type u.typ. +func (u *unmarshalInfo) computeUnmarshalInfo() { + u.lock.Lock() + defer u.lock.Unlock() + if u.initialized != 0 { + return + } + t := u.typ + n := t.NumField() + + // Set up the "not found" value for the unrecognized byte buffer. + // This is the default for proto3. + u.unrecognized = invalidField + u.extensions = invalidField + u.oldExtensions = invalidField + + // List of the generated type and offset for each oneof field. + type oneofField struct { + ityp reflect.Type // interface type of oneof field + field field // offset in containing message + } + var oneofFields []oneofField + + for i := 0; i < n; i++ { + f := t.Field(i) + if f.Name == "XXX_unrecognized" { + // The byte slice used to hold unrecognized input is special. + if f.Type != reflect.TypeOf(([]byte)(nil)) { + panic("bad type for XXX_unrecognized field: " + f.Type.Name()) + } + u.unrecognized = toField(&f) + continue + } + if f.Name == "XXX_InternalExtensions" { + // Ditto here. + if f.Type != reflect.TypeOf(XXX_InternalExtensions{}) { + panic("bad type for XXX_InternalExtensions field: " + f.Type.Name()) + } + u.extensions = toField(&f) + if f.Tag.Get("protobuf_messageset") == "1" { + u.isMessageSet = true + } + continue + } + if f.Name == "XXX_extensions" { + // An older form of the extensions field. + if f.Type != reflect.TypeOf((map[int32]Extension)(nil)) { + panic("bad type for XXX_extensions field: " + f.Type.Name()) + } + u.oldExtensions = toField(&f) + continue + } + if f.Name == "XXX_NoUnkeyedLiteral" || f.Name == "XXX_sizecache" { + continue + } + + oneof := f.Tag.Get("protobuf_oneof") + if oneof != "" { + oneofFields = append(oneofFields, oneofField{f.Type, toField(&f)}) + // The rest of oneof processing happens below. + continue + } + + tags := f.Tag.Get("protobuf") + tagArray := strings.Split(tags, ",") + if len(tagArray) < 2 { + panic("protobuf tag not enough fields in " + t.Name() + "." + f.Name + ": " + tags) + } + tag, err := strconv.Atoi(tagArray[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tagArray[1]) + } + + name := "" + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + } + + // Extract unmarshaling function from the field (its type and tags). + unmarshal := fieldUnmarshaler(&f) + + // Required field? + var reqMask uint64 + if tagArray[2] == "req" { + bit := len(u.reqFields) + u.reqFields = append(u.reqFields, name) + reqMask = uint64(1) << uint(bit) + // TODO: if we have more than 64 required fields, we end up + // not verifying that all required fields are present. + // Fix this, perhaps using a count of required fields? + } + + // Store the info in the correct slot in the message. + u.setTag(tag, toField(&f), unmarshal, reqMask, name) + } + + // Find any types associated with oneof fields. + var oneofImplementers []interface{} + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oneofImplementers = m.XXX_OneofFuncs() + case oneofWrappersIface: + oneofImplementers = m.XXX_OneofWrappers() + } + for _, v := range oneofImplementers { + tptr := reflect.TypeOf(v) // *Msg_X + typ := tptr.Elem() // Msg_X + + f := typ.Field(0) // oneof implementers have one field + baseUnmarshal := fieldUnmarshaler(&f) + tags := strings.Split(f.Tag.Get("protobuf"), ",") + fieldNum, err := strconv.Atoi(tags[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tags[1]) + } + var name string + for _, tag := range tags { + if strings.HasPrefix(tag, "name=") { + name = strings.TrimPrefix(tag, "name=") + break + } + } + + // Find the oneof field that this struct implements. + // Might take O(n^2) to process all of the oneofs, but who cares. + for _, of := range oneofFields { + if tptr.Implements(of.ityp) { + // We have found the corresponding interface for this struct. + // That lets us know where this struct should be stored + // when we encounter it during unmarshaling. + unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) + u.setTag(fieldNum, of.field, unmarshal, 0, name) + } + } + + } + + // Get extension ranges, if any. + fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") + if fn.IsValid() { + if !u.extensions.IsValid() && !u.oldExtensions.IsValid() { + panic("a message with extensions, but no extensions field in " + t.Name()) + } + u.extensionRanges = fn.Call(nil)[0].Interface().([]ExtensionRange) + } + + // Explicitly disallow tag 0. This will ensure we flag an error + // when decoding a buffer of all zeros. Without this code, we + // would decode and skip an all-zero buffer of even length. + // [0 0] is [tag=0/wiretype=varint varint-encoded-0]. + u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) { + return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w) + }, 0, "") + + // Set mask for required field check. + u.reqMask = uint64(1)<= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here? + for len(u.dense) <= tag { + u.dense = append(u.dense, unmarshalFieldInfo{}) + } + u.dense[tag] = i + return + } + if u.sparse == nil { + u.sparse = map[uint64]unmarshalFieldInfo{} + } + u.sparse[uint64(tag)] = i +} + +// fieldUnmarshaler returns an unmarshaler for the given field. +func fieldUnmarshaler(f *reflect.StructField) unmarshaler { + if f.Type.Kind() == reflect.Map { + return makeUnmarshalMap(f) + } + return typeUnmarshaler(f.Type, f.Tag.Get("protobuf")) +} + +// typeUnmarshaler returns an unmarshaler for the given field type / field tag pair. +func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { + tagArray := strings.Split(tags, ",") + encoding := tagArray[0] + name := "unknown" + proto3 := false + validateUTF8 := true + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + if tag == "proto3" { + proto3 = true + } + } + validateUTF8 = validateUTF8 && proto3 + + // Figure out packaging (pointer, slice, or both) + slice := false + pointer := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + // We'll never have both pointer and slice for basic types. + if pointer && slice && t.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + t.Name()) + } + + switch t.Kind() { + case reflect.Bool: + if pointer { + return unmarshalBoolPtr + } + if slice { + return unmarshalBoolSlice + } + return unmarshalBoolValue + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixedS32Ptr + } + if slice { + return unmarshalFixedS32Slice + } + return unmarshalFixedS32Value + case "varint": + // this could be int32 or enum + if pointer { + return unmarshalInt32Ptr + } + if slice { + return unmarshalInt32Slice + } + return unmarshalInt32Value + case "zigzag32": + if pointer { + return unmarshalSint32Ptr + } + if slice { + return unmarshalSint32Slice + } + return unmarshalSint32Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixedS64Ptr + } + if slice { + return unmarshalFixedS64Slice + } + return unmarshalFixedS64Value + case "varint": + if pointer { + return unmarshalInt64Ptr + } + if slice { + return unmarshalInt64Slice + } + return unmarshalInt64Value + case "zigzag64": + if pointer { + return unmarshalSint64Ptr + } + if slice { + return unmarshalSint64Slice + } + return unmarshalSint64Value + } + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixed32Ptr + } + if slice { + return unmarshalFixed32Slice + } + return unmarshalFixed32Value + case "varint": + if pointer { + return unmarshalUint32Ptr + } + if slice { + return unmarshalUint32Slice + } + return unmarshalUint32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixed64Ptr + } + if slice { + return unmarshalFixed64Slice + } + return unmarshalFixed64Value + case "varint": + if pointer { + return unmarshalUint64Ptr + } + if slice { + return unmarshalUint64Slice + } + return unmarshalUint64Value + } + case reflect.Float32: + if pointer { + return unmarshalFloat32Ptr + } + if slice { + return unmarshalFloat32Slice + } + return unmarshalFloat32Value + case reflect.Float64: + if pointer { + return unmarshalFloat64Ptr + } + if slice { + return unmarshalFloat64Slice + } + return unmarshalFloat64Value + case reflect.Map: + panic("map type in typeUnmarshaler in " + t.Name()) + case reflect.Slice: + if pointer { + panic("bad pointer in slice case in " + t.Name()) + } + if slice { + return unmarshalBytesSlice + } + return unmarshalBytesValue + case reflect.String: + if validateUTF8 { + if pointer { + return unmarshalUTF8StringPtr + } + if slice { + return unmarshalUTF8StringSlice + } + return unmarshalUTF8StringValue + } + if pointer { + return unmarshalStringPtr + } + if slice { + return unmarshalStringSlice + } + return unmarshalStringValue + case reflect.Struct: + // message or group field + if !pointer { + panic(fmt.Sprintf("message/group field %s:%s without pointer", t, encoding)) + } + switch encoding { + case "bytes": + if slice { + return makeUnmarshalMessageSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalMessagePtr(getUnmarshalInfo(t), name) + case "group": + if slice { + return makeUnmarshalGroupSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalGroupPtr(getUnmarshalInfo(t), name) + } + } + panic(fmt.Sprintf("unmarshaler not found type:%s encoding:%s", t, encoding)) +} + +// Below are all the unmarshalers for individual fields of various types. + +func unmarshalInt64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64() = v + return b, nil +} + +func unmarshalInt64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalInt64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalSint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64() = v + return b, nil +} + +func unmarshalSint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalSint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalUint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64() = v + return b, nil +} + +func unmarshalUint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64Ptr() = &v + return b, nil +} + +func unmarshalUint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalInt32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + *f.toInt32() = v + return b, nil +} + +func unmarshalInt32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalInt32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalSint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + *f.toInt32() = v + return b, nil +} + +func unmarshalSint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalSint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalUint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32() = v + return b, nil +} + +func unmarshalUint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32Ptr() = &v + return b, nil +} + +func unmarshalUint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalFixed64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64() = v + return b[8:], nil +} + +func unmarshalFixed64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixed64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixedS64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64() = v + return b[8:], nil +} + +func unmarshalFixedS64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixedS64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixed32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32() = v + return b[4:], nil +} + +func unmarshalFixed32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32Ptr() = &v + return b[4:], nil +} + +func unmarshalFixed32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalFixedS32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + *f.toInt32() = v + return b[4:], nil +} + +func unmarshalFixedS32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.setInt32Ptr(v) + return b[4:], nil +} + +func unmarshalFixedS32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + return b[4:], nil +} + +func unmarshalBoolValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + // Note: any length varint is allowed, even though any sane + // encoder will use one byte. + // See https://github.com/golang/protobuf/issues/76 + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + // TODO: check if x>1? Tests seem to indicate no. + v := x != 0 + *f.toBool() = v + return b[n:], nil +} + +func unmarshalBoolPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + *f.toBoolPtr() = &v + return b[n:], nil +} + +func unmarshalBoolSlice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + b = b[n:] + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + return b[n:], nil +} + +func unmarshalFloat64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64() = v + return b[8:], nil +} + +func unmarshalFloat64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64Ptr() = &v + return b[8:], nil +} + +func unmarshalFloat64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFloat32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32() = v + return b[4:], nil +} + +func unmarshalFloat32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32Ptr() = &v + return b[4:], nil +} + +func unmarshalFloat32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toString() = v + return b[x:], nil +} + +func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toStringPtr() = &v + return b[x:], nil +} + +func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + s := f.toStringSlice() + *s = append(*s, v) + return b[x:], nil +} + +func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toString() = v + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toStringPtr() = &v + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + s := f.toStringSlice() + *s = append(*s, v) + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +var emptyBuf [0]byte + +func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // The use of append here is a trick which avoids the zeroing + // that would be required if we used a make/copy pair. + // We append to emptyBuf instead of nil because we want + // a non-nil result even when the length is 0. + v := append(emptyBuf[:], b[:x]...) + *f.toBytes() = v + return b[x:], nil +} + +func unmarshalBytesSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := append(emptyBuf[:], b[:x]...) + s := f.toBytesSlice() + *s = append(*s, v) + return b[x:], nil +} + +func makeUnmarshalMessagePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // First read the message field to see if something is there. + // The semantics of multiple submessages are weird. Instead of + // the last one winning (as it is for all other fields), multiple + // submessages are merged. + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[x:], err + } +} + +func makeUnmarshalMessageSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[x:], err + } +} + +func makeUnmarshalGroupPtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[y:], err + } +} + +func makeUnmarshalGroupSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[y:], err + } +} + +func makeUnmarshalMap(f *reflect.StructField) unmarshaler { + t := f.Type + kt := t.Key() + vt := t.Elem() + unmarshalKey := typeUnmarshaler(kt, f.Tag.Get("protobuf_key")) + unmarshalVal := typeUnmarshaler(vt, f.Tag.Get("protobuf_val")) + return func(b []byte, f pointer, w int) ([]byte, error) { + // The map entry is a submessage. Figure out how big it is. + if w != WireBytes { + return nil, fmt.Errorf("proto: bad wiretype for map field: got %d want %d", w, WireBytes) + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + r := b[x:] // unused data to return + b = b[:x] // data for map entry + + // Note: we could use #keys * #values ~= 200 functions + // to do map decoding without reflection. Probably not worth it. + // Maps will be somewhat slow. Oh well. + + // Read key and value from data. + var nerr nonFatal + k := reflect.New(kt) + v := reflect.New(vt) + for len(b) > 0 { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + wire := int(x) & 7 + b = b[n:] + + var err error + switch x >> 3 { + case 1: + b, err = unmarshalKey(b, valToPointer(k), wire) + case 2: + b, err = unmarshalVal(b, valToPointer(v), wire) + default: + err = errInternalBadWireType // skip unknown tag + } + + if nerr.Merge(err) { + continue + } + if err != errInternalBadWireType { + return nil, err + } + + // Skip past unknown fields. + b, err = skipField(b, wire) + if err != nil { + return nil, err + } + } + + // Get map, allocate if needed. + m := f.asPointerTo(t).Elem() // an addressable map[K]T + if m.IsNil() { + m.Set(reflect.MakeMap(t)) + } + + // Insert into map. + m.SetMapIndex(k.Elem(), v.Elem()) + + return r, nerr.E + } +} + +// makeUnmarshalOneof makes an unmarshaler for oneof fields. +// for: +// message Msg { +// oneof F { +// int64 X = 1; +// float64 Y = 2; +// } +// } +// typ is the type of the concrete entry for a oneof case (e.g. Msg_X). +// ityp is the interface type of the oneof field (e.g. isMsg_F). +// unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64). +// Note that this function will be called once for each case in the oneof. +func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshaler { + sf := typ.Field(0) + field0 := toField(&sf) + return func(b []byte, f pointer, w int) ([]byte, error) { + // Allocate holder for value. + v := reflect.New(typ) + + // Unmarshal data into holder. + // We unmarshal into the first field of the holder object. + var err error + var nerr nonFatal + b, err = unmarshal(b, valToPointer(v).offset(field0), w) + if !nerr.Merge(err) { + return nil, err + } + + // Write pointer to holder into target field. + f.asPointerTo(ityp).Elem().Set(v) + + return b, nerr.E + } +} + +// Error used by decode internally. +var errInternalBadWireType = errors.New("proto: internal error: bad wiretype") + +// skipField skips past a field of type wire and returns the remaining bytes. +func skipField(b []byte, wire int) ([]byte, error) { + switch wire { + case WireVarint: + _, k := decodeVarint(b) + if k == 0 { + return b, io.ErrUnexpectedEOF + } + b = b[k:] + case WireFixed32: + if len(b) < 4 { + return b, io.ErrUnexpectedEOF + } + b = b[4:] + case WireFixed64: + if len(b) < 8 { + return b, io.ErrUnexpectedEOF + } + b = b[8:] + case WireBytes: + m, k := decodeVarint(b) + if k == 0 || uint64(len(b)-k) < m { + return b, io.ErrUnexpectedEOF + } + b = b[uint64(k)+m:] + case WireStartGroup: + _, i := findEndGroup(b) + if i == -1 { + return b, io.ErrUnexpectedEOF + } + b = b[i:] + default: + return b, fmt.Errorf("proto: can't skip unknown wire type %d", wire) + } + return b, nil +} + +// findEndGroup finds the index of the next EndGroup tag. +// Groups may be nested, so the "next" EndGroup tag is the first +// unpaired EndGroup. +// findEndGroup returns the indexes of the start and end of the EndGroup tag. +// Returns (-1,-1) if it can't find one. +func findEndGroup(b []byte) (int, int) { + depth := 1 + i := 0 + for { + x, n := decodeVarint(b[i:]) + if n == 0 { + return -1, -1 + } + j := i + i += n + switch x & 7 { + case WireVarint: + _, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + case WireFixed32: + if len(b)-4 < i { + return -1, -1 + } + i += 4 + case WireFixed64: + if len(b)-8 < i { + return -1, -1 + } + i += 8 + case WireBytes: + m, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + if uint64(len(b)-i) < m { + return -1, -1 + } + i += int(m) + case WireStartGroup: + depth++ + case WireEndGroup: + depth-- + if depth == 0 { + return j, i + } + default: + return -1, -1 + } + } +} + +// encodeVarint appends a varint-encoded integer to b and returns the result. +func encodeVarint(b []byte, x uint64) []byte { + for x >= 1<<7 { + b = append(b, byte(x&0x7f|0x80)) + x >>= 7 + } + return append(b, byte(x)) +} + +// decodeVarint reads a varint-encoded integer from b. +// Returns the decoded integer and the number of bytes read. +// If there is an error, it returns 0,0. +func decodeVarint(b []byte) (uint64, int) { + var x, y uint64 + if len(b) == 0 { + goto bad + } + x = uint64(b[0]) + if x < 0x80 { + return x, 1 + } + x -= 0x80 + + if len(b) <= 1 { + goto bad + } + y = uint64(b[1]) + x += y << 7 + if y < 0x80 { + return x, 2 + } + x -= 0x80 << 7 + + if len(b) <= 2 { + goto bad + } + y = uint64(b[2]) + x += y << 14 + if y < 0x80 { + return x, 3 + } + x -= 0x80 << 14 + + if len(b) <= 3 { + goto bad + } + y = uint64(b[3]) + x += y << 21 + if y < 0x80 { + return x, 4 + } + x -= 0x80 << 21 + + if len(b) <= 4 { + goto bad + } + y = uint64(b[4]) + x += y << 28 + if y < 0x80 { + return x, 5 + } + x -= 0x80 << 28 + + if len(b) <= 5 { + goto bad + } + y = uint64(b[5]) + x += y << 35 + if y < 0x80 { + return x, 6 + } + x -= 0x80 << 35 + + if len(b) <= 6 { + goto bad + } + y = uint64(b[6]) + x += y << 42 + if y < 0x80 { + return x, 7 + } + x -= 0x80 << 42 + + if len(b) <= 7 { + goto bad + } + y = uint64(b[7]) + x += y << 49 + if y < 0x80 { + return x, 8 + } + x -= 0x80 << 49 + + if len(b) <= 8 { + goto bad + } + y = uint64(b[8]) + x += y << 56 + if y < 0x80 { + return x, 9 + } + x -= 0x80 << 56 + + if len(b) <= 9 { + goto bad + } + y = uint64(b[9]) + x += y << 63 + if y < 2 { + return x, 10 + } + +bad: + return 0, 0 +} diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go index 965876bf03..1aaee725b4 100644 --- a/vendor/github.com/golang/protobuf/proto/text.go +++ b/vendor/github.com/golang/protobuf/proto/text.go @@ -50,7 +50,6 @@ import ( var ( newline = []byte("\n") spaces = []byte(" ") - gtNewline = []byte(">\n") endBraceNewline = []byte("}\n") backslashN = []byte{'\\', 'n'} backslashR = []byte{'\\', 'r'} @@ -170,11 +169,6 @@ func writeName(w *textWriter, props *Properties) error { return nil } -// raw is the interface satisfied by RawMessage. -type raw interface { - Bytes() []byte -} - func requiresQuotes(u string) bool { // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. for _, ch := range u { @@ -269,6 +263,10 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { props := sprops.Prop[i] name := st.Field(i).Name + if name == "XXX_NoUnkeyedLiteral" { + continue + } + if strings.HasPrefix(name, "XXX_") { // There are two XXX_ fields: // XXX_unrecognized []byte @@ -355,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if err := tm.writeAny(w, key, props.mkeyprop); err != nil { + if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { return err } if err := w.WriteByte('\n'); err != nil { @@ -372,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if err := tm.writeAny(w, val, props.mvalprop); err != nil { + if err := tm.writeAny(w, val, props.MapValProp); err != nil { return err } if err := w.WriteByte('\n'); err != nil { @@ -436,12 +434,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if b, ok := fv.Interface().(raw); ok { - if err := writeRaw(w, b.Bytes()); err != nil { - return err - } - continue - } // Enums have a String method, so writeAny will work fine. if err := tm.writeAny(w, fv, props); err != nil { @@ -455,7 +447,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { // Extensions (the XXX_extensions field). pv := sv.Addr() - if _, ok := extendable(pv.Interface()); ok { + if _, err := extendable(pv.Interface()); err == nil { if err := tm.writeExtensions(w, pv); err != nil { return err } @@ -464,27 +456,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return nil } -// writeRaw writes an uninterpreted raw message. -func writeRaw(w *textWriter, b []byte) error { - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if err := writeUnknownStruct(w, b); err != nil { - return err - } - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - return nil -} - // writeAny writes an arbitrary field. func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { v = reflect.Indirect(v) @@ -535,6 +506,19 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert } } w.indent() + if v.CanAddr() { + // Calling v.Interface on a struct causes the reflect package to + // copy the entire struct. This is racy with the new Marshaler + // since we atomically update the XXX_sizecache. + // + // Thus, we retrieve a pointer to the struct if possible to avoid + // a race since v.Interface on the pointer doesn't copy the struct. + // + // If v is not addressable, then we are not worried about a race + // since it implies that the binary Marshaler cannot possibly be + // mutating this value. + v = v.Addr() + } if etm, ok := v.Interface().(encoding.TextMarshaler); ok { text, err := etm.MarshalText() if err != nil { @@ -543,8 +527,13 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert if _, err = w.Write(text); err != nil { return err } - } else if err := tm.writeStruct(w, v); err != nil { - return err + } else { + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if err := tm.writeStruct(w, v); err != nil { + return err + } } w.unindent() if err := w.WriteByte(ket); err != nil { diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go index 5e14513f28..bb55a3af27 100644 --- a/vendor/github.com/golang/protobuf/proto/text_parser.go +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go @@ -206,7 +206,6 @@ func (p *textParser) advance() { var ( errBadUTF8 = errors.New("proto: bad UTF-8") - errBadHex = errors.New("proto: bad hexadecimal") ) func unquoteC(s string, quote rune) (string, error) { @@ -277,60 +276,47 @@ func unescape(s string) (ch string, tail string, err error) { return "?", s, nil // trigraph workaround case '\'', '"', '\\': return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + case '0', '1', '2', '3', '4', '5', '6', '7': if len(s) < 2 { return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) } - base := 8 - ss := s[:2] + ss := string(r) + s[:2] s = s[2:] - if r == 'x' || r == 'X' { - base = 16 - } else { - ss = string(r) + ss - } - i, err := strconv.ParseUint(ss, base, 8) + i, err := strconv.ParseUint(ss, 8, 8) if err != nil { - return "", "", err + return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) } return string([]byte{byte(i)}), s, nil - case 'u', 'U': - n := 4 - if r == 'U' { + case 'x', 'X', 'u', 'U': + var n int + switch r { + case 'x', 'X': + n = 2 + case 'u': + n = 4 + case 'U': n = 8 } if len(s) < n { - return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) - } - - bs := make([]byte, n/2) - for i := 0; i < n; i += 2 { - a, ok1 := unhex(s[i]) - b, ok2 := unhex(s[i+1]) - if !ok1 || !ok2 { - return "", "", errBadHex - } - bs[i/2] = a<<4 | b + return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) } + ss := s[:n] s = s[n:] - return string(bs), s, nil + i, err := strconv.ParseUint(ss, 16, 64) + if err != nil { + return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) + } + if r == 'x' || r == 'X' { + return string([]byte{byte(i)}), s, nil + } + if i > utf8.MaxRune { + return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) + } + return string(i), s, nil } return "", "", fmt.Errorf(`unknown escape \%c`, r) } -// Adapted from src/pkg/strconv/quote.go. -func unhex(b byte) (v byte, ok bool) { - switch { - case '0' <= b && b <= '9': - return b - '0', true - case 'a' <= b && b <= 'f': - return b - 'a' + 10, true - case 'A' <= b && b <= 'F': - return b - 'A' + 10, true - } - return 0, false -} - // Back off the parser by one token. Can only be done between calls to next(). // It makes the next advance() a no-op. func (p *textParser) back() { p.backed = true } @@ -644,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { if err := p.consumeToken(":"); err != nil { return err } - if err := p.readAny(key, props.mkeyprop); err != nil { + if err := p.readAny(key, props.MapKeyProp); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { return err } case "value": - if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { return err } - if err := p.readAny(val, props.mvalprop); err != nil { + if err := p.readAny(val, props.MapValProp); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { @@ -728,6 +714,9 @@ func (p *textParser) consumeExtName() (string, error) { if tok.err != nil { return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) } + if p.done && tok.value != "]" { + return "", p.errorf("unclosed type_url or extension name") + } } return strings.Join(parts, ""), nil } @@ -865,7 +854,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error { return p.readStruct(fv, terminator) case reflect.Uint32: if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - fv.SetUint(x) + fv.SetUint(uint64(x)) return nil } case reflect.Uint64: @@ -883,13 +872,9 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error { // UnmarshalText returns *RequiredNotSetError. func UnmarshalText(s string, pb Message) error { if um, ok := pb.(encoding.TextUnmarshaler); ok { - err := um.UnmarshalText([]byte(s)) - return err + return um.UnmarshalText([]byte(s)) } pb.Reset() v := reflect.ValueOf(pb) - if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { - return pe - } - return nil + return newTextParser(s).readStruct(v.Elem(), "") } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile deleted file mode 100644 index 41a2d04d01..0000000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Not stored here, but descriptor.proto is in https://github.com/google/protobuf/ -# at src/google/protobuf/descriptor.proto -regenerate: - @echo WARNING! THIS RULE IS PROBABLY NOT RIGHT FOR YOUR INSTALLATION - protoc --go_out=../../../../.. -I$(HOME)/src/protobuf/include $(HOME)/src/protobuf/include/google/protobuf/descriptor.proto diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go index 63cf2c80aa..1ded05bbe7 100644 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go @@ -1,39 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: google/protobuf/descriptor.proto -/* -Package descriptor is a generated protocol buffer package. - -It is generated from these files: - google/protobuf/descriptor.proto - -It has these top-level messages: - FileDescriptorSet - FileDescriptorProto - DescriptorProto - FieldDescriptorProto - OneofDescriptorProto - EnumDescriptorProto - EnumValueDescriptorProto - ServiceDescriptorProto - MethodDescriptorProto - FileOptions - MessageOptions - FieldOptions - OneofOptions - EnumOptions - EnumValueOptions - ServiceOptions - MethodOptions - UninterpretedOption - SourceCodeInfo - GeneratedCodeInfo -*/ package descriptor -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -44,7 +18,7 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type FieldDescriptorProto_Type int32 @@ -100,6 +74,7 @@ var FieldDescriptorProto_Type_name = map[int32]string{ 17: "TYPE_SINT32", 18: "TYPE_SINT64", } + var FieldDescriptorProto_Type_value = map[string]int32{ "TYPE_DOUBLE": 1, "TYPE_FLOAT": 2, @@ -126,9 +101,11 @@ func (x FieldDescriptorProto_Type) Enum() *FieldDescriptorProto_Type { *p = x return p } + func (x FieldDescriptorProto_Type) String() string { return proto.EnumName(FieldDescriptorProto_Type_name, int32(x)) } + func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Type_value, data, "FieldDescriptorProto_Type") if err != nil { @@ -137,7 +114,10 @@ func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error { *x = FieldDescriptorProto_Type(value) return nil } -func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} } + +func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{4, 0} +} type FieldDescriptorProto_Label int32 @@ -153,6 +133,7 @@ var FieldDescriptorProto_Label_name = map[int32]string{ 2: "LABEL_REQUIRED", 3: "LABEL_REPEATED", } + var FieldDescriptorProto_Label_value = map[string]int32{ "LABEL_OPTIONAL": 1, "LABEL_REQUIRED": 2, @@ -164,9 +145,11 @@ func (x FieldDescriptorProto_Label) Enum() *FieldDescriptorProto_Label { *p = x return p } + func (x FieldDescriptorProto_Label) String() string { return proto.EnumName(FieldDescriptorProto_Label_name, int32(x)) } + func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Label_value, data, "FieldDescriptorProto_Label") if err != nil { @@ -175,8 +158,9 @@ func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error { *x = FieldDescriptorProto_Label(value) return nil } + func (FieldDescriptorProto_Label) EnumDescriptor() ([]byte, []int) { - return fileDescriptor0, []int{3, 1} + return fileDescriptor_e5baabe45344a177, []int{4, 1} } // Generated classes can be optimized for speed or code size. @@ -194,6 +178,7 @@ var FileOptions_OptimizeMode_name = map[int32]string{ 2: "CODE_SIZE", 3: "LITE_RUNTIME", } + var FileOptions_OptimizeMode_value = map[string]int32{ "SPEED": 1, "CODE_SIZE": 2, @@ -205,9 +190,11 @@ func (x FileOptions_OptimizeMode) Enum() *FileOptions_OptimizeMode { *p = x return p } + func (x FileOptions_OptimizeMode) String() string { return proto.EnumName(FileOptions_OptimizeMode_name, int32(x)) } + func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(FileOptions_OptimizeMode_value, data, "FileOptions_OptimizeMode") if err != nil { @@ -216,7 +203,10 @@ func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error { *x = FileOptions_OptimizeMode(value) return nil } -func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{9, 0} } + +func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{10, 0} +} type FieldOptions_CType int32 @@ -232,6 +222,7 @@ var FieldOptions_CType_name = map[int32]string{ 1: "CORD", 2: "STRING_PIECE", } + var FieldOptions_CType_value = map[string]int32{ "STRING": 0, "CORD": 1, @@ -243,9 +234,11 @@ func (x FieldOptions_CType) Enum() *FieldOptions_CType { *p = x return p } + func (x FieldOptions_CType) String() string { return proto.EnumName(FieldOptions_CType_name, int32(x)) } + func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(FieldOptions_CType_value, data, "FieldOptions_CType") if err != nil { @@ -254,7 +247,10 @@ func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error { *x = FieldOptions_CType(value) return nil } -func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 0} } + +func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{12, 0} +} type FieldOptions_JSType int32 @@ -272,6 +268,7 @@ var FieldOptions_JSType_name = map[int32]string{ 1: "JS_STRING", 2: "JS_NUMBER", } + var FieldOptions_JSType_value = map[string]int32{ "JS_NORMAL": 0, "JS_STRING": 1, @@ -283,9 +280,11 @@ func (x FieldOptions_JSType) Enum() *FieldOptions_JSType { *p = x return p } + func (x FieldOptions_JSType) String() string { return proto.EnumName(FieldOptions_JSType_name, int32(x)) } + func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(FieldOptions_JSType_value, data, "FieldOptions_JSType") if err != nil { @@ -294,7 +293,10 @@ func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error { *x = FieldOptions_JSType(value) return nil } -func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 1} } + +func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{12, 1} +} // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, // or neither? HTTP based RPC implementation may choose GET verb for safe @@ -312,6 +314,7 @@ var MethodOptions_IdempotencyLevel_name = map[int32]string{ 1: "NO_SIDE_EFFECTS", 2: "IDEMPOTENT", } + var MethodOptions_IdempotencyLevel_value = map[string]int32{ "IDEMPOTENCY_UNKNOWN": 0, "NO_SIDE_EFFECTS": 1, @@ -323,9 +326,11 @@ func (x MethodOptions_IdempotencyLevel) Enum() *MethodOptions_IdempotencyLevel { *p = x return p } + func (x MethodOptions_IdempotencyLevel) String() string { return proto.EnumName(MethodOptions_IdempotencyLevel_name, int32(x)) } + func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(MethodOptions_IdempotencyLevel_value, data, "MethodOptions_IdempotencyLevel") if err != nil { @@ -334,21 +339,44 @@ func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error { *x = MethodOptions_IdempotencyLevel(value) return nil } + func (MethodOptions_IdempotencyLevel) EnumDescriptor() ([]byte, []int) { - return fileDescriptor0, []int{16, 0} + return fileDescriptor_e5baabe45344a177, []int{17, 0} } // The protocol compiler can output a FileDescriptorSet containing the .proto // files it parses. type FileDescriptorSet struct { - File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"` - XXX_unrecognized []byte `json:"-"` + File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} } -func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) } -func (*FileDescriptorSet) ProtoMessage() {} -func (*FileDescriptorSet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} } +func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) } +func (*FileDescriptorSet) ProtoMessage() {} +func (*FileDescriptorSet) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{0} +} + +func (m *FileDescriptorSet) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileDescriptorSet.Unmarshal(m, b) +} +func (m *FileDescriptorSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileDescriptorSet.Marshal(b, m, deterministic) +} +func (m *FileDescriptorSet) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileDescriptorSet.Merge(m, src) +} +func (m *FileDescriptorSet) XXX_Size() int { + return xxx_messageInfo_FileDescriptorSet.Size(m) +} +func (m *FileDescriptorSet) XXX_DiscardUnknown() { + xxx_messageInfo_FileDescriptorSet.DiscardUnknown(m) +} + +var xxx_messageInfo_FileDescriptorSet proto.InternalMessageInfo func (m *FileDescriptorSet) GetFile() []*FileDescriptorProto { if m != nil { @@ -381,14 +409,36 @@ type FileDescriptorProto struct { SourceCodeInfo *SourceCodeInfo `protobuf:"bytes,9,opt,name=source_code_info,json=sourceCodeInfo" json:"source_code_info,omitempty"` // The syntax of the proto file. // The supported values are "proto2" and "proto3". - Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"` - XXX_unrecognized []byte `json:"-"` + Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} } -func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*FileDescriptorProto) ProtoMessage() {} -func (*FileDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} } +func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*FileDescriptorProto) ProtoMessage() {} +func (*FileDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{1} +} + +func (m *FileDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileDescriptorProto.Unmarshal(m, b) +} +func (m *FileDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileDescriptorProto.Marshal(b, m, deterministic) +} +func (m *FileDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileDescriptorProto.Merge(m, src) +} +func (m *FileDescriptorProto) XXX_Size() int { + return xxx_messageInfo_FileDescriptorProto.Size(m) +} +func (m *FileDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_FileDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_FileDescriptorProto proto.InternalMessageInfo func (m *FileDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -487,14 +537,36 @@ type DescriptorProto struct { ReservedRange []*DescriptorProto_ReservedRange `protobuf:"bytes,9,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"` // Reserved field names, which may not be used by fields in the same message. // A given name may only be reserved once. - ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` - XXX_unrecognized []byte `json:"-"` + ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *DescriptorProto) Reset() { *m = DescriptorProto{} } -func (m *DescriptorProto) String() string { return proto.CompactTextString(m) } -func (*DescriptorProto) ProtoMessage() {} -func (*DescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (m *DescriptorProto) Reset() { *m = DescriptorProto{} } +func (m *DescriptorProto) String() string { return proto.CompactTextString(m) } +func (*DescriptorProto) ProtoMessage() {} +func (*DescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{2} +} + +func (m *DescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DescriptorProto.Unmarshal(m, b) +} +func (m *DescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DescriptorProto.Marshal(b, m, deterministic) +} +func (m *DescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_DescriptorProto.Merge(m, src) +} +func (m *DescriptorProto) XXX_Size() int { + return xxx_messageInfo_DescriptorProto.Size(m) +} +func (m *DescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_DescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_DescriptorProto proto.InternalMessageInfo func (m *DescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -567,18 +639,39 @@ func (m *DescriptorProto) GetReservedName() []string { } type DescriptorProto_ExtensionRange struct { - Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` - XXX_unrecognized []byte `json:"-"` + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + Options *ExtensionRangeOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *DescriptorProto_ExtensionRange) Reset() { *m = DescriptorProto_ExtensionRange{} } func (m *DescriptorProto_ExtensionRange) String() string { return proto.CompactTextString(m) } func (*DescriptorProto_ExtensionRange) ProtoMessage() {} func (*DescriptorProto_ExtensionRange) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{2, 0} + return fileDescriptor_e5baabe45344a177, []int{2, 0} } +func (m *DescriptorProto_ExtensionRange) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DescriptorProto_ExtensionRange.Unmarshal(m, b) +} +func (m *DescriptorProto_ExtensionRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DescriptorProto_ExtensionRange.Marshal(b, m, deterministic) +} +func (m *DescriptorProto_ExtensionRange) XXX_Merge(src proto.Message) { + xxx_messageInfo_DescriptorProto_ExtensionRange.Merge(m, src) +} +func (m *DescriptorProto_ExtensionRange) XXX_Size() int { + return xxx_messageInfo_DescriptorProto_ExtensionRange.Size(m) +} +func (m *DescriptorProto_ExtensionRange) XXX_DiscardUnknown() { + xxx_messageInfo_DescriptorProto_ExtensionRange.DiscardUnknown(m) +} + +var xxx_messageInfo_DescriptorProto_ExtensionRange proto.InternalMessageInfo + func (m *DescriptorProto_ExtensionRange) GetStart() int32 { if m != nil && m.Start != nil { return *m.Start @@ -593,22 +686,49 @@ func (m *DescriptorProto_ExtensionRange) GetEnd() int32 { return 0 } +func (m *DescriptorProto_ExtensionRange) GetOptions() *ExtensionRangeOptions { + if m != nil { + return m.Options + } + return nil +} + // Range of reserved tag numbers. Reserved tag numbers may not be used by // fields or extension ranges in the same message. Reserved ranges may // not overlap. type DescriptorProto_ReservedRange struct { - Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` - XXX_unrecognized []byte `json:"-"` + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *DescriptorProto_ReservedRange) Reset() { *m = DescriptorProto_ReservedRange{} } func (m *DescriptorProto_ReservedRange) String() string { return proto.CompactTextString(m) } func (*DescriptorProto_ReservedRange) ProtoMessage() {} func (*DescriptorProto_ReservedRange) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{2, 1} + return fileDescriptor_e5baabe45344a177, []int{2, 1} } +func (m *DescriptorProto_ReservedRange) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DescriptorProto_ReservedRange.Unmarshal(m, b) +} +func (m *DescriptorProto_ReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DescriptorProto_ReservedRange.Marshal(b, m, deterministic) +} +func (m *DescriptorProto_ReservedRange) XXX_Merge(src proto.Message) { + xxx_messageInfo_DescriptorProto_ReservedRange.Merge(m, src) +} +func (m *DescriptorProto_ReservedRange) XXX_Size() int { + return xxx_messageInfo_DescriptorProto_ReservedRange.Size(m) +} +func (m *DescriptorProto_ReservedRange) XXX_DiscardUnknown() { + xxx_messageInfo_DescriptorProto_ReservedRange.DiscardUnknown(m) +} + +var xxx_messageInfo_DescriptorProto_ReservedRange proto.InternalMessageInfo + func (m *DescriptorProto_ReservedRange) GetStart() int32 { if m != nil && m.Start != nil { return *m.Start @@ -623,6 +743,55 @@ func (m *DescriptorProto_ReservedRange) GetEnd() int32 { return 0 } +type ExtensionRangeOptions struct { + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExtensionRangeOptions) Reset() { *m = ExtensionRangeOptions{} } +func (m *ExtensionRangeOptions) String() string { return proto.CompactTextString(m) } +func (*ExtensionRangeOptions) ProtoMessage() {} +func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{3} +} + +var extRange_ExtensionRangeOptions = []proto.ExtensionRange{ + {Start: 1000, End: 536870911}, +} + +func (*ExtensionRangeOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_ExtensionRangeOptions +} + +func (m *ExtensionRangeOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ExtensionRangeOptions.Unmarshal(m, b) +} +func (m *ExtensionRangeOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ExtensionRangeOptions.Marshal(b, m, deterministic) +} +func (m *ExtensionRangeOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtensionRangeOptions.Merge(m, src) +} +func (m *ExtensionRangeOptions) XXX_Size() int { + return xxx_messageInfo_ExtensionRangeOptions.Size(m) +} +func (m *ExtensionRangeOptions) XXX_DiscardUnknown() { + xxx_messageInfo_ExtensionRangeOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtensionRangeOptions proto.InternalMessageInfo + +func (m *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + // Describes a field within a message. type FieldDescriptorProto struct { Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -653,15 +822,37 @@ type FieldDescriptorProto struct { // user has set a "json_name" option on this field, that option's value // will be used. Otherwise, it's deduced from the field's name by converting // it to camelCase. - JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` - Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` + Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } -func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*FieldDescriptorProto) ProtoMessage() {} -func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } +func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*FieldDescriptorProto) ProtoMessage() {} +func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{4} +} + +func (m *FieldDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FieldDescriptorProto.Unmarshal(m, b) +} +func (m *FieldDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FieldDescriptorProto.Marshal(b, m, deterministic) +} +func (m *FieldDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_FieldDescriptorProto.Merge(m, src) +} +func (m *FieldDescriptorProto) XXX_Size() int { + return xxx_messageInfo_FieldDescriptorProto.Size(m) +} +func (m *FieldDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_FieldDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_FieldDescriptorProto proto.InternalMessageInfo func (m *FieldDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -735,15 +926,37 @@ func (m *FieldDescriptorProto) GetOptions() *FieldOptions { // Describes a oneof. type OneofDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} } -func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*OneofDescriptorProto) ProtoMessage() {} -func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } +func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} } +func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*OneofDescriptorProto) ProtoMessage() {} +func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{5} +} + +func (m *OneofDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OneofDescriptorProto.Unmarshal(m, b) +} +func (m *OneofDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OneofDescriptorProto.Marshal(b, m, deterministic) +} +func (m *OneofDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_OneofDescriptorProto.Merge(m, src) +} +func (m *OneofDescriptorProto) XXX_Size() int { + return xxx_messageInfo_OneofDescriptorProto.Size(m) +} +func (m *OneofDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_OneofDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_OneofDescriptorProto proto.InternalMessageInfo func (m *OneofDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -761,16 +974,45 @@ func (m *OneofDescriptorProto) GetOptions() *OneofOptions { // Describes an enum type. type EnumDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"` - Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"` + Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + ReservedRange []*EnumDescriptorProto_EnumReservedRange `protobuf:"bytes,4,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"` + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + ReservedName []string `protobuf:"bytes,5,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} } -func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*EnumDescriptorProto) ProtoMessage() {} -func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } +func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} } +func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*EnumDescriptorProto) ProtoMessage() {} +func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{6} +} + +func (m *EnumDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumDescriptorProto.Unmarshal(m, b) +} +func (m *EnumDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumDescriptorProto.Marshal(b, m, deterministic) +} +func (m *EnumDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumDescriptorProto.Merge(m, src) +} +func (m *EnumDescriptorProto) XXX_Size() int { + return xxx_messageInfo_EnumDescriptorProto.Size(m) +} +func (m *EnumDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_EnumDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumDescriptorProto proto.InternalMessageInfo func (m *EnumDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -793,18 +1035,107 @@ func (m *EnumDescriptorProto) GetOptions() *EnumOptions { return nil } -// Describes a value within an enum. -type EnumValueDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"` - Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` +func (m *EnumDescriptorProto) GetReservedRange() []*EnumDescriptorProto_EnumReservedRange { + if m != nil { + return m.ReservedRange + } + return nil } -func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} } -func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*EnumValueDescriptorProto) ProtoMessage() {} -func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } +func (m *EnumDescriptorProto) GetReservedName() []string { + if m != nil { + return m.ReservedName + } + return nil +} + +// Range of reserved numeric values. Reserved values may not be used by +// entries in the same enum. Reserved ranges may not overlap. +// +// Note that this is distinct from DescriptorProto.ReservedRange in that it +// is inclusive such that it can appropriately represent the entire int32 +// domain. +type EnumDescriptorProto_EnumReservedRange struct { + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EnumDescriptorProto_EnumReservedRange) Reset() { *m = EnumDescriptorProto_EnumReservedRange{} } +func (m *EnumDescriptorProto_EnumReservedRange) String() string { return proto.CompactTextString(m) } +func (*EnumDescriptorProto_EnumReservedRange) ProtoMessage() {} +func (*EnumDescriptorProto_EnumReservedRange) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{6, 0} +} + +func (m *EnumDescriptorProto_EnumReservedRange) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Unmarshal(m, b) +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Marshal(b, m, deterministic) +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Merge(m, src) +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_Size() int { + return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Size(m) +} +func (m *EnumDescriptorProto_EnumReservedRange) XXX_DiscardUnknown() { + xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumDescriptorProto_EnumReservedRange proto.InternalMessageInfo + +func (m *EnumDescriptorProto_EnumReservedRange) GetStart() int32 { + if m != nil && m.Start != nil { + return *m.Start + } + return 0 +} + +func (m *EnumDescriptorProto_EnumReservedRange) GetEnd() int32 { + if m != nil && m.End != nil { + return *m.End + } + return 0 +} + +// Describes a value within an enum. +type EnumValueDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"` + Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} } +func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*EnumValueDescriptorProto) ProtoMessage() {} +func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{7} +} + +func (m *EnumValueDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumValueDescriptorProto.Unmarshal(m, b) +} +func (m *EnumValueDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumValueDescriptorProto.Marshal(b, m, deterministic) +} +func (m *EnumValueDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumValueDescriptorProto.Merge(m, src) +} +func (m *EnumValueDescriptorProto) XXX_Size() int { + return xxx_messageInfo_EnumValueDescriptorProto.Size(m) +} +func (m *EnumValueDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_EnumValueDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumValueDescriptorProto proto.InternalMessageInfo func (m *EnumValueDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -829,16 +1160,38 @@ func (m *EnumValueDescriptorProto) GetOptions() *EnumValueOptions { // Describes a service. type ServiceDescriptorProto struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"` - Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` - XXX_unrecognized []byte `json:"-"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"` + Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} } -func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*ServiceDescriptorProto) ProtoMessage() {} -func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } +func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} } +func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*ServiceDescriptorProto) ProtoMessage() {} +func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{8} +} + +func (m *ServiceDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ServiceDescriptorProto.Unmarshal(m, b) +} +func (m *ServiceDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ServiceDescriptorProto.Marshal(b, m, deterministic) +} +func (m *ServiceDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServiceDescriptorProto.Merge(m, src) +} +func (m *ServiceDescriptorProto) XXX_Size() int { + return xxx_messageInfo_ServiceDescriptorProto.Size(m) +} +func (m *ServiceDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_ServiceDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_ServiceDescriptorProto proto.InternalMessageInfo func (m *ServiceDescriptorProto) GetName() string { if m != nil && m.Name != nil { @@ -872,14 +1225,36 @@ type MethodDescriptorProto struct { // Identifies if client streams multiple client messages ClientStreaming *bool `protobuf:"varint,5,opt,name=client_streaming,json=clientStreaming,def=0" json:"client_streaming,omitempty"` // Identifies if server streams multiple server messages - ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"` - XXX_unrecognized []byte `json:"-"` + ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} } -func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) } -func (*MethodDescriptorProto) ProtoMessage() {} -func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } +func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} } +func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*MethodDescriptorProto) ProtoMessage() {} +func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{9} +} + +func (m *MethodDescriptorProto) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MethodDescriptorProto.Unmarshal(m, b) +} +func (m *MethodDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MethodDescriptorProto.Marshal(b, m, deterministic) +} +func (m *MethodDescriptorProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_MethodDescriptorProto.Merge(m, src) +} +func (m *MethodDescriptorProto) XXX_Size() int { + return xxx_messageInfo_MethodDescriptorProto.Size(m) +} +func (m *MethodDescriptorProto) XXX_DiscardUnknown() { + xxx_messageInfo_MethodDescriptorProto.DiscardUnknown(m) +} + +var xxx_messageInfo_MethodDescriptorProto proto.InternalMessageInfo const Default_MethodDescriptorProto_ClientStreaming bool = false const Default_MethodDescriptorProto_ServerStreaming bool = false @@ -946,7 +1321,7 @@ type FileOptions struct { // top-level extensions defined in the file. JavaMultipleFiles *bool `protobuf:"varint,10,opt,name=java_multiple_files,json=javaMultipleFiles,def=0" json:"java_multiple_files,omitempty"` // This option does nothing. - JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"` + JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"` // Deprecated: Do not use. // If set true, then the Java2 code generator will generate code that // throws an exception whenever an attempt is made to assign a non-UTF-8 // byte sequence to a string field. @@ -974,6 +1349,7 @@ type FileOptions struct { CcGenericServices *bool `protobuf:"varint,16,opt,name=cc_generic_services,json=ccGenericServices,def=0" json:"cc_generic_services,omitempty"` JavaGenericServices *bool `protobuf:"varint,17,opt,name=java_generic_services,json=javaGenericServices,def=0" json:"java_generic_services,omitempty"` PyGenericServices *bool `protobuf:"varint,18,opt,name=py_generic_services,json=pyGenericServices,def=0" json:"py_generic_services,omitempty"` + PhpGenericServices *bool `protobuf:"varint,42,opt,name=php_generic_services,json=phpGenericServices,def=0" json:"php_generic_services,omitempty"` // Is this file deprecated? // Depending on the target platform, this can emit Deprecated annotations // for everything in the file, or it will be completely ignored; in the very @@ -995,31 +1371,67 @@ type FileOptions struct { // Sets the php class prefix which is prepended to all php generated classes // from this .proto. Default is empty. PhpClassPrefix *string `protobuf:"bytes,40,opt,name=php_class_prefix,json=phpClassPrefix" json:"php_class_prefix,omitempty"` - // The parser stores options it doesn't recognize here. See above. + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + PhpNamespace *string `protobuf:"bytes,41,opt,name=php_namespace,json=phpNamespace" json:"php_namespace,omitempty"` + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be used + // for determining the namespace. + PhpMetadataNamespace *string `protobuf:"bytes,44,opt,name=php_metadata_namespace,json=phpMetadataNamespace" json:"php_metadata_namespace,omitempty"` + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + RubyPackage *string `protobuf:"bytes,45,opt,name=ruby_package,json=rubyPackage" json:"ruby_package,omitempty"` + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FileOptions) Reset() { *m = FileOptions{} } -func (m *FileOptions) String() string { return proto.CompactTextString(m) } -func (*FileOptions) ProtoMessage() {} -func (*FileOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } +func (m *FileOptions) Reset() { *m = FileOptions{} } +func (m *FileOptions) String() string { return proto.CompactTextString(m) } +func (*FileOptions) ProtoMessage() {} +func (*FileOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{10} +} var extRange_FileOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*FileOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_FileOptions } +func (m *FileOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileOptions.Unmarshal(m, b) +} +func (m *FileOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileOptions.Marshal(b, m, deterministic) +} +func (m *FileOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileOptions.Merge(m, src) +} +func (m *FileOptions) XXX_Size() int { + return xxx_messageInfo_FileOptions.Size(m) +} +func (m *FileOptions) XXX_DiscardUnknown() { + xxx_messageInfo_FileOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_FileOptions proto.InternalMessageInfo + const Default_FileOptions_JavaMultipleFiles bool = false const Default_FileOptions_JavaStringCheckUtf8 bool = false const Default_FileOptions_OptimizeFor FileOptions_OptimizeMode = FileOptions_SPEED const Default_FileOptions_CcGenericServices bool = false const Default_FileOptions_JavaGenericServices bool = false const Default_FileOptions_PyGenericServices bool = false +const Default_FileOptions_PhpGenericServices bool = false const Default_FileOptions_Deprecated bool = false const Default_FileOptions_CcEnableArenas bool = false @@ -1044,6 +1456,7 @@ func (m *FileOptions) GetJavaMultipleFiles() bool { return Default_FileOptions_JavaMultipleFiles } +// Deprecated: Do not use. func (m *FileOptions) GetJavaGenerateEqualsAndHash() bool { if m != nil && m.JavaGenerateEqualsAndHash != nil { return *m.JavaGenerateEqualsAndHash @@ -1093,6 +1506,13 @@ func (m *FileOptions) GetPyGenericServices() bool { return Default_FileOptions_PyGenericServices } +func (m *FileOptions) GetPhpGenericServices() bool { + if m != nil && m.PhpGenericServices != nil { + return *m.PhpGenericServices + } + return Default_FileOptions_PhpGenericServices +} + func (m *FileOptions) GetDeprecated() bool { if m != nil && m.Deprecated != nil { return *m.Deprecated @@ -1135,6 +1555,27 @@ func (m *FileOptions) GetPhpClassPrefix() string { return "" } +func (m *FileOptions) GetPhpNamespace() string { + if m != nil && m.PhpNamespace != nil { + return *m.PhpNamespace + } + return "" +} + +func (m *FileOptions) GetPhpMetadataNamespace() string { + if m != nil && m.PhpMetadataNamespace != nil { + return *m.PhpMetadataNamespace + } + return "" +} + +func (m *FileOptions) GetRubyPackage() string { + if m != nil && m.RubyPackage != nil { + return *m.RubyPackage + } + return "" +} + func (m *FileOptions) GetUninterpretedOption() []*UninterpretedOption { if m != nil { return m.UninterpretedOption @@ -1195,23 +1636,45 @@ type MessageOptions struct { MapEntry *bool `protobuf:"varint,7,opt,name=map_entry,json=mapEntry" json:"map_entry,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MessageOptions) Reset() { *m = MessageOptions{} } -func (m *MessageOptions) String() string { return proto.CompactTextString(m) } -func (*MessageOptions) ProtoMessage() {} -func (*MessageOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } +func (m *MessageOptions) Reset() { *m = MessageOptions{} } +func (m *MessageOptions) String() string { return proto.CompactTextString(m) } +func (*MessageOptions) ProtoMessage() {} +func (*MessageOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{11} +} var extRange_MessageOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*MessageOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_MessageOptions } +func (m *MessageOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MessageOptions.Unmarshal(m, b) +} +func (m *MessageOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MessageOptions.Marshal(b, m, deterministic) +} +func (m *MessageOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_MessageOptions.Merge(m, src) +} +func (m *MessageOptions) XXX_Size() int { + return xxx_messageInfo_MessageOptions.Size(m) +} +func (m *MessageOptions) XXX_DiscardUnknown() { + xxx_messageInfo_MessageOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_MessageOptions proto.InternalMessageInfo + const Default_MessageOptions_MessageSetWireFormat bool = false const Default_MessageOptions_NoStandardDescriptorAccessor bool = false const Default_MessageOptions_Deprecated bool = false @@ -1265,13 +1728,15 @@ type FieldOptions struct { Packed *bool `protobuf:"varint,2,opt,name=packed" json:"packed,omitempty"` // The jstype option determines the JavaScript type used for values of the // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). By default these types are - // represented as JavaScript strings. This avoids loss of precision that can - // happen when a large value is converted to a floating point JavaScript - // numbers. Specifying JS_NUMBER for the jstype causes the generated - // JavaScript code to use the JavaScript "number" type instead of strings. - // This option is an enum to permit additional types to be added, - // e.g. goog.math.Integer. + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. Jstype *FieldOptions_JSType `protobuf:"varint,6,opt,name=jstype,enum=google.protobuf.FieldOptions_JSType,def=0" json:"jstype,omitempty"` // Should this field be parsed lazily? Lazy applies only to message-type // fields. It means that when the outer message is initially parsed, the @@ -1311,23 +1776,45 @@ type FieldOptions struct { Weak *bool `protobuf:"varint,10,opt,name=weak,def=0" json:"weak,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *FieldOptions) Reset() { *m = FieldOptions{} } -func (m *FieldOptions) String() string { return proto.CompactTextString(m) } -func (*FieldOptions) ProtoMessage() {} -func (*FieldOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } +func (m *FieldOptions) Reset() { *m = FieldOptions{} } +func (m *FieldOptions) String() string { return proto.CompactTextString(m) } +func (*FieldOptions) ProtoMessage() {} +func (*FieldOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{12} +} var extRange_FieldOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*FieldOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_FieldOptions } +func (m *FieldOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FieldOptions.Unmarshal(m, b) +} +func (m *FieldOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FieldOptions.Marshal(b, m, deterministic) +} +func (m *FieldOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_FieldOptions.Merge(m, src) +} +func (m *FieldOptions) XXX_Size() int { + return xxx_messageInfo_FieldOptions.Size(m) +} +func (m *FieldOptions) XXX_DiscardUnknown() { + xxx_messageInfo_FieldOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_FieldOptions proto.InternalMessageInfo + const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING const Default_FieldOptions_Jstype FieldOptions_JSType = FieldOptions_JS_NORMAL const Default_FieldOptions_Lazy bool = false @@ -1386,23 +1873,45 @@ func (m *FieldOptions) GetUninterpretedOption() []*UninterpretedOption { type OneofOptions struct { // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *OneofOptions) Reset() { *m = OneofOptions{} } -func (m *OneofOptions) String() string { return proto.CompactTextString(m) } -func (*OneofOptions) ProtoMessage() {} -func (*OneofOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } +func (m *OneofOptions) Reset() { *m = OneofOptions{} } +func (m *OneofOptions) String() string { return proto.CompactTextString(m) } +func (*OneofOptions) ProtoMessage() {} +func (*OneofOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{13} +} var extRange_OneofOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*OneofOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_OneofOptions } +func (m *OneofOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OneofOptions.Unmarshal(m, b) +} +func (m *OneofOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OneofOptions.Marshal(b, m, deterministic) +} +func (m *OneofOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_OneofOptions.Merge(m, src) +} +func (m *OneofOptions) XXX_Size() int { + return xxx_messageInfo_OneofOptions.Size(m) +} +func (m *OneofOptions) XXX_DiscardUnknown() { + xxx_messageInfo_OneofOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_OneofOptions proto.InternalMessageInfo + func (m *OneofOptions) GetUninterpretedOption() []*UninterpretedOption { if m != nil { return m.UninterpretedOption @@ -1421,23 +1930,45 @@ type EnumOptions struct { Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *EnumOptions) Reset() { *m = EnumOptions{} } -func (m *EnumOptions) String() string { return proto.CompactTextString(m) } -func (*EnumOptions) ProtoMessage() {} -func (*EnumOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } +func (m *EnumOptions) Reset() { *m = EnumOptions{} } +func (m *EnumOptions) String() string { return proto.CompactTextString(m) } +func (*EnumOptions) ProtoMessage() {} +func (*EnumOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{14} +} var extRange_EnumOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*EnumOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_EnumOptions } +func (m *EnumOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumOptions.Unmarshal(m, b) +} +func (m *EnumOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumOptions.Marshal(b, m, deterministic) +} +func (m *EnumOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumOptions.Merge(m, src) +} +func (m *EnumOptions) XXX_Size() int { + return xxx_messageInfo_EnumOptions.Size(m) +} +func (m *EnumOptions) XXX_DiscardUnknown() { + xxx_messageInfo_EnumOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumOptions proto.InternalMessageInfo + const Default_EnumOptions_Deprecated bool = false func (m *EnumOptions) GetAllowAlias() bool { @@ -1469,23 +2000,45 @@ type EnumValueOptions struct { Deprecated *bool `protobuf:"varint,1,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } -func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) } -func (*EnumValueOptions) ProtoMessage() {} -func (*EnumValueOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } +func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } +func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) } +func (*EnumValueOptions) ProtoMessage() {} +func (*EnumValueOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{15} +} var extRange_EnumValueOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*EnumValueOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_EnumValueOptions } +func (m *EnumValueOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EnumValueOptions.Unmarshal(m, b) +} +func (m *EnumValueOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EnumValueOptions.Marshal(b, m, deterministic) +} +func (m *EnumValueOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_EnumValueOptions.Merge(m, src) +} +func (m *EnumValueOptions) XXX_Size() int { + return xxx_messageInfo_EnumValueOptions.Size(m) +} +func (m *EnumValueOptions) XXX_DiscardUnknown() { + xxx_messageInfo_EnumValueOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_EnumValueOptions proto.InternalMessageInfo + const Default_EnumValueOptions_Deprecated bool = false func (m *EnumValueOptions) GetDeprecated() bool { @@ -1510,23 +2063,45 @@ type ServiceOptions struct { Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } -func (m *ServiceOptions) String() string { return proto.CompactTextString(m) } -func (*ServiceOptions) ProtoMessage() {} -func (*ServiceOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } +func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } +func (m *ServiceOptions) String() string { return proto.CompactTextString(m) } +func (*ServiceOptions) ProtoMessage() {} +func (*ServiceOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{16} +} var extRange_ServiceOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*ServiceOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_ServiceOptions } +func (m *ServiceOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ServiceOptions.Unmarshal(m, b) +} +func (m *ServiceOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ServiceOptions.Marshal(b, m, deterministic) +} +func (m *ServiceOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServiceOptions.Merge(m, src) +} +func (m *ServiceOptions) XXX_Size() int { + return xxx_messageInfo_ServiceOptions.Size(m) +} +func (m *ServiceOptions) XXX_DiscardUnknown() { + xxx_messageInfo_ServiceOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_ServiceOptions proto.InternalMessageInfo + const Default_ServiceOptions_Deprecated bool = false func (m *ServiceOptions) GetDeprecated() bool { @@ -1552,23 +2127,45 @@ type MethodOptions struct { IdempotencyLevel *MethodOptions_IdempotencyLevel `protobuf:"varint,34,opt,name=idempotency_level,json=idempotencyLevel,enum=google.protobuf.MethodOptions_IdempotencyLevel,def=0" json:"idempotency_level,omitempty"` // The parser stores options it doesn't recognize here. See above. UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` proto.XXX_InternalExtensions `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *MethodOptions) Reset() { *m = MethodOptions{} } -func (m *MethodOptions) String() string { return proto.CompactTextString(m) } -func (*MethodOptions) ProtoMessage() {} -func (*MethodOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } +func (m *MethodOptions) Reset() { *m = MethodOptions{} } +func (m *MethodOptions) String() string { return proto.CompactTextString(m) } +func (*MethodOptions) ProtoMessage() {} +func (*MethodOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{17} +} var extRange_MethodOptions = []proto.ExtensionRange{ - {1000, 536870911}, + {Start: 1000, End: 536870911}, } func (*MethodOptions) ExtensionRangeArray() []proto.ExtensionRange { return extRange_MethodOptions } +func (m *MethodOptions) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MethodOptions.Unmarshal(m, b) +} +func (m *MethodOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MethodOptions.Marshal(b, m, deterministic) +} +func (m *MethodOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_MethodOptions.Merge(m, src) +} +func (m *MethodOptions) XXX_Size() int { + return xxx_messageInfo_MethodOptions.Size(m) +} +func (m *MethodOptions) XXX_DiscardUnknown() { + xxx_messageInfo_MethodOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_MethodOptions proto.InternalMessageInfo + const Default_MethodOptions_Deprecated bool = false const Default_MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel = MethodOptions_IDEMPOTENCY_UNKNOWN @@ -1603,19 +2200,41 @@ type UninterpretedOption struct { Name []*UninterpretedOption_NamePart `protobuf:"bytes,2,rep,name=name" json:"name,omitempty"` // The value of the uninterpreted option, in whatever type the tokenizer // identified it as during parsing. Exactly one of these should be set. - IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"` - PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"` - NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"` - DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` - StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` - AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"` - XXX_unrecognized []byte `json:"-"` + IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"` + PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"` + NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"` + DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` + StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` + AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} } -func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) } -func (*UninterpretedOption) ProtoMessage() {} -func (*UninterpretedOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } +func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} } +func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) } +func (*UninterpretedOption) ProtoMessage() {} +func (*UninterpretedOption) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{18} +} + +func (m *UninterpretedOption) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UninterpretedOption.Unmarshal(m, b) +} +func (m *UninterpretedOption) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UninterpretedOption.Marshal(b, m, deterministic) +} +func (m *UninterpretedOption) XXX_Merge(src proto.Message) { + xxx_messageInfo_UninterpretedOption.Merge(m, src) +} +func (m *UninterpretedOption) XXX_Size() int { + return xxx_messageInfo_UninterpretedOption.Size(m) +} +func (m *UninterpretedOption) XXX_DiscardUnknown() { + xxx_messageInfo_UninterpretedOption.DiscardUnknown(m) +} + +var xxx_messageInfo_UninterpretedOption proto.InternalMessageInfo func (m *UninterpretedOption) GetName() []*UninterpretedOption_NamePart { if m != nil { @@ -1672,18 +2291,38 @@ func (m *UninterpretedOption) GetAggregateValue() string { // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents // "foo.(bar.baz).qux". type UninterpretedOption_NamePart struct { - NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"` - IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"` - XXX_unrecognized []byte `json:"-"` + NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"` + IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *UninterpretedOption_NamePart) Reset() { *m = UninterpretedOption_NamePart{} } func (m *UninterpretedOption_NamePart) String() string { return proto.CompactTextString(m) } func (*UninterpretedOption_NamePart) ProtoMessage() {} func (*UninterpretedOption_NamePart) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{17, 0} + return fileDescriptor_e5baabe45344a177, []int{18, 0} } +func (m *UninterpretedOption_NamePart) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UninterpretedOption_NamePart.Unmarshal(m, b) +} +func (m *UninterpretedOption_NamePart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UninterpretedOption_NamePart.Marshal(b, m, deterministic) +} +func (m *UninterpretedOption_NamePart) XXX_Merge(src proto.Message) { + xxx_messageInfo_UninterpretedOption_NamePart.Merge(m, src) +} +func (m *UninterpretedOption_NamePart) XXX_Size() int { + return xxx_messageInfo_UninterpretedOption_NamePart.Size(m) +} +func (m *UninterpretedOption_NamePart) XXX_DiscardUnknown() { + xxx_messageInfo_UninterpretedOption_NamePart.DiscardUnknown(m) +} + +var xxx_messageInfo_UninterpretedOption_NamePart proto.InternalMessageInfo + func (m *UninterpretedOption_NamePart) GetNamePart() string { if m != nil && m.NamePart != nil { return *m.NamePart @@ -1744,14 +2383,36 @@ type SourceCodeInfo struct { // - Code which tries to interpret locations should probably be designed to // ignore those that it doesn't understand, as more types of locations could // be recorded in the future. - Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"` - XXX_unrecognized []byte `json:"-"` + Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} } -func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) } -func (*SourceCodeInfo) ProtoMessage() {} -func (*SourceCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } +func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} } +func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) } +func (*SourceCodeInfo) ProtoMessage() {} +func (*SourceCodeInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{19} +} + +func (m *SourceCodeInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SourceCodeInfo.Unmarshal(m, b) +} +func (m *SourceCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SourceCodeInfo.Marshal(b, m, deterministic) +} +func (m *SourceCodeInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_SourceCodeInfo.Merge(m, src) +} +func (m *SourceCodeInfo) XXX_Size() int { + return xxx_messageInfo_SourceCodeInfo.Size(m) +} +func (m *SourceCodeInfo) XXX_DiscardUnknown() { + xxx_messageInfo_SourceCodeInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_SourceCodeInfo proto.InternalMessageInfo func (m *SourceCodeInfo) GetLocation() []*SourceCodeInfo_Location { if m != nil { @@ -1841,13 +2502,35 @@ type SourceCodeInfo_Location struct { LeadingComments *string `protobuf:"bytes,3,opt,name=leading_comments,json=leadingComments" json:"leading_comments,omitempty"` TrailingComments *string `protobuf:"bytes,4,opt,name=trailing_comments,json=trailingComments" json:"trailing_comments,omitempty"` LeadingDetachedComments []string `protobuf:"bytes,6,rep,name=leading_detached_comments,json=leadingDetachedComments" json:"leading_detached_comments,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} } -func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) } -func (*SourceCodeInfo_Location) ProtoMessage() {} -func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18, 0} } +func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} } +func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) } +func (*SourceCodeInfo_Location) ProtoMessage() {} +func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{19, 0} +} + +func (m *SourceCodeInfo_Location) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SourceCodeInfo_Location.Unmarshal(m, b) +} +func (m *SourceCodeInfo_Location) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SourceCodeInfo_Location.Marshal(b, m, deterministic) +} +func (m *SourceCodeInfo_Location) XXX_Merge(src proto.Message) { + xxx_messageInfo_SourceCodeInfo_Location.Merge(m, src) +} +func (m *SourceCodeInfo_Location) XXX_Size() int { + return xxx_messageInfo_SourceCodeInfo_Location.Size(m) +} +func (m *SourceCodeInfo_Location) XXX_DiscardUnknown() { + xxx_messageInfo_SourceCodeInfo_Location.DiscardUnknown(m) +} + +var xxx_messageInfo_SourceCodeInfo_Location proto.InternalMessageInfo func (m *SourceCodeInfo_Location) GetPath() []int32 { if m != nil { @@ -1890,14 +2573,36 @@ func (m *SourceCodeInfo_Location) GetLeadingDetachedComments() []string { type GeneratedCodeInfo struct { // An Annotation connects some span of text in generated code to an element // of its generating .proto file. - Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"` - XXX_unrecognized []byte `json:"-"` + Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} } -func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) } -func (*GeneratedCodeInfo) ProtoMessage() {} -func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } +func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} } +func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) } +func (*GeneratedCodeInfo) ProtoMessage() {} +func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_e5baabe45344a177, []int{20} +} + +func (m *GeneratedCodeInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GeneratedCodeInfo.Unmarshal(m, b) +} +func (m *GeneratedCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GeneratedCodeInfo.Marshal(b, m, deterministic) +} +func (m *GeneratedCodeInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeneratedCodeInfo.Merge(m, src) +} +func (m *GeneratedCodeInfo) XXX_Size() int { + return xxx_messageInfo_GeneratedCodeInfo.Size(m) +} +func (m *GeneratedCodeInfo) XXX_DiscardUnknown() { + xxx_messageInfo_GeneratedCodeInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_GeneratedCodeInfo proto.InternalMessageInfo func (m *GeneratedCodeInfo) GetAnnotation() []*GeneratedCodeInfo_Annotation { if m != nil { @@ -1918,17 +2623,37 @@ type GeneratedCodeInfo_Annotation struct { // Identifies the ending offset in bytes in the generated code that // relates to the identified offset. The end offset should be one past // the last relevant byte (so the length of the text = end - begin). - End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"` - XXX_unrecognized []byte `json:"-"` + End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *GeneratedCodeInfo_Annotation) Reset() { *m = GeneratedCodeInfo_Annotation{} } func (m *GeneratedCodeInfo_Annotation) String() string { return proto.CompactTextString(m) } func (*GeneratedCodeInfo_Annotation) ProtoMessage() {} func (*GeneratedCodeInfo_Annotation) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{19, 0} + return fileDescriptor_e5baabe45344a177, []int{20, 0} } +func (m *GeneratedCodeInfo_Annotation) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GeneratedCodeInfo_Annotation.Unmarshal(m, b) +} +func (m *GeneratedCodeInfo_Annotation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GeneratedCodeInfo_Annotation.Marshal(b, m, deterministic) +} +func (m *GeneratedCodeInfo_Annotation) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeneratedCodeInfo_Annotation.Merge(m, src) +} +func (m *GeneratedCodeInfo_Annotation) XXX_Size() int { + return xxx_messageInfo_GeneratedCodeInfo_Annotation.Size(m) +} +func (m *GeneratedCodeInfo_Annotation) XXX_DiscardUnknown() { + xxx_messageInfo_GeneratedCodeInfo_Annotation.DiscardUnknown(m) +} + +var xxx_messageInfo_GeneratedCodeInfo_Annotation proto.InternalMessageInfo + func (m *GeneratedCodeInfo_Annotation) GetPath() []int32 { if m != nil { return m.Path @@ -1958,14 +2683,22 @@ func (m *GeneratedCodeInfo_Annotation) GetEnd() int32 { } func init() { + proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value) + proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value) + proto.RegisterEnum("google.protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value) + proto.RegisterEnum("google.protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value) + proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value) + proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value) proto.RegisterType((*FileDescriptorSet)(nil), "google.protobuf.FileDescriptorSet") proto.RegisterType((*FileDescriptorProto)(nil), "google.protobuf.FileDescriptorProto") proto.RegisterType((*DescriptorProto)(nil), "google.protobuf.DescriptorProto") proto.RegisterType((*DescriptorProto_ExtensionRange)(nil), "google.protobuf.DescriptorProto.ExtensionRange") proto.RegisterType((*DescriptorProto_ReservedRange)(nil), "google.protobuf.DescriptorProto.ReservedRange") + proto.RegisterType((*ExtensionRangeOptions)(nil), "google.protobuf.ExtensionRangeOptions") proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto") proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto") proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto") + proto.RegisterType((*EnumDescriptorProto_EnumReservedRange)(nil), "google.protobuf.EnumDescriptorProto.EnumReservedRange") proto.RegisterType((*EnumValueDescriptorProto)(nil), "google.protobuf.EnumValueDescriptorProto") proto.RegisterType((*ServiceDescriptorProto)(nil), "google.protobuf.ServiceDescriptorProto") proto.RegisterType((*MethodDescriptorProto)(nil), "google.protobuf.MethodDescriptorProto") @@ -1983,170 +2716,172 @@ func init() { proto.RegisterType((*SourceCodeInfo_Location)(nil), "google.protobuf.SourceCodeInfo.Location") proto.RegisterType((*GeneratedCodeInfo)(nil), "google.protobuf.GeneratedCodeInfo") proto.RegisterType((*GeneratedCodeInfo_Annotation)(nil), "google.protobuf.GeneratedCodeInfo.Annotation") - proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value) - proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value) - proto.RegisterEnum("google.protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value) - proto.RegisterEnum("google.protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value) - proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value) - proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value) } -func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor0) } +func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor_e5baabe45344a177) } -var fileDescriptor0 = []byte{ - // 2460 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x5b, 0x6f, 0xdb, 0xc8, - 0x15, 0x5e, 0x5d, 0x2d, 0x1d, 0xc9, 0xf2, 0x78, 0xec, 0x4d, 0x18, 0xef, 0x25, 0x8e, 0xf6, 0x12, - 0x6f, 0xd2, 0xc8, 0x0b, 0xe7, 0xb2, 0x59, 0xa7, 0x48, 0x21, 0x4b, 0x8c, 0x57, 0xa9, 0x2c, 0xa9, - 0x94, 0xdc, 0x4d, 0xf6, 0x85, 0x18, 0x93, 0x23, 0x99, 0x09, 0x45, 0x72, 0x49, 0x2a, 0x89, 0xf7, - 0x29, 0x40, 0x9f, 0x0a, 0xf4, 0x07, 0x14, 0x45, 0xd1, 0x87, 0x7d, 0x59, 0xa0, 0x3f, 0xa0, 0xcf, - 0xfd, 0x05, 0x05, 0xf6, 0xb9, 0x2f, 0x45, 0x51, 0xa0, 0xfd, 0x07, 0x7d, 0x2d, 0x66, 0x86, 0xa4, - 0x48, 0x5d, 0x12, 0x77, 0x81, 0xec, 0x3e, 0xd9, 0x73, 0xce, 0x77, 0x0e, 0xcf, 0x9c, 0xf9, 0x66, - 0xce, 0x99, 0x11, 0x6c, 0x8f, 0x6c, 0x7b, 0x64, 0xd2, 0x5d, 0xc7, 0xb5, 0x7d, 0xfb, 0x64, 0x32, - 0xdc, 0xd5, 0xa9, 0xa7, 0xb9, 0x86, 0xe3, 0xdb, 0x6e, 0x8d, 0xcb, 0xf0, 0x9a, 0x40, 0xd4, 0x42, - 0x44, 0xf5, 0x08, 0xd6, 0x1f, 0x18, 0x26, 0x6d, 0x46, 0xc0, 0x3e, 0xf5, 0xf1, 0x5d, 0xc8, 0x0e, - 0x0d, 0x93, 0x4a, 0xa9, 0xed, 0xcc, 0x4e, 0x69, 0xef, 0xc3, 0xda, 0x8c, 0x51, 0x2d, 0x69, 0xd1, - 0x63, 0x62, 0x85, 0x5b, 0x54, 0xff, 0x95, 0x85, 0x8d, 0x05, 0x5a, 0x8c, 0x21, 0x6b, 0x91, 0x31, - 0xf3, 0x98, 0xda, 0x29, 0x2a, 0xfc, 0x7f, 0x2c, 0xc1, 0x8a, 0x43, 0xb4, 0xa7, 0x64, 0x44, 0xa5, - 0x34, 0x17, 0x87, 0x43, 0xfc, 0x3e, 0x80, 0x4e, 0x1d, 0x6a, 0xe9, 0xd4, 0xd2, 0xce, 0xa4, 0xcc, - 0x76, 0x66, 0xa7, 0xa8, 0xc4, 0x24, 0xf8, 0x3a, 0xac, 0x3b, 0x93, 0x13, 0xd3, 0xd0, 0xd4, 0x18, - 0x0c, 0xb6, 0x33, 0x3b, 0x39, 0x05, 0x09, 0x45, 0x73, 0x0a, 0xbe, 0x0a, 0x6b, 0xcf, 0x29, 0x79, - 0x1a, 0x87, 0x96, 0x38, 0xb4, 0xc2, 0xc4, 0x31, 0x60, 0x03, 0xca, 0x63, 0xea, 0x79, 0x64, 0x44, - 0x55, 0xff, 0xcc, 0xa1, 0x52, 0x96, 0xcf, 0x7e, 0x7b, 0x6e, 0xf6, 0xb3, 0x33, 0x2f, 0x05, 0x56, - 0x83, 0x33, 0x87, 0xe2, 0x3a, 0x14, 0xa9, 0x35, 0x19, 0x0b, 0x0f, 0xb9, 0x25, 0xf9, 0x93, 0xad, - 0xc9, 0x78, 0xd6, 0x4b, 0x81, 0x99, 0x05, 0x2e, 0x56, 0x3c, 0xea, 0x3e, 0x33, 0x34, 0x2a, 0xe5, - 0xb9, 0x83, 0xab, 0x73, 0x0e, 0xfa, 0x42, 0x3f, 0xeb, 0x23, 0xb4, 0xc3, 0x0d, 0x28, 0xd2, 0x17, - 0x3e, 0xb5, 0x3c, 0xc3, 0xb6, 0xa4, 0x15, 0xee, 0xe4, 0xa3, 0x05, 0xab, 0x48, 0x4d, 0x7d, 0xd6, - 0xc5, 0xd4, 0x0e, 0xdf, 0x81, 0x15, 0xdb, 0xf1, 0x0d, 0xdb, 0xf2, 0xa4, 0xc2, 0x76, 0x6a, 0xa7, - 0xb4, 0xf7, 0xee, 0x42, 0x22, 0x74, 0x05, 0x46, 0x09, 0xc1, 0xb8, 0x05, 0xc8, 0xb3, 0x27, 0xae, - 0x46, 0x55, 0xcd, 0xd6, 0xa9, 0x6a, 0x58, 0x43, 0x5b, 0x2a, 0x72, 0x07, 0x97, 0xe7, 0x27, 0xc2, - 0x81, 0x0d, 0x5b, 0xa7, 0x2d, 0x6b, 0x68, 0x2b, 0x15, 0x2f, 0x31, 0xc6, 0x17, 0x20, 0xef, 0x9d, - 0x59, 0x3e, 0x79, 0x21, 0x95, 0x39, 0x43, 0x82, 0x51, 0xf5, 0xbf, 0x39, 0x58, 0x3b, 0x0f, 0xc5, - 0xee, 0x41, 0x6e, 0xc8, 0x66, 0x29, 0xa5, 0xff, 0x9f, 0x1c, 0x08, 0x9b, 0x64, 0x12, 0xf3, 0x3f, - 0x30, 0x89, 0x75, 0x28, 0x59, 0xd4, 0xf3, 0xa9, 0x2e, 0x18, 0x91, 0x39, 0x27, 0xa7, 0x40, 0x18, - 0xcd, 0x53, 0x2a, 0xfb, 0x83, 0x28, 0xf5, 0x08, 0xd6, 0xa2, 0x90, 0x54, 0x97, 0x58, 0xa3, 0x90, - 0x9b, 0xbb, 0xaf, 0x8b, 0xa4, 0x26, 0x87, 0x76, 0x0a, 0x33, 0x53, 0x2a, 0x34, 0x31, 0xc6, 0x4d, - 0x00, 0xdb, 0xa2, 0xf6, 0x50, 0xd5, 0xa9, 0x66, 0x4a, 0x85, 0x25, 0x59, 0xea, 0x32, 0xc8, 0x5c, - 0x96, 0x6c, 0x21, 0xd5, 0x4c, 0xfc, 0xf9, 0x94, 0x6a, 0x2b, 0x4b, 0x98, 0x72, 0x24, 0x36, 0xd9, - 0x1c, 0xdb, 0x8e, 0xa1, 0xe2, 0x52, 0xc6, 0x7b, 0xaa, 0x07, 0x33, 0x2b, 0xf2, 0x20, 0x6a, 0xaf, - 0x9d, 0x99, 0x12, 0x98, 0x89, 0x89, 0xad, 0xba, 0xf1, 0x21, 0xfe, 0x00, 0x22, 0x81, 0xca, 0x69, - 0x05, 0xfc, 0x14, 0x2a, 0x87, 0xc2, 0x0e, 0x19, 0xd3, 0xad, 0xbb, 0x50, 0x49, 0xa6, 0x07, 0x6f, - 0x42, 0xce, 0xf3, 0x89, 0xeb, 0x73, 0x16, 0xe6, 0x14, 0x31, 0xc0, 0x08, 0x32, 0xd4, 0xd2, 0xf9, - 0x29, 0x97, 0x53, 0xd8, 0xbf, 0x5b, 0x9f, 0xc1, 0x6a, 0xe2, 0xf3, 0xe7, 0x35, 0xac, 0xfe, 0x3e, - 0x0f, 0x9b, 0x8b, 0x38, 0xb7, 0x90, 0xfe, 0x17, 0x20, 0x6f, 0x4d, 0xc6, 0x27, 0xd4, 0x95, 0x32, - 0xdc, 0x43, 0x30, 0xc2, 0x75, 0xc8, 0x99, 0xe4, 0x84, 0x9a, 0x52, 0x76, 0x3b, 0xb5, 0x53, 0xd9, - 0xbb, 0x7e, 0x2e, 0x56, 0xd7, 0xda, 0xcc, 0x44, 0x11, 0x96, 0xf8, 0x3e, 0x64, 0x83, 0x23, 0x8e, - 0x79, 0xb8, 0x76, 0x3e, 0x0f, 0x8c, 0x8b, 0x0a, 0xb7, 0xc3, 0xef, 0x40, 0x91, 0xfd, 0x15, 0xb9, - 0xcd, 0xf3, 0x98, 0x0b, 0x4c, 0xc0, 0xf2, 0x8a, 0xb7, 0xa0, 0xc0, 0x69, 0xa6, 0xd3, 0xb0, 0x34, - 0x44, 0x63, 0xb6, 0x30, 0x3a, 0x1d, 0x92, 0x89, 0xe9, 0xab, 0xcf, 0x88, 0x39, 0xa1, 0x9c, 0x30, - 0x45, 0xa5, 0x1c, 0x08, 0x7f, 0xcd, 0x64, 0xf8, 0x32, 0x94, 0x04, 0x2b, 0x0d, 0x4b, 0xa7, 0x2f, - 0xf8, 0xe9, 0x93, 0x53, 0x04, 0x51, 0x5b, 0x4c, 0xc2, 0x3e, 0xff, 0xc4, 0xb3, 0xad, 0x70, 0x69, - 0xf9, 0x27, 0x98, 0x80, 0x7f, 0xfe, 0xb3, 0xd9, 0x83, 0xef, 0xbd, 0xc5, 0xd3, 0x9b, 0xe5, 0x62, - 0xf5, 0x2f, 0x69, 0xc8, 0xf2, 0xfd, 0xb6, 0x06, 0xa5, 0xc1, 0xe3, 0x9e, 0xac, 0x36, 0xbb, 0xc7, - 0x07, 0x6d, 0x19, 0xa5, 0x70, 0x05, 0x80, 0x0b, 0x1e, 0xb4, 0xbb, 0xf5, 0x01, 0x4a, 0x47, 0xe3, - 0x56, 0x67, 0x70, 0xe7, 0x16, 0xca, 0x44, 0x06, 0xc7, 0x42, 0x90, 0x8d, 0x03, 0x6e, 0xee, 0xa1, - 0x1c, 0x46, 0x50, 0x16, 0x0e, 0x5a, 0x8f, 0xe4, 0xe6, 0x9d, 0x5b, 0x28, 0x9f, 0x94, 0xdc, 0xdc, - 0x43, 0x2b, 0x78, 0x15, 0x8a, 0x5c, 0x72, 0xd0, 0xed, 0xb6, 0x51, 0x21, 0xf2, 0xd9, 0x1f, 0x28, - 0xad, 0xce, 0x21, 0x2a, 0x46, 0x3e, 0x0f, 0x95, 0xee, 0x71, 0x0f, 0x41, 0xe4, 0xe1, 0x48, 0xee, - 0xf7, 0xeb, 0x87, 0x32, 0x2a, 0x45, 0x88, 0x83, 0xc7, 0x03, 0xb9, 0x8f, 0xca, 0x89, 0xb0, 0x6e, - 0xee, 0xa1, 0xd5, 0xe8, 0x13, 0x72, 0xe7, 0xf8, 0x08, 0x55, 0xf0, 0x3a, 0xac, 0x8a, 0x4f, 0x84, - 0x41, 0xac, 0xcd, 0x88, 0xee, 0xdc, 0x42, 0x68, 0x1a, 0x88, 0xf0, 0xb2, 0x9e, 0x10, 0xdc, 0xb9, - 0x85, 0x70, 0xb5, 0x01, 0x39, 0xce, 0x2e, 0x8c, 0xa1, 0xd2, 0xae, 0x1f, 0xc8, 0x6d, 0xb5, 0xdb, - 0x1b, 0xb4, 0xba, 0x9d, 0x7a, 0x1b, 0xa5, 0xa6, 0x32, 0x45, 0xfe, 0xd5, 0x71, 0x4b, 0x91, 0x9b, - 0x28, 0x1d, 0x97, 0xf5, 0xe4, 0xfa, 0x40, 0x6e, 0xa2, 0x4c, 0x55, 0x83, 0xcd, 0x45, 0xe7, 0xcc, - 0xc2, 0x9d, 0x11, 0x5b, 0xe2, 0xf4, 0x92, 0x25, 0xe6, 0xbe, 0xe6, 0x96, 0xf8, 0xdb, 0x14, 0x6c, - 0x2c, 0x38, 0x6b, 0x17, 0x7e, 0xe4, 0x17, 0x90, 0x13, 0x14, 0x15, 0xd5, 0xe7, 0x93, 0x85, 0x87, - 0x36, 0x27, 0xec, 0x5c, 0x05, 0xe2, 0x76, 0xf1, 0x0a, 0x9c, 0x59, 0x52, 0x81, 0x99, 0x8b, 0xb9, - 0x20, 0x7f, 0x93, 0x02, 0x69, 0x99, 0xef, 0xd7, 0x1c, 0x14, 0xe9, 0xc4, 0x41, 0x71, 0x6f, 0x36, - 0x80, 0x2b, 0xcb, 0xe7, 0x30, 0x17, 0xc5, 0x77, 0x29, 0xb8, 0xb0, 0xb8, 0x51, 0x59, 0x18, 0xc3, - 0x7d, 0xc8, 0x8f, 0xa9, 0x7f, 0x6a, 0x87, 0xc5, 0xfa, 0xe3, 0x05, 0x25, 0x80, 0xa9, 0x67, 0x73, - 0x15, 0x58, 0xc5, 0x6b, 0x48, 0x66, 0x59, 0xb7, 0x21, 0xa2, 0x99, 0x8b, 0xf4, 0xb7, 0x69, 0x78, - 0x7b, 0xa1, 0xf3, 0x85, 0x81, 0xbe, 0x07, 0x60, 0x58, 0xce, 0xc4, 0x17, 0x05, 0x59, 0x9c, 0x4f, - 0x45, 0x2e, 0xe1, 0x7b, 0x9f, 0x9d, 0x3d, 0x13, 0x3f, 0xd2, 0x67, 0xb8, 0x1e, 0x84, 0x88, 0x03, - 0xee, 0x4e, 0x03, 0xcd, 0xf2, 0x40, 0xdf, 0x5f, 0x32, 0xd3, 0xb9, 0x5a, 0xf7, 0x29, 0x20, 0xcd, - 0x34, 0xa8, 0xe5, 0xab, 0x9e, 0xef, 0x52, 0x32, 0x36, 0xac, 0x11, 0x3f, 0x80, 0x0b, 0xfb, 0xb9, - 0x21, 0x31, 0x3d, 0xaa, 0xac, 0x09, 0x75, 0x3f, 0xd4, 0x32, 0x0b, 0x5e, 0x65, 0xdc, 0x98, 0x45, - 0x3e, 0x61, 0x21, 0xd4, 0x91, 0x45, 0xf5, 0xef, 0x2b, 0x50, 0x8a, 0xb5, 0x75, 0xf8, 0x0a, 0x94, - 0x9f, 0x90, 0x67, 0x44, 0x0d, 0x5b, 0x75, 0x91, 0x89, 0x12, 0x93, 0xf5, 0x82, 0x76, 0xfd, 0x53, - 0xd8, 0xe4, 0x10, 0x7b, 0xe2, 0x53, 0x57, 0xd5, 0x4c, 0xe2, 0x79, 0x3c, 0x69, 0x05, 0x0e, 0xc5, - 0x4c, 0xd7, 0x65, 0xaa, 0x46, 0xa8, 0xc1, 0xb7, 0x61, 0x83, 0x5b, 0x8c, 0x27, 0xa6, 0x6f, 0x38, - 0x26, 0x55, 0xd9, 0xe5, 0xc1, 0xe3, 0x07, 0x71, 0x14, 0xd9, 0x3a, 0x43, 0x1c, 0x05, 0x00, 0x16, - 0x91, 0x87, 0x9b, 0xf0, 0x1e, 0x37, 0x1b, 0x51, 0x8b, 0xba, 0xc4, 0xa7, 0x2a, 0xfd, 0x7a, 0x42, - 0x4c, 0x4f, 0x25, 0x96, 0xae, 0x9e, 0x12, 0xef, 0x54, 0xda, 0x64, 0x0e, 0x0e, 0xd2, 0x52, 0x4a, - 0xb9, 0xc4, 0x80, 0x87, 0x01, 0x4e, 0xe6, 0xb0, 0xba, 0xa5, 0x7f, 0x41, 0xbc, 0x53, 0xbc, 0x0f, - 0x17, 0xb8, 0x17, 0xcf, 0x77, 0x0d, 0x6b, 0xa4, 0x6a, 0xa7, 0x54, 0x7b, 0xaa, 0x4e, 0xfc, 0xe1, - 0x5d, 0xe9, 0x9d, 0xf8, 0xf7, 0x79, 0x84, 0x7d, 0x8e, 0x69, 0x30, 0xc8, 0xb1, 0x3f, 0xbc, 0x8b, - 0xfb, 0x50, 0x66, 0x8b, 0x31, 0x36, 0xbe, 0xa1, 0xea, 0xd0, 0x76, 0x79, 0x65, 0xa9, 0x2c, 0xd8, - 0xd9, 0xb1, 0x0c, 0xd6, 0xba, 0x81, 0xc1, 0x91, 0xad, 0xd3, 0xfd, 0x5c, 0xbf, 0x27, 0xcb, 0x4d, - 0xa5, 0x14, 0x7a, 0x79, 0x60, 0xbb, 0x8c, 0x50, 0x23, 0x3b, 0x4a, 0x70, 0x49, 0x10, 0x6a, 0x64, - 0x87, 0xe9, 0xbd, 0x0d, 0x1b, 0x9a, 0x26, 0xe6, 0x6c, 0x68, 0x6a, 0xd0, 0xe2, 0x7b, 0x12, 0x4a, - 0x24, 0x4b, 0xd3, 0x0e, 0x05, 0x20, 0xe0, 0xb8, 0x87, 0x3f, 0x87, 0xb7, 0xa7, 0xc9, 0x8a, 0x1b, - 0xae, 0xcf, 0xcd, 0x72, 0xd6, 0xf4, 0x36, 0x6c, 0x38, 0x67, 0xf3, 0x86, 0x38, 0xf1, 0x45, 0xe7, - 0x6c, 0xd6, 0xec, 0x23, 0x7e, 0x6d, 0x73, 0xa9, 0x46, 0x7c, 0xaa, 0x4b, 0x17, 0xe3, 0xe8, 0x98, - 0x02, 0xef, 0x02, 0xd2, 0x34, 0x95, 0x5a, 0xe4, 0xc4, 0xa4, 0x2a, 0x71, 0xa9, 0x45, 0x3c, 0xe9, - 0x72, 0x1c, 0x5c, 0xd1, 0x34, 0x99, 0x6b, 0xeb, 0x5c, 0x89, 0xaf, 0xc1, 0xba, 0x7d, 0xf2, 0x44, - 0x13, 0xcc, 0x52, 0x1d, 0x97, 0x0e, 0x8d, 0x17, 0xd2, 0x87, 0x3c, 0x4d, 0x6b, 0x4c, 0xc1, 0x79, - 0xd5, 0xe3, 0x62, 0xfc, 0x09, 0x20, 0xcd, 0x3b, 0x25, 0xae, 0xc3, 0x4b, 0xbb, 0xe7, 0x10, 0x8d, - 0x4a, 0x1f, 0x09, 0xa8, 0x90, 0x77, 0x42, 0x31, 0x63, 0xb6, 0xf7, 0xdc, 0x18, 0xfa, 0xa1, 0xc7, - 0xab, 0x82, 0xd9, 0x5c, 0x16, 0x78, 0xdb, 0x01, 0xe4, 0x9c, 0x3a, 0xc9, 0x0f, 0xef, 0x70, 0x58, - 0xc5, 0x39, 0x75, 0xe2, 0xdf, 0x7d, 0x04, 0x9b, 0x13, 0xcb, 0xb0, 0x7c, 0xea, 0x3a, 0x2e, 0x65, - 0xed, 0xbe, 0xd8, 0xb3, 0xd2, 0xbf, 0x57, 0x96, 0x34, 0xec, 0xc7, 0x71, 0xb4, 0xa0, 0x8a, 0xb2, - 0x31, 0x99, 0x17, 0x56, 0xf7, 0xa1, 0x1c, 0x67, 0x10, 0x2e, 0x82, 0xe0, 0x10, 0x4a, 0xb1, 0x6a, - 0xdc, 0xe8, 0x36, 0x59, 0x1d, 0xfd, 0x4a, 0x46, 0x69, 0x56, 0xcf, 0xdb, 0xad, 0x81, 0xac, 0x2a, - 0xc7, 0x9d, 0x41, 0xeb, 0x48, 0x46, 0x99, 0x6b, 0xc5, 0xc2, 0x7f, 0x56, 0xd0, 0xcb, 0x97, 0x2f, - 0x5f, 0xa6, 0x1f, 0x66, 0x0b, 0x1f, 0xa3, 0xab, 0xd5, 0xef, 0xd3, 0x50, 0x49, 0x76, 0xd2, 0xf8, - 0xe7, 0x70, 0x31, 0xbc, 0xf6, 0x7a, 0xd4, 0x57, 0x9f, 0x1b, 0x2e, 0xa7, 0xf6, 0x98, 0x88, 0x5e, - 0x34, 0x5a, 0x95, 0xcd, 0x00, 0xd5, 0xa7, 0xfe, 0x97, 0x86, 0xcb, 0x88, 0x3b, 0x26, 0x3e, 0x6e, - 0xc3, 0x65, 0xcb, 0x56, 0x3d, 0x9f, 0x58, 0x3a, 0x71, 0x75, 0x75, 0xfa, 0xe0, 0xa0, 0x12, 0x4d, - 0xa3, 0x9e, 0x67, 0x8b, 0x92, 0x12, 0x79, 0x79, 0xd7, 0xb2, 0xfb, 0x01, 0x78, 0x7a, 0xd6, 0xd6, - 0x03, 0xe8, 0x0c, 0x83, 0x32, 0xcb, 0x18, 0xf4, 0x0e, 0x14, 0xc7, 0xc4, 0x51, 0xa9, 0xe5, 0xbb, - 0x67, 0xbc, 0xff, 0x2b, 0x28, 0x85, 0x31, 0x71, 0x64, 0x36, 0x7e, 0x73, 0x2b, 0x91, 0xcc, 0x66, - 0x01, 0x15, 0x1f, 0x66, 0x0b, 0x45, 0x04, 0xd5, 0x7f, 0x66, 0xa0, 0x1c, 0xef, 0x07, 0x59, 0x7b, - 0xad, 0xf1, 0xb3, 0x3f, 0xc5, 0x4f, 0x87, 0x0f, 0x5e, 0xd9, 0x3d, 0xd6, 0x1a, 0xac, 0x28, 0xec, - 0xe7, 0x45, 0x97, 0xa6, 0x08, 0x4b, 0x56, 0x90, 0xd9, 0x79, 0x40, 0x45, 0xef, 0x5f, 0x50, 0x82, - 0x11, 0x3e, 0x84, 0xfc, 0x13, 0x8f, 0xfb, 0xce, 0x73, 0xdf, 0x1f, 0xbe, 0xda, 0xf7, 0xc3, 0x3e, - 0x77, 0x5e, 0x7c, 0xd8, 0x57, 0x3b, 0x5d, 0xe5, 0xa8, 0xde, 0x56, 0x02, 0x73, 0x7c, 0x09, 0xb2, - 0x26, 0xf9, 0xe6, 0x2c, 0x59, 0x3e, 0xb8, 0xe8, 0xbc, 0x8b, 0x70, 0x09, 0xb2, 0xcf, 0x29, 0x79, - 0x9a, 0x3c, 0xb4, 0xb9, 0xe8, 0x0d, 0x6e, 0x86, 0x5d, 0xc8, 0xf1, 0x7c, 0x61, 0x80, 0x20, 0x63, - 0xe8, 0x2d, 0x5c, 0x80, 0x6c, 0xa3, 0xab, 0xb0, 0x0d, 0x81, 0xa0, 0x2c, 0xa4, 0x6a, 0xaf, 0x25, - 0x37, 0x64, 0x94, 0xae, 0xde, 0x86, 0xbc, 0x48, 0x02, 0xdb, 0x2c, 0x51, 0x1a, 0xd0, 0x5b, 0xc1, - 0x30, 0xf0, 0x91, 0x0a, 0xb5, 0xc7, 0x47, 0x07, 0xb2, 0x82, 0xd2, 0xc9, 0xa5, 0xce, 0xa2, 0x5c, - 0xd5, 0x83, 0x72, 0xbc, 0x21, 0xfc, 0x51, 0x58, 0x56, 0xfd, 0x6b, 0x0a, 0x4a, 0xb1, 0x06, 0x8f, - 0xb5, 0x16, 0xc4, 0x34, 0xed, 0xe7, 0x2a, 0x31, 0x0d, 0xe2, 0x05, 0xd4, 0x00, 0x2e, 0xaa, 0x33, - 0xc9, 0x79, 0x97, 0xee, 0x47, 0xda, 0x22, 0x39, 0x94, 0xaf, 0xfe, 0x29, 0x05, 0x68, 0xb6, 0x45, - 0x9c, 0x09, 0x33, 0xf5, 0x53, 0x86, 0x59, 0xfd, 0x63, 0x0a, 0x2a, 0xc9, 0xbe, 0x70, 0x26, 0xbc, - 0x2b, 0x3f, 0x69, 0x78, 0xff, 0x48, 0xc3, 0x6a, 0xa2, 0x1b, 0x3c, 0x6f, 0x74, 0x5f, 0xc3, 0xba, - 0xa1, 0xd3, 0xb1, 0x63, 0xfb, 0xd4, 0xd2, 0xce, 0x54, 0x93, 0x3e, 0xa3, 0xa6, 0x54, 0xe5, 0x87, - 0xc6, 0xee, 0xab, 0xfb, 0xcd, 0x5a, 0x6b, 0x6a, 0xd7, 0x66, 0x66, 0xfb, 0x1b, 0xad, 0xa6, 0x7c, - 0xd4, 0xeb, 0x0e, 0xe4, 0x4e, 0xe3, 0xb1, 0x7a, 0xdc, 0xf9, 0x65, 0xa7, 0xfb, 0x65, 0x47, 0x41, - 0xc6, 0x0c, 0xec, 0x0d, 0x6e, 0xfb, 0x1e, 0xa0, 0xd9, 0xa0, 0xf0, 0x45, 0x58, 0x14, 0x16, 0x7a, - 0x0b, 0x6f, 0xc0, 0x5a, 0xa7, 0xab, 0xf6, 0x5b, 0x4d, 0x59, 0x95, 0x1f, 0x3c, 0x90, 0x1b, 0x83, - 0xbe, 0xb8, 0x80, 0x47, 0xe8, 0x41, 0x62, 0x83, 0x57, 0xff, 0x90, 0x81, 0x8d, 0x05, 0x91, 0xe0, - 0x7a, 0xd0, 0xfb, 0x8b, 0xeb, 0xc8, 0x8d, 0xf3, 0x44, 0x5f, 0x63, 0xdd, 0x45, 0x8f, 0xb8, 0x7e, - 0x70, 0x55, 0xf8, 0x04, 0x58, 0x96, 0x2c, 0xdf, 0x18, 0x1a, 0xd4, 0x0d, 0xde, 0x2b, 0xc4, 0x85, - 0x60, 0x6d, 0x2a, 0x17, 0x4f, 0x16, 0x3f, 0x03, 0xec, 0xd8, 0x9e, 0xe1, 0x1b, 0xcf, 0xa8, 0x6a, - 0x58, 0xe1, 0xe3, 0x06, 0xbb, 0x20, 0x64, 0x15, 0x14, 0x6a, 0x5a, 0x96, 0x1f, 0xa1, 0x2d, 0x3a, - 0x22, 0x33, 0x68, 0x76, 0x98, 0x67, 0x14, 0x14, 0x6a, 0x22, 0xf4, 0x15, 0x28, 0xeb, 0xf6, 0x84, - 0xb5, 0x5b, 0x02, 0xc7, 0x6a, 0x47, 0x4a, 0x29, 0x09, 0x59, 0x04, 0x09, 0xfa, 0xe1, 0xe9, 0xab, - 0x4a, 0x59, 0x29, 0x09, 0x99, 0x80, 0x5c, 0x85, 0x35, 0x32, 0x1a, 0xb9, 0xcc, 0x79, 0xe8, 0x48, - 0x74, 0xf8, 0x95, 0x48, 0xcc, 0x81, 0x5b, 0x0f, 0xa1, 0x10, 0xe6, 0x81, 0x95, 0x6a, 0x96, 0x09, - 0xd5, 0x11, 0x6f, 0x5b, 0xe9, 0x9d, 0xa2, 0x52, 0xb0, 0x42, 0xe5, 0x15, 0x28, 0x1b, 0x9e, 0x3a, - 0x7d, 0x64, 0x4d, 0x6f, 0xa7, 0x77, 0x0a, 0x4a, 0xc9, 0xf0, 0xa2, 0x57, 0xb5, 0xea, 0x77, 0x69, - 0xa8, 0x24, 0x1f, 0x89, 0x71, 0x13, 0x0a, 0xa6, 0xad, 0x11, 0x4e, 0x2d, 0xf1, 0x0b, 0xc5, 0xce, - 0x6b, 0xde, 0x95, 0x6b, 0xed, 0x00, 0xaf, 0x44, 0x96, 0x5b, 0x7f, 0x4b, 0x41, 0x21, 0x14, 0xe3, - 0x0b, 0x90, 0x75, 0x88, 0x7f, 0xca, 0xdd, 0xe5, 0x0e, 0xd2, 0x28, 0xa5, 0xf0, 0x31, 0x93, 0x7b, - 0x0e, 0xb1, 0x38, 0x05, 0x02, 0x39, 0x1b, 0xb3, 0x75, 0x35, 0x29, 0xd1, 0xf9, 0xf5, 0xc1, 0x1e, - 0x8f, 0xa9, 0xe5, 0x7b, 0xe1, 0xba, 0x06, 0xf2, 0x46, 0x20, 0xc6, 0xd7, 0x61, 0xdd, 0x77, 0x89, - 0x61, 0x26, 0xb0, 0x59, 0x8e, 0x45, 0xa1, 0x22, 0x02, 0xef, 0xc3, 0xa5, 0xd0, 0xaf, 0x4e, 0x7d, - 0xa2, 0x9d, 0x52, 0x7d, 0x6a, 0x94, 0xe7, 0x2f, 0x90, 0x17, 0x03, 0x40, 0x33, 0xd0, 0x87, 0xb6, - 0xd5, 0xef, 0x53, 0xb0, 0x1e, 0x5e, 0x78, 0xf4, 0x28, 0x59, 0x47, 0x00, 0xc4, 0xb2, 0x6c, 0x3f, - 0x9e, 0xae, 0x79, 0x2a, 0xcf, 0xd9, 0xd5, 0xea, 0x91, 0x91, 0x12, 0x73, 0xb0, 0x35, 0x06, 0x98, - 0x6a, 0x96, 0xa6, 0xed, 0x32, 0x94, 0x82, 0x5f, 0x00, 0xf8, 0xcf, 0x48, 0xe2, 0x8a, 0x0c, 0x42, - 0xc4, 0x6e, 0x46, 0x78, 0x13, 0x72, 0x27, 0x74, 0x64, 0x58, 0xc1, 0xbb, 0xa4, 0x18, 0x84, 0xaf, - 0x9d, 0xd9, 0xe8, 0xb5, 0xf3, 0xe0, 0x77, 0x29, 0xd8, 0xd0, 0xec, 0xf1, 0x6c, 0xbc, 0x07, 0x68, - 0xe6, 0x9e, 0xee, 0x7d, 0x91, 0xfa, 0xea, 0xfe, 0xc8, 0xf0, 0x4f, 0x27, 0x27, 0x35, 0xcd, 0x1e, - 0xef, 0x8e, 0x6c, 0x93, 0x58, 0xa3, 0xe9, 0xef, 0x60, 0xfc, 0x1f, 0xed, 0xc6, 0x88, 0x5a, 0x37, - 0x46, 0x76, 0xec, 0x57, 0xb1, 0x7b, 0xd3, 0x7f, 0xbf, 0x4d, 0x67, 0x0e, 0x7b, 0x07, 0x7f, 0x4e, - 0x6f, 0x1d, 0x8a, 0x6f, 0xf5, 0xc2, 0xdc, 0x28, 0x74, 0x68, 0x52, 0x8d, 0xcd, 0xf7, 0x7f, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x8e, 0x54, 0xe7, 0xef, 0x60, 0x1b, 0x00, 0x00, +var fileDescriptor_e5baabe45344a177 = []byte{ + // 2589 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xdd, 0x8e, 0xdb, 0xc6, + 0x15, 0x0e, 0xf5, 0xb7, 0xd2, 0x91, 0x56, 0x3b, 0x3b, 0xbb, 0xb1, 0xe9, 0xcd, 0x8f, 0xd7, 0xca, + 0x8f, 0xd7, 0x4e, 0xac, 0x0d, 0x1c, 0xdb, 0x71, 0xd6, 0x45, 0x5a, 0xad, 0x44, 0x6f, 0xe4, 0xee, + 0x4a, 0x2a, 0xa5, 0x6d, 0x7e, 0x80, 0x82, 0x98, 0x25, 0x47, 0x12, 0x6d, 0x8a, 0x64, 0x48, 0xca, + 0xf6, 0x06, 0xbd, 0x30, 0xd0, 0xab, 0x5e, 0x15, 0xe8, 0x55, 0x51, 0x14, 0xbd, 0xe8, 0x4d, 0x80, + 0x3e, 0x40, 0x81, 0xde, 0xf5, 0x09, 0x0a, 0xe4, 0x0d, 0x8a, 0xb6, 0x40, 0xfb, 0x08, 0xbd, 0x2c, + 0x66, 0x86, 0xa4, 0x48, 0x49, 0x1b, 0x6f, 0x02, 0xc4, 0xb9, 0x92, 0xe6, 0x3b, 0xdf, 0x39, 0x73, + 0xe6, 0xcc, 0x99, 0x99, 0x33, 0x43, 0xd8, 0x1e, 0x39, 0xce, 0xc8, 0xa2, 0xbb, 0xae, 0xe7, 0x04, + 0xce, 0xc9, 0x74, 0xb8, 0x6b, 0x50, 0x5f, 0xf7, 0x4c, 0x37, 0x70, 0xbc, 0x3a, 0xc7, 0xf0, 0x9a, + 0x60, 0xd4, 0x23, 0x46, 0xed, 0x08, 0xd6, 0xef, 0x9b, 0x16, 0x6d, 0xc5, 0xc4, 0x3e, 0x0d, 0xf0, + 0x5d, 0xc8, 0x0d, 0x4d, 0x8b, 0xca, 0xd2, 0x76, 0x76, 0xa7, 0x7c, 0xf3, 0xcd, 0xfa, 0x9c, 0x52, + 0x3d, 0xad, 0xd1, 0x63, 0xb0, 0xca, 0x35, 0x6a, 0xff, 0xce, 0xc1, 0xc6, 0x12, 0x29, 0xc6, 0x90, + 0xb3, 0xc9, 0x84, 0x59, 0x94, 0x76, 0x4a, 0x2a, 0xff, 0x8f, 0x65, 0x58, 0x71, 0x89, 0xfe, 0x88, + 0x8c, 0xa8, 0x9c, 0xe1, 0x70, 0xd4, 0xc4, 0xaf, 0x03, 0x18, 0xd4, 0xa5, 0xb6, 0x41, 0x6d, 0xfd, + 0x54, 0xce, 0x6e, 0x67, 0x77, 0x4a, 0x6a, 0x02, 0xc1, 0xef, 0xc0, 0xba, 0x3b, 0x3d, 0xb1, 0x4c, + 0x5d, 0x4b, 0xd0, 0x60, 0x3b, 0xbb, 0x93, 0x57, 0x91, 0x10, 0xb4, 0x66, 0xe4, 0xab, 0xb0, 0xf6, + 0x84, 0x92, 0x47, 0x49, 0x6a, 0x99, 0x53, 0xab, 0x0c, 0x4e, 0x10, 0x9b, 0x50, 0x99, 0x50, 0xdf, + 0x27, 0x23, 0xaa, 0x05, 0xa7, 0x2e, 0x95, 0x73, 0x7c, 0xf4, 0xdb, 0x0b, 0xa3, 0x9f, 0x1f, 0x79, + 0x39, 0xd4, 0x1a, 0x9c, 0xba, 0x14, 0x37, 0xa0, 0x44, 0xed, 0xe9, 0x44, 0x58, 0xc8, 0x9f, 0x11, + 0x3f, 0xc5, 0x9e, 0x4e, 0xe6, 0xad, 0x14, 0x99, 0x5a, 0x68, 0x62, 0xc5, 0xa7, 0xde, 0x63, 0x53, + 0xa7, 0x72, 0x81, 0x1b, 0xb8, 0xba, 0x60, 0xa0, 0x2f, 0xe4, 0xf3, 0x36, 0x22, 0x3d, 0xdc, 0x84, + 0x12, 0x7d, 0x1a, 0x50, 0xdb, 0x37, 0x1d, 0x5b, 0x5e, 0xe1, 0x46, 0xde, 0x5a, 0x32, 0x8b, 0xd4, + 0x32, 0xe6, 0x4d, 0xcc, 0xf4, 0xf0, 0x1d, 0x58, 0x71, 0xdc, 0xc0, 0x74, 0x6c, 0x5f, 0x2e, 0x6e, + 0x4b, 0x3b, 0xe5, 0x9b, 0xaf, 0x2e, 0x4d, 0x84, 0xae, 0xe0, 0xa8, 0x11, 0x19, 0xb7, 0x01, 0xf9, + 0xce, 0xd4, 0xd3, 0xa9, 0xa6, 0x3b, 0x06, 0xd5, 0x4c, 0x7b, 0xe8, 0xc8, 0x25, 0x6e, 0xe0, 0xf2, + 0xe2, 0x40, 0x38, 0xb1, 0xe9, 0x18, 0xb4, 0x6d, 0x0f, 0x1d, 0xb5, 0xea, 0xa7, 0xda, 0xf8, 0x02, + 0x14, 0xfc, 0x53, 0x3b, 0x20, 0x4f, 0xe5, 0x0a, 0xcf, 0x90, 0xb0, 0x55, 0xfb, 0x6b, 0x01, 0xd6, + 0xce, 0x93, 0x62, 0xf7, 0x20, 0x3f, 0x64, 0xa3, 0x94, 0x33, 0xdf, 0x26, 0x06, 0x42, 0x27, 0x1d, + 0xc4, 0xc2, 0x77, 0x0c, 0x62, 0x03, 0xca, 0x36, 0xf5, 0x03, 0x6a, 0x88, 0x8c, 0xc8, 0x9e, 0x33, + 0xa7, 0x40, 0x28, 0x2d, 0xa6, 0x54, 0xee, 0x3b, 0xa5, 0xd4, 0xa7, 0xb0, 0x16, 0xbb, 0xa4, 0x79, + 0xc4, 0x1e, 0x45, 0xb9, 0xb9, 0xfb, 0x3c, 0x4f, 0xea, 0x4a, 0xa4, 0xa7, 0x32, 0x35, 0xb5, 0x4a, + 0x53, 0x6d, 0xdc, 0x02, 0x70, 0x6c, 0xea, 0x0c, 0x35, 0x83, 0xea, 0x96, 0x5c, 0x3c, 0x23, 0x4a, + 0x5d, 0x46, 0x59, 0x88, 0x92, 0x23, 0x50, 0xdd, 0xc2, 0x1f, 0xce, 0x52, 0x6d, 0xe5, 0x8c, 0x4c, + 0x39, 0x12, 0x8b, 0x6c, 0x21, 0xdb, 0x8e, 0xa1, 0xea, 0x51, 0x96, 0xf7, 0xd4, 0x08, 0x47, 0x56, + 0xe2, 0x4e, 0xd4, 0x9f, 0x3b, 0x32, 0x35, 0x54, 0x13, 0x03, 0x5b, 0xf5, 0x92, 0x4d, 0xfc, 0x06, + 0xc4, 0x80, 0xc6, 0xd3, 0x0a, 0xf8, 0x2e, 0x54, 0x89, 0xc0, 0x0e, 0x99, 0xd0, 0xad, 0x2f, 0xa1, + 0x9a, 0x0e, 0x0f, 0xde, 0x84, 0xbc, 0x1f, 0x10, 0x2f, 0xe0, 0x59, 0x98, 0x57, 0x45, 0x03, 0x23, + 0xc8, 0x52, 0xdb, 0xe0, 0xbb, 0x5c, 0x5e, 0x65, 0x7f, 0xf1, 0x4f, 0x66, 0x03, 0xce, 0xf2, 0x01, + 0xbf, 0xbd, 0x38, 0xa3, 0x29, 0xcb, 0xf3, 0xe3, 0xde, 0xfa, 0x00, 0x56, 0x53, 0x03, 0x38, 0x6f, + 0xd7, 0xb5, 0x5f, 0xc2, 0xcb, 0x4b, 0x4d, 0xe3, 0x4f, 0x61, 0x73, 0x6a, 0x9b, 0x76, 0x40, 0x3d, + 0xd7, 0xa3, 0x2c, 0x63, 0x45, 0x57, 0xf2, 0x7f, 0x56, 0xce, 0xc8, 0xb9, 0xe3, 0x24, 0x5b, 0x58, + 0x51, 0x37, 0xa6, 0x8b, 0xe0, 0xf5, 0x52, 0xf1, 0xbf, 0x2b, 0xe8, 0xd9, 0xb3, 0x67, 0xcf, 0x32, + 0xb5, 0xdf, 0x15, 0x60, 0x73, 0xd9, 0x9a, 0x59, 0xba, 0x7c, 0x2f, 0x40, 0xc1, 0x9e, 0x4e, 0x4e, + 0xa8, 0xc7, 0x83, 0x94, 0x57, 0xc3, 0x16, 0x6e, 0x40, 0xde, 0x22, 0x27, 0xd4, 0x92, 0x73, 0xdb, + 0xd2, 0x4e, 0xf5, 0xe6, 0x3b, 0xe7, 0x5a, 0x95, 0xf5, 0x43, 0xa6, 0xa2, 0x0a, 0x4d, 0xfc, 0x11, + 0xe4, 0xc2, 0x2d, 0x9a, 0x59, 0xb8, 0x7e, 0x3e, 0x0b, 0x6c, 0x2d, 0xa9, 0x5c, 0x0f, 0xbf, 0x02, + 0x25, 0xf6, 0x2b, 0x72, 0xa3, 0xc0, 0x7d, 0x2e, 0x32, 0x80, 0xe5, 0x05, 0xde, 0x82, 0x22, 0x5f, + 0x26, 0x06, 0x8d, 0x8e, 0xb6, 0xb8, 0xcd, 0x12, 0xcb, 0xa0, 0x43, 0x32, 0xb5, 0x02, 0xed, 0x31, + 0xb1, 0xa6, 0x94, 0x27, 0x7c, 0x49, 0xad, 0x84, 0xe0, 0xcf, 0x19, 0x86, 0x2f, 0x43, 0x59, 0xac, + 0x2a, 0xd3, 0x36, 0xe8, 0x53, 0xbe, 0x7b, 0xe6, 0x55, 0xb1, 0xd0, 0xda, 0x0c, 0x61, 0xdd, 0x3f, + 0xf4, 0x1d, 0x3b, 0x4a, 0x4d, 0xde, 0x05, 0x03, 0x78, 0xf7, 0x1f, 0xcc, 0x6f, 0xdc, 0xaf, 0x2d, + 0x1f, 0xde, 0x7c, 0x4e, 0xd5, 0xfe, 0x92, 0x81, 0x1c, 0xdf, 0x2f, 0xd6, 0xa0, 0x3c, 0xf8, 0xac, + 0xa7, 0x68, 0xad, 0xee, 0xf1, 0xfe, 0xa1, 0x82, 0x24, 0x5c, 0x05, 0xe0, 0xc0, 0xfd, 0xc3, 0x6e, + 0x63, 0x80, 0x32, 0x71, 0xbb, 0xdd, 0x19, 0xdc, 0xb9, 0x85, 0xb2, 0xb1, 0xc2, 0xb1, 0x00, 0x72, + 0x49, 0xc2, 0xfb, 0x37, 0x51, 0x1e, 0x23, 0xa8, 0x08, 0x03, 0xed, 0x4f, 0x95, 0xd6, 0x9d, 0x5b, + 0xa8, 0x90, 0x46, 0xde, 0xbf, 0x89, 0x56, 0xf0, 0x2a, 0x94, 0x38, 0xb2, 0xdf, 0xed, 0x1e, 0xa2, + 0x62, 0x6c, 0xb3, 0x3f, 0x50, 0xdb, 0x9d, 0x03, 0x54, 0x8a, 0x6d, 0x1e, 0xa8, 0xdd, 0xe3, 0x1e, + 0x82, 0xd8, 0xc2, 0x91, 0xd2, 0xef, 0x37, 0x0e, 0x14, 0x54, 0x8e, 0x19, 0xfb, 0x9f, 0x0d, 0x94, + 0x3e, 0xaa, 0xa4, 0xdc, 0x7a, 0xff, 0x26, 0x5a, 0x8d, 0xbb, 0x50, 0x3a, 0xc7, 0x47, 0xa8, 0x8a, + 0xd7, 0x61, 0x55, 0x74, 0x11, 0x39, 0xb1, 0x36, 0x07, 0xdd, 0xb9, 0x85, 0xd0, 0xcc, 0x11, 0x61, + 0x65, 0x3d, 0x05, 0xdc, 0xb9, 0x85, 0x70, 0xad, 0x09, 0x79, 0x9e, 0x5d, 0x18, 0x43, 0xf5, 0xb0, + 0xb1, 0xaf, 0x1c, 0x6a, 0xdd, 0xde, 0xa0, 0xdd, 0xed, 0x34, 0x0e, 0x91, 0x34, 0xc3, 0x54, 0xe5, + 0x67, 0xc7, 0x6d, 0x55, 0x69, 0xa1, 0x4c, 0x12, 0xeb, 0x29, 0x8d, 0x81, 0xd2, 0x42, 0xd9, 0x9a, + 0x0e, 0x9b, 0xcb, 0xf6, 0xc9, 0xa5, 0x2b, 0x23, 0x31, 0xc5, 0x99, 0x33, 0xa6, 0x98, 0xdb, 0x5a, + 0x98, 0xe2, 0x7f, 0x65, 0x60, 0x63, 0xc9, 0x59, 0xb1, 0xb4, 0x93, 0x1f, 0x43, 0x5e, 0xa4, 0xa8, + 0x38, 0x3d, 0xaf, 0x2d, 0x3d, 0x74, 0x78, 0xc2, 0x2e, 0x9c, 0xa0, 0x5c, 0x2f, 0x59, 0x41, 0x64, + 0xcf, 0xa8, 0x20, 0x98, 0x89, 0x85, 0x3d, 0xfd, 0x17, 0x0b, 0x7b, 0xba, 0x38, 0xf6, 0xee, 0x9c, + 0xe7, 0xd8, 0xe3, 0xd8, 0xb7, 0xdb, 0xdb, 0xf3, 0x4b, 0xf6, 0xf6, 0x7b, 0xb0, 0xbe, 0x60, 0xe8, + 0xdc, 0x7b, 0xec, 0xaf, 0x24, 0x90, 0xcf, 0x0a, 0xce, 0x73, 0x76, 0xba, 0x4c, 0x6a, 0xa7, 0xbb, + 0x37, 0x1f, 0xc1, 0x2b, 0x67, 0x4f, 0xc2, 0xc2, 0x5c, 0x7f, 0x25, 0xc1, 0x85, 0xe5, 0x95, 0xe2, + 0x52, 0x1f, 0x3e, 0x82, 0xc2, 0x84, 0x06, 0x63, 0x27, 0xaa, 0x96, 0xde, 0x5e, 0x72, 0x06, 0x33, + 0xf1, 0xfc, 0x64, 0x87, 0x5a, 0xc9, 0x43, 0x3c, 0x7b, 0x56, 0xb9, 0x27, 0xbc, 0x59, 0xf0, 0xf4, + 0xd7, 0x19, 0x78, 0x79, 0xa9, 0xf1, 0xa5, 0x8e, 0xbe, 0x06, 0x60, 0xda, 0xee, 0x34, 0x10, 0x15, + 0x91, 0xd8, 0x60, 0x4b, 0x1c, 0xe1, 0x9b, 0x17, 0xdb, 0x3c, 0xa7, 0x41, 0x2c, 0xcf, 0x72, 0x39, + 0x08, 0x88, 0x13, 0xee, 0xce, 0x1c, 0xcd, 0x71, 0x47, 0x5f, 0x3f, 0x63, 0xa4, 0x0b, 0x89, 0xf9, + 0x1e, 0x20, 0xdd, 0x32, 0xa9, 0x1d, 0x68, 0x7e, 0xe0, 0x51, 0x32, 0x31, 0xed, 0x11, 0x3f, 0x41, + 0x8a, 0x7b, 0xf9, 0x21, 0xb1, 0x7c, 0xaa, 0xae, 0x09, 0x71, 0x3f, 0x92, 0x32, 0x0d, 0x9e, 0x40, + 0x5e, 0x42, 0xa3, 0x90, 0xd2, 0x10, 0xe2, 0x58, 0xa3, 0xf6, 0xdb, 0x12, 0x94, 0x13, 0x75, 0x35, + 0xbe, 0x02, 0x95, 0x87, 0xe4, 0x31, 0xd1, 0xa2, 0xbb, 0x92, 0x88, 0x44, 0x99, 0x61, 0xbd, 0xf0, + 0xbe, 0xf4, 0x1e, 0x6c, 0x72, 0x8a, 0x33, 0x0d, 0xa8, 0xa7, 0xe9, 0x16, 0xf1, 0x7d, 0x1e, 0xb4, + 0x22, 0xa7, 0x62, 0x26, 0xeb, 0x32, 0x51, 0x33, 0x92, 0xe0, 0xdb, 0xb0, 0xc1, 0x35, 0x26, 0x53, + 0x2b, 0x30, 0x5d, 0x8b, 0x6a, 0xec, 0xf6, 0xe6, 0xf3, 0x93, 0x24, 0xf6, 0x6c, 0x9d, 0x31, 0x8e, + 0x42, 0x02, 0xf3, 0xc8, 0xc7, 0x2d, 0x78, 0x8d, 0xab, 0x8d, 0xa8, 0x4d, 0x3d, 0x12, 0x50, 0x8d, + 0x7e, 0x31, 0x25, 0x96, 0xaf, 0x11, 0xdb, 0xd0, 0xc6, 0xc4, 0x1f, 0xcb, 0x9b, 0xcc, 0xc0, 0x7e, + 0x46, 0x96, 0xd4, 0x4b, 0x8c, 0x78, 0x10, 0xf2, 0x14, 0x4e, 0x6b, 0xd8, 0xc6, 0xc7, 0xc4, 0x1f, + 0xe3, 0x3d, 0xb8, 0xc0, 0xad, 0xf8, 0x81, 0x67, 0xda, 0x23, 0x4d, 0x1f, 0x53, 0xfd, 0x91, 0x36, + 0x0d, 0x86, 0x77, 0xe5, 0x57, 0x92, 0xfd, 0x73, 0x0f, 0xfb, 0x9c, 0xd3, 0x64, 0x94, 0xe3, 0x60, + 0x78, 0x17, 0xf7, 0xa1, 0xc2, 0x26, 0x63, 0x62, 0x7e, 0x49, 0xb5, 0xa1, 0xe3, 0xf1, 0xa3, 0xb1, + 0xba, 0x64, 0x6b, 0x4a, 0x44, 0xb0, 0xde, 0x0d, 0x15, 0x8e, 0x1c, 0x83, 0xee, 0xe5, 0xfb, 0x3d, + 0x45, 0x69, 0xa9, 0xe5, 0xc8, 0xca, 0x7d, 0xc7, 0x63, 0x09, 0x35, 0x72, 0xe2, 0x00, 0x97, 0x45, + 0x42, 0x8d, 0x9c, 0x28, 0xbc, 0xb7, 0x61, 0x43, 0xd7, 0xc5, 0x98, 0x4d, 0x5d, 0x0b, 0xef, 0x58, + 0xbe, 0x8c, 0x52, 0xc1, 0xd2, 0xf5, 0x03, 0x41, 0x08, 0x73, 0xdc, 0xc7, 0x1f, 0xc2, 0xcb, 0xb3, + 0x60, 0x25, 0x15, 0xd7, 0x17, 0x46, 0x39, 0xaf, 0x7a, 0x1b, 0x36, 0xdc, 0xd3, 0x45, 0x45, 0x9c, + 0xea, 0xd1, 0x3d, 0x9d, 0x57, 0xfb, 0x00, 0x36, 0xdd, 0xb1, 0xbb, 0xa8, 0x77, 0x3d, 0xa9, 0x87, + 0xdd, 0xb1, 0x3b, 0xaf, 0xf8, 0x16, 0xbf, 0x70, 0x7b, 0x54, 0x27, 0x01, 0x35, 0xe4, 0x8b, 0x49, + 0x7a, 0x42, 0x80, 0x77, 0x01, 0xe9, 0xba, 0x46, 0x6d, 0x72, 0x62, 0x51, 0x8d, 0x78, 0xd4, 0x26, + 0xbe, 0x7c, 0x39, 0x49, 0xae, 0xea, 0xba, 0xc2, 0xa5, 0x0d, 0x2e, 0xc4, 0xd7, 0x61, 0xdd, 0x39, + 0x79, 0xa8, 0x8b, 0x94, 0xd4, 0x5c, 0x8f, 0x0e, 0xcd, 0xa7, 0xf2, 0x9b, 0x3c, 0xbe, 0x6b, 0x4c, + 0xc0, 0x13, 0xb2, 0xc7, 0x61, 0x7c, 0x0d, 0x90, 0xee, 0x8f, 0x89, 0xe7, 0xf2, 0x3d, 0xd9, 0x77, + 0x89, 0x4e, 0xe5, 0xb7, 0x04, 0x55, 0xe0, 0x9d, 0x08, 0x66, 0x4b, 0xc2, 0x7f, 0x62, 0x0e, 0x83, + 0xc8, 0xe2, 0x55, 0xb1, 0x24, 0x38, 0x16, 0x5a, 0xdb, 0x01, 0xc4, 0x42, 0x91, 0xea, 0x78, 0x87, + 0xd3, 0xaa, 0xee, 0xd8, 0x4d, 0xf6, 0xfb, 0x06, 0xac, 0x32, 0xe6, 0xac, 0xd3, 0x6b, 0xa2, 0x20, + 0x73, 0xc7, 0x89, 0x1e, 0x6f, 0xc1, 0x05, 0x46, 0x9a, 0xd0, 0x80, 0x18, 0x24, 0x20, 0x09, 0xf6, + 0xbb, 0x9c, 0xcd, 0xe2, 0x7e, 0x14, 0x0a, 0x53, 0x7e, 0x7a, 0xd3, 0x93, 0xd3, 0x38, 0xb3, 0x6e, + 0x08, 0x3f, 0x19, 0x16, 0xe5, 0xd6, 0xf7, 0x56, 0x74, 0xd7, 0xf6, 0xa0, 0x92, 0x4c, 0x7c, 0x5c, + 0x02, 0x91, 0xfa, 0x48, 0x62, 0x55, 0x50, 0xb3, 0xdb, 0x62, 0xf5, 0xcb, 0xe7, 0x0a, 0xca, 0xb0, + 0x3a, 0xea, 0xb0, 0x3d, 0x50, 0x34, 0xf5, 0xb8, 0x33, 0x68, 0x1f, 0x29, 0x28, 0x9b, 0x28, 0xd8, + 0x1f, 0xe4, 0x8a, 0x6f, 0xa3, 0xab, 0xb5, 0xaf, 0x33, 0x50, 0x4d, 0xdf, 0xc0, 0xf0, 0x8f, 0xe0, + 0x62, 0xf4, 0x5c, 0xe2, 0xd3, 0x40, 0x7b, 0x62, 0x7a, 0x7c, 0x45, 0x4e, 0x88, 0x38, 0x1d, 0xe3, + 0x9c, 0xd8, 0x0c, 0x59, 0x7d, 0x1a, 0x7c, 0x62, 0x7a, 0x6c, 0xbd, 0x4d, 0x48, 0x80, 0x0f, 0xe1, + 0xb2, 0xed, 0x68, 0x7e, 0x40, 0x6c, 0x83, 0x78, 0x86, 0x36, 0x7b, 0xa8, 0xd2, 0x88, 0xae, 0x53, + 0xdf, 0x77, 0xc4, 0x49, 0x18, 0x5b, 0x79, 0xd5, 0x76, 0xfa, 0x21, 0x79, 0x76, 0x44, 0x34, 0x42, + 0xea, 0x5c, 0xfe, 0x66, 0xcf, 0xca, 0xdf, 0x57, 0xa0, 0x34, 0x21, 0xae, 0x46, 0xed, 0xc0, 0x3b, + 0xe5, 0x75, 0x77, 0x51, 0x2d, 0x4e, 0x88, 0xab, 0xb0, 0xf6, 0x0b, 0xb9, 0xfe, 0x3c, 0xc8, 0x15, + 0x8b, 0xa8, 0xf4, 0x20, 0x57, 0x2c, 0x21, 0xa8, 0xfd, 0x33, 0x0b, 0x95, 0x64, 0x1d, 0xce, 0xae, + 0x35, 0x3a, 0x3f, 0xb2, 0x24, 0xbe, 0xa9, 0xbd, 0xf1, 0x8d, 0x55, 0x7b, 0xbd, 0xc9, 0xce, 0xb2, + 0xbd, 0x82, 0xa8, 0x8e, 0x55, 0xa1, 0xc9, 0xea, 0x08, 0x96, 0x6c, 0x54, 0x54, 0x23, 0x45, 0x35, + 0x6c, 0xe1, 0x03, 0x28, 0x3c, 0xf4, 0xb9, 0xed, 0x02, 0xb7, 0xfd, 0xe6, 0x37, 0xdb, 0x7e, 0xd0, + 0xe7, 0xc6, 0x4b, 0x0f, 0xfa, 0x5a, 0xa7, 0xab, 0x1e, 0x35, 0x0e, 0xd5, 0x50, 0x1d, 0x5f, 0x82, + 0x9c, 0x45, 0xbe, 0x3c, 0x4d, 0x9f, 0x7a, 0x1c, 0x3a, 0xef, 0x24, 0x5c, 0x82, 0xdc, 0x13, 0x4a, + 0x1e, 0xa5, 0xcf, 0x1a, 0x0e, 0x7d, 0x8f, 0x8b, 0x61, 0x17, 0xf2, 0x3c, 0x5e, 0x18, 0x20, 0x8c, + 0x18, 0x7a, 0x09, 0x17, 0x21, 0xd7, 0xec, 0xaa, 0x6c, 0x41, 0x20, 0xa8, 0x08, 0x54, 0xeb, 0xb5, + 0x95, 0xa6, 0x82, 0x32, 0xb5, 0xdb, 0x50, 0x10, 0x41, 0x60, 0x8b, 0x25, 0x0e, 0x03, 0x7a, 0x29, + 0x6c, 0x86, 0x36, 0xa4, 0x48, 0x7a, 0x7c, 0xb4, 0xaf, 0xa8, 0x28, 0x93, 0x9e, 0xea, 0x1c, 0xca, + 0xd7, 0x7c, 0xa8, 0x24, 0x0b, 0xf1, 0x17, 0x73, 0xc9, 0xfe, 0x9b, 0x04, 0xe5, 0x44, 0x61, 0xcd, + 0x2a, 0x22, 0x62, 0x59, 0xce, 0x13, 0x8d, 0x58, 0x26, 0xf1, 0xc3, 0xd4, 0x00, 0x0e, 0x35, 0x18, + 0x72, 0xde, 0xa9, 0x7b, 0x41, 0x4b, 0x24, 0x8f, 0x0a, 0xb5, 0x3f, 0x4a, 0x80, 0xe6, 0x2b, 0xdb, + 0x39, 0x37, 0xa5, 0x1f, 0xd2, 0xcd, 0xda, 0x1f, 0x24, 0xa8, 0xa6, 0xcb, 0xd9, 0x39, 0xf7, 0xae, + 0xfc, 0xa0, 0xee, 0xfd, 0x23, 0x03, 0xab, 0xa9, 0x22, 0xf6, 0xbc, 0xde, 0x7d, 0x01, 0xeb, 0xa6, + 0x41, 0x27, 0xae, 0x13, 0x50, 0x5b, 0x3f, 0xd5, 0x2c, 0xfa, 0x98, 0x5a, 0x72, 0x8d, 0x6f, 0x1a, + 0xbb, 0xdf, 0x5c, 0x26, 0xd7, 0xdb, 0x33, 0xbd, 0x43, 0xa6, 0xb6, 0xb7, 0xd1, 0x6e, 0x29, 0x47, + 0xbd, 0xee, 0x40, 0xe9, 0x34, 0x3f, 0xd3, 0x8e, 0x3b, 0x3f, 0xed, 0x74, 0x3f, 0xe9, 0xa8, 0xc8, + 0x9c, 0xa3, 0x7d, 0x8f, 0xcb, 0xbe, 0x07, 0x68, 0xde, 0x29, 0x7c, 0x11, 0x96, 0xb9, 0x85, 0x5e, + 0xc2, 0x1b, 0xb0, 0xd6, 0xe9, 0x6a, 0xfd, 0x76, 0x4b, 0xd1, 0x94, 0xfb, 0xf7, 0x95, 0xe6, 0xa0, + 0x2f, 0x1e, 0x3e, 0x62, 0xf6, 0x20, 0xb5, 0xc0, 0x6b, 0xbf, 0xcf, 0xc2, 0xc6, 0x12, 0x4f, 0x70, + 0x23, 0xbc, 0xb2, 0x88, 0x5b, 0xd4, 0x8d, 0xf3, 0x78, 0x5f, 0x67, 0x35, 0x43, 0x8f, 0x78, 0x41, + 0x78, 0xc3, 0xb9, 0x06, 0x2c, 0x4a, 0x76, 0x60, 0x0e, 0x4d, 0xea, 0x85, 0xef, 0x44, 0xe2, 0x1e, + 0xb3, 0x36, 0xc3, 0xc5, 0x53, 0xd1, 0xbb, 0x80, 0x5d, 0xc7, 0x37, 0x03, 0xf3, 0x31, 0xd5, 0x4c, + 0x3b, 0x7a, 0x54, 0x62, 0xf7, 0x9a, 0x9c, 0x8a, 0x22, 0x49, 0xdb, 0x0e, 0x62, 0xb6, 0x4d, 0x47, + 0x64, 0x8e, 0xcd, 0x36, 0xf3, 0xac, 0x8a, 0x22, 0x49, 0xcc, 0xbe, 0x02, 0x15, 0xc3, 0x99, 0xb2, + 0x62, 0x4f, 0xf0, 0xd8, 0xd9, 0x21, 0xa9, 0x65, 0x81, 0xc5, 0x94, 0xb0, 0x8c, 0x9f, 0xbd, 0x66, + 0x55, 0xd4, 0xb2, 0xc0, 0x04, 0xe5, 0x2a, 0xac, 0x91, 0xd1, 0xc8, 0x63, 0xc6, 0x23, 0x43, 0xe2, + 0x62, 0x52, 0x8d, 0x61, 0x4e, 0xdc, 0x7a, 0x00, 0xc5, 0x28, 0x0e, 0xec, 0xa8, 0x66, 0x91, 0xd0, + 0x5c, 0x71, 0xdb, 0xce, 0xec, 0x94, 0xd4, 0xa2, 0x1d, 0x09, 0xaf, 0x40, 0xc5, 0xf4, 0xb5, 0xd9, + 0xe3, 0x7c, 0x66, 0x3b, 0xb3, 0x53, 0x54, 0xcb, 0xa6, 0x1f, 0x3f, 0x6c, 0xd6, 0xbe, 0xca, 0x40, + 0x35, 0xfd, 0x71, 0x01, 0xb7, 0xa0, 0x68, 0x39, 0x3a, 0xe1, 0xa9, 0x25, 0xbe, 0x6c, 0xed, 0x3c, + 0xe7, 0x7b, 0x44, 0xfd, 0x30, 0xe4, 0xab, 0xb1, 0xe6, 0xd6, 0xdf, 0x25, 0x28, 0x46, 0x30, 0xbe, + 0x00, 0x39, 0x97, 0x04, 0x63, 0x6e, 0x2e, 0xbf, 0x9f, 0x41, 0x92, 0xca, 0xdb, 0x0c, 0xf7, 0x5d, + 0x62, 0xf3, 0x14, 0x08, 0x71, 0xd6, 0x66, 0xf3, 0x6a, 0x51, 0x62, 0xf0, 0x5b, 0x8f, 0x33, 0x99, + 0x50, 0x3b, 0xf0, 0xa3, 0x79, 0x0d, 0xf1, 0x66, 0x08, 0xe3, 0x77, 0x60, 0x3d, 0xf0, 0x88, 0x69, + 0xa5, 0xb8, 0x39, 0xce, 0x45, 0x91, 0x20, 0x26, 0xef, 0xc1, 0xa5, 0xc8, 0xae, 0x41, 0x03, 0xa2, + 0x8f, 0xa9, 0x31, 0x53, 0x2a, 0xf0, 0xd7, 0x8d, 0x8b, 0x21, 0xa1, 0x15, 0xca, 0x23, 0xdd, 0xda, + 0xd7, 0x12, 0xac, 0x47, 0xf7, 0x34, 0x23, 0x0e, 0xd6, 0x11, 0x00, 0xb1, 0x6d, 0x27, 0x48, 0x86, + 0x6b, 0x31, 0x95, 0x17, 0xf4, 0xea, 0x8d, 0x58, 0x49, 0x4d, 0x18, 0xd8, 0x9a, 0x00, 0xcc, 0x24, + 0x67, 0x86, 0xed, 0x32, 0x94, 0xc3, 0x2f, 0x47, 0xfc, 0xf3, 0xa3, 0xb8, 0xd9, 0x83, 0x80, 0xd8, + 0x85, 0x0e, 0x6f, 0x42, 0xfe, 0x84, 0x8e, 0x4c, 0x3b, 0x7c, 0x0f, 0x16, 0x8d, 0xe8, 0xfd, 0x25, + 0x17, 0xbf, 0xbf, 0xec, 0xff, 0x46, 0x82, 0x0d, 0xdd, 0x99, 0xcc, 0xfb, 0xbb, 0x8f, 0xe6, 0x9e, + 0x17, 0xfc, 0x8f, 0xa5, 0xcf, 0x3f, 0x1a, 0x99, 0xc1, 0x78, 0x7a, 0x52, 0xd7, 0x9d, 0xc9, 0xee, + 0xc8, 0xb1, 0x88, 0x3d, 0x9a, 0x7d, 0x3f, 0xe5, 0x7f, 0xf4, 0x1b, 0x23, 0x6a, 0xdf, 0x18, 0x39, + 0x89, 0xaf, 0xa9, 0xf7, 0x66, 0x7f, 0xff, 0x27, 0x49, 0x7f, 0xca, 0x64, 0x0f, 0x7a, 0xfb, 0x7f, + 0xce, 0x6c, 0x1d, 0x88, 0xee, 0x7a, 0x51, 0x78, 0x54, 0x3a, 0xb4, 0xa8, 0xce, 0x86, 0xfc, 0xff, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x3e, 0xe8, 0xef, 0xc4, 0x9b, 0x1d, 0x00, 0x00, } diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto new file mode 100644 index 0000000000..ed08fcbc54 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto @@ -0,0 +1,883 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + + +syntax = "proto2"; + +package google.protobuf; +option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; +option csharp_namespace = "Google.Protobuf.Reflection"; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2" and "proto3". + optional string syntax = 12; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; + optional int32 end = 2; + + optional ExtensionRangeOptions options = 3; + } + repeated ExtensionRange extension_range = 5; + + repeated OneofDescriptorProto oneof_decl = 8; + + optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; +} + +message ExtensionRangeOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + // Tag-delimited aggregate. + // Group type is deprecated and not supported in proto3. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + }; + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + }; + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + // TODO(kenton): Base-64 encode? + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default=false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default=false]; +} + + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + + // If set, all the classes from the .proto file are wrapped in a single + // outer class with the given name. This applies to both Proto1 + // (equivalent to the old "--one_java_file" option) and Proto2 (where + // a .proto always translates to a single class, but you may want to + // explicitly choose the class name). + optional string java_outer_classname = 8; + + // If set true, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the outer class + // named by java_outer_classname. However, the outer class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default=false]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // If set true, then the Java2 code generator will generate code that + // throws an exception whenever an attempt is made to assign a non-UTF-8 + // byte sequence to a string field. + // Message reflection will do the same. + // However, an extension field still accepts non-UTF-8 byte sequences. + // This option has no effect on when used with the lite runtime. + optional bool java_string_check_utf8 = 27 [default=false]; + + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default=SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default=false]; + optional bool java_generic_services = 17 [default=false]; + optional bool py_generic_services = 18 [default=false]; + optional bool php_generic_services = 42 [default=false]; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default=false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default=false]; + + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be used + // for determining the namespace. + optional string php_metadata_namespace = 44; + + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + optional string ruby_package = 45; + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default=false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default=false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default=false]; + + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementions still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outer message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + optional bool lazy = 5 [default=false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default=false]; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default=false]; + + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype +} + +message OneofOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default=false]; + + reserved 5; // javanano_as_lite + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default=false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = + 34 [default=IDEMPOTENCY_UNKNOWN]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + // "foo.(bar.baz).qux". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendent. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition. For + // example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed=true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed=true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to qux. + // // + // // Another line attached to qux. + // optional double qux = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to qux or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed=true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified offset. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + } +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 2780671cd3..6fd5e58b27 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -159,16 +159,16 @@ "revisionTime": "2017-07-10T16:04:46Z" }, { - "checksumSHA1": "yqF125xVSkmfLpIVGrLlfE05IUk=", + "checksumSHA1": "CGj8VcI/CpzxaNqlqpEVM7qElD4=", "path": "github.com/golang/protobuf/proto", - "revision": "748d386b5c1ea99658fd69fe9f03991ce86a90c1", - "revisionTime": "2017-07-26T21:28:29Z" + "revision": "b285ee9cfc6c881bb20c0d8dc73370ea9b9ec90f", + "revisionTime": "2019-05-17T06:12:10Z" }, { - "checksumSHA1": "Z1gJ3PKzwBpOoPnTSEM5yd0zHYA=", + "checksumSHA1": "WOkXetG3AqJnfVVuqTJvdukcHps=", "path": "github.com/golang/protobuf/protoc-gen-go/descriptor", - "revision": "748d386b5c1ea99658fd69fe9f03991ce86a90c1", - "revisionTime": "2017-07-26T21:28:29Z" + "revision": "b285ee9cfc6c881bb20c0d8dc73370ea9b9ec90f", + "revisionTime": "2019-05-17T06:12:10Z" }, { "checksumSHA1": "p/8vSviYF91gFflhrt5vkyksroo=", From 17381ecc6695ea9c2d8e5ee0aee5cf70d59a301a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 3 Jun 2019 16:56:05 +0200 Subject: [PATCH 29/47] core/signer, clef: improve ui-test flow, fix errors in uint handling (#19584) * core/signer, clef: improve ui-test flow, fix errors in uint handling for eip-712 * core/signer: add fuzzer testcases + crashfixes * signer: address review concerns, check sign in integer parsing --- cmd/clef/main.go | 35 +- common/math/big.go | 7 + signer/core/api.go | 1 - signer/core/signed_data.go | 212 ++++--- signer/core/signed_data_internal_test.go | 51 ++ signer/core/signed_data_test.go | 576 +++--------------- signer/core/testdata/README.md | 5 + signer/core/testdata/arrays-1.json | 60 ++ signer/core/testdata/custom_arraytype.json | 54 ++ signer/core/testdata/eip712.json | 76 +++ .../testdata/expfail_arraytype_overload.json | 67 ++ .../core/testdata/expfail_datamismatch_1.json | 64 ++ signer/core/testdata/expfail_extradata-1.json | 76 +++ signer/core/testdata/expfail_extradata-2.json | 77 +++ .../testdata/expfail_malformeddomainkeys.json | 64 ++ .../testdata/expfail_nonexistant_type.json | 64 ++ .../core/testdata/expfail_toolargeuint.json | 38 ++ .../core/testdata/expfail_toolargeuint2.json | 38 ++ .../testdata/expfail_unconvertiblefloat.json | 38 ++ .../testdata/expfail_unconvertiblefloat2.json | 38 ++ .../2850f6ccf2d7f5f846dfb73119b60e09e712783f | 38 ++ .../36fb987a774011dc675e1b5246ac5c1d44d84d92 | 60 ++ .../37ec7b55c7ba014cced204c5f9989d2d0eb9ff6d | 38 ++ .../582fa92154b784daa1faa293b695fa388fe34bf1 | 1 + .../ab57cb2b2b5ce614efe13a47bc73814580f2cce8 | 54 ++ .../e4303e23ca34fbbc43164a232b2caa7a3af2bf8d | 64 ++ .../f658340af009dd4a35abe645a00a7b732bc30921 | 1 + 27 files changed, 1333 insertions(+), 564 deletions(-) create mode 100644 signer/core/signed_data_internal_test.go create mode 100644 signer/core/testdata/README.md create mode 100644 signer/core/testdata/arrays-1.json create mode 100644 signer/core/testdata/custom_arraytype.json create mode 100644 signer/core/testdata/eip712.json create mode 100644 signer/core/testdata/expfail_arraytype_overload.json create mode 100644 signer/core/testdata/expfail_datamismatch_1.json create mode 100644 signer/core/testdata/expfail_extradata-1.json create mode 100644 signer/core/testdata/expfail_extradata-2.json create mode 100644 signer/core/testdata/expfail_malformeddomainkeys.json create mode 100644 signer/core/testdata/expfail_nonexistant_type.json create mode 100644 signer/core/testdata/expfail_toolargeuint.json create mode 100644 signer/core/testdata/expfail_toolargeuint2.json create mode 100644 signer/core/testdata/expfail_unconvertiblefloat.json create mode 100644 signer/core/testdata/expfail_unconvertiblefloat2.json create mode 100644 signer/core/testdata/fuzzing/2850f6ccf2d7f5f846dfb73119b60e09e712783f create mode 100644 signer/core/testdata/fuzzing/36fb987a774011dc675e1b5246ac5c1d44d84d92 create mode 100644 signer/core/testdata/fuzzing/37ec7b55c7ba014cced204c5f9989d2d0eb9ff6d create mode 100644 signer/core/testdata/fuzzing/582fa92154b784daa1faa293b695fa388fe34bf1 create mode 100644 signer/core/testdata/fuzzing/ab57cb2b2b5ce614efe13a47bc73814580f2cce8 create mode 100644 signer/core/testdata/fuzzing/e4303e23ca34fbbc43164a232b2caa7a3af2bf8d create mode 100644 signer/core/testdata/fuzzing/f658340af009dd4a35abe645a00a7b732bc30921 diff --git a/cmd/clef/main.go b/cmd/clef/main.go index fecfcafaff..ad7ba186d0 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -33,6 +33,7 @@ import ( "path/filepath" "runtime" "strings" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -638,6 +639,10 @@ func testExternalUI(api *core.SignerAPI) { errs := make([]string, 0) a := common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef") + addErr := func(errStr string) { + log.Info("Test error", "error", errStr) + errs = append(errs, errStr) + } queryUser := func(q string) string { resp, err := api.UI.OnInputRequired(core.UserInputRequest{ @@ -645,36 +650,39 @@ func testExternalUI(api *core.SignerAPI) { Prompt: q, }) if err != nil { - errs = append(errs, err.Error()) + addErr(err.Error()) } return resp.Text } expectResponse := func(testcase, question, expect string) { if got := queryUser(question); got != expect { - errs = append(errs, fmt.Sprintf("%s: got %v, expected %v", testcase, got, expect)) + addErr(fmt.Sprintf("%s: got %v, expected %v", testcase, got, expect)) } } expectApprove := func(testcase string, err error) { if err == nil || err == accounts.ErrUnknownAccount { return } - errs = append(errs, fmt.Sprintf("%v: expected no error, got %v", testcase, err.Error())) + addErr(fmt.Sprintf("%v: expected no error, got %v", testcase, err.Error())) } expectDeny := func(testcase string, err error) { if err == nil || err != core.ErrRequestDenied { - errs = append(errs, fmt.Sprintf("%v: expected ErrRequestDenied, got %v", testcase, err)) + addErr(fmt.Sprintf("%v: expected ErrRequestDenied, got %v", testcase, err)) } } - + var delay = 1 * time.Second // Test display of info and error { api.UI.ShowInfo("If you see this message, enter 'yes' to next question") + time.Sleep(delay) expectResponse("showinfo", "Did you see the message? [yes/no]", "yes") api.UI.ShowError("If you see this message, enter 'yes' to the next question") + time.Sleep(delay) expectResponse("showerror", "Did you see the message? [yes/no]", "yes") } { // Sign data test - clique header api.UI.ShowInfo("Please approve the next request for signing a clique header") + time.Sleep(delay) cliqueHeader := types.Header{ common.HexToHash("0000H45H"), common.HexToHash("0000H45H"), @@ -700,14 +708,27 @@ func testExternalUI(api *core.SignerAPI) { _, err = api.SignData(ctx, accounts.MimetypeClique, *addr, hexutil.Encode(cliqueRlp)) expectApprove("signdata - clique header", err) } + { // Sign data test - typed data + api.UI.ShowInfo("Please approve the next request for signing EIP-712 typed data") + time.Sleep(delay) + addr, _ := common.NewMixedcaseAddressFromString("0x0011223344556677889900112233445566778899") + data := `{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"test","type":"uint8"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":"1","verifyingContract":"0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","test":"3","wallet":"0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","test":"2"},"contents":"Hello, Bob!"}}` + //_, err := api.SignData(ctx, accounts.MimetypeTypedData, *addr, hexutil.Encode([]byte(data))) + var typedData core.TypedData + err := json.Unmarshal([]byte(data), &typedData) + _, err = api.SignTypedData(ctx, *addr, typedData) + expectApprove("sign 712 typed data", err) + } { // Sign data test - plain text api.UI.ShowInfo("Please approve the next request for signing text") + time.Sleep(delay) addr, _ := common.NewMixedcaseAddressFromString("0x0011223344556677889900112233445566778899") _, err := api.SignData(ctx, accounts.MimetypeTextPlain, *addr, hexutil.Encode([]byte("hello world"))) expectApprove("signdata - text", err) } { // Sign data test - plain text reject api.UI.ShowInfo("Please deny the next request for signing text") + time.Sleep(delay) addr, _ := common.NewMixedcaseAddressFromString("0x0011223344556677889900112233445566778899") _, err := api.SignData(ctx, accounts.MimetypeTextPlain, *addr, hexutil.Encode([]byte("hello world"))) expectDeny("signdata - text", err) @@ -715,6 +736,7 @@ func testExternalUI(api *core.SignerAPI) { { // Sign transaction api.UI.ShowInfo("Please reject next transaction") + time.Sleep(delay) data := hexutil.Bytes([]byte{}) to := common.NewMixedcaseAddress(a) tx := core.SendTxArgs{ @@ -733,16 +755,19 @@ func testExternalUI(api *core.SignerAPI) { } { // Listing api.UI.ShowInfo("Please reject listing-request") + time.Sleep(delay) _, err := api.List(ctx) expectDeny("list", err) } { // Import api.UI.ShowInfo("Please reject new account-request") + time.Sleep(delay) _, err := api.New(ctx) expectDeny("newaccount", err) } { // Metadata api.UI.ShowInfo("Please check if you see the Origin in next listing (approve or deny)") + time.Sleep(delay) api.List(context.WithValue(ctx, "Origin", "origin.com")) expectResponse("metadata - origin", "Did you see origin (origin.com)? [yes/no] ", "yes") } diff --git a/common/math/big.go b/common/math/big.go index 9d2e7946d1..d31c59af10 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -42,6 +42,13 @@ const ( // HexOrDecimal256 marshals big.Int as hex or decimal. type HexOrDecimal256 big.Int +// NewHexOrDecimal256 creates a new HexOrDecimal256 +func NewHexOrDecimal256(x int64) *HexOrDecimal256 { + b := big.NewInt(x) + h := HexOrDecimal256(*b) + return &h +} + // UnmarshalText implements encoding.TextUnmarshaler. func (i *HexOrDecimal256) UnmarshalText(input []byte) error { bigint, ok := ParseBig256(string(input)) diff --git a/signer/core/api.go b/signer/core/api.go index 783aaece46..73a94634e0 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -482,7 +482,6 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth return nil, err } } - req := SignTxRequest{ Transaction: args, Meta: MetadataFromContext(ctx), diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index 9dfd7b3f69..27eca91831 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -23,6 +23,7 @@ import ( "fmt" "math/big" "mime" + "reflect" "regexp" "sort" "strconv" @@ -95,6 +96,9 @@ func (t *Type) typeName() string { } func (t *Type) isReferenceType() bool { + if len(t.Type) == 0 { + return false + } // Reference types must have a leading uppercase characer return unicode.IsUpper([]rune(t.Type)[0]) } @@ -109,11 +113,11 @@ type TypePriority struct { type TypedDataMessage = map[string]interface{} type TypedDataDomain struct { - Name string `json:"name"` - Version string `json:"version"` - ChainId *big.Int `json:"chainId"` - VerifyingContract string `json:"verifyingContract"` - Salt string `json:"salt"` + Name string `json:"name"` + Version string `json:"version"` + ChainId *math.HexOrDecimal256 `json:"chainId"` + VerifyingContract string `json:"verifyingContract"` + Salt string `json:"salt"` } var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Z](\w*)(\[\])?$`) @@ -323,7 +327,10 @@ func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAd } rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) sighash := crypto.Keccak256(rawData) - message := typedData.Format() + message, err := typedData.Format() + if err != nil { + return nil, err + } req := &SignDataRequest{ContentType: DataTyped.Mime, Rawdata: rawData, Message: message, Hash: sighash} signature, err := api.sign(addr, req, true) if err != nil { @@ -377,9 +384,11 @@ func (typedData *TypedData) Dependencies(primaryType string, found []string) []s func (typedData *TypedData) EncodeType(primaryType string) hexutil.Bytes { // Get dependencies primary first, then alphabetical deps := typedData.Dependencies(primaryType, []string{}) - slicedDeps := deps[1:] - sort.Strings(slicedDeps) - deps = append([]string{primaryType}, slicedDeps...) + if len(deps) > 0 { + slicedDeps := deps[1:] + sort.Strings(slicedDeps) + deps = append([]string{primaryType}, slicedDeps...) + } // Format as a string with fields var buffer bytes.Buffer @@ -476,10 +485,60 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter return buffer.Bytes(), nil } +func parseInteger(encType string, encValue interface{}) (*big.Int, error) { + var ( + length = 0 + signed = strings.HasPrefix(encType, "int") + b *big.Int + ) + if encType == "int" || encType == "uint" { + length = 256 + } else { + lengthStr := "" + if strings.HasPrefix(encType, "uint") { + lengthStr = strings.TrimPrefix(encType, "uint") + } else { + lengthStr = strings.TrimPrefix(encType, "int") + } + atoiSize, err := strconv.Atoi(lengthStr) + if err != nil { + return nil, fmt.Errorf("invalid size on integer: %v", lengthStr) + } + length = atoiSize + } + switch v := encValue.(type) { + case *math.HexOrDecimal256: + b = (*big.Int)(v) + case string: + var hexIntValue math.HexOrDecimal256 + if err := hexIntValue.UnmarshalText([]byte(v)); err != nil { + return nil, err + } + b = (*big.Int)(&hexIntValue) + case float64: + // JSON parses non-strings as float64. Fail if we cannot + // convert it losslessly + if float64(int64(v)) == v { + b = big.NewInt(int64(v)) + } else { + return nil, fmt.Errorf("invalid float value %v for type %v", v, encType) + } + } + if b == nil { + return nil, fmt.Errorf("invalid integer value %v/%v for type %v", encValue, reflect.TypeOf(encValue), encType) + } + if b.BitLen() > length { + return nil, fmt.Errorf("integer larger than '%v'", encType) + } + if !signed && b.Sign() == -1 { + return nil, fmt.Errorf("invalid negative value for unsigned type %v", encType) + } + return b, nil +} + // EncodePrimitiveValue deals with the primitive values found // while searching through the typed data func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interface{}, depth int) ([]byte, error) { - switch encType { case "address": stringValue, ok := encValue.(string) @@ -527,30 +586,11 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf } } if strings.HasPrefix(encType, "int") || strings.HasPrefix(encType, "uint") { - length := 0 - if encType == "int" || encType == "uint" { - length = 256 - } else { - lengthStr := "" - if strings.HasPrefix(encType, "uint") { - lengthStr = strings.TrimPrefix(encType, "uint") - } else { - lengthStr = strings.TrimPrefix(encType, "int") - } - atoiSize, err := strconv.Atoi(lengthStr) - if err != nil { - return nil, fmt.Errorf("invalid size on integer: %v", lengthStr) - } - length = atoiSize + b, err := parseInteger(encType, encValue) + if err != nil { + return nil, err } - bigIntValue, ok := encValue.(*big.Int) - if bigIntValue.BitLen() > length { - return nil, fmt.Errorf("integer larger than '%v'", encType) - } - if !ok { - return nil, dataMismatchError(encType, encValue) - } - return abi.U256(bigIntValue), nil + return abi.U256(b), nil } return nil, fmt.Errorf("unrecognized type '%s'", encType) @@ -649,35 +689,32 @@ func (typedData *TypedData) Map() map[string]interface{} { return dataMap } -// PrettyPrint generates a nice output to help the users -// of clef present data in their apps -func (typedData *TypedData) PrettyPrint() string { - output := bytes.Buffer{} - formatted := typedData.Format() - for _, item := range formatted { - output.WriteString(fmt.Sprintf("%v\n", item.Pprint(0))) - } - return output.String() -} - // Format returns a representation of typedData, which can be easily displayed by a user-interface // without in-depth knowledge about 712 rules -func (typedData *TypedData) Format() []*NameValueType { +func (typedData *TypedData) Format() ([]*NameValueType, error) { + domain, err := typedData.formatData("EIP712Domain", typedData.Domain.Map()) + if err != nil { + return nil, err + } + ptype, err := typedData.formatData(typedData.PrimaryType, typedData.Message) + if err != nil { + return nil, err + } var nvts []*NameValueType nvts = append(nvts, &NameValueType{ Name: "EIP712Domain", - Value: typedData.formatData("EIP712Domain", typedData.Domain.Map()), + Value: domain, Typ: "domain", }) nvts = append(nvts, &NameValueType{ Name: typedData.PrimaryType, - Value: typedData.formatData(typedData.PrimaryType, typedData.Message), + Value: ptype, Typ: "primary type", }) - return nvts + return nvts, nil } -func (typedData *TypedData) formatData(primaryType string, data map[string]interface{}) []*NameValueType { +func (typedData *TypedData) formatData(primaryType string, data map[string]interface{}) ([]*NameValueType, error) { var output []*NameValueType // Add field contents. Structs and arrays have special handlers. @@ -694,44 +731,70 @@ func (typedData *TypedData) formatData(primaryType string, data map[string]inter for _, v := range arrayValue { if typedData.Types[parsedType] != nil { mapValue, _ := v.(map[string]interface{}) - mapOutput := typedData.formatData(parsedType, mapValue) + mapOutput, err := typedData.formatData(parsedType, mapValue) + if err != nil { + return nil, err + } item.Value = mapOutput } else { - primitiveOutput := formatPrimitiveValue(field.Type, encValue) + primitiveOutput, err := formatPrimitiveValue(field.Type, encValue) + if err != nil { + return nil, err + } item.Value = primitiveOutput } } } else if typedData.Types[field.Type] != nil { - mapValue, _ := encValue.(map[string]interface{}) - mapOutput := typedData.formatData(field.Type, mapValue) - item.Value = mapOutput + if mapValue, ok := encValue.(map[string]interface{}); ok { + mapOutput, err := typedData.formatData(field.Type, mapValue) + if err != nil { + return nil, err + } + item.Value = mapOutput + } else { + item.Value = "" + } } else { - primitiveOutput := formatPrimitiveValue(field.Type, encValue) + primitiveOutput, err := formatPrimitiveValue(field.Type, encValue) + if err != nil { + return nil, err + } item.Value = primitiveOutput } output = append(output, item) } - return output + return output, nil } -func formatPrimitiveValue(encType string, encValue interface{}) string { +func formatPrimitiveValue(encType string, encValue interface{}) (string, error) { switch encType { case "address": - stringValue, _ := encValue.(string) - return common.HexToAddress(stringValue).String() + if stringValue, ok := encValue.(string); !ok { + return "", fmt.Errorf("could not format value %v as address", encValue) + } else { + return common.HexToAddress(stringValue).String(), nil + } case "bool": - boolValue, _ := encValue.(bool) - return fmt.Sprintf("%t", boolValue) + if boolValue, ok := encValue.(bool); !ok { + return "", fmt.Errorf("could not format value %v as bool", encValue) + } else { + return fmt.Sprintf("%t", boolValue), nil + } case "bytes", "string": - return fmt.Sprintf("%s", encValue) + return fmt.Sprintf("%s", encValue), nil } if strings.HasPrefix(encType, "bytes") { - return fmt.Sprintf("%s", encValue) - } else if strings.HasPrefix(encType, "uint") || strings.HasPrefix(encType, "int") { - bigIntValue, _ := encValue.(*big.Int) - return fmt.Sprintf("%d (0x%x)", bigIntValue, bigIntValue) + return fmt.Sprintf("%s", encValue), nil + } - return "NA" + if strings.HasPrefix(encType, "uint") || strings.HasPrefix(encType, "int") { + if b, err := parseInteger(encType, encValue); err != nil { + return "", err + } else { + return fmt.Sprintf("%d (0x%x)", b, b), nil + } + } + return "", fmt.Errorf("unhandled type %v", encType) } // NameValueType is a very simple struct with Name, Value and Type. It's meant for simple @@ -762,12 +825,21 @@ func (nvt *NameValueType) Pprint(depth int) string { // Validate checks if the types object is conformant to the specs func (t Types) validate() error { for typeKey, typeArr := range t { - for _, typeObj := range typeArr { + if len(typeKey) == 0 { + return fmt.Errorf("empty type key") + } + for i, typeObj := range typeArr { + if len(typeObj.Type) == 0 { + return fmt.Errorf("type %v:%d: empty Type", typeKey, i) + } + if len(typeObj.Name) == 0 { + return fmt.Errorf("type %v:%d: empty Name", typeKey, i) + } if typeKey == typeObj.Type { return fmt.Errorf("type '%s' cannot reference itself", typeObj.Type) } if typeObj.isReferenceType() { - if _, exist := t[typeObj.Type]; !exist { + if _, exist := t[typeObj.typeName()]; !exist { return fmt.Errorf("reference type '%s' is undefined", typeObj.Type) } if !typedDataReferenceTypeRegexp.MatchString(typeObj.Type) { @@ -895,7 +967,7 @@ func isPrimitiveTypeValid(primitiveType string) bool { // validate checks if the given domain is valid, i.e. contains at least // the minimum viable keys and values func (domain *TypedDataDomain) validate() error { - if domain.ChainId == big.NewInt(0) { + if domain.ChainId == nil { return errors.New("chainId must be specified according to EIP-155") } diff --git a/signer/core/signed_data_internal_test.go b/signer/core/signed_data_internal_test.go new file mode 100644 index 0000000000..b81872566d --- /dev/null +++ b/signer/core/signed_data_internal_test.go @@ -0,0 +1,51 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . +// +package core + +import ( + "math/big" + "testing" +) + +func TestParseInteger(t *testing.T) { + for i, tt := range []struct { + t string + v interface{} + exp *big.Int + }{ + {"uint32", "-123", nil}, + {"int32", "-123", big.NewInt(-123)}, + {"uint32", "0xff", big.NewInt(0xff)}, + {"int8", "0xffff", nil}, + } { + res, err := parseInteger(tt.t, tt.v) + if tt.exp == nil && res == nil { + continue + } + if tt.exp == nil && res != nil { + t.Errorf("test %d, got %v, expected nil", i, res) + continue + } + if tt.exp != nil && res == nil { + t.Errorf("test %d, got '%v', expected %v", i, err, tt.exp) + continue + } + if tt.exp.Cmp(res) != 0 { + t.Errorf("test %d, got %v expected %v", i, res, tt.exp) + } + } +} diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index f7d1994227..5a18defaac 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -20,12 +20,16 @@ import ( "context" "encoding/json" "fmt" - "math/big" + "io/ioutil" + "path" + "strings" "testing" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/signer/core" ) @@ -128,7 +132,7 @@ var jsonTypedData = ` "domain": { "name": "Ether Mail", "version": "1", - "chainId": 1, + "chainId": "1", "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" }, "message": { @@ -151,7 +155,7 @@ const primaryType = "Mail" var domainStandard = core.TypedDataDomain{ "Ether Mail", "1", - big.NewInt(1), + math.NewHexOrDecimal256(1), "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", "", } @@ -241,7 +245,6 @@ func TestDomainChainId(t *testing.T) { if _, ok := withoutChainID.Domain.Map()["chainId"]; ok { t.Errorf("Expected the chainId key to not be present in the domain map") } - withChainID := core.TypedData{ Types: core.Types{ "EIP712Domain": []core.Type{ @@ -251,7 +254,7 @@ func TestDomainChainId(t *testing.T) { }, Domain: core.TypedDataDomain{ Name: "test", - ChainId: big.NewInt(1), + ChainId: math.NewHexOrDecimal256(1), }, } @@ -310,495 +313,13 @@ func TestEncodeData(t *testing.T) { } } -func TestMalformedDomainkeys(t *testing.T) { - // Verifies that malformed domain keys are properly caught: - //{ - // "name": "Ether Mail", - // "version": "1", - // "chainId": 1, - // "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - //} - jsonTypedData := ` - { - "types": { - "EIP712Domain": [ - { - "name": "name", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "chainId", - "type": "uint256" - }, - { - "name": "verifyingContract", - "type": "address" - } - ], - "Person": [ - { - "name": "name", - "type": "string" - }, - { - "name": "wallet", - "type": "address" - } - ], - "Mail": [ - { - "name": "from", - "type": "Person" - }, - { - "name": "to", - "type": "Person" - }, - { - "name": "contents", - "type": "string" - } - ] - }, - "primaryType": "Mail", - "domain": { - "name": "Ether Mail", - "version": "1", - "chainId": 1, - "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - }, - "message": { - "from": { - "name": "Cow", - "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" - }, - "to": { - "name": "Bob", - "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" - }, - "contents": "Hello, Bob!" - } - } -` - var malformedDomainTypedData core.TypedData - err := json.Unmarshal([]byte(jsonTypedData), &malformedDomainTypedData) - if err != nil { - t.Fatalf("unmarshalling failed '%v'", err) - } - _, err = malformedDomainTypedData.HashStruct("EIP712Domain", malformedDomainTypedData.Domain.Map()) - if err == nil || err.Error() != "provided data '' doesn't match type 'address'" { - t.Errorf("Expected `provided data '' doesn't match type 'address'`, got '%v'", err) - } -} - -func TestMalformedTypesAndExtradata(t *testing.T) { - // Verifies several quirks - // 1. Using dynamic types and only validating the prefix: - //{ - // "name": "chainId", - // "type": "uint256 ... and now for something completely different" - //} - // 2. Extra data in message: - //{ - // "blahonga": "zonk bonk" - //} - jsonTypedData := ` - { - "types": { - "EIP712Domain": [ - { - "name": "name", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "chainId", - "type": "uint256 ... and now for something completely different" - }, - { - "name": "verifyingContract", - "type": "address" - } - ], - "Person": [ - { - "name": "name", - "type": "string" - }, - { - "name": "wallet", - "type": "address" - } - ], - "Mail": [ - { - "name": "from", - "type": "Person" - }, - { - "name": "to", - "type": "Person" - }, - { - "name": "contents", - "type": "string" - } - ] - }, - "primaryType": "Mail", - "domain": { - "name": "Ether Mail", - "version": "1", - "chainId": 1, - "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - }, - "message": { - "from": { - "name": "Cow", - "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" - }, - "to": { - "name": "Bob", - "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" - }, - "contents": "Hello, Bob!" - } - } -` - var malformedTypedData core.TypedData - err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) - if err != nil { - t.Fatalf("unmarshalling failed '%v'", err) - } - - malformedTypedData.Types["EIP712Domain"][2].Type = "uint256" - malformedTypedData.Message["blahonga"] = "zonk bonk" - _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) - if err == nil || err.Error() != "there is extra data provided in the message" { - t.Errorf("Expected `there is extra data provided in the message`, got '%v'", err) - } -} - -func TestTypeMismatch(t *testing.T) { - // Verifies that: - // 1. Mismatches between the given type and data, i.e. `Person` and - // the data item is a string, are properly caught: - //{ - // "name": "contents", - // "type": "Person" - //}, - //{ - // "contents": "Hello, Bob!" <-- string not "Person" - //} - // 2. Nonexistent types are properly caught: - //{ - // "name": "contents", - // "type": "Blahonga" - //} - jsonTypedData := ` - { - "types": { - "EIP712Domain": [ - { - "name": "name", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "chainId", - "type": "uint256" - }, - { - "name": "verifyingContract", - "type": "address" - } - ], - "Person": [ - { - "name": "name", - "type": "string" - }, - { - "name": "wallet", - "type": "address" - } - ], - "Mail": [ - { - "name": "from", - "type": "Person" - }, - { - "name": "to", - "type": "Person" - }, - { - "name": "contents", - "type": "Person" - } - ] - }, - "primaryType": "Mail", - "domain": { - "name": "Ether Mail", - "version": "1", - "chainId": 1, - "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - }, - "message": { - "from": { - "name": "Cow", - "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" - }, - "to": { - "name": "Bob", - "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" - }, - "contents": "Hello, Bob!" - } - } -` - var mismatchTypedData core.TypedData - err := json.Unmarshal([]byte(jsonTypedData), &mismatchTypedData) - if err != nil { - t.Fatalf("unmarshalling failed '%v'", err) - } - _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) - if err.Error() != "provided data 'Hello, Bob!' doesn't match type 'Person'" { - t.Errorf("Expected `provided data 'Hello, Bob!' doesn't match type 'Person'`, got '%v'", err) - } - - mismatchTypedData.Types["Mail"][2].Type = "Blahonga" - _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) - if err == nil || err.Error() != "reference type 'Blahonga' is undefined" { - t.Fatalf("Expected `reference type 'Blahonga' is undefined`, got '%v'", err) - } -} - -func TestTypeOverflow(t *testing.T) { - // Verifies data that doesn't fit into it: - //{ - // "test": 65536 <-- test defined as uint8 - //} - var overflowTypedData core.TypedData - err := json.Unmarshal([]byte(jsonTypedData), &overflowTypedData) - if err != nil { - t.Fatalf("unmarshalling failed '%v'", err) - } - // Set test to something outside uint8 - (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(65536) - - _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) - if err == nil || err.Error() != "integer larger than 'uint8'" { - t.Fatalf("Expected `integer larger than 'uint8'`, got '%v'", err) - } - - (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(3) - (overflowTypedData.Message["to"]).(map[string]interface{})["test"] = big.NewInt(4) - - _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) - if err != nil { - t.Fatalf("Expected no err, got '%v'", err) - } -} - -func TestArray(t *testing.T) { - // Makes sure that arrays work fine - //{ - // "type": "address[]" - //}, - //{ - // "type": "string[]" - //}, - //{ - // "type": "uint16[]", - //} - - jsonTypedData := ` - { - "types": { - "EIP712Domain": [ - { - "name": "name", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "chainId", - "type": "uint256" - }, - { - "name": "verifyingContract", - "type": "address" - } - ], - "Foo": [ - { - "name": "bar", - "type": "address[]" - } - ] - }, - "primaryType": "Foo", - "domain": { - "name": "Lorem", - "version": "1", - "chainId": 1, - "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - }, - "message": { - "bar": [ - "0x0000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000003" - ] - } - } - ` - var arrayTypedData core.TypedData - err := json.Unmarshal([]byte(jsonTypedData), &arrayTypedData) - if err != nil { - t.Fatalf("unmarshalling failed '%v'", err) - } - _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) - if err != nil { - t.Fatalf("Expected no err, got '%v'", err) - } - - // Change array to string - arrayTypedData.Types["Foo"][0].Type = "string[]" - arrayTypedData.Message["bar"] = []interface{}{ - "lorem", - "ipsum", - "dolores", - } - _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) - if err != nil { - t.Fatalf("Expected no err, got '%v'", err) - } - - // Change array to uint - arrayTypedData.Types["Foo"][0].Type = "uint[]" - arrayTypedData.Message["bar"] = []interface{}{ - big.NewInt(1955), - big.NewInt(108), - big.NewInt(44010), - } - _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) - if err != nil { - t.Fatalf("Expected no err, got '%v'", err) - } - - // Should not work with fixed-size arrays - arrayTypedData.Types["Foo"][0].Type = "uint[3]" - _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) - if err == nil || err.Error() != "unknown type 'uint[3]'" { - t.Fatalf("Expected `unknown type 'uint[3]'`, got '%v'", err) - } -} - -func TestCustomTypeAsArray(t *testing.T) { - var jsonTypedData = ` - { - "types": { - "EIP712Domain": [ - { - "name": "name", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "chainId", - "type": "uint256" - }, - { - "name": "verifyingContract", - "type": "address" - } - ], - "Person": [ - { - "name": "name", - "type": "string" - }, - { - "name": "wallet", - "type": "address" - } - ], - "Person[]": [ - { - "name": "baz", - "type": "string" - } - ], - "Mail": [ - { - "name": "from", - "type": "Person" - }, - { - "name": "to", - "type": "Person[]" - }, - { - "name": "contents", - "type": "string" - } - ] - }, - "primaryType": "Mail", - "domain": { - "name": "Ether Mail", - "version": "1", - "chainId": 1, - "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - }, - "message": { - "from": { - "name": "Cow", - "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" - }, - "to": {"baz": "foo"}, - "contents": "Hello, Bob!" - } - } - -` - var malformedTypedData core.TypedData - err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) - if err != nil { - t.Fatalf("unmarshalling failed '%v'", err) - } - _, err = malformedTypedData.HashStruct("EIP712Domain", malformedTypedData.Domain.Map()) - if err != nil { - t.Errorf("Expected no error, got '%v'", err) - } -} - func TestFormatter(t *testing.T) { var d core.TypedData err := json.Unmarshal([]byte(jsonTypedData), &d) if err != nil { t.Fatalf("unmarshalling failed '%v'", err) } - formatted := d.Format() + formatted, _ := d.Format() for _, item := range formatted { fmt.Printf("'%v'\n", item.Pprint(0)) } @@ -806,3 +327,82 @@ func TestFormatter(t *testing.T) { j, _ := json.Marshal(formatted) fmt.Printf("'%v'\n", string(j)) } + +func sign(typedData core.TypedData) ([]byte, []byte, error) { + domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) + if err != nil { + return nil, nil, err + } + typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) + if err != nil { + return nil, nil, err + } + rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) + sighash := crypto.Keccak256(rawData) + return typedDataHash, sighash, nil +} + +func TestJsonFiles(t *testing.T) { + testfiles, err := ioutil.ReadDir("testdata/") + if err != nil { + t.Fatalf("failed reading files: %v", err) + } + for i, fInfo := range testfiles { + if !strings.HasSuffix(fInfo.Name(), "json") { + continue + } + expectedFailure := strings.HasPrefix(fInfo.Name(), "expfail") + data, err := ioutil.ReadFile(path.Join("testdata", fInfo.Name())) + if err != nil { + t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) + continue + } + var typedData core.TypedData + err = json.Unmarshal([]byte(data), &typedData) + if err != nil { + t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err) + continue + } + _, _, err = sign(typedData) + fmt.Printf("Error %v\n", err) + if err != nil && !expectedFailure { + t.Errorf("Test %d failed, file %v: %v", i, fInfo.Name(), err) + } + if expectedFailure && err == nil { + t.Errorf("Test %d succeeded (expected failure), file %v: %v", i, fInfo.Name(), err) + } + } +} + +// TestFuzzerFiles tests some files that have been found by fuzzing to cause +// crashes or hangs. +func TestFuzzerFiles(t *testing.T) { + corpusdir := path.Join("testdata", "fuzzing") + testfiles, err := ioutil.ReadDir(corpusdir) + if err != nil { + t.Fatalf("failed reading files: %v", err) + } + verbose := false + for i, fInfo := range testfiles { + data, err := ioutil.ReadFile(path.Join(corpusdir, fInfo.Name())) + if err != nil { + t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) + continue + } + var typedData core.TypedData + err = json.Unmarshal([]byte(data), &typedData) + if err != nil { + t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err) + continue + } + _, err = typedData.EncodeData("EIP712Domain", typedData.Domain.Map(), 1) + if verbose && err != nil { + fmt.Printf("%d, EncodeData[1] err: %v\n", i, err) + } + _, err = typedData.EncodeData(typedData.PrimaryType, typedData.Message, 1) + if verbose && err != nil { + fmt.Printf("%d, EncodeData[2] err: %v\n", i, err) + } + typedData.Format() + } +} diff --git a/signer/core/testdata/README.md b/signer/core/testdata/README.md new file mode 100644 index 0000000000..f425450a06 --- /dev/null +++ b/signer/core/testdata/README.md @@ -0,0 +1,5 @@ +### EIP 712 tests + +These tests are json files which are converted into eip-712 typed data. +All files are expected to be proper json, and tests will fail if they are not. +Files that begin with `expfail' are expected to not pass the hashstruct construction. diff --git a/signer/core/testdata/arrays-1.json b/signer/core/testdata/arrays-1.json new file mode 100644 index 0000000000..fea82b42c6 --- /dev/null +++ b/signer/core/testdata/arrays-1.json @@ -0,0 +1,60 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Foo": [ + { + "name": "addys", + "type": "address[]" + }, + { + "name": "stringies", + "type": "string[]" + }, + { + "name": "inties", + "type": "uint[]" + } + ] + }, + "primaryType": "Foo", + "domain": { + "name": "Lorem", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "addys": [ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003" + ], + "stringies": [ + "lorem", + "ipsum", + "dolores" + ], + "inties": [ + "0x0000000000000000000000000000000000000001", + "3", + 4.0 + ] + } +} diff --git a/signer/core/testdata/custom_arraytype.json b/signer/core/testdata/custom_arraytype.json new file mode 100644 index 0000000000..078de88c22 --- /dev/null +++ b/signer/core/testdata/custom_arraytype.json @@ -0,0 +1,54 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person[]" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { "name": "Cow"}, + "to": [{ "name": "Moose"},{ "name": "Goose"}], + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/eip712.json b/signer/core/testdata/eip712.json new file mode 100644 index 0000000000..7b1cb8ae2d --- /dev/null +++ b/signer/core/testdata/eip712.json @@ -0,0 +1,76 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "test", + "type": "uint8" + }, + { + "name": "test2", + "type": "uint8" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "test": "3", + "test2": 5.0, + "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "test": "0", + "test2": 5, + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/expfail_arraytype_overload.json b/signer/core/testdata/expfail_arraytype_overload.json new file mode 100644 index 0000000000..786487f100 --- /dev/null +++ b/signer/core/testdata/expfail_arraytype_overload.json @@ -0,0 +1,67 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Person[]": [ + { + "name": "baz", + "type": "string" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person[]" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": {"baz": "foo"}, + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/expfail_datamismatch_1.json b/signer/core/testdata/expfail_datamismatch_1.json new file mode 100644 index 0000000000..d19d470d1e --- /dev/null +++ b/signer/core/testdata/expfail_datamismatch_1.json @@ -0,0 +1,64 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "Person" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/expfail_extradata-1.json b/signer/core/testdata/expfail_extradata-1.json new file mode 100644 index 0000000000..fd704209bc --- /dev/null +++ b/signer/core/testdata/expfail_extradata-1.json @@ -0,0 +1,76 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256 ... and now for something completely different" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "test", + "type": "uint8" + }, + { + "name": "test2", + "type": "uint8" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "test": "3", + "test2": 5.0, + "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "test": "0", + "test2": 5, + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/expfail_extradata-2.json b/signer/core/testdata/expfail_extradata-2.json new file mode 100644 index 0000000000..10f91c23af --- /dev/null +++ b/signer/core/testdata/expfail_extradata-2.json @@ -0,0 +1,77 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "test", + "type": "uint8" + }, + { + "name": "test2", + "type": "uint8" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "blahonga": "zonk bonk", + "from": { + "name": "Cow", + "test": "3", + "test2": 5.0, + "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "test": "0", + "test2": 5, + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/expfail_malformeddomainkeys.json b/signer/core/testdata/expfail_malformeddomainkeys.json new file mode 100644 index 0000000000..354b3cc859 --- /dev/null +++ b/signer/core/testdata/expfail_malformeddomainkeys.json @@ -0,0 +1,64 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "vFAILFAILerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/expfail_nonexistant_type.json b/signer/core/testdata/expfail_nonexistant_type.json new file mode 100644 index 0000000000..d06bc20b9f --- /dev/null +++ b/signer/core/testdata/expfail_nonexistant_type.json @@ -0,0 +1,64 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "Blahonga" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } +} diff --git a/signer/core/testdata/expfail_toolargeuint.json b/signer/core/testdata/expfail_toolargeuint.json new file mode 100644 index 0000000000..9854b65b17 --- /dev/null +++ b/signer/core/testdata/expfail_toolargeuint.json @@ -0,0 +1,38 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Mail": [ + { + "name": "test", + "type": "uint8" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "test":"257" + } +} diff --git a/signer/core/testdata/expfail_toolargeuint2.json b/signer/core/testdata/expfail_toolargeuint2.json new file mode 100644 index 0000000000..c63ed41f9c --- /dev/null +++ b/signer/core/testdata/expfail_toolargeuint2.json @@ -0,0 +1,38 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Mail": [ + { + "name": "test", + "type": "uint8" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "test":257 + } +} diff --git a/signer/core/testdata/expfail_unconvertiblefloat.json b/signer/core/testdata/expfail_unconvertiblefloat.json new file mode 100644 index 0000000000..8229a333ca --- /dev/null +++ b/signer/core/testdata/expfail_unconvertiblefloat.json @@ -0,0 +1,38 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Mail": [ + { + "name": "test", + "type": "uint8" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "test":"255.3" + } +} diff --git a/signer/core/testdata/expfail_unconvertiblefloat2.json b/signer/core/testdata/expfail_unconvertiblefloat2.json new file mode 100644 index 0000000000..59e6d38d24 --- /dev/null +++ b/signer/core/testdata/expfail_unconvertiblefloat2.json @@ -0,0 +1,38 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Mail": [ + { + "name": "test", + "type": "uint8" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "test": 255.3 + } +} diff --git a/signer/core/testdata/fuzzing/2850f6ccf2d7f5f846dfb73119b60e09e712783f b/signer/core/testdata/fuzzing/2850f6ccf2d7f5f846dfb73119b60e09e712783f new file mode 100644 index 0000000000..8229a333ca --- /dev/null +++ b/signer/core/testdata/fuzzing/2850f6ccf2d7f5f846dfb73119b60e09e712783f @@ -0,0 +1,38 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Mail": [ + { + "name": "test", + "type": "uint8" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "test":"255.3" + } +} diff --git a/signer/core/testdata/fuzzing/36fb987a774011dc675e1b5246ac5c1d44d84d92 b/signer/core/testdata/fuzzing/36fb987a774011dc675e1b5246ac5c1d44d84d92 new file mode 100644 index 0000000000..fea82b42c6 --- /dev/null +++ b/signer/core/testdata/fuzzing/36fb987a774011dc675e1b5246ac5c1d44d84d92 @@ -0,0 +1,60 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Foo": [ + { + "name": "addys", + "type": "address[]" + }, + { + "name": "stringies", + "type": "string[]" + }, + { + "name": "inties", + "type": "uint[]" + } + ] + }, + "primaryType": "Foo", + "domain": { + "name": "Lorem", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "addys": [ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003" + ], + "stringies": [ + "lorem", + "ipsum", + "dolores" + ], + "inties": [ + "0x0000000000000000000000000000000000000001", + "3", + 4.0 + ] + } +} diff --git a/signer/core/testdata/fuzzing/37ec7b55c7ba014cced204c5f9989d2d0eb9ff6d b/signer/core/testdata/fuzzing/37ec7b55c7ba014cced204c5f9989d2d0eb9ff6d new file mode 100644 index 0000000000..c63ed41f9c --- /dev/null +++ b/signer/core/testdata/fuzzing/37ec7b55c7ba014cced204c5f9989d2d0eb9ff6d @@ -0,0 +1,38 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Mail": [ + { + "name": "test", + "type": "uint8" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": "1", + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "test":257 + } +} diff --git a/signer/core/testdata/fuzzing/582fa92154b784daa1faa293b695fa388fe34bf1 b/signer/core/testdata/fuzzing/582fa92154b784daa1faa293b695fa388fe34bf1 new file mode 100644 index 0000000000..9bc43938d5 --- /dev/null +++ b/signer/core/testdata/fuzzing/582fa92154b784daa1faa293b695fa388fe34bf1 @@ -0,0 +1 @@ +{"domain":{"version":"0","chainId":""}} \ No newline at end of file diff --git a/signer/core/testdata/fuzzing/ab57cb2b2b5ce614efe13a47bc73814580f2cce8 b/signer/core/testdata/fuzzing/ab57cb2b2b5ce614efe13a47bc73814580f2cce8 new file mode 100644 index 0000000000..fe27de916c --- /dev/null +++ b/signer/core/testdata/fuzzing/ab57cb2b2b5ce614efe13a47bc73814580f2cce8 @@ -0,0 +1,54 @@ +{ "types": { "":[ { + "name": "name", + "type":"string" }, + { + "name":"version", + "type": "string" }, { + "name": "chaiI", + "type":"uint256 . ad nowretig omeedifere" }, { + "ae": "eifinC", + "ty":"dess" + } + ], + "Person":[ + { + "name":"name", + "type": "string" + }, { + "name":"tes", "type":"it8" + }, + { "name":"t", "tye":"uit8" + }, + { + "a":"ale", + "type": "ress" + } + ], + "Mail": [ + { + "name":"from", "type":"Person" }, + { + "name": "to", "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, "primaryType": "Mail", + "domain": { +"name":"theMail", "version": "1", + "chainId": "1", + "verifyingntract": "0xCcccCCCcCCCCCCCcCCcCCCcCcccccC" + }, + "message": { "from": { + "name": "Cow", + "test": "3", + "est2":5.0, + "llt": "0xcD2a3938E13D947E0bE734DfDD86" }, "to": { "name": "Bob", + "ts":"", + "tet2": 5, + "allet": "0bBBBBbbBBbbbbBbbBbbbbBBBbB" + }, + "contents": "Hello, Bob!" } +} \ No newline at end of file diff --git a/signer/core/testdata/fuzzing/e4303e23ca34fbbc43164a232b2caa7a3af2bf8d b/signer/core/testdata/fuzzing/e4303e23ca34fbbc43164a232b2caa7a3af2bf8d new file mode 100644 index 0000000000..c5e14b39ed --- /dev/null +++ b/signer/core/testdata/fuzzing/e4303e23ca34fbbc43164a232b2caa7a3af2bf8d @@ -0,0 +1,64 @@ +{ + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "int" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Mail" + }, + { + "name": "s", + "type": "Person" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "l", + "version": "1", + "chainId": "", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "": "" + } +} diff --git a/signer/core/testdata/fuzzing/f658340af009dd4a35abe645a00a7b732bc30921 b/signer/core/testdata/fuzzing/f658340af009dd4a35abe645a00a7b732bc30921 new file mode 100644 index 0000000000..c4841cb07b --- /dev/null +++ b/signer/core/testdata/fuzzing/f658340af009dd4a35abe645a00a7b732bc30921 @@ -0,0 +1 @@ +{"types":{"0":[{}]}} \ No newline at end of file From 15f24ff1896835e6ab908b0d17c1cc36b300c408 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Mon, 3 Jun 2019 18:52:02 +0300 Subject: [PATCH 30/47] ethclient: ensure tx json is not nil before accessing it (#19653) TransactionInBlock crashed if json was nil and there was an error because it tried to access fields `From` and `BlockHash` of the nil object. --- ethclient/ethclient.go | 13 +++++++------ ethclient/ethclient_test.go | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index f3163e19b3..aedf2814ad 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -241,12 +241,13 @@ func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) ( func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { var json *rpcTransaction err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index)) - if err == nil { - if json == nil { - return nil, ethereum.NotFound - } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { - return nil, fmt.Errorf("server returned transaction without signature") - } + if err != nil { + return nil, err + } + if json == nil { + return nil, ethereum.NotFound + } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { + return nil, fmt.Errorf("server returned transaction without signature") } if json.From != nil && json.BlockHash != nil { setSenderFromServer(json.tx, *json.From, *json.BlockHash) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 74711bd390..2e464cd42b 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -301,3 +301,21 @@ func TestBalanceAt(t *testing.T) { }) } } + +func TestTransactionInBlockInterrupted(t *testing.T) { + backend, _ := newTestBackend(t) + client, _ := backend.Attach() + defer backend.Stop() + defer client.Close() + + ec := NewClient(client) + ctx, cancel := context.WithCancel(context.Background()) + cancel() + tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1) + if tx != nil { + t.Fatal("transaction should be nil") + } + if err == nil { + t.Fatal("error should not be nil") + } +} From 42b81f94adba9aae7f7727951f35e92184b1eedb Mon Sep 17 00:00:00 2001 From: Rafael Matias Date: Tue, 4 Jun 2019 15:35:36 +0200 Subject: [PATCH 31/47] swarm: code cleanup, move to ethersphere/swarm (#19661) --- .travis.yml | 21 +- Makefile | 10 +- README.md | 21 +- build/deb/ethereum-swarm/deb.changelog | 5 - build/deb/ethereum-swarm/deb.control | 19 - build/deb/ethereum-swarm/deb.copyright | 14 - build/deb/ethereum-swarm/deb.docs | 1 - build/deb/ethereum-swarm/deb.install | 1 - build/deb/ethereum-swarm/deb.rules | 16 - build/deb/ethereum/deb.control | 4 +- build/update-license.go | 2 - cmd/swarm/access.go | 297 --- cmd/swarm/access_test.go | 617 ----- cmd/swarm/bootnodes.go | 24 - cmd/swarm/config.go | 451 ---- cmd/swarm/config_test.go | 575 ----- cmd/swarm/db.go | 239 -- cmd/swarm/download.go | 112 - cmd/swarm/explore.go | 60 - cmd/swarm/export_test.go | 287 --- cmd/swarm/feeds.go | 238 -- cmd/swarm/feeds_test.go | 196 -- cmd/swarm/flags.go | 189 -- cmd/swarm/fs.go | 162 -- cmd/swarm/fs_test.go | 260 -- cmd/swarm/global-store/explorer.go | 66 - cmd/swarm/global-store/explorer_test.go | 254 -- cmd/swarm/global-store/global_store.go | 120 - cmd/swarm/global-store/global_store_test.go | 207 -- cmd/swarm/global-store/main.go | 124 - cmd/swarm/global-store/run_test.go | 49 - cmd/swarm/hash.go | 116 - cmd/swarm/list.go | 70 - cmd/swarm/main.go | 475 ---- cmd/swarm/manifest.go | 353 --- cmd/swarm/manifest_test.go | 597 ----- cmd/swarm/mimegen/generator.go | 124 - cmd/swarm/mimegen/mime.types | 1828 -------------- cmd/swarm/run_test.go | 502 ---- cmd/swarm/swarm-smoke/feed_upload_and_sync.go | 291 --- cmd/swarm/swarm-smoke/main.go | 195 -- cmd/swarm/swarm-smoke/sliding_window.go | 149 -- cmd/swarm/swarm-smoke/upload_and_sync.go | 376 --- cmd/swarm/swarm-smoke/upload_speed.go | 73 - cmd/swarm/swarm-smoke/util.go | 231 -- cmd/swarm/swarm-snapshot/create.go | 160 -- cmd/swarm/swarm-snapshot/create_test.go | 140 -- cmd/swarm/swarm-snapshot/main.go | 83 - cmd/swarm/swarm-snapshot/run_test.go | 49 - cmd/swarm/testdata/datastore_fixture.go | 1390 ----------- cmd/swarm/upload.go | 188 -- cmd/swarm/upload_test.go | 359 --- contracts/chequebook/api.go | 68 - contracts/chequebook/cheque.go | 642 ----- contracts/chequebook/cheque_test.go | 487 ---- contracts/chequebook/contract/chequebook.go | 367 --- contracts/chequebook/contract/chequebook.sol | 47 - contracts/chequebook/contract/code.go | 5 - contracts/chequebook/contract/mortal.sol | 10 - contracts/chequebook/contract/owned.sol | 15 - contracts/chequebook/gencode.go | 70 - contracts/ens/README.md | 30 - contracts/ens/cid.go | 121 - contracts/ens/cid_test.go | 158 -- contracts/ens/contract/ENS.sol | 26 - contracts/ens/contract/ENSRegistry.sol | 99 - contracts/ens/contract/FIFSRegistrar.sol | 36 - contracts/ens/contract/PublicResolver.sol | 212 -- contracts/ens/contract/ens.go | 892 ------- contracts/ens/contract/ensregistry.go | 892 ------- contracts/ens/contract/fifsregistrar.go | 210 -- contracts/ens/contract/publicresolver.go | 1319 ----------- contracts/ens/ens.go | 263 --- contracts/ens/ens_test.go | 126 - .../ens/fallback_contract/PublicResolver.sol | 212 -- .../ens/fallback_contract/publicresolver.go | 1321 ----------- p2p/protocols/accounting.go | 182 -- p2p/protocols/accounting_api.go | 94 - p2p/protocols/accounting_simulation_test.go | 323 --- p2p/protocols/accounting_test.go | 223 -- p2p/protocols/protocol.go | 443 ---- p2p/protocols/protocol_test.go | 624 ----- p2p/protocols/reporter.go | 162 -- p2p/protocols/reporter_test.go | 83 - swarm/AUTHORS | 35 - swarm/OWNERS | 25 - swarm/README.md | 243 +- swarm/api/act.go | 538 ----- swarm/api/api.go | 993 -------- swarm/api/api_test.go | 576 ----- swarm/api/client/client.go | 829 ------- swarm/api/client/client_test.go | 608 ----- swarm/api/config.go | 174 -- swarm/api/config_test.go | 66 - swarm/api/encrypt.go | 78 - swarm/api/filesystem.go | 292 --- swarm/api/filesystem_test.go | 200 -- swarm/api/gen_mime.go | 1201 ---------- swarm/api/http/middleware.go | 162 -- swarm/api/http/response.go | 132 -- swarm/api/http/response_test.go | 170 -- swarm/api/http/roundtripper.go | 66 - swarm/api/http/roundtripper_test.go | 69 - swarm/api/http/sctx.go | 34 - swarm/api/http/server.go | 937 -------- swarm/api/http/server_test.go | 1409 ----------- swarm/api/http/templates.go | 306 --- swarm/api/http/test_server.go | 100 - swarm/api/inspector.go | 84 - swarm/api/manifest.go | 584 ----- swarm/api/manifest_test.go | 176 -- swarm/api/testdata/test0/img/logo.png | Bin 4119 -> 0 bytes swarm/api/testdata/test0/index.css | 9 - swarm/api/testdata/test0/index.html | 10 - swarm/api/uri.go | 144 -- swarm/api/uri_test.go | 175 -- swarm/bmt/bmt.go | 690 ------ swarm/bmt/bmt_r.go | 84 - swarm/bmt/bmt_test.go | 583 ----- swarm/chunk/chunk.go | 261 -- swarm/chunk/proximity_test.go | 186 -- swarm/chunk/tag.go | 218 -- swarm/chunk/tag_test.go | 273 --- swarm/chunk/tags.go | 96 - swarm/chunk/tags_test.go | 48 - swarm/dev/.dockerignore | 2 - swarm/dev/.gitignore | 2 - swarm/dev/Dockerfile | 42 - swarm/dev/Makefile | 14 - swarm/dev/README.md | 20 - swarm/dev/bashrc | 21 - swarm/dev/run.sh | 90 - swarm/dev/scripts/boot-cluster.sh | 288 --- swarm/dev/scripts/random-uploads.sh | 96 - swarm/dev/scripts/stop-cluster.sh | 98 - swarm/dev/scripts/util.sh | 53 - swarm/docker/Dockerfile | 32 - swarm/docker/run-smoke.sh | 7 - swarm/docker/run.sh | 26 - swarm/docs/migration-v0.3-to-v0.4.md | 31 - swarm/fuse/fuse_dir.go | 161 -- swarm/fuse/fuse_file.go | 146 -- swarm/fuse/fuse_root.go | 35 - swarm/fuse/swarmfs.go | 65 - swarm/fuse/swarmfs_fallback.go | 51 - swarm/fuse/swarmfs_test.go | 1672 ------------- swarm/fuse/swarmfs_unix.go | 285 --- swarm/fuse/swarmfs_util.go | 121 - swarm/log/log.go | 48 - swarm/metrics/flags.go | 143 -- swarm/network/README.md | 152 -- swarm/network/bitvector/bitvector.go | 62 - swarm/network/bitvector/bitvector_test.go | 104 - swarm/network/common.go | 30 - swarm/network/discovery.go | 220 -- swarm/network/discovery_test.go | 264 --- swarm/network/enr.go | 93 - swarm/network/fetcher.go | 336 --- swarm/network/fetcher_test.go | 476 ---- swarm/network/hive.go | 251 -- swarm/network/hive_test.go | 177 -- swarm/network/kademlia.go | 911 ------- swarm/network/kademlia_test.go | 672 ------ swarm/network/network.go | 105 - swarm/network/networkid_test.go | 263 --- swarm/network/priorityqueue/priorityqueue.go | 118 - .../priorityqueue/priorityqueue_test.go | 97 - swarm/network/protocol.go | 335 --- swarm/network/protocol_test.go | 343 --- swarm/network/simulation/bucket.go | 79 - swarm/network/simulation/bucket_test.go | 155 -- swarm/network/simulation/events.go | 217 -- swarm/network/simulation/events_test.go | 107 - swarm/network/simulation/example_test.go | 141 -- swarm/network/simulation/http.go | 68 - swarm/network/simulation/http_test.go | 110 - swarm/network/simulation/kademlia.go | 203 -- swarm/network/simulation/kademlia_test.go | 310 --- swarm/network/simulation/node.go | 341 --- swarm/network/simulation/node_test.go | 446 ---- swarm/network/simulation/service.go | 65 - swarm/network/simulation/service_test.go | 46 - swarm/network/simulation/simulation.go | 218 -- swarm/network/simulation/simulation_test.go | 203 -- .../simulations/discovery/discovery.go | 17 - .../simulations/discovery/discovery_test.go | 536 ----- .../simulations/discovery/snapshot.json | 1 - swarm/network/simulations/overlay.go | 144 -- swarm/network/simulations/overlay_test.go | 194 -- swarm/network/stream/common_test.go | 401 ---- swarm/network/stream/delivery.go | 245 -- swarm/network/stream/delivery_test.go | 593 ----- .../network/stream/intervals/dbstore_test.go | 42 - swarm/network/stream/intervals/intervals.go | 206 -- .../stream/intervals/intervals_test.go | 395 ---- swarm/network/stream/intervals/store_test.go | 77 - swarm/network/stream/intervals_test.go | 361 --- swarm/network/stream/lightnode_test.go | 129 - swarm/network/stream/messages.go | 417 ---- swarm/network/stream/peer.go | 588 ----- swarm/network/stream/peer_test.go | 309 --- .../network/stream/snapshot_retrieval_test.go | 484 ---- swarm/network/stream/snapshot_sync_test.go | 317 --- swarm/network/stream/stream.go | 811 ------- swarm/network/stream/streamer_test.go | 1214 ---------- swarm/network/stream/syncer.go | 235 -- swarm/network/stream/syncer_test.go | 347 --- .../network/stream/testing/snapshot_128.json | 1 - swarm/network/stream/testing/snapshot_16.json | 1 - .../network/stream/testing/snapshot_256.json | 1 - swarm/network/stream/testing/snapshot_32.json | 1 - swarm/network/stream/testing/snapshot_4.json | 1 - swarm/network/stream/testing/snapshot_64.json | 1 - swarm/network_test.go | 562 ----- swarm/pot/address.go | 210 -- swarm/pot/doc.go | 83 - swarm/pot/pot.go | 787 ------- swarm/pot/pot_test.go | 741 ------ swarm/pss/ARCHITECTURE.md | 144 -- swarm/pss/README.md | 318 --- swarm/pss/api.go | 195 -- swarm/pss/client/client.go | 352 --- swarm/pss/client/client_test.go | 287 --- swarm/pss/client/doc.go | 96 - swarm/pss/doc.go | 61 - swarm/pss/forwarding_test.go | 357 --- swarm/pss/handshake.go | 592 ----- swarm/pss/handshake_none.go | 27 - swarm/pss/handshake_test.go | 265 --- swarm/pss/keystore.go | 281 --- swarm/pss/notify/notify.go | 394 ---- swarm/pss/notify/notify_test.go | 265 --- swarm/pss/ping.go | 97 - swarm/pss/protocol.go | 283 --- swarm/pss/protocol_none.go | 23 - swarm/pss/protocol_test.go | 164 -- swarm/pss/prox_test.go | 467 ---- swarm/pss/pss.go | 857 ------- swarm/pss/pss_test.go | 2092 ----------------- swarm/pss/testdata/snapshot_128.json | 1 - swarm/pss/testdata/snapshot_16.json | 1 - swarm/pss/testdata/snapshot_2.json | 1 - swarm/pss/testdata/snapshot_256.json | 1 - swarm/pss/testdata/snapshot_3.json | 1 - swarm/pss/testdata/snapshot_32.json | 1 - swarm/pss/testdata/snapshot_4.json | 1 - swarm/pss/testdata/snapshot_64.json | 1 - swarm/pss/testdata/snapshot_8.json | 1 - swarm/pss/types.go | 217 -- swarm/pss/writeup.md | 125 - swarm/sctx/sctx.go | 37 - swarm/services/swap/swap.go | 301 --- swarm/services/swap/swap/swap.go | 252 -- swarm/services/swap/swap/swap_test.go | 194 -- swarm/shed/db.go | 311 --- swarm/shed/db_test.go | 112 - swarm/shed/example_store_test.go | 332 --- swarm/shed/field_string.go | 66 - swarm/shed/field_string_test.go | 110 - swarm/shed/field_struct.go | 71 - swarm/shed/field_struct_test.go | 127 - swarm/shed/field_uint64.go | 146 -- swarm/shed/field_uint64_test.go | 300 --- swarm/shed/index.go | 390 --- swarm/shed/index_test.go | 962 -------- swarm/shed/schema.go | 134 -- swarm/shed/schema_test.go | 126 - swarm/shed/vector_uint64.go | 146 -- swarm/shed/vector_uint64_test.go | 312 --- swarm/spancontext/spancontext.go | 49 - swarm/state/dbstore.go | 111 - swarm/state/dbstore_test.go | 125 - swarm/storage/chunker.go | 612 ----- swarm/storage/chunker_test.go | 470 ---- swarm/storage/common_test.go | 277 --- swarm/storage/encryption/encryption.go | 152 -- swarm/storage/encryption/encryption_test.go | 151 -- swarm/storage/error.go | 36 - swarm/storage/feed/binaryserializer.go | 44 - swarm/storage/feed/binaryserializer_test.go | 98 - swarm/storage/feed/cacheentry.go | 48 - swarm/storage/feed/doc.go | 43 - swarm/storage/feed/error.go | 73 - swarm/storage/feed/feed.go | 125 - swarm/storage/feed/feed_test.go | 36 - swarm/storage/feed/handler.go | 298 --- swarm/storage/feed/handler_test.go | 505 ---- swarm/storage/feed/id.go | 123 - swarm/storage/feed/id_test.go | 28 - .../feed/lookup/algorithm_fluzcapacitor.go | 63 - .../feed/lookup/algorithm_longearth.go | 185 -- swarm/storage/feed/lookup/epoch.go | 91 - swarm/storage/feed/lookup/epoch_test.go | 57 - swarm/storage/feed/lookup/lookup.go | 136 -- swarm/storage/feed/lookup/lookup_test.go | 641 ----- swarm/storage/feed/lookup/store_test.go | 154 -- swarm/storage/feed/lookup/timesim_test.go | 128 - swarm/storage/feed/query.go | 78 - swarm/storage/feed/query_test.go | 38 - swarm/storage/feed/request.go | 286 --- swarm/storage/feed/request_test.go | 312 --- swarm/storage/feed/sign.go | 75 - swarm/storage/feed/testutil.go | 72 - swarm/storage/feed/timestampprovider.go | 62 - swarm/storage/feed/topic.go | 105 - swarm/storage/feed/topic_test.go | 50 - swarm/storage/feed/update.go | 134 -- swarm/storage/feed/update_test.go | 50 - swarm/storage/filestore.go | 163 -- swarm/storage/filestore_test.go | 202 -- swarm/storage/hasherstore.go | 270 --- swarm/storage/hasherstore_test.go | 124 - swarm/storage/localstore/doc.go | 56 - swarm/storage/localstore/export.go | 204 -- swarm/storage/localstore/export_test.go | 80 - swarm/storage/localstore/gc.go | 194 -- swarm/storage/localstore/gc_test.go | 363 --- swarm/storage/localstore/index_test.go | 216 -- swarm/storage/localstore/localstore.go | 400 ---- swarm/storage/localstore/localstore_test.go | 453 ---- swarm/storage/localstore/mode_get.go | 148 -- swarm/storage/localstore/mode_get_test.go | 238 -- swarm/storage/localstore/mode_has.go | 39 - swarm/storage/localstore/mode_has_test.go | 56 - swarm/storage/localstore/mode_put.go | 176 -- swarm/storage/localstore/mode_put_test.go | 362 --- swarm/storage/localstore/mode_set.go | 194 -- swarm/storage/localstore/mode_set_test.go | 129 - .../localstore/retrieval_index_test.go | 147 -- swarm/storage/localstore/schema.go | 52 - swarm/storage/localstore/subscription_pull.go | 221 -- .../localstore/subscription_pull_test.go | 585 ----- swarm/storage/localstore/subscription_push.go | 160 -- .../localstore/subscription_push_test.go | 206 -- swarm/storage/mock/db/db.go | 476 ---- swarm/storage/mock/db/db_test.go | 75 - swarm/storage/mock/explorer/explorer.go | 257 -- swarm/storage/mock/explorer/explorer_test.go | 471 ---- swarm/storage/mock/explorer/headers_test.go | 163 -- swarm/storage/mock/explorer/swagger.yaml | 176 -- swarm/storage/mock/mem/mem.go | 385 --- swarm/storage/mock/mem/mem_test.go | 42 - swarm/storage/mock/mock.go | 142 -- swarm/storage/mock/rpc/rpc.go | 114 - swarm/storage/mock/rpc/rpc_test.go | 64 - swarm/storage/mock/test/test.go | 362 --- swarm/storage/netstore.go | 335 --- swarm/storage/netstore_test.go | 702 ------ swarm/storage/pyramid.go | 697 ------ swarm/storage/swarmhasher.go | 41 - swarm/storage/types.go | 250 -- swarm/swap/swap.go | 98 - swarm/swap/swap_test.go | 184 -- swarm/swarm.go | 559 ----- swarm/swarm_test.go | 387 --- swarm/testutil/file.go | 65 - swarm/testutil/norace.go | 26 - swarm/testutil/race.go | 23 - swarm/testutil/tag.go | 51 - swarm/tracing/tracing.go | 173 -- swarm/version/version.go | 67 - 361 files changed, 22 insertions(+), 87054 deletions(-) delete mode 100644 build/deb/ethereum-swarm/deb.changelog delete mode 100644 build/deb/ethereum-swarm/deb.control delete mode 100644 build/deb/ethereum-swarm/deb.copyright delete mode 100644 build/deb/ethereum-swarm/deb.docs delete mode 100644 build/deb/ethereum-swarm/deb.install delete mode 100644 build/deb/ethereum-swarm/deb.rules delete mode 100644 cmd/swarm/access.go delete mode 100644 cmd/swarm/access_test.go delete mode 100644 cmd/swarm/bootnodes.go delete mode 100644 cmd/swarm/config.go delete mode 100644 cmd/swarm/config_test.go delete mode 100644 cmd/swarm/db.go delete mode 100644 cmd/swarm/download.go delete mode 100644 cmd/swarm/explore.go delete mode 100644 cmd/swarm/export_test.go delete mode 100644 cmd/swarm/feeds.go delete mode 100644 cmd/swarm/feeds_test.go delete mode 100644 cmd/swarm/flags.go delete mode 100644 cmd/swarm/fs.go delete mode 100644 cmd/swarm/fs_test.go delete mode 100644 cmd/swarm/global-store/explorer.go delete mode 100644 cmd/swarm/global-store/explorer_test.go delete mode 100644 cmd/swarm/global-store/global_store.go delete mode 100644 cmd/swarm/global-store/global_store_test.go delete mode 100644 cmd/swarm/global-store/main.go delete mode 100644 cmd/swarm/global-store/run_test.go delete mode 100644 cmd/swarm/hash.go delete mode 100644 cmd/swarm/list.go delete mode 100644 cmd/swarm/main.go delete mode 100644 cmd/swarm/manifest.go delete mode 100644 cmd/swarm/manifest_test.go delete mode 100644 cmd/swarm/mimegen/generator.go delete mode 100644 cmd/swarm/mimegen/mime.types delete mode 100644 cmd/swarm/run_test.go delete mode 100644 cmd/swarm/swarm-smoke/feed_upload_and_sync.go delete mode 100644 cmd/swarm/swarm-smoke/main.go delete mode 100644 cmd/swarm/swarm-smoke/sliding_window.go delete mode 100644 cmd/swarm/swarm-smoke/upload_and_sync.go delete mode 100644 cmd/swarm/swarm-smoke/upload_speed.go delete mode 100644 cmd/swarm/swarm-smoke/util.go delete mode 100644 cmd/swarm/swarm-snapshot/create.go delete mode 100644 cmd/swarm/swarm-snapshot/create_test.go delete mode 100644 cmd/swarm/swarm-snapshot/main.go delete mode 100644 cmd/swarm/swarm-snapshot/run_test.go delete mode 100644 cmd/swarm/testdata/datastore_fixture.go delete mode 100644 cmd/swarm/upload.go delete mode 100644 cmd/swarm/upload_test.go delete mode 100644 contracts/chequebook/api.go delete mode 100644 contracts/chequebook/cheque.go delete mode 100644 contracts/chequebook/cheque_test.go delete mode 100644 contracts/chequebook/contract/chequebook.go delete mode 100644 contracts/chequebook/contract/chequebook.sol delete mode 100644 contracts/chequebook/contract/code.go delete mode 100644 contracts/chequebook/contract/mortal.sol delete mode 100644 contracts/chequebook/contract/owned.sol delete mode 100644 contracts/chequebook/gencode.go delete mode 100644 contracts/ens/README.md delete mode 100644 contracts/ens/cid.go delete mode 100644 contracts/ens/cid_test.go delete mode 100644 contracts/ens/contract/ENS.sol delete mode 100644 contracts/ens/contract/ENSRegistry.sol delete mode 100644 contracts/ens/contract/FIFSRegistrar.sol delete mode 100644 contracts/ens/contract/PublicResolver.sol delete mode 100644 contracts/ens/contract/ens.go delete mode 100644 contracts/ens/contract/ensregistry.go delete mode 100644 contracts/ens/contract/fifsregistrar.go delete mode 100644 contracts/ens/contract/publicresolver.go delete mode 100644 contracts/ens/ens.go delete mode 100644 contracts/ens/ens_test.go delete mode 100644 contracts/ens/fallback_contract/PublicResolver.sol delete mode 100644 contracts/ens/fallback_contract/publicresolver.go delete mode 100644 p2p/protocols/accounting.go delete mode 100644 p2p/protocols/accounting_api.go delete mode 100644 p2p/protocols/accounting_simulation_test.go delete mode 100644 p2p/protocols/accounting_test.go delete mode 100644 p2p/protocols/protocol.go delete mode 100644 p2p/protocols/protocol_test.go delete mode 100644 p2p/protocols/reporter.go delete mode 100644 p2p/protocols/reporter_test.go delete mode 100644 swarm/AUTHORS delete mode 100644 swarm/OWNERS delete mode 100644 swarm/api/act.go delete mode 100644 swarm/api/api.go delete mode 100644 swarm/api/api_test.go delete mode 100644 swarm/api/client/client.go delete mode 100644 swarm/api/client/client_test.go delete mode 100644 swarm/api/config.go delete mode 100644 swarm/api/config_test.go delete mode 100644 swarm/api/encrypt.go delete mode 100644 swarm/api/filesystem.go delete mode 100644 swarm/api/filesystem_test.go delete mode 100644 swarm/api/gen_mime.go delete mode 100644 swarm/api/http/middleware.go delete mode 100644 swarm/api/http/response.go delete mode 100644 swarm/api/http/response_test.go delete mode 100644 swarm/api/http/roundtripper.go delete mode 100644 swarm/api/http/roundtripper_test.go delete mode 100644 swarm/api/http/sctx.go delete mode 100644 swarm/api/http/server.go delete mode 100644 swarm/api/http/server_test.go delete mode 100644 swarm/api/http/templates.go delete mode 100644 swarm/api/http/test_server.go delete mode 100644 swarm/api/inspector.go delete mode 100644 swarm/api/manifest.go delete mode 100644 swarm/api/manifest_test.go delete mode 100644 swarm/api/testdata/test0/img/logo.png delete mode 100644 swarm/api/testdata/test0/index.css delete mode 100644 swarm/api/testdata/test0/index.html delete mode 100644 swarm/api/uri.go delete mode 100644 swarm/api/uri_test.go delete mode 100644 swarm/bmt/bmt.go delete mode 100644 swarm/bmt/bmt_r.go delete mode 100644 swarm/bmt/bmt_test.go delete mode 100644 swarm/chunk/chunk.go delete mode 100644 swarm/chunk/proximity_test.go delete mode 100644 swarm/chunk/tag.go delete mode 100644 swarm/chunk/tag_test.go delete mode 100644 swarm/chunk/tags.go delete mode 100644 swarm/chunk/tags_test.go delete mode 100644 swarm/dev/.dockerignore delete mode 100644 swarm/dev/.gitignore delete mode 100644 swarm/dev/Dockerfile delete mode 100644 swarm/dev/Makefile delete mode 100644 swarm/dev/README.md delete mode 100644 swarm/dev/bashrc delete mode 100755 swarm/dev/run.sh delete mode 100755 swarm/dev/scripts/boot-cluster.sh delete mode 100755 swarm/dev/scripts/random-uploads.sh delete mode 100755 swarm/dev/scripts/stop-cluster.sh delete mode 100644 swarm/dev/scripts/util.sh delete mode 100644 swarm/docker/Dockerfile delete mode 100755 swarm/docker/run-smoke.sh delete mode 100755 swarm/docker/run.sh delete mode 100644 swarm/docs/migration-v0.3-to-v0.4.md delete mode 100644 swarm/fuse/fuse_dir.go delete mode 100644 swarm/fuse/fuse_file.go delete mode 100644 swarm/fuse/fuse_root.go delete mode 100644 swarm/fuse/swarmfs.go delete mode 100644 swarm/fuse/swarmfs_fallback.go delete mode 100644 swarm/fuse/swarmfs_test.go delete mode 100644 swarm/fuse/swarmfs_unix.go delete mode 100644 swarm/fuse/swarmfs_util.go delete mode 100644 swarm/log/log.go delete mode 100644 swarm/metrics/flags.go delete mode 100644 swarm/network/README.md delete mode 100644 swarm/network/bitvector/bitvector.go delete mode 100644 swarm/network/bitvector/bitvector_test.go delete mode 100644 swarm/network/common.go delete mode 100644 swarm/network/discovery.go delete mode 100644 swarm/network/discovery_test.go delete mode 100644 swarm/network/enr.go delete mode 100644 swarm/network/fetcher.go delete mode 100644 swarm/network/fetcher_test.go delete mode 100644 swarm/network/hive.go delete mode 100644 swarm/network/hive_test.go delete mode 100644 swarm/network/kademlia.go delete mode 100644 swarm/network/kademlia_test.go delete mode 100644 swarm/network/network.go delete mode 100644 swarm/network/networkid_test.go delete mode 100644 swarm/network/priorityqueue/priorityqueue.go delete mode 100644 swarm/network/priorityqueue/priorityqueue_test.go delete mode 100644 swarm/network/protocol.go delete mode 100644 swarm/network/protocol_test.go delete mode 100644 swarm/network/simulation/bucket.go delete mode 100644 swarm/network/simulation/bucket_test.go delete mode 100644 swarm/network/simulation/events.go delete mode 100644 swarm/network/simulation/events_test.go delete mode 100644 swarm/network/simulation/example_test.go delete mode 100644 swarm/network/simulation/http.go delete mode 100644 swarm/network/simulation/http_test.go delete mode 100644 swarm/network/simulation/kademlia.go delete mode 100644 swarm/network/simulation/kademlia_test.go delete mode 100644 swarm/network/simulation/node.go delete mode 100644 swarm/network/simulation/node_test.go delete mode 100644 swarm/network/simulation/service.go delete mode 100644 swarm/network/simulation/service_test.go delete mode 100644 swarm/network/simulation/simulation.go delete mode 100644 swarm/network/simulation/simulation_test.go delete mode 100644 swarm/network/simulations/discovery/discovery.go delete mode 100644 swarm/network/simulations/discovery/discovery_test.go delete mode 100755 swarm/network/simulations/discovery/snapshot.json delete mode 100644 swarm/network/simulations/overlay.go delete mode 100644 swarm/network/simulations/overlay_test.go delete mode 100644 swarm/network/stream/common_test.go delete mode 100644 swarm/network/stream/delivery.go delete mode 100644 swarm/network/stream/delivery_test.go delete mode 100644 swarm/network/stream/intervals/dbstore_test.go delete mode 100644 swarm/network/stream/intervals/intervals.go delete mode 100644 swarm/network/stream/intervals/intervals_test.go delete mode 100644 swarm/network/stream/intervals/store_test.go delete mode 100644 swarm/network/stream/intervals_test.go delete mode 100644 swarm/network/stream/lightnode_test.go delete mode 100644 swarm/network/stream/messages.go delete mode 100644 swarm/network/stream/peer.go delete mode 100644 swarm/network/stream/peer_test.go delete mode 100644 swarm/network/stream/snapshot_retrieval_test.go delete mode 100644 swarm/network/stream/snapshot_sync_test.go delete mode 100644 swarm/network/stream/stream.go delete mode 100644 swarm/network/stream/streamer_test.go delete mode 100644 swarm/network/stream/syncer.go delete mode 100644 swarm/network/stream/syncer_test.go delete mode 100644 swarm/network/stream/testing/snapshot_128.json delete mode 100644 swarm/network/stream/testing/snapshot_16.json delete mode 100644 swarm/network/stream/testing/snapshot_256.json delete mode 100644 swarm/network/stream/testing/snapshot_32.json delete mode 100644 swarm/network/stream/testing/snapshot_4.json delete mode 100644 swarm/network/stream/testing/snapshot_64.json delete mode 100644 swarm/network_test.go delete mode 100644 swarm/pot/address.go delete mode 100644 swarm/pot/doc.go delete mode 100644 swarm/pot/pot.go delete mode 100644 swarm/pot/pot_test.go delete mode 100644 swarm/pss/ARCHITECTURE.md delete mode 100644 swarm/pss/README.md delete mode 100644 swarm/pss/api.go delete mode 100644 swarm/pss/client/client.go delete mode 100644 swarm/pss/client/client_test.go delete mode 100644 swarm/pss/client/doc.go delete mode 100644 swarm/pss/doc.go delete mode 100644 swarm/pss/forwarding_test.go delete mode 100644 swarm/pss/handshake.go delete mode 100644 swarm/pss/handshake_none.go delete mode 100644 swarm/pss/handshake_test.go delete mode 100644 swarm/pss/keystore.go delete mode 100644 swarm/pss/notify/notify.go delete mode 100644 swarm/pss/notify/notify_test.go delete mode 100644 swarm/pss/ping.go delete mode 100644 swarm/pss/protocol.go delete mode 100644 swarm/pss/protocol_none.go delete mode 100644 swarm/pss/protocol_test.go delete mode 100644 swarm/pss/prox_test.go delete mode 100644 swarm/pss/pss.go delete mode 100644 swarm/pss/pss_test.go delete mode 100644 swarm/pss/testdata/snapshot_128.json delete mode 100644 swarm/pss/testdata/snapshot_16.json delete mode 100644 swarm/pss/testdata/snapshot_2.json delete mode 100644 swarm/pss/testdata/snapshot_256.json delete mode 100644 swarm/pss/testdata/snapshot_3.json delete mode 100644 swarm/pss/testdata/snapshot_32.json delete mode 100644 swarm/pss/testdata/snapshot_4.json delete mode 100644 swarm/pss/testdata/snapshot_64.json delete mode 100644 swarm/pss/testdata/snapshot_8.json delete mode 100644 swarm/pss/types.go delete mode 100644 swarm/pss/writeup.md delete mode 100644 swarm/sctx/sctx.go delete mode 100644 swarm/services/swap/swap.go delete mode 100644 swarm/services/swap/swap/swap.go delete mode 100644 swarm/services/swap/swap/swap_test.go delete mode 100644 swarm/shed/db.go delete mode 100644 swarm/shed/db_test.go delete mode 100644 swarm/shed/example_store_test.go delete mode 100644 swarm/shed/field_string.go delete mode 100644 swarm/shed/field_string_test.go delete mode 100644 swarm/shed/field_struct.go delete mode 100644 swarm/shed/field_struct_test.go delete mode 100644 swarm/shed/field_uint64.go delete mode 100644 swarm/shed/field_uint64_test.go delete mode 100644 swarm/shed/index.go delete mode 100644 swarm/shed/index_test.go delete mode 100644 swarm/shed/schema.go delete mode 100644 swarm/shed/schema_test.go delete mode 100644 swarm/shed/vector_uint64.go delete mode 100644 swarm/shed/vector_uint64_test.go delete mode 100644 swarm/spancontext/spancontext.go delete mode 100644 swarm/state/dbstore.go delete mode 100644 swarm/state/dbstore_test.go delete mode 100644 swarm/storage/chunker.go delete mode 100644 swarm/storage/chunker_test.go delete mode 100644 swarm/storage/common_test.go delete mode 100644 swarm/storage/encryption/encryption.go delete mode 100644 swarm/storage/encryption/encryption_test.go delete mode 100644 swarm/storage/error.go delete mode 100644 swarm/storage/feed/binaryserializer.go delete mode 100644 swarm/storage/feed/binaryserializer_test.go delete mode 100644 swarm/storage/feed/cacheentry.go delete mode 100644 swarm/storage/feed/doc.go delete mode 100644 swarm/storage/feed/error.go delete mode 100644 swarm/storage/feed/feed.go delete mode 100644 swarm/storage/feed/feed_test.go delete mode 100644 swarm/storage/feed/handler.go delete mode 100644 swarm/storage/feed/handler_test.go delete mode 100644 swarm/storage/feed/id.go delete mode 100644 swarm/storage/feed/id_test.go delete mode 100644 swarm/storage/feed/lookup/algorithm_fluzcapacitor.go delete mode 100644 swarm/storage/feed/lookup/algorithm_longearth.go delete mode 100644 swarm/storage/feed/lookup/epoch.go delete mode 100644 swarm/storage/feed/lookup/epoch_test.go delete mode 100644 swarm/storage/feed/lookup/lookup.go delete mode 100644 swarm/storage/feed/lookup/lookup_test.go delete mode 100644 swarm/storage/feed/lookup/store_test.go delete mode 100644 swarm/storage/feed/lookup/timesim_test.go delete mode 100644 swarm/storage/feed/query.go delete mode 100644 swarm/storage/feed/query_test.go delete mode 100644 swarm/storage/feed/request.go delete mode 100644 swarm/storage/feed/request_test.go delete mode 100644 swarm/storage/feed/sign.go delete mode 100644 swarm/storage/feed/testutil.go delete mode 100644 swarm/storage/feed/timestampprovider.go delete mode 100644 swarm/storage/feed/topic.go delete mode 100644 swarm/storage/feed/topic_test.go delete mode 100644 swarm/storage/feed/update.go delete mode 100644 swarm/storage/feed/update_test.go delete mode 100644 swarm/storage/filestore.go delete mode 100644 swarm/storage/filestore_test.go delete mode 100644 swarm/storage/hasherstore.go delete mode 100644 swarm/storage/hasherstore_test.go delete mode 100644 swarm/storage/localstore/doc.go delete mode 100644 swarm/storage/localstore/export.go delete mode 100644 swarm/storage/localstore/export_test.go delete mode 100644 swarm/storage/localstore/gc.go delete mode 100644 swarm/storage/localstore/gc_test.go delete mode 100644 swarm/storage/localstore/index_test.go delete mode 100644 swarm/storage/localstore/localstore.go delete mode 100644 swarm/storage/localstore/localstore_test.go delete mode 100644 swarm/storage/localstore/mode_get.go delete mode 100644 swarm/storage/localstore/mode_get_test.go delete mode 100644 swarm/storage/localstore/mode_has.go delete mode 100644 swarm/storage/localstore/mode_has_test.go delete mode 100644 swarm/storage/localstore/mode_put.go delete mode 100644 swarm/storage/localstore/mode_put_test.go delete mode 100644 swarm/storage/localstore/mode_set.go delete mode 100644 swarm/storage/localstore/mode_set_test.go delete mode 100644 swarm/storage/localstore/retrieval_index_test.go delete mode 100644 swarm/storage/localstore/schema.go delete mode 100644 swarm/storage/localstore/subscription_pull.go delete mode 100644 swarm/storage/localstore/subscription_pull_test.go delete mode 100644 swarm/storage/localstore/subscription_push.go delete mode 100644 swarm/storage/localstore/subscription_push_test.go delete mode 100644 swarm/storage/mock/db/db.go delete mode 100644 swarm/storage/mock/db/db_test.go delete mode 100644 swarm/storage/mock/explorer/explorer.go delete mode 100644 swarm/storage/mock/explorer/explorer_test.go delete mode 100644 swarm/storage/mock/explorer/headers_test.go delete mode 100644 swarm/storage/mock/explorer/swagger.yaml delete mode 100644 swarm/storage/mock/mem/mem.go delete mode 100644 swarm/storage/mock/mem/mem_test.go delete mode 100644 swarm/storage/mock/mock.go delete mode 100644 swarm/storage/mock/rpc/rpc.go delete mode 100644 swarm/storage/mock/rpc/rpc_test.go delete mode 100644 swarm/storage/mock/test/test.go delete mode 100644 swarm/storage/netstore.go delete mode 100644 swarm/storage/netstore_test.go delete mode 100644 swarm/storage/pyramid.go delete mode 100644 swarm/storage/swarmhasher.go delete mode 100644 swarm/storage/types.go delete mode 100644 swarm/swap/swap.go delete mode 100644 swarm/swap/swap_test.go delete mode 100644 swarm/swarm.go delete mode 100644 swarm/swarm_test.go delete mode 100644 swarm/testutil/file.go delete mode 100644 swarm/testutil/norace.go delete mode 100644 swarm/testutil/race.go delete mode 100644 swarm/testutil/tag.go delete mode 100644 swarm/tracing/tracing.go delete mode 100644 swarm/version/version.go diff --git a/.travis.yml b/.travis.yml index c0faa62a45..552a0f1d77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,7 +64,7 @@ matrix: - go run build/ci.go lint # This builder does the Ubuntu PPA upload - - if: repo = ethereum/go-ethereum AND type = push + - if: type = push os: linux dist: xenial go: 1.12.x @@ -86,7 +86,7 @@ matrix: - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder " # This builder does the Linux Azure uploads - - if: repo = ethereum/go-ethereum AND type = push + - if: type = push os: linux dist: xenial sudo: required @@ -120,7 +120,7 @@ matrix: - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds # This builder does the Linux Azure MIPS xgo uploads - - if: repo = ethereum/go-ethereum AND type = push + - if: type = push os: linux dist: xenial services: @@ -148,7 +148,7 @@ matrix: - go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds # This builder does the Android Maven and Azure uploads - - if: repo = ethereum/go-ethereum AND type = push + - if: type = push os: linux dist: xenial addons: @@ -185,7 +185,7 @@ matrix: - go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds # This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads - - if: repo = ethereum/go-ethereum AND type = push + - if: type = push os: osx go: 1.12.x env: @@ -214,7 +214,7 @@ matrix: - go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds # This builder does the Azure archive purges to avoid accumulating junk - - if: repo = ethereum/go-ethereum AND type = cron + - if: type = cron os: linux dist: xenial go: 1.12.x @@ -224,12 +224,3 @@ matrix: submodules: false # avoid cloning ethereum/tests script: - go run build/ci.go purge -store gethstore/builds -days 14 - - - name: Race Detector for Swarm - if: repo = ethersphere/go-ethereum - os: linux - dist: xenial - go: 1.12.x - git: - submodules: false # avoid cloning ethereum/tests - script: ./build/travis_keepalive.sh go test -timeout 20m -race ./swarm... ./p2p/{protocols,simulations,testing}/... diff --git a/Makefile b/Makefile index 966bf9cbba..4bf52f5c96 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # with Go source code. If you know what GOPATH is then you probably # don't need to bother with make. -.PHONY: geth android ios geth-cross swarm evm all test clean +.PHONY: geth android ios geth-cross evm all test clean .PHONY: geth-linux geth-linux-386 geth-linux-amd64 geth-linux-mips64 geth-linux-mips64le .PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64 .PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64 @@ -16,11 +16,6 @@ geth: @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." -swarm: - build/env.sh go run build/ci.go install ./cmd/swarm - @echo "Done building." - @echo "Run \"$(GOBIN)/swarm\" to launch swarm." - all: build/env.sh go run build/ci.go install @@ -57,9 +52,6 @@ devtools: @type "solc" 2> /dev/null || echo 'Please install solc' @type "protoc" 2> /dev/null || echo 'Please install protoc' -swarm-devtools: - env GOBIN= go install ./cmd/swarm/mimegen - # Cross Compilation Targets (xgo) geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios diff --git a/README.md b/README.md index ea8b0a499d..5ae8e7a650 100644 --- a/README.md +++ b/README.md @@ -32,16 +32,15 @@ or, to build the full suite of utilities: The go-ethereum project comes with several wrappers/executables found in the `cmd` directory. -| Command | Description | -|:----------:|-------------| -| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. | -| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. | -| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | -| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). | -| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. | -| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | -| `swarm` | Swarm daemon and tools. This is the entry point for the Swarm network. `swarm --help` for command line options and subcommands. See [Swarm README](https://github.com/ethereum/go-ethereum/tree/master/swarm) for more information. | -| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | +| Command | Description | +| :-----------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. | +| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. | +| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | +| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). | +| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. | +| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | +| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | ## Running geth @@ -95,7 +94,7 @@ Specifying the `--testnet` flag, however, will reconfigure your Geth instance a `geth attach /testnet/geth.ipc`. Windows users are not affected by this. * Instead of connecting the main Ethereum network, the client will connect to the test network, which uses different P2P bootnodes, different network IDs and genesis states. - + *Note: Although there are some internal protective measures to prevent transactions from crossing over between the main network and test network, you should make sure to always use separate accounts for play-money and real-money. Unless you manually move accounts, Geth will by default correctly diff --git a/build/deb/ethereum-swarm/deb.changelog b/build/deb/ethereum-swarm/deb.changelog deleted file mode 100644 index 83f804a833..0000000000 --- a/build/deb/ethereum-swarm/deb.changelog +++ /dev/null @@ -1,5 +0,0 @@ -{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low - - * git build of {{.Env.Commit}} - - -- {{.Author}} {{.Time}} diff --git a/build/deb/ethereum-swarm/deb.control b/build/deb/ethereum-swarm/deb.control deleted file mode 100644 index b0ced141b6..0000000000 --- a/build/deb/ethereum-swarm/deb.control +++ /dev/null @@ -1,19 +0,0 @@ -Source: {{.Name}} -Section: science -Priority: extra -Maintainer: {{.Author}} -Build-Depends: debhelper (>= 8.0.0), golang-1.11 -Standards-Version: 3.9.5 -Homepage: https://ethereum.org -Vcs-Git: git://github.com/ethereum/go-ethereum.git -Vcs-Browser: https://github.com/ethereum/go-ethereum - -{{range .Executables}} -Package: {{$.ExeName .}} -Conflicts: {{$.ExeConflicts .}} -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Built-Using: ${misc:Built-Using} -Description: {{.Description}} - {{.Description}} -{{end}} diff --git a/build/deb/ethereum-swarm/deb.copyright b/build/deb/ethereum-swarm/deb.copyright deleted file mode 100644 index fe6e36ad9d..0000000000 --- a/build/deb/ethereum-swarm/deb.copyright +++ /dev/null @@ -1,14 +0,0 @@ -Copyright 2018 The go-ethereum Authors - -go-ethereum is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -go-ethereum is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with go-ethereum. If not, see . diff --git a/build/deb/ethereum-swarm/deb.docs b/build/deb/ethereum-swarm/deb.docs deleted file mode 100644 index 62deb04972..0000000000 --- a/build/deb/ethereum-swarm/deb.docs +++ /dev/null @@ -1 +0,0 @@ -AUTHORS diff --git a/build/deb/ethereum-swarm/deb.install b/build/deb/ethereum-swarm/deb.install deleted file mode 100644 index e7666ce5fb..0000000000 --- a/build/deb/ethereum-swarm/deb.install +++ /dev/null @@ -1 +0,0 @@ -build/bin/{{.BinaryName}} usr/bin diff --git a/build/deb/ethereum-swarm/deb.rules b/build/deb/ethereum-swarm/deb.rules deleted file mode 100644 index 5280e0e55a..0000000000 --- a/build/deb/ethereum-swarm/deb.rules +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -# Launchpad rejects Go's access to $HOME/.cache, use custom folder -export GOCACHE=/tmp/go-build - -override_dh_auto_build: - build/env.sh /usr/lib/go-1.11/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} - -override_dh_auto_test: - -%: - dh $@ diff --git a/build/deb/ethereum/deb.control b/build/deb/ethereum/deb.control index 018067a19d..5b3ff93542 100644 --- a/build/deb/ethereum/deb.control +++ b/build/deb/ethereum/deb.control @@ -11,8 +11,8 @@ Vcs-Browser: https://github.com/ethereum/go-ethereum Package: {{.Name}} Architecture: any Depends: ${misc:Depends}, {{.ExeList}} -Description: Meta-package to install geth, swarm, and other tools - Meta-package to install geth, swarm and other tools +Description: Meta-package to install geth and other tools + Meta-package to install geth and other tools {{range .Executables}} Package: {{$.ExeName .}} diff --git a/build/update-license.go b/build/update-license.go index e3e00d4cc0..0ce8292336 100644 --- a/build/update-license.go +++ b/build/update-license.go @@ -72,8 +72,6 @@ var ( "internal/jsre/deps", "log/", "common/bitutil/bitutil", - // don't license generated files - "contracts/chequebook/contract/code.go", } // paths with this prefix are licensed as GPL. all other files are LGPL. diff --git a/cmd/swarm/access.go b/cmd/swarm/access.go deleted file mode 100644 index cc0cc8201a..0000000000 --- a/cmd/swarm/access.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . -package main - -import ( - "crypto/rand" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "strings" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/api/client" - "gopkg.in/urfave/cli.v1" -) - -var ( - salt = make([]byte, 32) - accessCommand = cli.Command{ - CustomHelpTemplate: helpTemplate, - Name: "access", - Usage: "encrypts a reference and embeds it into a root manifest", - ArgsUsage: "", - Description: "encrypts a reference and embeds it into a root manifest", - Subcommands: []cli.Command{ - { - CustomHelpTemplate: helpTemplate, - Name: "new", - Usage: "encrypts a reference and embeds it into a root manifest", - ArgsUsage: "", - Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", - Subcommands: []cli.Command{ - { - Action: accessNewPass, - CustomHelpTemplate: helpTemplate, - Flags: []cli.Flag{ - utils.PasswordFileFlag, - SwarmDryRunFlag, - }, - Name: "pass", - Usage: "encrypts a reference with a password and embeds it into a root manifest", - ArgsUsage: "", - Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", - }, - { - Action: accessNewPK, - CustomHelpTemplate: helpTemplate, - Flags: []cli.Flag{ - utils.PasswordFileFlag, - SwarmDryRunFlag, - SwarmAccessGrantKeyFlag, - }, - Name: "pk", - Usage: "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest", - ArgsUsage: "", - Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", - }, - { - Action: accessNewACT, - CustomHelpTemplate: helpTemplate, - Flags: []cli.Flag{ - SwarmAccessGrantKeysFlag, - SwarmDryRunFlag, - utils.PasswordFileFlag, - }, - Name: "act", - Usage: "encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest", - ArgsUsage: "", - Description: "encrypts a reference and embeds it into a root access manifest and prints the resulting manifest", - }, - }, - }, - }, - } -) - -func init() { - if _, err := io.ReadFull(rand.Reader, salt); err != nil { - panic("reading from crypto/rand failed: " + err.Error()) - } -} - -func accessNewPass(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 1 { - utils.Fatalf("Expected 1 argument - the ref") - } - - var ( - ae *api.AccessEntry - accessKey []byte - err error - ref = args[0] - password = getPassPhrase("", 0, makePasswordList(ctx)) - dryRun = ctx.Bool(SwarmDryRunFlag.Name) - ) - accessKey, ae, err = api.DoPassword(ctx, password, salt) - if err != nil { - utils.Fatalf("error getting session key: %v", err) - } - m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae) - if err != nil { - utils.Fatalf("had an error generating the manifest: %v", err) - } - if dryRun { - err = printManifests(m, nil) - if err != nil { - utils.Fatalf("had an error printing the manifests: %v", err) - } - } else { - err = uploadManifests(ctx, m, nil) - if err != nil { - utils.Fatalf("had an error uploading the manifests: %v", err) - } - } -} - -func accessNewPK(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 1 { - utils.Fatalf("Expected 1 argument - the ref") - } - - var ( - ae *api.AccessEntry - sessionKey []byte - err error - ref = args[0] - privateKey = getPrivKey(ctx) - granteePublicKey = ctx.String(SwarmAccessGrantKeyFlag.Name) - dryRun = ctx.Bool(SwarmDryRunFlag.Name) - ) - sessionKey, ae, err = api.DoPK(ctx, privateKey, granteePublicKey, salt) - if err != nil { - utils.Fatalf("error getting session key: %v", err) - } - m, err := api.GenerateAccessControlManifest(ctx, ref, sessionKey, ae) - if err != nil { - utils.Fatalf("had an error generating the manifest: %v", err) - } - if dryRun { - err = printManifests(m, nil) - if err != nil { - utils.Fatalf("had an error printing the manifests: %v", err) - } - } else { - err = uploadManifests(ctx, m, nil) - if err != nil { - utils.Fatalf("had an error uploading the manifests: %v", err) - } - } -} - -func accessNewACT(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 1 { - utils.Fatalf("Expected 1 argument - the ref") - } - - var ( - ae *api.AccessEntry - actManifest *api.Manifest - accessKey []byte - err error - ref = args[0] - pkGrantees []string - passGrantees []string - pkGranteesFilename = ctx.String(SwarmAccessGrantKeysFlag.Name) - passGranteesFilename = ctx.String(utils.PasswordFileFlag.Name) - privateKey = getPrivKey(ctx) - dryRun = ctx.Bool(SwarmDryRunFlag.Name) - ) - if pkGranteesFilename == "" && passGranteesFilename == "" { - utils.Fatalf("you have to provide either a grantee public-keys file or an encryption passwords file (or both)") - } - - if pkGranteesFilename != "" { - bytes, err := ioutil.ReadFile(pkGranteesFilename) - if err != nil { - utils.Fatalf("had an error reading the grantee public key list") - } - pkGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n") - } - - if passGranteesFilename != "" { - bytes, err := ioutil.ReadFile(passGranteesFilename) - if err != nil { - utils.Fatalf("could not read password filename: %v", err) - } - passGrantees = strings.Split(strings.Trim(string(bytes), "\n"), "\n") - } - accessKey, ae, actManifest, err = api.DoACT(ctx, privateKey, salt, pkGrantees, passGrantees) - if err != nil { - utils.Fatalf("error generating ACT manifest: %v", err) - } - - if err != nil { - utils.Fatalf("error getting session key: %v", err) - } - m, err := api.GenerateAccessControlManifest(ctx, ref, accessKey, ae) - if err != nil { - utils.Fatalf("error generating root access manifest: %v", err) - } - - if dryRun { - err = printManifests(m, actManifest) - if err != nil { - utils.Fatalf("had an error printing the manifests: %v", err) - } - } else { - err = uploadManifests(ctx, m, actManifest) - if err != nil { - utils.Fatalf("had an error uploading the manifests: %v", err) - } - } -} - -func printManifests(rootAccessManifest, actManifest *api.Manifest) error { - js, err := json.Marshal(rootAccessManifest) - if err != nil { - return err - } - fmt.Println(string(js)) - - if actManifest != nil { - js, err := json.Marshal(actManifest) - if err != nil { - return err - } - fmt.Println(string(js)) - } - return nil -} - -func uploadManifests(ctx *cli.Context, rootAccessManifest, actManifest *api.Manifest) error { - bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client := client.NewClient(bzzapi) - - var ( - key string - err error - ) - if actManifest != nil { - key, err = client.UploadManifest(actManifest, false) - if err != nil { - return err - } - - rootAccessManifest.Entries[0].Access.Act = key - } - key, err = client.UploadManifest(rootAccessManifest, false) - if err != nil { - return err - } - fmt.Println(key) - return nil -} - -// makePasswordList reads password lines from the file specified by the global --password flag -// and also by the same subcommand --password flag. -// This function ia a fork of utils.MakePasswordList to lookup cli context for subcommand. -// Function ctx.SetGlobal is not setting the global flag value that can be accessed -// by ctx.GlobalString using the current version of cli package. -func makePasswordList(ctx *cli.Context) []string { - path := ctx.GlobalString(utils.PasswordFileFlag.Name) - if path == "" { - path = ctx.String(utils.PasswordFileFlag.Name) - if path == "" { - return nil - } - } - text, err := ioutil.ReadFile(path) - if err != nil { - utils.Fatalf("Failed to read password file: %v", err) - } - lines := strings.Split(string(text), "\n") - // Sanitise DOS line endings. - for i := range lines { - lines[i] = strings.TrimRight(lines[i], "\r") - } - return lines -} diff --git a/cmd/swarm/access_test.go b/cmd/swarm/access_test.go deleted file mode 100644 index 0aaaad0306..0000000000 --- a/cmd/swarm/access_test.go +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "crypto/rand" - "encoding/hex" - "encoding/json" - "io" - "io/ioutil" - gorand "math/rand" - "net/http" - "os" - "runtime" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/api" - swarmapi "github.com/ethereum/go-ethereum/swarm/api/client" - "github.com/ethereum/go-ethereum/swarm/testutil" - "golang.org/x/crypto/sha3" -) - -const ( - hashRegexp = `[a-f\d]{128}` - data = "notsorandomdata" -) - -var DefaultCurve = crypto.S256() - -func TestACT(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - cluster := newTestCluster(t, clusterSize) - defer cluster.Shutdown() - - cases := []struct { - name string - f func(t *testing.T, cluster *testCluster) - }{ - {"Password", testPassword}, - {"PK", testPK}, - {"ACTWithoutBogus", testACTWithoutBogus}, - {"ACTWithBogus", testACTWithBogus}, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - tc.f(t, cluster) - }) - } -} - -// testPassword tests for the correct creation of an ACT manifest protected by a password. -// The test creates bogus content, uploads it encrypted, then creates the wrapping manifest with the Access entry -// The parties participating - node (publisher), uploads to second node then disappears. Content which was uploaded -// is then fetched through 2nd node. since the tested code is not key-aware - we can just -// fetch from the 2nd node using HTTP BasicAuth -func testPassword(t *testing.T, cluster *testCluster) { - dataFilename := testutil.TempFileWithContent(t, data) - defer os.RemoveAll(dataFilename) - - // upload the file with 'swarm up' and expect a hash - up := runSwarm(t, - "--bzzapi", - cluster.Nodes[0].URL, - "up", - "--encrypt", - dataFilename) - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - - if len(matches) < 1 { - t.Fatal("no matches found") - } - - ref := matches[0] - tmp, err := ioutil.TempDir("", "swarm-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmp) - password := "smth" - passwordFilename := testutil.TempFileWithContent(t, "smth") - defer os.RemoveAll(passwordFilename) - - up = runSwarm(t, - "access", - "new", - "pass", - "--dry-run", - "--password", - passwordFilename, - ref, - ) - - _, matches = up.ExpectRegexp(".+") - up.ExpectExit() - - if len(matches) == 0 { - t.Fatalf("stdout not matched") - } - - var m api.Manifest - - err = json.Unmarshal([]byte(matches[0]), &m) - if err != nil { - t.Fatalf("unmarshal manifest: %v", err) - } - - if len(m.Entries) != 1 { - t.Fatalf("expected one manifest entry, got %v", len(m.Entries)) - } - - e := m.Entries[0] - - ct := "application/bzz-manifest+json" - if e.ContentType != ct { - t.Errorf("expected %q content type, got %q", ct, e.ContentType) - } - - if e.Access == nil { - t.Fatal("manifest access is nil") - } - - a := e.Access - - if a.Type != "pass" { - t.Errorf(`got access type %q, expected "pass"`, a.Type) - } - if len(a.Salt) < 32 { - t.Errorf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt)) - } - if a.KdfParams == nil { - t.Fatal("manifest access kdf params is nil") - } - if a.Publisher != "" { - t.Fatal("should be empty") - } - - client := swarmapi.NewClient(cluster.Nodes[0].URL) - - hash, err := client.UploadManifest(&m, false) - if err != nil { - t.Fatal(err) - } - - url := cluster.Nodes[0].URL + "/" + "bzz:/" + hash - - httpClient := &http.Client{} - response, err := httpClient.Get(url) - if err != nil { - t.Fatal(err) - } - if response.StatusCode != http.StatusUnauthorized { - t.Fatal("should be a 401") - } - authHeader := response.Header.Get("WWW-Authenticate") - if authHeader == "" { - t.Fatal("should be something here") - } - - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - t.Fatal(err) - } - req.SetBasicAuth("", password) - - response, err = http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - defer response.Body.Close() - - if response.StatusCode != http.StatusOK { - t.Errorf("expected status %v, got %v", http.StatusOK, response.StatusCode) - } - d, err := ioutil.ReadAll(response.Body) - if err != nil { - t.Fatal(err) - } - if string(d) != data { - t.Errorf("expected decrypted data %q, got %q", data, string(d)) - } - - wrongPasswordFilename := testutil.TempFileWithContent(t, "just wr0ng") - defer os.RemoveAll(wrongPasswordFilename) - - //download file with 'swarm down' with wrong password - up = runSwarm(t, - "--bzzapi", - cluster.Nodes[0].URL, - "down", - "bzz:/"+hash, - tmp, - "--password", - wrongPasswordFilename) - - _, matches = up.ExpectRegexp("unauthorized") - if len(matches) != 1 && matches[0] != "unauthorized" { - t.Fatal(`"unauthorized" not found in output"`) - } - up.ExpectExit() -} - -// testPK tests for the correct creation of an ACT manifest between two parties (publisher and grantee). -// The test creates bogus content, uploads it encrypted, then creates the wrapping manifest with the Access entry -// The parties participating - node (publisher), uploads to second node (which is also the grantee) then disappears. -// Content which was uploaded is then fetched through the grantee's http proxy. Since the tested code is private-key aware, -// the test will fail if the proxy's given private key is not granted on the ACT. -func testPK(t *testing.T, cluster *testCluster) { - dataFilename := testutil.TempFileWithContent(t, data) - defer os.RemoveAll(dataFilename) - - // upload the file with 'swarm up' and expect a hash - up := runSwarm(t, - "--bzzapi", - cluster.Nodes[0].URL, - "up", - "--encrypt", - dataFilename) - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - - if len(matches) < 1 { - t.Fatal("no matches found") - } - - ref := matches[0] - pk := cluster.Nodes[0].PrivateKey - granteePubKey := crypto.CompressPubkey(&pk.PublicKey) - - publisherDir, err := ioutil.TempDir("", "swarm-account-dir-temp") - if err != nil { - t.Fatal(err) - } - - passwordFilename := testutil.TempFileWithContent(t, testPassphrase) - defer os.RemoveAll(passwordFilename) - - _, publisherAccount := getTestAccount(t, publisherDir) - up = runSwarm(t, - "--bzzaccount", - publisherAccount.Address.String(), - "--password", - passwordFilename, - "--datadir", - publisherDir, - "--bzzapi", - cluster.Nodes[0].URL, - "access", - "new", - "pk", - "--dry-run", - "--grant-key", - hex.EncodeToString(granteePubKey), - ref, - ) - - _, matches = up.ExpectRegexp(".+") - up.ExpectExit() - - if len(matches) == 0 { - t.Fatalf("stdout not matched") - } - - //get the public key from the publisher directory - publicKeyFromDataDir := runSwarm(t, - "--bzzaccount", - publisherAccount.Address.String(), - "--password", - passwordFilename, - "--datadir", - publisherDir, - "print-keys", - "--compressed", - ) - _, publicKeyString := publicKeyFromDataDir.ExpectRegexp(".+") - publicKeyFromDataDir.ExpectExit() - pkComp := strings.Split(publicKeyString[0], "=")[1] - var m api.Manifest - - err = json.Unmarshal([]byte(matches[0]), &m) - if err != nil { - t.Fatalf("unmarshal manifest: %v", err) - } - - if len(m.Entries) != 1 { - t.Fatalf("expected one manifest entry, got %v", len(m.Entries)) - } - - e := m.Entries[0] - - ct := "application/bzz-manifest+json" - if e.ContentType != ct { - t.Errorf("expected %q content type, got %q", ct, e.ContentType) - } - - if e.Access == nil { - t.Fatal("manifest access is nil") - } - - a := e.Access - - if a.Type != "pk" { - t.Errorf(`got access type %q, expected "pk"`, a.Type) - } - if len(a.Salt) < 32 { - t.Errorf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt)) - } - if a.KdfParams != nil { - t.Fatal("manifest access kdf params should be nil") - } - if a.Publisher != pkComp { - t.Fatal("publisher key did not match") - } - client := swarmapi.NewClient(cluster.Nodes[0].URL) - - hash, err := client.UploadManifest(&m, false) - if err != nil { - t.Fatal(err) - } - - httpClient := &http.Client{} - - url := cluster.Nodes[0].URL + "/" + "bzz:/" + hash - response, err := httpClient.Get(url) - if err != nil { - t.Fatal(err) - } - if response.StatusCode != http.StatusOK { - t.Fatal("should be a 200") - } - d, err := ioutil.ReadAll(response.Body) - if err != nil { - t.Fatal(err) - } - if string(d) != data { - t.Errorf("expected decrypted data %q, got %q", data, string(d)) - } -} - -// testACTWithoutBogus tests the creation of the ACT manifest end-to-end, without any bogus entries (i.e. default scenario = 3 nodes 1 unauthorized) -func testACTWithoutBogus(t *testing.T, cluster *testCluster) { - testACT(t, cluster, 0) -} - -// testACTWithBogus tests the creation of the ACT manifest end-to-end, with 100 bogus entries (i.e. 100 EC keys + default scenario = 3 nodes 1 unauthorized = 103 keys in the ACT manifest) -func testACTWithBogus(t *testing.T, cluster *testCluster) { - testACT(t, cluster, 100) -} - -// testACT tests the e2e creation, uploading and downloading of an ACT access control with both EC keys AND password protection -// the test fires up a 3 node cluster, then randomly picks 2 nodes which will be acting as grantees to the data -// set and also protects the ACT with a password. the third node should fail decoding the reference as it will not be granted access. -// the third node then then tries to download using a correct password (and succeeds) then uses a wrong password and fails. -// the publisher uploads through one of the nodes then disappears. -func testACT(t *testing.T, cluster *testCluster, bogusEntries int) { - var uploadThroughNode = cluster.Nodes[0] - client := swarmapi.NewClient(uploadThroughNode.URL) - - r1 := gorand.New(gorand.NewSource(time.Now().UnixNano())) - nodeToSkip := r1.Intn(clusterSize) // a number between 0 and 2 (node indices in `cluster`) - dataFilename := testutil.TempFileWithContent(t, data) - defer os.RemoveAll(dataFilename) - - // upload the file with 'swarm up' and expect a hash - up := runSwarm(t, - "--bzzapi", - cluster.Nodes[0].URL, - "up", - "--encrypt", - dataFilename) - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - - if len(matches) < 1 { - t.Fatal("no matches found") - } - - ref := matches[0] - var grantees []string - for i, v := range cluster.Nodes { - if i == nodeToSkip { - continue - } - pk := v.PrivateKey - granteePubKey := crypto.CompressPubkey(&pk.PublicKey) - grantees = append(grantees, hex.EncodeToString(granteePubKey)) - } - - if bogusEntries > 0 { - var bogusGrantees []string - - for i := 0; i < bogusEntries; i++ { - prv, err := ecies.GenerateKey(rand.Reader, DefaultCurve, nil) - if err != nil { - t.Fatal(err) - } - bogusGrantees = append(bogusGrantees, hex.EncodeToString(crypto.CompressPubkey(&prv.ExportECDSA().PublicKey))) - } - r2 := gorand.New(gorand.NewSource(time.Now().UnixNano())) - for i := 0; i < len(grantees); i++ { - insertAtIdx := r2.Intn(len(bogusGrantees)) - bogusGrantees = append(bogusGrantees[:insertAtIdx], append([]string{grantees[i]}, bogusGrantees[insertAtIdx:]...)...) - } - grantees = bogusGrantees - } - granteesPubkeyListFile := testutil.TempFileWithContent(t, strings.Join(grantees, "\n")) - defer os.RemoveAll(granteesPubkeyListFile) - - publisherDir, err := ioutil.TempDir("", "swarm-account-dir-temp") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(publisherDir) - - passwordFilename := testutil.TempFileWithContent(t, testPassphrase) - defer os.RemoveAll(passwordFilename) - actPasswordFilename := testutil.TempFileWithContent(t, "smth") - defer os.RemoveAll(actPasswordFilename) - _, publisherAccount := getTestAccount(t, publisherDir) - up = runSwarm(t, - "--bzzaccount", - publisherAccount.Address.String(), - "--password", - passwordFilename, - "--datadir", - publisherDir, - "--bzzapi", - cluster.Nodes[0].URL, - "access", - "new", - "act", - "--grant-keys", - granteesPubkeyListFile, - "--password", - actPasswordFilename, - ref, - ) - - _, matches = up.ExpectRegexp(`[a-f\d]{64}`) - up.ExpectExit() - - if len(matches) == 0 { - t.Fatalf("stdout not matched") - } - - //get the public key from the publisher directory - publicKeyFromDataDir := runSwarm(t, - "--bzzaccount", - publisherAccount.Address.String(), - "--password", - passwordFilename, - "--datadir", - publisherDir, - "print-keys", - "--compressed", - ) - _, publicKeyString := publicKeyFromDataDir.ExpectRegexp(".+") - publicKeyFromDataDir.ExpectExit() - pkComp := strings.Split(publicKeyString[0], "=")[1] - - hash := matches[0] - m, _, err := client.DownloadManifest(hash) - if err != nil { - t.Fatalf("unmarshal manifest: %v", err) - } - - if len(m.Entries) != 1 { - t.Fatalf("expected one manifest entry, got %v", len(m.Entries)) - } - - e := m.Entries[0] - - ct := "application/bzz-manifest+json" - if e.ContentType != ct { - t.Errorf("expected %q content type, got %q", ct, e.ContentType) - } - - if e.Access == nil { - t.Fatal("manifest access is nil") - } - - a := e.Access - - if a.Type != "act" { - t.Fatalf(`got access type %q, expected "act"`, a.Type) - } - if len(a.Salt) < 32 { - t.Fatalf(`got salt with length %v, expected not less the 32 bytes`, len(a.Salt)) - } - - if a.Publisher != pkComp { - t.Fatal("publisher key did not match") - } - httpClient := &http.Client{} - - // all nodes except the skipped node should be able to decrypt the content - for i, node := range cluster.Nodes { - log.Debug("trying to fetch from node", "node index", i) - - url := node.URL + "/" + "bzz:/" + hash - response, err := httpClient.Get(url) - if err != nil { - t.Fatal(err) - } - log.Debug("got response from node", "response code", response.StatusCode) - - if i == nodeToSkip { - log.Debug("reached node to skip", "status code", response.StatusCode) - - if response.StatusCode != http.StatusUnauthorized { - t.Fatalf("should be a 401") - } - - // try downloading using a password instead, using the unauthorized node - passwordUrl := strings.Replace(url, "http://", "http://:smth@", -1) - response, err = httpClient.Get(passwordUrl) - if err != nil { - t.Fatal(err) - } - if response.StatusCode != http.StatusOK { - t.Fatal("should be a 200") - } - - // now try with the wrong password, expect 401 - passwordUrl = strings.Replace(url, "http://", "http://:smthWrong@", -1) - response, err = httpClient.Get(passwordUrl) - if err != nil { - t.Fatal(err) - } - if response.StatusCode != http.StatusUnauthorized { - t.Fatal("should be a 401") - } - continue - } - - if response.StatusCode != http.StatusOK { - t.Fatal("should be a 200") - } - d, err := ioutil.ReadAll(response.Body) - if err != nil { - t.Fatal(err) - } - if string(d) != data { - t.Errorf("expected decrypted data %q, got %q", data, string(d)) - } - } -} - -// TestKeypairSanity is a sanity test for the crypto scheme for ACT. it asserts the correct shared secret according to -// the specs at https://github.com/ethersphere/swarm-docs/blob/eb857afda906c6e7bb90d37f3f334ccce5eef230/act.md -func TestKeypairSanity(t *testing.T) { - salt := make([]byte, 32) - if _, err := io.ReadFull(rand.Reader, salt); err != nil { - t.Fatalf("reading from crypto/rand failed: %v", err.Error()) - } - sharedSecret := "a85586744a1ddd56a7ed9f33fa24f40dd745b3a941be296a0d60e329dbdb896d" - - for i, v := range []struct { - publisherPriv string - granteePub string - }{ - { - publisherPriv: "ec5541555f3bc6376788425e9d1a62f55a82901683fd7062c5eddcc373a73459", - granteePub: "0226f213613e843a413ad35b40f193910d26eb35f00154afcde9ded57479a6224a", - }, - { - publisherPriv: "70c7a73011aa56584a0009ab874794ee7e5652fd0c6911cd02f8b6267dd82d2d", - granteePub: "02e6f8d5e28faaa899744972bb847b6eb805a160494690c9ee7197ae9f619181db", - }, - } { - b, _ := hex.DecodeString(v.granteePub) - granteePub, _ := crypto.DecompressPubkey(b) - publisherPrivate, _ := crypto.HexToECDSA(v.publisherPriv) - - ssKey, err := api.NewSessionKeyPK(publisherPrivate, granteePub, salt) - if err != nil { - t.Fatal(err) - } - - hasher := sha3.NewLegacyKeccak256() - hasher.Write(salt) - shared, err := hex.DecodeString(sharedSecret) - if err != nil { - t.Fatal(err) - } - hasher.Write(shared) - sum := hasher.Sum(nil) - - if !bytes.Equal(ssKey, sum) { - t.Fatalf("%d: got a session key mismatch", i) - } - } -} diff --git a/cmd/swarm/bootnodes.go b/cmd/swarm/bootnodes.go deleted file mode 100644 index ce3cd5288e..0000000000 --- a/cmd/swarm/bootnodes.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -var SwarmBootnodes = []string{ - // EF Swarm Bootnode - AWS - eu-central-1 - "enode://4c113504601930bf2000c29bcd98d1716b6167749f58bad703bae338332fe93cc9d9204f08afb44100dc7bea479205f5d162df579f9a8f76f8b402d339709023@3.122.203.99:30301", - // EF Swarm Bootnode - AWS - us-west-2 - "enode://89f2ede3371bff1ad9f2088f2012984e280287a4e2b68007c2a6ad994909c51886b4a8e9e2ecc97f9910aca538398e0a5804b0ee80a187fde1ba4f32626322ba@52.35.212.179:30301", -} diff --git a/cmd/swarm/config.go b/cmd/swarm/config.go deleted file mode 100644 index e4b3335499..0000000000 --- a/cmd/swarm/config.go +++ /dev/null @@ -1,451 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "errors" - "fmt" - "io" - "os" - "reflect" - "strconv" - "strings" - "time" - "unicode" - - cli "gopkg.in/urfave/cli.v1" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/naoina/toml" - - bzzapi "github.com/ethereum/go-ethereum/swarm/api" -) - -var ( - //flag definition for the dumpconfig command - DumpConfigCommand = cli.Command{ - Action: utils.MigrateFlags(dumpConfig), - Name: "dumpconfig", - Usage: "Show configuration values", - ArgsUsage: "", - Flags: app.Flags, - Category: "MISCELLANEOUS COMMANDS", - Description: `The dumpconfig command shows configuration values.`, - } - - //flag definition for the config file command - SwarmTomlConfigPathFlag = cli.StringFlag{ - Name: "config", - Usage: "TOML configuration file", - } -) - -//constants for environment variables -const ( - SwarmEnvChequebookAddr = "SWARM_CHEQUEBOOK_ADDR" - SwarmEnvAccount = "SWARM_ACCOUNT" - SwarmEnvListenAddr = "SWARM_LISTEN_ADDR" - SwarmEnvPort = "SWARM_PORT" - SwarmEnvNetworkID = "SWARM_NETWORK_ID" - SwarmEnvSwapEnable = "SWARM_SWAP_ENABLE" - SwarmEnvSwapAPI = "SWARM_SWAP_API" - SwarmEnvSyncDisable = "SWARM_SYNC_DISABLE" - SwarmEnvSyncUpdateDelay = "SWARM_ENV_SYNC_UPDATE_DELAY" - SwarmEnvMaxStreamPeerServers = "SWARM_ENV_MAX_STREAM_PEER_SERVERS" - SwarmEnvLightNodeEnable = "SWARM_LIGHT_NODE_ENABLE" - SwarmEnvDeliverySkipCheck = "SWARM_DELIVERY_SKIP_CHECK" - SwarmEnvENSAPI = "SWARM_ENS_API" - SwarmEnvENSAddr = "SWARM_ENS_ADDR" - SwarmEnvCORS = "SWARM_CORS" - SwarmEnvBootnodes = "SWARM_BOOTNODES" - SwarmEnvPSSEnable = "SWARM_PSS_ENABLE" - SwarmEnvStorePath = "SWARM_STORE_PATH" - SwarmEnvStoreCapacity = "SWARM_STORE_CAPACITY" - SwarmEnvStoreCacheCapacity = "SWARM_STORE_CACHE_CAPACITY" - SwarmEnvBootnodeMode = "SWARM_BOOTNODE_MODE" - SwarmAccessPassword = "SWARM_ACCESS_PASSWORD" - SwarmAutoDefaultPath = "SWARM_AUTO_DEFAULTPATH" - SwarmGlobalstoreAPI = "SWARM_GLOBALSTORE_API" - GethEnvDataDir = "GETH_DATADIR" -) - -// These settings ensure that TOML keys use the same names as Go struct fields. -var tomlSettings = toml.Config{ - NormFieldName: func(rt reflect.Type, key string) string { - return key - }, - FieldToKey: func(rt reflect.Type, field string) string { - return field - }, - MissingField: func(rt reflect.Type, field string) error { - link := "" - if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { - link = fmt.Sprintf(", check github.com/ethereum/go-ethereum/swarm/api/config.go for available fields") - } - return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) - }, -} - -//before booting the swarm node, build the configuration -func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) { - //start by creating a default config - config = bzzapi.NewConfig() - //first load settings from config file (if provided) - config, err = configFileOverride(config, ctx) - if err != nil { - return nil, err - } - //override settings provided by environment variables - config = envVarsOverride(config) - //override settings provided by command line - config = cmdLineOverride(config, ctx) - //validate configuration parameters - err = validateConfig(config) - - return -} - -//finally, after the configuration build phase is finished, initialize -func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context, nodeconfig *node.Config) error { - //at this point, all vars should be set in the Config - //get the account for the provided swarm account - prvkey := getAccount(config.BzzAccount, ctx, stack) - //set the resolved config path (geth --datadir) - config.Path = expandPath(stack.InstanceDir()) - //finally, initialize the configuration - err := config.Init(prvkey, nodeconfig.NodeKey()) - if err != nil { - return err - } - //configuration phase completed here - log.Debug("Starting Swarm with the following parameters:") - //after having created the config, print it to screen - log.Debug(printConfig(config)) - return nil -} - -//configFileOverride overrides the current config with the config file, if a config file has been provided -func configFileOverride(config *bzzapi.Config, ctx *cli.Context) (*bzzapi.Config, error) { - var err error - - //only do something if the -config flag has been set - if ctx.GlobalIsSet(SwarmTomlConfigPathFlag.Name) { - var filepath string - if filepath = ctx.GlobalString(SwarmTomlConfigPathFlag.Name); filepath == "" { - utils.Fatalf("Config file flag provided with invalid file path") - } - var f *os.File - f, err = os.Open(filepath) - if err != nil { - return nil, err - } - defer f.Close() - - //decode the TOML file into a Config struct - //note that we are decoding into the existing defaultConfig; - //if an entry is not present in the file, the default entry is kept - err = tomlSettings.NewDecoder(f).Decode(&config) - // Add file name to errors that have a line number. - if _, ok := err.(*toml.LineError); ok { - err = errors.New(filepath + ", " + err.Error()) - } - } - return config, err -} - -// cmdLineOverride overrides the current config with whatever is provided through the command line -// most values are not allowed a zero value (empty string), if not otherwise noted -func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Config { - if keyid := ctx.GlobalString(SwarmAccountFlag.Name); keyid != "" { - currentConfig.BzzAccount = keyid - } - - if chbookaddr := ctx.GlobalString(ChequebookAddrFlag.Name); chbookaddr != "" { - currentConfig.Contract = common.HexToAddress(chbookaddr) - } - - if networkid := ctx.GlobalString(SwarmNetworkIdFlag.Name); networkid != "" { - id, err := strconv.ParseUint(networkid, 10, 64) - if err != nil { - utils.Fatalf("invalid cli flag %s: %v", SwarmNetworkIdFlag.Name, err) - } - if id != 0 { - currentConfig.NetworkID = id - } - } - - if ctx.GlobalIsSet(utils.DataDirFlag.Name) { - if datadir := ctx.GlobalString(utils.DataDirFlag.Name); datadir != "" { - currentConfig.Path = expandPath(datadir) - } - } - - bzzport := ctx.GlobalString(SwarmPortFlag.Name) - if len(bzzport) > 0 { - currentConfig.Port = bzzport - } - - if bzzaddr := ctx.GlobalString(SwarmListenAddrFlag.Name); bzzaddr != "" { - currentConfig.ListenAddr = bzzaddr - } - - if ctx.GlobalIsSet(SwarmSwapEnabledFlag.Name) { - currentConfig.SwapEnabled = true - } - - if ctx.GlobalIsSet(SwarmSyncDisabledFlag.Name) { - currentConfig.SyncEnabled = false - } - - if d := ctx.GlobalDuration(SwarmSyncUpdateDelay.Name); d > 0 { - currentConfig.SyncUpdateDelay = d - } - - // any value including 0 is acceptable - currentConfig.MaxStreamPeerServers = ctx.GlobalInt(SwarmMaxStreamPeerServersFlag.Name) - - if ctx.GlobalIsSet(SwarmLightNodeEnabled.Name) { - currentConfig.LightNodeEnabled = true - } - - if ctx.GlobalIsSet(SwarmDeliverySkipCheckFlag.Name) { - currentConfig.DeliverySkipCheck = true - } - - currentConfig.SwapAPI = ctx.GlobalString(SwarmSwapAPIFlag.Name) - if currentConfig.SwapEnabled && currentConfig.SwapAPI == "" { - utils.Fatalf(SwarmErrSwapSetNoAPI) - } - - if ctx.GlobalIsSet(EnsAPIFlag.Name) { - ensAPIs := ctx.GlobalStringSlice(EnsAPIFlag.Name) - // preserve backward compatibility to disable ENS with --ens-api="" - if len(ensAPIs) == 1 && ensAPIs[0] == "" { - ensAPIs = nil - } - for i := range ensAPIs { - ensAPIs[i] = expandPath(ensAPIs[i]) - } - - currentConfig.EnsAPIs = ensAPIs - } - - if cors := ctx.GlobalString(CorsStringFlag.Name); cors != "" { - currentConfig.Cors = cors - } - - if storePath := ctx.GlobalString(SwarmStorePath.Name); storePath != "" { - currentConfig.ChunkDbPath = storePath - } - - if storeCapacity := ctx.GlobalUint64(SwarmStoreCapacity.Name); storeCapacity != 0 { - currentConfig.DbCapacity = storeCapacity - } - - if ctx.GlobalIsSet(SwarmStoreCacheCapacity.Name) { - currentConfig.CacheCapacity = ctx.GlobalUint(SwarmStoreCacheCapacity.Name) - } - - if ctx.GlobalIsSet(SwarmBootnodeModeFlag.Name) { - currentConfig.BootnodeMode = ctx.GlobalBool(SwarmBootnodeModeFlag.Name) - } - - if ctx.GlobalIsSet(SwarmGlobalStoreAPIFlag.Name) { - currentConfig.GlobalStoreAPI = ctx.GlobalString(SwarmGlobalStoreAPIFlag.Name) - } - - return currentConfig - -} - -// envVarsOverride overrides the current config with whatver is provided in environment variables -// most values are not allowed a zero value (empty string), if not otherwise noted -func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) { - if keyid := os.Getenv(SwarmEnvAccount); keyid != "" { - currentConfig.BzzAccount = keyid - } - - if chbookaddr := os.Getenv(SwarmEnvChequebookAddr); chbookaddr != "" { - currentConfig.Contract = common.HexToAddress(chbookaddr) - } - - if networkid := os.Getenv(SwarmEnvNetworkID); networkid != "" { - id, err := strconv.ParseUint(networkid, 10, 64) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmEnvNetworkID, err) - } - if id != 0 { - currentConfig.NetworkID = id - } - } - - if datadir := os.Getenv(GethEnvDataDir); datadir != "" { - currentConfig.Path = expandPath(datadir) - } - - bzzport := os.Getenv(SwarmEnvPort) - if len(bzzport) > 0 { - currentConfig.Port = bzzport - } - - if bzzaddr := os.Getenv(SwarmEnvListenAddr); bzzaddr != "" { - currentConfig.ListenAddr = bzzaddr - } - - if swapenable := os.Getenv(SwarmEnvSwapEnable); swapenable != "" { - swap, err := strconv.ParseBool(swapenable) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSwapEnable, err) - } - currentConfig.SwapEnabled = swap - } - - if syncdisable := os.Getenv(SwarmEnvSyncDisable); syncdisable != "" { - sync, err := strconv.ParseBool(syncdisable) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSyncDisable, err) - } - currentConfig.SyncEnabled = !sync - } - - if v := os.Getenv(SwarmEnvDeliverySkipCheck); v != "" { - skipCheck, err := strconv.ParseBool(v) - if err != nil { - currentConfig.DeliverySkipCheck = skipCheck - } - } - - if v := os.Getenv(SwarmEnvSyncUpdateDelay); v != "" { - d, err := time.ParseDuration(v) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmEnvSyncUpdateDelay, err) - } - currentConfig.SyncUpdateDelay = d - } - - if max := os.Getenv(SwarmEnvMaxStreamPeerServers); max != "" { - m, err := strconv.Atoi(max) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmEnvMaxStreamPeerServers, err) - } - currentConfig.MaxStreamPeerServers = m - } - - if lne := os.Getenv(SwarmEnvLightNodeEnable); lne != "" { - lightnode, err := strconv.ParseBool(lne) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmEnvLightNodeEnable, err) - } - currentConfig.LightNodeEnabled = lightnode - } - - if swapapi := os.Getenv(SwarmEnvSwapAPI); swapapi != "" { - currentConfig.SwapAPI = swapapi - } - - if currentConfig.SwapEnabled && currentConfig.SwapAPI == "" { - utils.Fatalf(SwarmErrSwapSetNoAPI) - } - - if ensapi := os.Getenv(SwarmEnvENSAPI); ensapi != "" { - currentConfig.EnsAPIs = strings.Split(ensapi, ",") - } - - if ensaddr := os.Getenv(SwarmEnvENSAddr); ensaddr != "" { - currentConfig.EnsRoot = common.HexToAddress(ensaddr) - } - - if cors := os.Getenv(SwarmEnvCORS); cors != "" { - currentConfig.Cors = cors - } - - if bm := os.Getenv(SwarmEnvBootnodeMode); bm != "" { - bootnodeMode, err := strconv.ParseBool(bm) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmEnvBootnodeMode, err) - } - currentConfig.BootnodeMode = bootnodeMode - } - - if api := os.Getenv(SwarmGlobalstoreAPI); api != "" { - currentConfig.GlobalStoreAPI = api - } - - return currentConfig -} - -// dumpConfig is the dumpconfig command. -// writes a default config to STDOUT -func dumpConfig(ctx *cli.Context) error { - cfg, err := buildConfig(ctx) - if err != nil { - utils.Fatalf(fmt.Sprintf("Uh oh - dumpconfig triggered an error %v", err)) - } - comment := "" - out, err := tomlSettings.Marshal(&cfg) - if err != nil { - return err - } - io.WriteString(os.Stdout, comment) - os.Stdout.Write(out) - return nil -} - -//validate configuration parameters -func validateConfig(cfg *bzzapi.Config) (err error) { - for _, ensAPI := range cfg.EnsAPIs { - if ensAPI != "" { - if err := validateEnsAPIs(ensAPI); err != nil { - return fmt.Errorf("invalid format [tld:][contract-addr@]url for ENS API endpoint configuration %q: %v", ensAPI, err) - } - } - } - return nil -} - -//validate EnsAPIs configuration parameter -func validateEnsAPIs(s string) (err error) { - // missing contract address - if strings.HasPrefix(s, "@") { - return errors.New("missing contract address") - } - // missing url - if strings.HasSuffix(s, "@") { - return errors.New("missing url") - } - // missing tld - if strings.HasPrefix(s, ":") { - return errors.New("missing tld") - } - // missing url - if strings.HasSuffix(s, ":") { - return errors.New("missing url") - } - return nil -} - -//print a Config as string -func printConfig(config *bzzapi.Config) string { - out, err := tomlSettings.Marshal(&config) - if err != nil { - return fmt.Sprintf("Something is not right with the configuration: %v", err) - } - return string(out) -} diff --git a/cmd/swarm/config_test.go b/cmd/swarm/config_test.go deleted file mode 100644 index 484f6dec39..0000000000 --- a/cmd/swarm/config_test.go +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "io" - "io/ioutil" - "net" - "os" - "os/exec" - "testing" - "time" - - "github.com/docker/docker/pkg/reexec" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm" - "github.com/ethereum/go-ethereum/swarm/api" -) - -func TestConfigDump(t *testing.T) { - swarm := runSwarm(t, "dumpconfig") - defaultConf := api.NewConfig() - out, err := tomlSettings.Marshal(&defaultConf) - if err != nil { - t.Fatal(err) - } - swarm.Expect(string(out)) - swarm.ExpectExit() -} - -func TestConfigFailsSwapEnabledNoSwapApi(t *testing.T) { - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42", - fmt.Sprintf("--%s", SwarmPortFlag.Name), "54545", - fmt.Sprintf("--%s", SwarmSwapEnabledFlag.Name), - } - - swarm := runSwarm(t, flags...) - swarm.Expect("Fatal: " + SwarmErrSwapSetNoAPI + "\n") - swarm.ExpectExit() -} - -func TestConfigFailsNoBzzAccount(t *testing.T) { - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42", - fmt.Sprintf("--%s", SwarmPortFlag.Name), "54545", - } - - swarm := runSwarm(t, flags...) - swarm.Expect("Fatal: " + SwarmErrNoBZZAccount + "\n") - swarm.ExpectExit() -} - -func TestConfigCmdLineOverrides(t *testing.T) { - dir, err := ioutil.TempDir("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42", - fmt.Sprintf("--%s", SwarmPortFlag.Name), httpPort, - fmt.Sprintf("--%s", SwarmSyncDisabledFlag.Name), - fmt.Sprintf("--%s", CorsStringFlag.Name), "*", - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - fmt.Sprintf("--%s", SwarmDeliverySkipCheckFlag.Name), - fmt.Sprintf("--%s", EnsAPIFlag.Name), "", - fmt.Sprintf("--%s", utils.DataDirFlag.Name), dir, - fmt.Sprintf("--%s", utils.IPCPathFlag.Name), conf.IPCPath, - } - node.Cmd = runSwarm(t, flags...) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkID != 42 { - t.Fatalf("Expected network ID to be %d, got %d", 42, info.NetworkID) - } - - if info.SyncEnabled { - t.Fatal("Expected Sync to be disabled, but is true") - } - - if !info.DeliverySkipCheck { - t.Fatal("Expected DeliverySkipCheck to be enabled, but it is not") - } - - if info.Cors != "*" { - t.Fatalf("Expected Cors flag to be set to %s, got %s", "*", info.Cors) - } - - node.Shutdown() -} - -func TestConfigFileOverrides(t *testing.T) { - - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - //create a config file - //first, create a default conf - defaultConf := api.NewConfig() - //change some values in order to test if they have been loaded - defaultConf.SyncEnabled = false - defaultConf.DeliverySkipCheck = true - defaultConf.NetworkID = 54 - defaultConf.Port = httpPort - defaultConf.DbCapacity = 9000000 - defaultConf.HiveParams.KeepAliveInterval = 6000000000 - defaultConf.Swap.Params.Strategy.AutoCashInterval = 600 * time.Second - //defaultConf.SyncParams.KeyBufferSize = 512 - //create a TOML string - out, err := tomlSettings.Marshal(&defaultConf) - if err != nil { - t.Fatalf("Error creating TOML file in TestFileOverride: %v", err) - } - //create file - f, err := ioutil.TempFile("", "testconfig.toml") - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - //write file - _, err = f.WriteString(string(out)) - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - f.Sync() - - dir, err := ioutil.TempDir("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - flags := []string{ - fmt.Sprintf("--%s", SwarmTomlConfigPathFlag.Name), f.Name(), - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - fmt.Sprintf("--%s", EnsAPIFlag.Name), "", - fmt.Sprintf("--%s", utils.DataDirFlag.Name), dir, - fmt.Sprintf("--%s", utils.IPCPathFlag.Name), conf.IPCPath, - } - node.Cmd = runSwarm(t, flags...) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkID != 54 { - t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkID) - } - - if info.SyncEnabled { - t.Fatal("Expected Sync to be disabled, but is true") - } - - if !info.DeliverySkipCheck { - t.Fatal("Expected DeliverySkipCheck to be enabled, but it is not") - } - - if info.DbCapacity != 9000000 { - t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkID) - } - - if info.HiveParams.KeepAliveInterval != 6000000000 { - t.Fatalf("Expected HiveParams KeepAliveInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.KeepAliveInterval)) - } - - if info.Swap.Params.Strategy.AutoCashInterval != 600*time.Second { - t.Fatalf("Expected SwapParams AutoCashInterval to be %ds, got %d", 600, info.Swap.Params.Strategy.AutoCashInterval) - } - - // if info.SyncParams.KeyBufferSize != 512 { - // t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize) - // } - - node.Shutdown() -} - -func TestConfigEnvVars(t *testing.T) { - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - envVars := os.Environ() - envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmPortFlag.EnvVar, httpPort)) - envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmNetworkIdFlag.EnvVar, "999")) - envVars = append(envVars, fmt.Sprintf("%s=%s", CorsStringFlag.EnvVar, "*")) - envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmSyncDisabledFlag.EnvVar, "true")) - envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmDeliverySkipCheckFlag.EnvVar, "true")) - - dir, err := ioutil.TempDir("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - flags := []string{ - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - "--ens-api", "", - "--datadir", dir, - "--ipcpath", conf.IPCPath, - } - - //node.Cmd = runSwarm(t,flags...) - //node.Cmd.cmd.Env = envVars - //the above assignment does not work, so we need a custom Cmd here in order to pass envVars: - cmd := &exec.Cmd{ - Path: reexec.Self(), - Args: append([]string{"swarm-test"}, flags...), - Stderr: os.Stderr, - Stdout: os.Stdout, - } - cmd.Env = envVars - //stdout, err := cmd.StdoutPipe() - //if err != nil { - // t.Fatal(err) - //} - //stdout = bufio.NewReader(stdout) - var stdin io.WriteCloser - if stdin, err = cmd.StdinPipe(); err != nil { - t.Fatal(err) - } - if err := cmd.Start(); err != nil { - t.Fatal(err) - } - - //cmd.InputLine(testPassphrase) - io.WriteString(stdin, testPassphrase+"\n") - defer func() { - if t.Failed() { - node.Shutdown() - cmd.Process.Kill() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkID != 999 { - t.Fatalf("Expected network ID to be %d, got %d", 999, info.NetworkID) - } - - if info.Cors != "*" { - t.Fatalf("Expected Cors flag to be set to %s, got %s", "*", info.Cors) - } - - if info.SyncEnabled { - t.Fatal("Expected Sync to be disabled, but is true") - } - - if !info.DeliverySkipCheck { - t.Fatal("Expected DeliverySkipCheck to be enabled, but it is not") - } - - node.Shutdown() - cmd.Process.Kill() -} - -func TestConfigCmdLineOverridesFile(t *testing.T) { - - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - //create a config file - //first, create a default conf - defaultConf := api.NewConfig() - //change some values in order to test if they have been loaded - defaultConf.SyncEnabled = true - defaultConf.NetworkID = 54 - defaultConf.Port = "8588" - defaultConf.DbCapacity = 9000000 - defaultConf.HiveParams.KeepAliveInterval = 6000000000 - defaultConf.Swap.Params.Strategy.AutoCashInterval = 600 * time.Second - //defaultConf.SyncParams.KeyBufferSize = 512 - //create a TOML file - out, err := tomlSettings.Marshal(&defaultConf) - if err != nil { - t.Fatalf("Error creating TOML file in TestFileOverride: %v", err) - } - //write file - fname := "testconfig.toml" - f, err := ioutil.TempFile("", fname) - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - defer os.Remove(fname) - //write file - _, err = f.WriteString(string(out)) - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - f.Sync() - - dir, err := ioutil.TempDir("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - expectNetworkId := uint64(77) - - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "77", - fmt.Sprintf("--%s", SwarmPortFlag.Name), httpPort, - fmt.Sprintf("--%s", SwarmSyncDisabledFlag.Name), - fmt.Sprintf("--%s", SwarmTomlConfigPathFlag.Name), f.Name(), - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - fmt.Sprintf("--%s", EnsAPIFlag.Name), "", - fmt.Sprintf("--%s", utils.DataDirFlag.Name), dir, - fmt.Sprintf("--%s", utils.IPCPathFlag.Name), conf.IPCPath, - } - node.Cmd = runSwarm(t, flags...) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkID != expectNetworkId { - t.Fatalf("Expected network ID to be %d, got %d", expectNetworkId, info.NetworkID) - } - - if info.SyncEnabled { - t.Fatal("Expected Sync to be disabled, but is true") - } - - if info.DbCapacity != 9000000 { - t.Fatalf("Expected Capacity to be %d, got %d", 9000000, info.DbCapacity) - } - - if info.HiveParams.KeepAliveInterval != 6000000000 { - t.Fatalf("Expected HiveParams KeepAliveInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.KeepAliveInterval)) - } - - if info.Swap.Params.Strategy.AutoCashInterval != 600*time.Second { - t.Fatalf("Expected SwapParams AutoCashInterval to be %ds, got %d", 600, info.Swap.Params.Strategy.AutoCashInterval) - } - - // if info.SyncParams.KeyBufferSize != 512 { - // t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize) - // } - - node.Shutdown() -} - -func TestConfigValidate(t *testing.T) { - for _, c := range []struct { - cfg *api.Config - err string - }{ - { - cfg: &api.Config{EnsAPIs: []string{ - "/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "http://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "ws://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "test:/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "test:ws://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:12344", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "eth:", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"eth:\": missing url", - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"314159265dD8dbb310642f98f50C066173C1259b@\": missing url", - }, - { - cfg: &api.Config{EnsAPIs: []string{ - ":314159265dD8dbb310642f98f50C066173C1259", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \":314159265dD8dbb310642f98f50C066173C1259\": missing tld", - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "@/data/testnet/geth.ipc", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"@/data/testnet/geth.ipc\": missing contract address", - }, - } { - err := validateConfig(c.cfg) - if c.err != "" && err.Error() != c.err { - t.Errorf("expected error %q, got %q", c.err, err) - } - if c.err == "" && err != nil { - t.Errorf("unexpected error %q", err) - } - } -} - -func assignTCPPort() (string, error) { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return "", err - } - l.Close() - _, port, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return "", err - } - return port, nil -} diff --git a/cmd/swarm/db.go b/cmd/swarm/db.go deleted file mode 100644 index b0e9f367fd..0000000000 --- a/cmd/swarm/db.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "archive/tar" - "bytes" - "encoding/binary" - "encoding/hex" - "fmt" - "io" - "os" - "path/filepath" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/opt" - "gopkg.in/urfave/cli.v1" -) - -var legacyKeyIndex = byte(0) -var keyData = byte(6) - -type dpaDBIndex struct { - Idx uint64 - Access uint64 -} - -var dbCommand = cli.Command{ - Name: "db", - CustomHelpTemplate: helpTemplate, - Usage: "manage the local chunk database", - ArgsUsage: "db COMMAND", - Description: "Manage the local chunk database", - Subcommands: []cli.Command{ - { - Action: dbExport, - CustomHelpTemplate: helpTemplate, - Name: "export", - Usage: "export a local chunk database as a tar archive (use - to send to stdout)", - ArgsUsage: " ", - Description: ` -Export a local chunk database as a tar archive (use - to send to stdout). - - swarm db export ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar - -The export may be quite large, consider piping the output through the Unix -pv(1) tool to get a progress bar: - - swarm db export ~/.ethereum/swarm/bzz-KEY/chunks - | pv > chunks.tar -`, - }, - { - Action: dbImport, - CustomHelpTemplate: helpTemplate, - Name: "import", - Usage: "import chunks from a tar archive into a local chunk database (use - to read from stdin)", - ArgsUsage: " ", - Description: `Import chunks from a tar archive into a local chunk database (use - to read from stdin). - - swarm db import ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar - -The import may be quite large, consider piping the input through the Unix -pv(1) tool to get a progress bar: - - pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks -`, - Flags: []cli.Flag{ - SwarmLegacyFlag, - }, - }, - }, -} - -func dbExport(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 3 { - utils.Fatalf("invalid arguments, please specify both (path to a local chunk database), (path to write the tar archive to, - for stdout) and the base key") - } - - var out io.Writer - if args[1] == "-" { - out = os.Stdout - } else { - f, err := os.Create(args[1]) - if err != nil { - utils.Fatalf("error opening output file: %s", err) - } - defer f.Close() - out = f - } - - isLegacy := localstore.IsLegacyDatabase(args[0]) - if isLegacy { - count, err := exportLegacy(args[0], common.Hex2Bytes(args[2]), out) - if err != nil { - utils.Fatalf("error exporting legacy local chunk database: %s", err) - } - - log.Info(fmt.Sprintf("successfully exported %d chunks from legacy db", count)) - return - } - - store, err := openLDBStore(args[0], common.Hex2Bytes(args[2])) - if err != nil { - utils.Fatalf("error opening local chunk database: %s", err) - } - defer store.Close() - - count, err := store.Export(out) - if err != nil { - utils.Fatalf("error exporting local chunk database: %s", err) - } - - log.Info(fmt.Sprintf("successfully exported %d chunks", count)) -} - -func dbImport(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 3 { - utils.Fatalf("invalid arguments, please specify both (path to a local chunk database), (path to read the tar archive from, - for stdin) and the base key") - } - - legacy := ctx.IsSet(SwarmLegacyFlag.Name) - - store, err := openLDBStore(args[0], common.Hex2Bytes(args[2])) - if err != nil { - utils.Fatalf("error opening local chunk database: %s", err) - } - defer store.Close() - - var in io.Reader - if args[1] == "-" { - in = os.Stdin - } else { - f, err := os.Open(args[1]) - if err != nil { - utils.Fatalf("error opening input file: %s", err) - } - defer f.Close() - in = f - } - - count, err := store.Import(in, legacy) - if err != nil { - utils.Fatalf("error importing local chunk database: %s", err) - } - - log.Info(fmt.Sprintf("successfully imported %d chunks", count)) -} - -func openLDBStore(path string, basekey []byte) (*localstore.DB, error) { - if _, err := os.Stat(filepath.Join(path, "CURRENT")); err != nil { - return nil, fmt.Errorf("invalid chunkdb path: %s", err) - } - - return localstore.New(path, basekey, nil) -} - -func decodeIndex(data []byte, index *dpaDBIndex) error { - dec := rlp.NewStream(bytes.NewReader(data), 0) - return dec.Decode(index) -} - -func getDataKey(idx uint64, po uint8) []byte { - key := make([]byte, 10) - key[0] = keyData - key[1] = po - binary.BigEndian.PutUint64(key[2:], idx) - - return key -} - -func exportLegacy(path string, basekey []byte, out io.Writer) (int64, error) { - tw := tar.NewWriter(out) - defer tw.Close() - db, err := leveldb.OpenFile(path, &opt.Options{OpenFilesCacheCapacity: 128}) - if err != nil { - return 0, err - } - defer db.Close() - - it := db.NewIterator(nil, nil) - defer it.Release() - var count int64 - for ok := it.Seek([]byte{legacyKeyIndex}); ok; ok = it.Next() { - key := it.Key() - if (key == nil) || (key[0] != legacyKeyIndex) { - break - } - - var index dpaDBIndex - - hash := key[1:] - decodeIndex(it.Value(), &index) - - po := uint8(chunk.Proximity(basekey, hash)) - - datakey := getDataKey(index.Idx, po) - data, err := db.Get(datakey, nil) - if err != nil { - log.Crit(fmt.Sprintf("Chunk %x found but could not be accessed: %v, %x", key, err, datakey)) - continue - } - - hdr := &tar.Header{ - Name: hex.EncodeToString(hash), - Mode: 0644, - Size: int64(len(data)), - } - if err := tw.WriteHeader(hdr); err != nil { - return count, err - } - if _, err := tw.Write(data); err != nil { - return count, err - } - count++ - } - - return count, nil -} diff --git a/cmd/swarm/download.go b/cmd/swarm/download.go deleted file mode 100644 index fcbefa0206..0000000000 --- a/cmd/swarm/download.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . -package main - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/api" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - "gopkg.in/urfave/cli.v1" -) - -var downloadCommand = cli.Command{ - Action: download, - Name: "down", - Flags: []cli.Flag{SwarmRecursiveFlag, SwarmAccessPasswordFlag}, - Usage: "downloads a swarm manifest or a file inside a manifest", - ArgsUsage: " []", - Description: `Downloads a swarm bzz uri to the given dir. When no dir is provided, working directory is assumed. --recursive flag is expected when downloading a manifest with multiple entries.`, -} - -func download(ctx *cli.Context) { - log.Debug("downloading content using swarm down") - args := ctx.Args() - dest := "." - - switch len(args) { - case 0: - utils.Fatalf("Usage: swarm down [options] []") - case 1: - log.Trace(fmt.Sprintf("swarm down: no destination path - assuming working dir")) - default: - log.Trace(fmt.Sprintf("destination path arg: %s", args[1])) - if absDest, err := filepath.Abs(args[1]); err == nil { - dest = absDest - } else { - utils.Fatalf("could not get download path: %v", err) - } - } - - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - isRecursive = ctx.Bool(SwarmRecursiveFlag.Name) - client = swarm.NewClient(bzzapi) - ) - - if fi, err := os.Stat(dest); err == nil { - if isRecursive && !fi.Mode().IsDir() { - utils.Fatalf("destination path is not a directory!") - } - } else { - if !os.IsNotExist(err) { - utils.Fatalf("could not stat path: %v", err) - } - } - - uri, err := api.Parse(args[0]) - if err != nil { - utils.Fatalf("could not parse uri argument: %v", err) - } - - dl := func(credentials string) error { - // assume behaviour according to --recursive switch - if isRecursive { - if err := client.DownloadDirectory(uri.Addr, uri.Path, dest, credentials); err != nil { - if err == swarm.ErrUnauthorized { - return err - } - return fmt.Errorf("directory %s: %v", uri.Path, err) - } - } else { - // we are downloading a file - log.Debug("downloading file/path from a manifest", "uri.Addr", uri.Addr, "uri.Path", uri.Path) - - err := client.DownloadFile(uri.Addr, uri.Path, dest, credentials) - if err != nil { - if err == swarm.ErrUnauthorized { - return err - } - return fmt.Errorf("file %s from address: %s: %v", uri.Path, uri.Addr, err) - } - } - return nil - } - if passwords := makePasswordList(ctx); passwords != nil { - password := getPassPhrase(fmt.Sprintf("Downloading %s is restricted", uri), 0, passwords) - err = dl(password) - } else { - err = dl("") - } - if err != nil { - utils.Fatalf("download: %v", err) - } -} diff --git a/cmd/swarm/explore.go b/cmd/swarm/explore.go deleted file mode 100644 index 9566213e41..0000000000 --- a/cmd/swarm/explore.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command bzzhash computes a swarm tree hash. -package main - -import ( - "context" - "fmt" - "os" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" - "gopkg.in/urfave/cli.v1" -) - -var hashesCommand = cli.Command{ - Action: hashes, - CustomHelpTemplate: helpTemplate, - Name: "hashes", - Usage: "print all hashes of a file to STDOUT", - ArgsUsage: "", - Description: "Prints all hashes of a file to STDOUT", -} - -func hashes(ctx *cli.Context) { - args := ctx.Args() - if len(args) < 1 { - utils.Fatalf("Usage: swarm hashes ") - } - f, err := os.Open(args[0]) - if err != nil { - utils.Fatalf("Error opening file " + args[1]) - } - defer f.Close() - - fileStore := storage.NewFileStore(&storage.FakeChunkStore{}, storage.NewFileStoreParams(), chunk.NewTags()) - refs, err := fileStore.GetAllReferences(context.TODO(), f, false) - if err != nil { - utils.Fatalf("%v\n", err) - } else { - for _, r := range refs { - fmt.Println(r.String()) - } - } -} diff --git a/cmd/swarm/export_test.go b/cmd/swarm/export_test.go deleted file mode 100644 index ca82cfd4c9..0000000000 --- a/cmd/swarm/export_test.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "archive/tar" - "bytes" - "compress/gzip" - "crypto/md5" - "encoding/base64" - "encoding/hex" - "io" - "io/ioutil" - "net/http" - "os" - "path" - "runtime" - "strings" - "testing" - - "github.com/ethereum/go-ethereum/cmd/swarm/testdata" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -const ( - DATABASE_FIXTURE_BZZ_ACCOUNT = "0aa159029fa13ffa8fa1c6fff6ebceface99d6a4" - DATABASE_FIXTURE_PASSWORD = "pass" - FIXTURE_DATADIR_PREFIX = "swarm/bzz-0aa159029fa13ffa8fa1c6fff6ebceface99d6a4" - FixtureBaseKey = "a9f22b3d77b4bdf5f3eefce995d6c8e7cecf2636f20956f08a0d1ed95adb52ad" -) - -// TestCLISwarmExportImport perform the following test: -// 1. runs swarm node -// 2. uploads a random file -// 3. runs an export of the local datastore -// 4. runs a second swarm node -// 5. imports the exported datastore -// 6. fetches the uploaded random file from the second node -func TestCLISwarmExportImport(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - cluster := newTestCluster(t, 1) - - // generate random 1mb file - content := testutil.RandomBytes(1, 1000000) - fileName := testutil.TempFileWithContent(t, string(content)) - defer os.Remove(fileName) - - // upload the file with 'swarm up' and expect a hash - up := runSwarm(t, "--bzzapi", cluster.Nodes[0].URL, "up", fileName) - _, matches := up.ExpectRegexp(`[a-f\d]{64}`) - up.ExpectExit() - hash := matches[0] - - var info swarm.Info - if err := cluster.Nodes[0].Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - cluster.Stop() - defer cluster.Cleanup() - - // generate an export.tar - exportCmd := runSwarm(t, "db", "export", info.Path+"/chunks", info.Path+"/export.tar", strings.TrimPrefix(info.BzzKey, "0x")) - exportCmd.ExpectExit() - - // start second cluster - cluster2 := newTestCluster(t, 1) - - var info2 swarm.Info - if err := cluster2.Nodes[0].Client.Call(&info2, "bzz_info"); err != nil { - t.Fatal(err) - } - - // stop second cluster, so that we close LevelDB - cluster2.Stop() - defer cluster2.Cleanup() - - // import the export.tar - importCmd := runSwarm(t, "db", "import", info2.Path+"/chunks", info.Path+"/export.tar", strings.TrimPrefix(info2.BzzKey, "0x")) - importCmd.ExpectExit() - - // spin second cluster back up - cluster2.StartExistingNodes(t, 1, strings.TrimPrefix(info2.BzzAccount, "0x")) - - // try to fetch imported file - res, err := http.Get(cluster2.Nodes[0].URL + "/bzz:/" + hash) - if err != nil { - t.Fatal(err) - } - - if res.StatusCode != 200 { - t.Fatalf("expected HTTP status %d, got %s", 200, res.Status) - } - - // compare downloaded file with the generated random file - mustEqualFiles(t, bytes.NewReader(content), res.Body) -} - -// TestExportLegacyToNew checks that an old database gets imported correctly into the new localstore structure -// The test sequence is as follows: -// 1. unpack database fixture to tmp dir -// 2. try to open with new swarm binary that should complain about old database -// 3. export from old database -// 4. remove the chunks folder -// 5. import the dump -// 6. file should be accessible -func TestExportLegacyToNew(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() // this should be reenabled once the appveyor tests underlying issue is fixed - } - /* - fixture bzz account 0aa159029fa13ffa8fa1c6fff6ebceface99d6a4 - */ - const UPLOADED_FILE_MD5_HASH = "a001fdae53ba50cae584b8b02b06f821" - const UPLOADED_HASH = "67a86082ee0ea1bc7dd8d955bb1e14d04f61d55ae6a4b37b3d0296a3a95e454a" - tmpdir, err := ioutil.TempDir("", "swarm-test") - log.Trace("running legacy datastore migration test", "temp dir", tmpdir) - defer os.RemoveAll(tmpdir) - if err != nil { - t.Fatal(err) - } - inflateBase64Gzip(t, testdata.DATADIR_MIGRATION_FIXTURE, tmpdir) - - tmpPassword := testutil.TempFileWithContent(t, DATABASE_FIXTURE_PASSWORD) - defer os.Remove(tmpPassword) - - flags := []string{ - "--datadir", tmpdir, - "--bzzaccount", DATABASE_FIXTURE_BZZ_ACCOUNT, - "--password", tmpPassword, - } - - newSwarmOldDb := runSwarm(t, flags...) - _, matches := newSwarmOldDb.ExpectRegexp(".+") - newSwarmOldDb.ExpectExit() - - if len(matches) == 0 { - t.Fatalf("stdout not matched") - } - - if newSwarmOldDb.ExitStatus() == 0 { - t.Fatal("should error") - } - t.Log("exporting legacy database") - actualDataDir := path.Join(tmpdir, FIXTURE_DATADIR_PREFIX) - exportCmd := runSwarm(t, "--verbosity", "5", "db", "export", actualDataDir+"/chunks", tmpdir+"/export.tar", FixtureBaseKey) - exportCmd.ExpectExit() - - stat, err := os.Stat(tmpdir + "/export.tar") - if err != nil { - t.Fatal(err) - } - - // make some silly size assumption - if stat.Size() < 90000 { - t.Fatal("export size too small") - } - log.Info("removing chunk datadir") - err = os.RemoveAll(path.Join(actualDataDir, "chunks")) - if err != nil { - t.Fatal(err) - } - - // start second cluster - cluster2 := newTestCluster(t, 1) - var info2 swarm.Info - if err := cluster2.Nodes[0].Client.Call(&info2, "bzz_info"); err != nil { - t.Fatal(err) - } - - // stop second cluster, so that we close LevelDB - cluster2.Stop() - defer cluster2.Cleanup() - - // import the export.tar - importCmd := runSwarm(t, "db", "import", "--legacy", info2.Path+"/chunks", tmpdir+"/export.tar", strings.TrimPrefix(info2.BzzKey, "0x")) - importCmd.ExpectExit() - - // spin second cluster back up - cluster2.StartExistingNodes(t, 1, strings.TrimPrefix(info2.BzzAccount, "0x")) - t.Log("trying to http get the file") - // try to fetch imported file - res, err := http.Get(cluster2.Nodes[0].URL + "/bzz:/" + UPLOADED_HASH) - if err != nil { - t.Fatal(err) - } - - if res.StatusCode != 200 { - t.Fatalf("expected HTTP status %d, got %s", 200, res.Status) - } - h := md5.New() - if _, err := io.Copy(h, res.Body); err != nil { - t.Fatal(err) - } - - sum := h.Sum(nil) - - b, err := hex.DecodeString(UPLOADED_FILE_MD5_HASH) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(sum, b) { - t.Fatal("should be equal") - } -} - -func mustEqualFiles(t *testing.T, up io.Reader, down io.Reader) { - h := md5.New() - upLen, err := io.Copy(h, up) - if err != nil { - t.Fatal(err) - } - upHash := h.Sum(nil) - h.Reset() - downLen, err := io.Copy(h, down) - if err != nil { - t.Fatal(err) - } - downHash := h.Sum(nil) - - if !bytes.Equal(upHash, downHash) || upLen != downLen { - t.Fatalf("downloaded imported file md5=%x (length %v) is not the same as the generated one mp5=%x (length %v)", downHash, downLen, upHash, upLen) - } -} - -func inflateBase64Gzip(t *testing.T, base64File, directory string) { - t.Helper() - - f := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64File)) - gzf, err := gzip.NewReader(f) - if err != nil { - t.Fatal(err) - } - - tarReader := tar.NewReader(gzf) - - for { - header, err := tarReader.Next() - if err == io.EOF { - break - } - - if err != nil { - t.Fatal(err) - } - - name := header.Name - - switch header.Typeflag { - case tar.TypeDir: - err := os.Mkdir(path.Join(directory, name), os.ModePerm) - if err != nil { - t.Fatal(err) - } - case tar.TypeReg: - file, err := os.Create(path.Join(directory, name)) - if err != nil { - t.Fatal(err) - } - if _, err := io.Copy(file, tarReader); err != nil { - t.Fatal(err) - } - file.Close() - default: - t.Fatal("shouldn't happen") - } - } -} diff --git a/cmd/swarm/feeds.go b/cmd/swarm/feeds.go deleted file mode 100644 index 6cd971a92c..0000000000 --- a/cmd/swarm/feeds.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command feed allows the user to create and update signed Swarm feeds -package main - -import ( - "fmt" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - - "github.com/ethereum/go-ethereum/cmd/utils" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "gopkg.in/urfave/cli.v1" -) - -var feedCommand = cli.Command{ - CustomHelpTemplate: helpTemplate, - Name: "feed", - Usage: "(Advanced) Create and update Swarm Feeds", - ArgsUsage: "", - Description: "Works with Swarm Feeds", - Subcommands: []cli.Command{ - { - Action: feedCreateManifest, - CustomHelpTemplate: helpTemplate, - Name: "create", - Usage: "creates and publishes a new feed manifest", - Description: `creates and publishes a new feed manifest pointing to a specified user's updates about a particular topic. - The feed topic can be built in the following ways: - * use --topic to set the topic to an arbitrary binary hex string. - * use --name to set the topic to a human-readable name. - For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture. - * use both --topic and --name to create named subtopics. - For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning - this feed tracks a discussion about that contract. - The --user flag allows to have this manifest refer to a user other than yourself. If not specified, - it will then default to your local account (--bzzaccount)`, - Flags: []cli.Flag{SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag}, - }, - { - Action: feedUpdate, - CustomHelpTemplate: helpTemplate, - Name: "update", - Usage: "updates the content of an existing Swarm Feed", - ArgsUsage: "<0x Hex data>", - Description: `publishes a new update on the specified topic - The feed topic can be built in the following ways: - * use --topic to set the topic to an arbitrary binary hex string. - * use --name to set the topic to a human-readable name. - For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture. - * use both --topic and --name to create named subtopics. - For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning - this feed tracks a discussion about that contract. - - If you have a manifest, you can specify it with --manifest to refer to the feed, - instead of using --topic / --name - `, - Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag}, - }, - { - Action: feedInfo, - CustomHelpTemplate: helpTemplate, - Name: "info", - Usage: "obtains information about an existing Swarm feed", - Description: `obtains information about an existing Swarm feed - The topic can be specified directly with the --topic flag as an hex string - If no topic is specified, the default topic (zero) will be used - The --name flag can be used to specify subtopics with a specific name. - The --user flag allows to refer to a user other than yourself. If not specified, - it will then default to your local account (--bzzaccount) - If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user - to refer to the feed`, - Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag}, - }, - }, -} - -func NewGenericSigner(ctx *cli.Context) feed.Signer { - return feed.NewGenericSigner(getPrivKey(ctx)) -} - -func getTopic(ctx *cli.Context) (topic feed.Topic) { - var name = ctx.String(SwarmFeedNameFlag.Name) - var relatedTopic = ctx.String(SwarmFeedTopicFlag.Name) - var relatedTopicBytes []byte - var err error - - if relatedTopic != "" { - relatedTopicBytes, err = hexutil.Decode(relatedTopic) - if err != nil { - utils.Fatalf("Error parsing topic: %s", err) - } - } - - topic, err = feed.NewTopic(name, relatedTopicBytes) - if err != nil { - utils.Fatalf("Error parsing topic: %s", err) - } - return topic -} - -// swarm feed create [--name ] [--data <0x Hexdata> [--multihash=false]] -// swarm feed update <0x Hexdata> [--multihash=false] -// swarm feed info - -func feedCreateManifest(ctx *cli.Context) { - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client = swarm.NewClient(bzzapi) - ) - - newFeedUpdateRequest := feed.NewFirstRequest(getTopic(ctx)) - newFeedUpdateRequest.Feed.User = feedGetUser(ctx) - - manifestAddress, err := client.CreateFeedWithManifest(newFeedUpdateRequest) - if err != nil { - utils.Fatalf("Error creating feed manifest: %s", err.Error()) - return - } - fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up) - -} - -func feedUpdate(ctx *cli.Context) { - args := ctx.Args() - - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client = swarm.NewClient(bzzapi) - manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name) - ) - - if len(args) < 1 { - fmt.Println("Incorrect number of arguments") - cli.ShowCommandHelpAndExit(ctx, "update", 1) - return - } - - signer := NewGenericSigner(ctx) - - data, err := hexutil.Decode(args[0]) - if err != nil { - utils.Fatalf("Error parsing data: %s", err.Error()) - return - } - - var updateRequest *feed.Request - var query *feed.Query - - if manifestAddressOrDomain == "" { - query = new(feed.Query) - query.User = signer.Address() - query.Topic = getTopic(ctx) - } - - // Retrieve a feed update request - updateRequest, err = client.GetFeedRequest(query, manifestAddressOrDomain) - if err != nil { - utils.Fatalf("Error retrieving feed status: %s", err.Error()) - } - - // Check that the provided signer matches the request to sign - if updateRequest.User != signer.Address() { - utils.Fatalf("Signer address does not match the update request") - } - - // set the new data - updateRequest.SetData(data) - - // sign update - if err = updateRequest.Sign(signer); err != nil { - utils.Fatalf("Error signing feed update: %s", err.Error()) - } - - // post update - err = client.UpdateFeed(updateRequest) - if err != nil { - utils.Fatalf("Error updating feed: %s", err.Error()) - return - } -} - -func feedInfo(ctx *cli.Context) { - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client = swarm.NewClient(bzzapi) - manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name) - ) - - var query *feed.Query - if manifestAddressOrDomain == "" { - query = new(feed.Query) - query.Topic = getTopic(ctx) - query.User = feedGetUser(ctx) - } - - metadata, err := client.GetFeedRequest(query, manifestAddressOrDomain) - if err != nil { - utils.Fatalf("Error retrieving feed metadata: %s", err.Error()) - return - } - encodedMetadata, err := metadata.MarshalJSON() - if err != nil { - utils.Fatalf("Error encoding metadata to JSON for display:%s", err) - } - fmt.Println(string(encodedMetadata)) -} - -func feedGetUser(ctx *cli.Context) common.Address { - var user = ctx.String(SwarmFeedUserFlag.Name) - if user != "" { - return common.HexToAddress(user) - } - pk := getPrivKey(ctx) - if pk == nil { - utils.Fatalf("Cannot read private key. Must specify --user or --bzzaccount") - } - return crypto.PubkeyToAddress(pk.PublicKey) - -} diff --git a/cmd/swarm/feeds_test.go b/cmd/swarm/feeds_test.go deleted file mode 100644 index 4c40f62a82..0000000000 --- a/cmd/swarm/feeds_test.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "io/ioutil" - "os" - "testing" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/api" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -func TestCLIFeedUpdate(t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, func(api *api.API) swarmhttp.TestServer { - return swarmhttp.NewServer(api, "") - }, nil) - log.Info("starting a test swarm server") - defer srv.Close() - - // create a private key file for signing - privkeyHex := "0000000000000000000000000000000000000000000000000000000000001979" - privKey, _ := crypto.HexToECDSA(privkeyHex) - address := crypto.PubkeyToAddress(privKey.PublicKey) - - pkFileName := testutil.TempFileWithContent(t, privkeyHex) - defer os.Remove(pkFileName) - - // compose a topic. We'll be doing quotes about Miguel de Cervantes - var topic feed.Topic - subject := []byte("Miguel de Cervantes") - copy(topic[:], subject[:]) - name := "quotes" - - // prepare some data for the update - data := []byte("En boca cerrada no entran moscas") - hexData := hexutil.Encode(data) - - flags := []string{ - "--bzzapi", srv.URL, - "--bzzaccount", pkFileName, - "feed", "update", - "--topic", topic.Hex(), - "--name", name, - hexData} - - // create an update and expect an exit without errors - log.Info("updating a feed with 'swarm feed update'") - cmd := runSwarm(t, flags...) - cmd.ExpectExit() - - // now try to get the update using the client - client := swarm.NewClient(srv.URL) - - // build the same topic as before, this time - // we use NewTopic to create a topic automatically. - topic, err := feed.NewTopic(name, subject) - if err != nil { - t.Fatal(err) - } - - // Feed configures whose updates we will be looking up. - fd := feed.Feed{ - Topic: topic, - User: address, - } - - // Build a query to get the latest update - query := feed.NewQueryLatest(&fd, lookup.NoClue) - - // retrieve content! - reader, err := client.QueryFeed(query, "") - if err != nil { - t.Fatal(err) - } - - retrieved, err := ioutil.ReadAll(reader) - if err != nil { - t.Fatal(err) - } - - // check we retrieved the sent information - if !bytes.Equal(data, retrieved) { - t.Fatalf("Received %s, expected %s", retrieved, data) - } - - // Now retrieve info for the next update - flags = []string{ - "--bzzapi", srv.URL, - "feed", "info", - "--topic", topic.Hex(), - "--user", address.Hex(), - } - - log.Info("getting feed info with 'swarm feed info'") - cmd = runSwarm(t, flags...) - _, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout - cmd.ExpectExit() - - // verify we can deserialize the result as a valid JSON - var request feed.Request - err = json.Unmarshal([]byte(matches[0]), &request) - if err != nil { - t.Fatal(err) - } - - // make sure the retrieved feed is the same - if request.Feed != fd { - t.Fatalf("Expected feed to be: %s, got %s", fd, request.Feed) - } - - // test publishing a manifest - flags = []string{ - "--bzzapi", srv.URL, - "--bzzaccount", pkFileName, - "feed", "create", - "--topic", topic.Hex(), - } - - log.Info("Publishing manifest with 'swarm feed create'") - cmd = runSwarm(t, flags...) - _, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) - cmd.ExpectExit() - - manifestAddress := matches[0] // read the received feed manifest - - // now attempt to lookup the latest update using a manifest instead - reader, err = client.QueryFeed(nil, manifestAddress) - if err != nil { - t.Fatal(err) - } - - retrieved, err = ioutil.ReadAll(reader) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(data, retrieved) { - t.Fatalf("Received %s, expected %s", retrieved, data) - } - - // test publishing a manifest for a different user - flags = []string{ - "--bzzapi", srv.URL, - "feed", "create", - "--topic", topic.Hex(), - "--user", "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // different user - } - - log.Info("Publishing manifest with 'swarm feed create' for a different user") - cmd = runSwarm(t, flags...) - _, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) - cmd.ExpectExit() - - manifestAddress = matches[0] // read the received feed manifest - - // now let's try to update that user's manifest which we don't have the private key for - flags = []string{ - "--bzzapi", srv.URL, - "--bzzaccount", pkFileName, - "feed", "update", - "--manifest", manifestAddress, - hexData} - - // create an update and expect an error given there is a user mismatch - log.Info("updating a feed with 'swarm feed update'") - cmd = runSwarm(t, flags...) - cmd.ExpectRegexp("Fatal:.*") // best way so far to detect a failure. - cmd.ExpectExit() - if cmd.ExitStatus() == 0 { - t.Fatal("Expected nonzero exit code when updating a manifest with the wrong user. Got 0.") - } -} diff --git a/cmd/swarm/flags.go b/cmd/swarm/flags.go deleted file mode 100644 index 6093149e3c..0000000000 --- a/cmd/swarm/flags.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command feed allows the user to create and update signed Swarm feeds -package main - -import cli "gopkg.in/urfave/cli.v1" - -var ( - ChequebookAddrFlag = cli.StringFlag{ - Name: "chequebook", - Usage: "chequebook contract address", - EnvVar: SwarmEnvChequebookAddr, - } - SwarmAccountFlag = cli.StringFlag{ - Name: "bzzaccount", - Usage: "Swarm account key file", - EnvVar: SwarmEnvAccount, - } - SwarmListenAddrFlag = cli.StringFlag{ - Name: "httpaddr", - Usage: "Swarm HTTP API listening interface", - EnvVar: SwarmEnvListenAddr, - } - SwarmPortFlag = cli.StringFlag{ - Name: "bzzport", - Usage: "Swarm local http api port", - EnvVar: SwarmEnvPort, - } - SwarmNetworkIdFlag = cli.IntFlag{ - Name: "bzznetworkid", - Usage: "Network identifier (integer, default 3=swarm testnet)", - EnvVar: SwarmEnvNetworkID, - } - SwarmSwapEnabledFlag = cli.BoolFlag{ - Name: "swap", - Usage: "Swarm SWAP enabled (default false)", - EnvVar: SwarmEnvSwapEnable, - } - SwarmSwapAPIFlag = cli.StringFlag{ - Name: "swap-api", - Usage: "URL of the Ethereum API provider to use to settle SWAP payments", - EnvVar: SwarmEnvSwapAPI, - } - SwarmSyncDisabledFlag = cli.BoolTFlag{ - Name: "nosync", - Usage: "Disable swarm syncing", - EnvVar: SwarmEnvSyncDisable, - } - SwarmSyncUpdateDelay = cli.DurationFlag{ - Name: "sync-update-delay", - Usage: "Duration for sync subscriptions update after no new peers are added (default 15s)", - EnvVar: SwarmEnvSyncUpdateDelay, - } - SwarmMaxStreamPeerServersFlag = cli.IntFlag{ - Name: "max-stream-peer-servers", - Usage: "Limit of Stream peer servers, 0 denotes unlimited", - EnvVar: SwarmEnvMaxStreamPeerServers, - Value: 10000, // A very large default value is possible as stream servers have very small memory footprint - } - SwarmLightNodeEnabled = cli.BoolFlag{ - Name: "lightnode", - Usage: "Enable Swarm LightNode (default false)", - EnvVar: SwarmEnvLightNodeEnable, - } - SwarmDeliverySkipCheckFlag = cli.BoolFlag{ - Name: "delivery-skip-check", - Usage: "Skip chunk delivery check (default false)", - EnvVar: SwarmEnvDeliverySkipCheck, - } - EnsAPIFlag = cli.StringSliceFlag{ - Name: "ens-api", - Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url", - EnvVar: SwarmEnvENSAPI, - } - SwarmApiFlag = cli.StringFlag{ - Name: "bzzapi", - Usage: "Specifies the Swarm HTTP endpoint to connect to", - Value: "http://127.0.0.1:8500", - } - SwarmRecursiveFlag = cli.BoolFlag{ - Name: "recursive", - Usage: "Upload directories recursively", - } - SwarmWantManifestFlag = cli.BoolTFlag{ - Name: "manifest", - Usage: "Automatic manifest upload (default true)", - } - SwarmUploadDefaultPath = cli.StringFlag{ - Name: "defaultpath", - Usage: "path to file served for empty url path (none)", - } - SwarmAccessGrantKeyFlag = cli.StringFlag{ - Name: "grant-key", - Usage: "grants a given public key access to an ACT", - } - SwarmAccessGrantKeysFlag = cli.StringFlag{ - Name: "grant-keys", - Usage: "grants a given list of public keys in the following file (separated by line breaks) access to an ACT", - } - SwarmUpFromStdinFlag = cli.BoolFlag{ - Name: "stdin", - Usage: "reads data to be uploaded from stdin", - } - SwarmUploadMimeType = cli.StringFlag{ - Name: "mime", - Usage: "Manually specify MIME type", - } - SwarmEncryptedFlag = cli.BoolFlag{ - Name: "encrypt", - Usage: "use encrypted upload", - } - SwarmAccessPasswordFlag = cli.StringFlag{ - Name: "password", - Usage: "Password", - EnvVar: SwarmAccessPassword, - } - SwarmDryRunFlag = cli.BoolFlag{ - Name: "dry-run", - Usage: "dry-run", - } - CorsStringFlag = cli.StringFlag{ - Name: "corsdomain", - Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')", - EnvVar: SwarmEnvCORS, - } - SwarmStorePath = cli.StringFlag{ - Name: "store.path", - Usage: "Path to leveldb chunk DB (default <$GETH_ENV_DIR>/swarm/bzz-<$BZZ_KEY>/chunks)", - EnvVar: SwarmEnvStorePath, - } - SwarmStoreCapacity = cli.Uint64Flag{ - Name: "store.size", - Usage: "Number of chunks (5M is roughly 20-25GB) (default 5000000)", - EnvVar: SwarmEnvStoreCapacity, - } - SwarmStoreCacheCapacity = cli.UintFlag{ - Name: "store.cache.size", - Usage: "Number of recent chunks cached in memory", - EnvVar: SwarmEnvStoreCacheCapacity, - Value: 10000, - } - SwarmCompressedFlag = cli.BoolFlag{ - Name: "compressed", - Usage: "Prints encryption keys in compressed form", - } - SwarmBootnodeModeFlag = cli.BoolFlag{ - Name: "bootnode-mode", - Usage: "Run Swarm in Bootnode mode", - } - SwarmFeedNameFlag = cli.StringFlag{ - Name: "name", - Usage: "User-defined name for the new feed, limited to 32 characters. If combined with topic, it will refer to a subtopic with this name", - } - SwarmFeedTopicFlag = cli.StringFlag{ - Name: "topic", - Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters", - } - SwarmFeedManifestFlag = cli.StringFlag{ - Name: "manifest", - Usage: "Refers to the feed through a manifest", - } - SwarmFeedUserFlag = cli.StringFlag{ - Name: "user", - Usage: "Indicates the user who updates the feed", - } - SwarmGlobalStoreAPIFlag = cli.StringFlag{ - Name: "globalstore-api", - Usage: "URL of the Global Store API provider (only for testing)", - EnvVar: SwarmGlobalstoreAPI, - } - SwarmLegacyFlag = cli.BoolFlag{ - Name: "legacy", - Usage: "Use this flag when importing a db export from a legacy local store database dump (for schemas older than 'sanctuary')", - } -) diff --git a/cmd/swarm/fs.go b/cmd/swarm/fs.go deleted file mode 100644 index 7f156523ba..0000000000 --- a/cmd/swarm/fs.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "context" - "fmt" - "path/filepath" - "strings" - "time" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/fuse" - "gopkg.in/urfave/cli.v1" -) - -var fsCommand = cli.Command{ - Name: "fs", - CustomHelpTemplate: helpTemplate, - Usage: "perform FUSE operations", - ArgsUsage: "fs COMMAND", - Description: "Performs FUSE operations by mounting/unmounting/listing mount points. This assumes you already have a Swarm node running locally. For all operation you must reference the correct path to bzzd.ipc in order to communicate with the node", - Subcommands: []cli.Command{ - { - Action: mount, - CustomHelpTemplate: helpTemplate, - Name: "mount", - Usage: "mount a swarm hash to a mount point", - ArgsUsage: "swarm fs mount ", - Description: "Mounts a Swarm manifest hash to a given mount point. This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", - }, - { - Action: unmount, - CustomHelpTemplate: helpTemplate, - Name: "unmount", - Usage: "unmount a swarmfs mount", - ArgsUsage: "swarm fs unmount ", - Description: "Unmounts a swarmfs mount residing at . This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", - }, - { - Action: listMounts, - CustomHelpTemplate: helpTemplate, - Name: "list", - Usage: "list swarmfs mounts", - ArgsUsage: "swarm fs list", - Description: "Lists all mounted swarmfs volumes. This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", - }, - }, -} - -func mount(cliContext *cli.Context) { - args := cliContext.Args() - if len(args) < 2 { - utils.Fatalf("Usage: swarm fs mount ") - } - - client, err := dialRPC(cliContext) - if err != nil { - utils.Fatalf("had an error dailing to RPC endpoint: %v", err) - } - defer client.Close() - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - mf := &fuse.MountInfo{} - mountPoint, err := filepath.Abs(filepath.Clean(args[1])) - if err != nil { - utils.Fatalf("error expanding path for mount point: %v", err) - } - err = client.CallContext(ctx, mf, "swarmfs_mount", args[0], mountPoint) - if err != nil { - utils.Fatalf("had an error calling the RPC endpoint while mounting: %v", err) - } -} - -func unmount(cliContext *cli.Context) { - args := cliContext.Args() - - if len(args) < 1 { - utils.Fatalf("Usage: swarm fs unmount ") - } - client, err := dialRPC(cliContext) - if err != nil { - utils.Fatalf("had an error dailing to RPC endpoint: %v", err) - } - defer client.Close() - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - mf := fuse.MountInfo{} - err = client.CallContext(ctx, &mf, "swarmfs_unmount", args[0]) - if err != nil { - utils.Fatalf("encountered an error calling the RPC endpoint while unmounting: %v", err) - } - fmt.Printf("%s\n", mf.LatestManifest) //print the latest manifest hash for user reference -} - -func listMounts(cliContext *cli.Context) { - client, err := dialRPC(cliContext) - if err != nil { - utils.Fatalf("had an error dailing to RPC endpoint: %v", err) - } - defer client.Close() - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - var mf []fuse.MountInfo - err = client.CallContext(ctx, &mf, "swarmfs_listmounts") - if err != nil { - utils.Fatalf("encountered an error calling the RPC endpoint while listing mounts: %v", err) - } - if len(mf) == 0 { - fmt.Print("Could not found any swarmfs mounts. Please make sure you've specified the correct RPC endpoint\n") - } else { - fmt.Printf("Found %d swarmfs mount(s):\n", len(mf)) - for i, mountInfo := range mf { - fmt.Printf("%d:\n", i) - fmt.Printf("\tMount point: %s\n", mountInfo.MountPoint) - fmt.Printf("\tLatest Manifest: %s\n", mountInfo.LatestManifest) - fmt.Printf("\tStart Manifest: %s\n", mountInfo.StartManifest) - } - } -} - -func dialRPC(ctx *cli.Context) (*rpc.Client, error) { - endpoint := getIPCEndpoint(ctx) - log.Info("IPC endpoint", "path", endpoint) - return rpc.Dial(endpoint) -} - -func getIPCEndpoint(ctx *cli.Context) string { - cfg := defaultNodeConfig - utils.SetNodeConfig(ctx, &cfg) - - endpoint := cfg.IPCEndpoint() - - if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { - // Backwards compatibility with geth < 1.5 which required - // these prefixes. - endpoint = endpoint[4:] - } - return endpoint -} diff --git a/cmd/swarm/fs_test.go b/cmd/swarm/fs_test.go deleted file mode 100644 index 5f58d6c0d8..0000000000 --- a/cmd/swarm/fs_test.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// +build linux freebsd - -package main - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/log" -) - -type testFile struct { - filePath string - content string -} - -// TestCLISwarmFsDefaultIPCPath tests if the most basic fs command, i.e., list -// can find and correctly connect to a running Swarm node on the default -// IPCPath. -func TestCLISwarmFsDefaultIPCPath(t *testing.T) { - cluster := newTestCluster(t, 1) - defer cluster.Shutdown() - - handlingNode := cluster.Nodes[0] - list := runSwarm(t, []string{ - "--datadir", handlingNode.Dir, - "fs", - "list", - }...) - - list.WaitExit() - if list.Err != nil { - t.Fatal(list.Err) - } -} - -// TestCLISwarmFs is a high-level test of swarmfs -// -// This test fails on travis for macOS as this executable exits with code 1 -// and without any log messages in the log: -// /Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse. -// This is the reason for this file not being built on darwin architecture. -func TestCLISwarmFs(t *testing.T) { - cluster := newTestCluster(t, 3) - defer cluster.Shutdown() - - // create a tmp dir - mountPoint, err := ioutil.TempDir("", "swarm-test") - log.Debug("swarmfs cli test", "1st mount", mountPoint) - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(mountPoint) - - handlingNode := cluster.Nodes[0] - mhash := doUploadEmptyDir(t, handlingNode) - log.Debug("swarmfs cli test: mounting first run", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath)) - - mount := runSwarm(t, []string{ - fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), - "fs", - "mount", - mhash, - mountPoint, - }...) - mount.ExpectExit() - - filesToAssert := []*testFile{} - - dirPath, err := createDirInDir(mountPoint, "testSubDir") - if err != nil { - t.Fatal(err) - } - dirPath2, err := createDirInDir(dirPath, "AnotherTestSubDir") - if err != nil { - t.Fatal(err) - } - - dummyContent := "somerandomtestcontentthatshouldbeasserted" - dirs := []string{ - mountPoint, - dirPath, - dirPath2, - } - files := []string{"f1.tmp", "f2.tmp"} - for _, d := range dirs { - for _, entry := range files { - tFile, err := createTestFileInPath(d, entry, dummyContent) - if err != nil { - t.Fatal(err) - } - filesToAssert = append(filesToAssert, tFile) - } - } - if len(filesToAssert) != len(dirs)*len(files) { - t.Fatalf("should have %d files to assert now, got %d", len(dirs)*len(files), len(filesToAssert)) - } - hashRegexp := `[a-f\d]{64}` - log.Debug("swarmfs cli test: unmounting first run...", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath)) - - unmount := runSwarm(t, []string{ - fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), - "fs", - "unmount", - mountPoint, - }...) - _, matches := unmount.ExpectRegexp(hashRegexp) - unmount.ExpectExit() - - hash := matches[0] - if hash == mhash { - t.Fatal("this should not be equal") - } - log.Debug("swarmfs cli test: asserting no files in mount point") - - //check that there's nothing in the mount folder - filesInDir, err := ioutil.ReadDir(mountPoint) - if err != nil { - t.Fatalf("had an error reading the directory: %v", err) - } - - if len(filesInDir) != 0 { - t.Fatal("there shouldn't be anything here") - } - - secondMountPoint, err := ioutil.TempDir("", "swarm-test") - log.Debug("swarmfs cli test", "2nd mount point at", secondMountPoint) - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(secondMountPoint) - - log.Debug("swarmfs cli test: remounting at second mount point", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath)) - - //remount, check files - newMount := runSwarm(t, []string{ - fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), - "fs", - "mount", - hash, // the latest hash - secondMountPoint, - }...) - - newMount.ExpectExit() - time.Sleep(1 * time.Second) - - filesInDir, err = ioutil.ReadDir(secondMountPoint) - if err != nil { - t.Fatal(err) - } - - if len(filesInDir) == 0 { - t.Fatal("there should be something here") - } - - log.Debug("swarmfs cli test: traversing file tree to see it matches previous mount") - - for _, file := range filesToAssert { - file.filePath = strings.Replace(file.filePath, mountPoint, secondMountPoint, -1) - fileBytes, err := ioutil.ReadFile(file.filePath) - - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(fileBytes, bytes.NewBufferString(file.content).Bytes()) { - t.Fatal("this should be equal") - } - } - - log.Debug("swarmfs cli test: unmounting second run", "ipc path", filepath.Join(handlingNode.Dir, handlingNode.IpcPath)) - - unmountSec := runSwarm(t, []string{ - fmt.Sprintf("--%s", utils.IPCPathFlag.Name), filepath.Join(handlingNode.Dir, handlingNode.IpcPath), - "fs", - "unmount", - secondMountPoint, - }...) - - _, matches = unmountSec.ExpectRegexp(hashRegexp) - unmountSec.ExpectExit() - - if matches[0] != hash { - t.Fatal("these should be equal - no changes made") - } -} - -func doUploadEmptyDir(t *testing.T, node *testNode) string { - // create a tmp dir - tmpDir, err := ioutil.TempDir("", "swarm-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - hashRegexp := `[a-f\d]{64}` - - flags := []string{ - "--bzzapi", node.URL, - "--recursive", - "up", - tmpDir} - - log.Info("swarmfs cli test: uploading dir with 'swarm up'") - up := runSwarm(t, flags...) - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - hash := matches[0] - log.Info("swarmfs cli test: dir uploaded", "hash", hash) - return hash -} - -func createDirInDir(createInDir string, dirToCreate string) (string, error) { - fullpath := filepath.Join(createInDir, dirToCreate) - err := os.MkdirAll(fullpath, 0777) - if err != nil { - return "", err - } - return fullpath, nil -} - -func createTestFileInPath(dir, filename, content string) (*testFile, error) { - tFile := &testFile{} - filePath := filepath.Join(dir, filename) - if file, err := os.Create(filePath); err == nil { - tFile.content = content - tFile.filePath = filePath - - _, err = io.WriteString(file, content) - if err != nil { - return nil, err - } - file.Close() - } - - return tFile, nil -} diff --git a/cmd/swarm/global-store/explorer.go b/cmd/swarm/global-store/explorer.go deleted file mode 100644 index 634ff1ebb6..0000000000 --- a/cmd/swarm/global-store/explorer.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "context" - "fmt" - "net" - "net/http" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - "github.com/ethereum/go-ethereum/swarm/storage/mock/explorer" - cli "gopkg.in/urfave/cli.v1" -) - -// serveChunkExplorer starts an http server in background with chunk explorer handler -// using the provided global store. Server is started if the returned shutdown function -// is not nil. -func serveChunkExplorer(ctx *cli.Context, globalStore mock.GlobalStorer) (shutdown func(), err error) { - if !ctx.IsSet("explorer-address") { - return nil, nil - } - - corsOrigins := ctx.StringSlice("explorer-cors-origin") - server := &http.Server{ - Handler: explorer.NewHandler(globalStore, corsOrigins), - IdleTimeout: 30 * time.Minute, - ReadTimeout: 2 * time.Minute, - WriteTimeout: 2 * time.Minute, - } - listener, err := net.Listen("tcp", ctx.String("explorer-address")) - if err != nil { - return nil, fmt.Errorf("explorer: %v", err) - } - log.Info("chunk explorer http", "address", listener.Addr().String(), "origins", corsOrigins) - - go func() { - if err := server.Serve(listener); err != nil { - log.Error("chunk explorer", "err", err) - } - }() - - return func() { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - if err := server.Shutdown(ctx); err != nil { - log.Error("chunk explorer: shutdown", "err", err) - } - }, nil -} diff --git a/cmd/swarm/global-store/explorer_test.go b/cmd/swarm/global-store/explorer_test.go deleted file mode 100644 index 2e4928c8fc..0000000000 --- a/cmd/swarm/global-store/explorer_test.go +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - "net/http" - "sort" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage/mock/explorer" - mockRPC "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" -) - -// TestExplorer validates basic chunk explorer functionality by storing -// a small set of chunk and making http requests on exposed endpoint. -// Full chunk explorer validation is done in mock/explorer package. -func TestExplorer(t *testing.T) { - addr := findFreeTCPAddress(t) - explorerAddr := findFreeTCPAddress(t) - testCmd := runGlobalStore(t, "ws", "--addr", addr, "--explorer-address", explorerAddr) - defer testCmd.Kill() - - client := websocketClient(t, addr) - - store := mockRPC.NewGlobalStore(client) - defer store.Close() - - nodeKeys := map[string][]string{ - "a1": {"b1", "b2", "b3"}, - "a2": {"b3", "b4", "b5"}, - } - - keyNodes := make(map[string][]string) - - for addr, keys := range nodeKeys { - for _, key := range keys { - keyNodes[key] = append(keyNodes[key], addr) - } - } - - invalidAddr := "c1" - invalidKey := "d1" - - for addr, keys := range nodeKeys { - for _, key := range keys { - err := store.Put(common.HexToAddress(addr), common.Hex2Bytes(key), []byte("data")) - if err != nil { - t.Fatal(err) - } - } - } - - endpoint := "http://" + explorerAddr - - t.Run("has key", func(t *testing.T) { - for addr, keys := range nodeKeys { - for _, key := range keys { - testStatusResponse(t, endpoint+"/api/has-key/"+addr+"/"+key, http.StatusOK) - testStatusResponse(t, endpoint+"/api/has-key/"+invalidAddr+"/"+key, http.StatusNotFound) - } - testStatusResponse(t, endpoint+"/api/has-key/"+addr+"/"+invalidKey, http.StatusNotFound) - } - testStatusResponse(t, endpoint+"/api/has-key/"+invalidAddr+"/"+invalidKey, http.StatusNotFound) - }) - - t.Run("keys", func(t *testing.T) { - var keys []string - for key := range keyNodes { - keys = append(keys, key) - } - sort.Strings(keys) - testKeysResponse(t, endpoint+"/api/keys", explorer.KeysResponse{ - Keys: keys, - }) - }) - - t.Run("nodes", func(t *testing.T) { - var nodes []string - for addr := range nodeKeys { - nodes = append(nodes, common.HexToAddress(addr).Hex()) - } - sort.Strings(nodes) - testNodesResponse(t, endpoint+"/api/nodes", explorer.NodesResponse{ - Nodes: nodes, - }) - }) - - t.Run("node keys", func(t *testing.T) { - for addr, keys := range nodeKeys { - testKeysResponse(t, endpoint+"/api/keys?node="+addr, explorer.KeysResponse{ - Keys: keys, - }) - } - testKeysResponse(t, endpoint+"/api/keys?node="+invalidAddr, explorer.KeysResponse{}) - }) - - t.Run("key nodes", func(t *testing.T) { - for key, addrs := range keyNodes { - var nodes []string - for _, addr := range addrs { - nodes = append(nodes, common.HexToAddress(addr).Hex()) - } - sort.Strings(nodes) - testNodesResponse(t, endpoint+"/api/nodes?key="+key, explorer.NodesResponse{ - Nodes: nodes, - }) - } - testNodesResponse(t, endpoint+"/api/nodes?key="+invalidKey, explorer.NodesResponse{}) - }) -} - -// TestExplorer_CORSOrigin validates if chunk explorer returns -// correct CORS origin header in GET and OPTIONS requests. -func TestExplorer_CORSOrigin(t *testing.T) { - origin := "http://localhost/" - addr := findFreeTCPAddress(t) - explorerAddr := findFreeTCPAddress(t) - testCmd := runGlobalStore(t, "ws", - "--addr", addr, - "--explorer-address", explorerAddr, - "--explorer-cors-origin", origin, - ) - defer testCmd.Kill() - - // wait until the server is started - waitHTTPEndpoint(t, explorerAddr) - - url := "http://" + explorerAddr + "/api/keys" - - t.Run("get", func(t *testing.T) { - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - t.Fatal(err) - } - req.Header.Set("Origin", origin) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - header := resp.Header.Get("Access-Control-Allow-Origin") - if header != origin { - t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, origin) - } - }) - - t.Run("preflight", func(t *testing.T) { - req, err := http.NewRequest(http.MethodOptions, url, nil) - if err != nil { - t.Fatal(err) - } - req.Header.Set("Origin", origin) - req.Header.Set("Access-Control-Request-Method", "GET") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - header := resp.Header.Get("Access-Control-Allow-Origin") - if header != origin { - t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, origin) - } - }) -} - -// testStatusResponse makes an http request to provided url -// and validates if response is explorer.StatusResponse for -// the expected status code. -func testStatusResponse(t *testing.T, url string, code int) { - t.Helper() - - resp, err := http.Get(url) - if err != nil { - t.Fatal(err) - } - if resp.StatusCode != code { - t.Errorf("got status code %v, want %v", resp.StatusCode, code) - } - var r explorer.StatusResponse - if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { - t.Fatal(err) - } - if r.Code != code { - t.Errorf("got response code %v, want %v", r.Code, code) - } - if r.Message != http.StatusText(code) { - t.Errorf("got response message %q, want %q", r.Message, http.StatusText(code)) - } -} - -// testKeysResponse makes an http request to provided url -// and validates if response machhes expected explorer.KeysResponse. -func testKeysResponse(t *testing.T, url string, want explorer.KeysResponse) { - t.Helper() - - resp, err := http.Get(url) - if err != nil { - t.Fatal(err) - } - if resp.StatusCode != http.StatusOK { - t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) - } - var r explorer.KeysResponse - if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { - t.Fatal(err) - } - if fmt.Sprint(r.Keys) != fmt.Sprint(want.Keys) { - t.Errorf("got keys %v, want %v", r.Keys, want.Keys) - } - if r.Next != want.Next { - t.Errorf("got next %s, want %s", r.Next, want.Next) - } -} - -// testNodeResponse makes an http request to provided url -// and validates if response machhes expected explorer.NodeResponse. -func testNodesResponse(t *testing.T, url string, want explorer.NodesResponse) { - t.Helper() - - resp, err := http.Get(url) - if err != nil { - t.Fatal(err) - } - if resp.StatusCode != http.StatusOK { - t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) - } - var r explorer.NodesResponse - if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { - t.Fatal(err) - } - if fmt.Sprint(r.Nodes) != fmt.Sprint(want.Nodes) { - t.Errorf("got nodes %v, want %v", r.Nodes, want.Nodes) - } - if r.Next != want.Next { - t.Errorf("got next %s, want %s", r.Next, want.Next) - } -} diff --git a/cmd/swarm/global-store/global_store.go b/cmd/swarm/global-store/global_store.go deleted file mode 100644 index f93b464dbc..0000000000 --- a/cmd/swarm/global-store/global_store.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "io" - "net" - "net/http" - "os" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - "github.com/ethereum/go-ethereum/swarm/storage/mock/db" - "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" - cli "gopkg.in/urfave/cli.v1" -) - -// startHTTP starts a global store with HTTP RPC server. -// It is used for "http" cli command. -func startHTTP(ctx *cli.Context) (err error) { - server, cleanup, err := newServer(ctx) - if err != nil { - return err - } - defer cleanup() - - listener, err := net.Listen("tcp", ctx.String("addr")) - if err != nil { - return err - } - log.Info("http", "address", listener.Addr().String()) - - return http.Serve(listener, server) -} - -// startWS starts a global store with WebSocket RPC server. -// It is used for "websocket" cli command. -func startWS(ctx *cli.Context) (err error) { - server, cleanup, err := newServer(ctx) - if err != nil { - return err - } - defer cleanup() - - listener, err := net.Listen("tcp", ctx.String("addr")) - if err != nil { - return err - } - origins := ctx.StringSlice("origins") - log.Info("websocket", "address", listener.Addr().String(), "origins", origins) - - return http.Serve(listener, server.WebsocketHandler(origins)) -} - -// newServer creates a global store and starts a chunk explorer server if configured. -// Returned cleanup function should be called only if err is nil. -func newServer(ctx *cli.Context) (server *rpc.Server, cleanup func(), err error) { - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(false)))) - - cleanup = func() {} - var globalStore mock.GlobalStorer - dir := ctx.String("dir") - if dir != "" { - dbStore, err := db.NewGlobalStore(dir) - if err != nil { - return nil, nil, err - } - cleanup = func() { - if err := dbStore.Close(); err != nil { - log.Error("global store: close", "err", err) - } - } - globalStore = dbStore - log.Info("database global store", "dir", dir) - } else { - globalStore = mem.NewGlobalStore() - log.Info("in-memory global store") - } - - server = rpc.NewServer() - if err := server.RegisterName("mockStore", globalStore); err != nil { - cleanup() - return nil, nil, err - } - - shutdown, err := serveChunkExplorer(ctx, globalStore) - if err != nil { - cleanup() - return nil, nil, err - } - if shutdown != nil { - cleanup = func() { - shutdown() - - if c, ok := globalStore.(io.Closer); ok { - if err := c.Close(); err != nil { - log.Error("global store: close", "err", err) - } - } - } - } - - return server, cleanup, nil -} diff --git a/cmd/swarm/global-store/global_store_test.go b/cmd/swarm/global-store/global_store_test.go deleted file mode 100644 index c437c9d453..0000000000 --- a/cmd/swarm/global-store/global_store_test.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "context" - "io/ioutil" - "net" - "net/http" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rpc" - mockRPC "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" -) - -// TestHTTP_InMemory tests in-memory global store that exposes -// HTTP server. -func TestHTTP_InMemory(t *testing.T) { - testHTTP(t, true) -} - -// TestHTTP_Database tests global store with persisted database -// that exposes HTTP server. -func TestHTTP_Database(t *testing.T) { - dir, err := ioutil.TempDir("", "swarm-global-store-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - // create a fresh global store - testHTTP(t, true, "--dir", dir) - - // check if data saved by the previous global store instance - testHTTP(t, false, "--dir", dir) -} - -// testWebsocket starts global store binary with HTTP server -// and validates that it can store and retrieve data. -// If put is false, no data will be stored, only retrieved, -// giving the possibility to check if data is present in the -// storage directory. -func testHTTP(t *testing.T, put bool, args ...string) { - addr := findFreeTCPAddress(t) - testCmd := runGlobalStore(t, append([]string{"http", "--addr", addr}, args...)...) - defer testCmd.Kill() - - client, err := rpc.DialHTTP("http://" + addr) - if err != nil { - t.Fatal(err) - } - - // wait until global store process is started as - // rpc.DialHTTP is actually not connecting - waitHTTPEndpoint(t, addr) - - store := mockRPC.NewGlobalStore(client) - defer store.Close() - - node := store.NewNodeStore(common.HexToAddress("123abc")) - - wantKey := "key" - wantValue := "value" - - if put { - err = node.Put([]byte(wantKey), []byte(wantValue)) - if err != nil { - t.Fatal(err) - } - } - - gotValue, err := node.Get([]byte(wantKey)) - if err != nil { - t.Fatal(err) - } - - if string(gotValue) != wantValue { - t.Errorf("got value %s for key %s, want %s", string(gotValue), wantKey, wantValue) - } -} - -// TestWebsocket_InMemory tests in-memory global store that exposes -// WebSocket server. -func TestWebsocket_InMemory(t *testing.T) { - testWebsocket(t, true) -} - -// TestWebsocket_Database tests global store with persisted database -// that exposes HTTP server. -func TestWebsocket_Database(t *testing.T) { - dir, err := ioutil.TempDir("", "swarm-global-store-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - // create a fresh global store - testWebsocket(t, true, "--dir", dir) - - // check if data saved by the previous global store instance - testWebsocket(t, false, "--dir", dir) -} - -// testWebsocket starts global store binary with WebSocket server -// and validates that it can store and retrieve data. -// If put is false, no data will be stored, only retrieved, -// giving the possibility to check if data is present in the -// storage directory. -func testWebsocket(t *testing.T, put bool, args ...string) { - addr := findFreeTCPAddress(t) - testCmd := runGlobalStore(t, append([]string{"ws", "--addr", addr}, args...)...) - defer testCmd.Kill() - - client := websocketClient(t, addr) - - store := mockRPC.NewGlobalStore(client) - defer store.Close() - - node := store.NewNodeStore(common.HexToAddress("123abc")) - - wantKey := "key" - wantValue := "value" - - if put { - err := node.Put([]byte(wantKey), []byte(wantValue)) - if err != nil { - t.Fatal(err) - } - } - - gotValue, err := node.Get([]byte(wantKey)) - if err != nil { - t.Fatal(err) - } - - if string(gotValue) != wantValue { - t.Errorf("got value %s for key %s, want %s", string(gotValue), wantKey, wantValue) - } -} - -// findFreeTCPAddress returns a local address (IP:Port) to which -// global store can listen on. -func findFreeTCPAddress(t *testing.T) (addr string) { - t.Helper() - - listener, err := net.Listen("tcp", "") - if err != nil { - t.Fatal(err) - } - defer listener.Close() - - return listener.Addr().String() -} - -// websocketClient waits until global store process is started -// and returns rpc client. -func websocketClient(t *testing.T, addr string) (client *rpc.Client) { - t.Helper() - - var err error - for i := 0; i < 1000; i++ { - client, err = rpc.DialWebsocket(context.Background(), "ws://"+addr, "") - if err == nil { - break - } - time.Sleep(10 * time.Millisecond) - } - if err != nil { - t.Fatal(err) - } - return client -} - -// waitHTTPEndpoint retries http requests to a provided -// address until the connection is established. -func waitHTTPEndpoint(t *testing.T, addr string) { - t.Helper() - - var err error - for i := 0; i < 1000; i++ { - _, err = http.Get("http://" + addr) - if err == nil { - break - } - time.Sleep(10 * time.Millisecond) - } - if err != nil { - t.Fatal(err) - } -} diff --git a/cmd/swarm/global-store/main.go b/cmd/swarm/global-store/main.go deleted file mode 100644 index 58505f9886..0000000000 --- a/cmd/swarm/global-store/main.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "os" - - "github.com/ethereum/go-ethereum/log" - cli "gopkg.in/urfave/cli.v1" -) - -var ( - version = "0.1" - gitCommit string // Git SHA1 commit hash of the release (set via linker flags) - gitDate string -) - -func main() { - err := newApp().Run(os.Args) - if err != nil { - log.Error(err.Error()) - os.Exit(1) - } -} - -// newApp construct a new instance of Swarm Global Store. -// Method Run is called on it in the main function and in tests. -func newApp() (app *cli.App) { - app = cli.NewApp() - app.Name = "global-store" - app.Version = version - if len(gitCommit) >= 8 { - app.Version += "-" + gitCommit[:8] - } - if gitDate != "" { - app.Version += "-" + gitDate - } - app.Usage = "Swarm Global Store" - - // app flags (for all commands) - app.Flags = []cli.Flag{ - cli.IntFlag{ - Name: "verbosity", - Value: 3, - Usage: "Verbosity level.", - }, - cli.StringFlag{ - Name: "explorer-address", - Value: "", - Usage: "Chunk explorer HTTP listener address.", - }, - cli.StringSliceFlag{ - Name: "explorer-cors-origin", - Value: nil, - Usage: "Chunk explorer CORS origin (can be specified multiple times).", - }, - } - - app.Commands = []cli.Command{ - { - Name: "http", - Aliases: []string{"h"}, - Usage: "Start swarm global store with HTTP server.", - Action: startHTTP, - // Flags only for "start" command. - // Allow app flags to be specified after the - // command argument. - Flags: append(app.Flags, - cli.StringFlag{ - Name: "dir", - Value: "", - Usage: "Data directory.", - }, - cli.StringFlag{ - Name: "addr", - Value: "0.0.0.0:3033", - Usage: "Address to listen for HTTP connections.", - }, - ), - }, - { - Name: "websocket", - Aliases: []string{"ws"}, - Usage: "Start swarm global store with WebSocket server.", - Action: startWS, - // Flags only for "start" command. - // Allow app flags to be specified after the - // command argument. - Flags: append(app.Flags, - cli.StringFlag{ - Name: "dir", - Value: "", - Usage: "Data directory.", - }, - cli.StringFlag{ - Name: "addr", - Value: "0.0.0.0:3033", - Usage: "Address to listen for WebSocket connections.", - }, - cli.StringSliceFlag{ - Name: "origin", - Value: nil, - Usage: "WebSocket CORS origin (can be specified multiple times).", - }, - ), - }, - } - - return app -} diff --git a/cmd/swarm/global-store/run_test.go b/cmd/swarm/global-store/run_test.go deleted file mode 100644 index d7ef626e55..0000000000 --- a/cmd/swarm/global-store/run_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "os" - "testing" - - "github.com/docker/docker/pkg/reexec" - "github.com/ethereum/go-ethereum/internal/cmdtest" -) - -func init() { - reexec.Register("swarm-global-store", func() { - if err := newApp().Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - os.Exit(0) - }) -} - -func runGlobalStore(t *testing.T, args ...string) *cmdtest.TestCmd { - tt := cmdtest.NewTestCmd(t, nil) - tt.Run("swarm-global-store", args...) - return tt -} - -func TestMain(m *testing.M) { - if reexec.Init() { - return - } - os.Exit(m.Run()) -} diff --git a/cmd/swarm/hash.go b/cmd/swarm/hash.go deleted file mode 100644 index ff786fa105..0000000000 --- a/cmd/swarm/hash.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command bzzhash computes a swarm tree hash. -package main - -import ( - "context" - "encoding/hex" - "fmt" - "os" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/ens" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" - "gopkg.in/urfave/cli.v1" -) - -var hashCommand = cli.Command{ - Action: hash, - CustomHelpTemplate: helpTemplate, - Name: "hash", - Usage: "print the swarm hash of a file or directory", - ArgsUsage: "", - Description: "Prints the swarm hash of file or directory", - Subcommands: []cli.Command{ - { - CustomHelpTemplate: helpTemplate, - Name: "ens", - Usage: "converts a swarm hash to an ens EIP1577 compatible CIDv1 hash", - ArgsUsage: "", - Description: "", - Subcommands: []cli.Command{ - { - Action: encodeEipHash, - CustomHelpTemplate: helpTemplate, - Name: "contenthash", - Usage: "converts a swarm hash to an ens EIP1577 compatible CIDv1 hash", - ArgsUsage: "", - Description: "", - }, - { - Action: ensNodeHash, - CustomHelpTemplate: helpTemplate, - Name: "node", - Usage: "converts an ens name to an ENS node hash", - ArgsUsage: "", - Description: "", - }, - }, - }, - }} - -func hash(ctx *cli.Context) { - args := ctx.Args() - if len(args) < 1 { - utils.Fatalf("Usage: swarm hash ") - } - f, err := os.Open(args[0]) - if err != nil { - utils.Fatalf("Error opening file " + args[1]) - } - defer f.Close() - - stat, _ := f.Stat() - fileStore := storage.NewFileStore(&storage.FakeChunkStore{}, storage.NewFileStoreParams(), chunk.NewTags()) - addr, _, err := fileStore.Store(context.TODO(), f, stat.Size(), false) - if err != nil { - utils.Fatalf("%v\n", err) - } else { - fmt.Printf("%v\n", addr) - } -} -func ensNodeHash(ctx *cli.Context) { - args := ctx.Args() - if len(args) < 1 { - utils.Fatalf("Usage: swarm hash ens node ") - } - ensName := args[0] - - hash := ens.EnsNode(ensName) - - stringHex := hex.EncodeToString(hash[:]) - fmt.Println(stringHex) -} -func encodeEipHash(ctx *cli.Context) { - args := ctx.Args() - if len(args) < 1 { - utils.Fatalf("Usage: swarm hash ens ") - } - swarmHash := args[0] - - hash := common.HexToHash(swarmHash) - ensHash, err := ens.EncodeSwarmHash(hash) - if err != nil { - utils.Fatalf("error converting swarm hash", err) - } - - stringHex := hex.EncodeToString(ensHash) - fmt.Println(stringHex) -} diff --git a/cmd/swarm/list.go b/cmd/swarm/list.go deleted file mode 100644 index 5d35154a57..0000000000 --- a/cmd/swarm/list.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "os" - "strings" - "text/tabwriter" - - "github.com/ethereum/go-ethereum/cmd/utils" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - "gopkg.in/urfave/cli.v1" -) - -var listCommand = cli.Command{ - Action: list, - CustomHelpTemplate: helpTemplate, - Name: "ls", - Usage: "list files and directories contained in a manifest", - ArgsUsage: " []", - Description: "Lists files and directories contained in a manifest", -} - -func list(ctx *cli.Context) { - args := ctx.Args() - - if len(args) < 1 { - utils.Fatalf("Please supply a manifest reference as the first argument") - } else if len(args) > 2 { - utils.Fatalf("Too many arguments - usage 'swarm ls manifest [prefix]'") - } - manifest := args[0] - - var prefix string - if len(args) == 2 { - prefix = args[1] - } - - bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client := swarm.NewClient(bzzapi) - list, err := client.List(manifest, prefix, "") - if err != nil { - utils.Fatalf("Failed to generate file and directory list: %s", err) - } - - w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintln(w, "HASH\tCONTENT TYPE\tPATH") - for _, prefix := range list.CommonPrefixes { - fmt.Fprintf(w, "%s\t%s\t%s\n", "", "DIR", prefix) - } - for _, entry := range list.Entries { - fmt.Fprintf(w, "%s\t%s\t%s\n", entry.Hash, entry.ContentType, entry.Path) - } -} diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go deleted file mode 100644 index f4c1dd688c..0000000000 --- a/cmd/swarm/main.go +++ /dev/null @@ -1,475 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "crypto/ecdsa" - "encoding/hex" - "fmt" - "io/ioutil" - "os" - "os/signal" - "runtime" - "sort" - "strconv" - "strings" - "syscall" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/console" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/debug" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm" - bzzapi "github.com/ethereum/go-ethereum/swarm/api" - swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - mockrpc "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" - "github.com/ethereum/go-ethereum/swarm/tracing" - sv "github.com/ethereum/go-ethereum/swarm/version" - - cli "gopkg.in/urfave/cli.v1" -) - -const clientIdentifier = "swarm" -const helpTemplate = `NAME: -{{.HelpName}} - {{.Usage}} - -USAGE: -{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} - -CATEGORY: -{{.Category}}{{end}}{{if .Description}} - -DESCRIPTION: -{{.Description}}{{end}}{{if .VisibleFlags}} - -OPTIONS: -{{range .VisibleFlags}}{{.}} -{{end}}{{end}} -` - -// Git SHA1 commit hash of the release (set via linker flags) -// this variable will be assigned if corresponding parameter is passed with install, but not with test -// e.g.: go install -ldflags "-X main.gitCommit=ed1312d01b19e04ef578946226e5d8069d5dfd5a" ./cmd/swarm -var gitCommit string - -//declare a few constant error messages, useful for later error check comparisons in test -var ( - SwarmErrNoBZZAccount = "bzzaccount option is required but not set; check your config file, command line or environment variables" - SwarmErrSwapSetNoAPI = "SWAP is enabled but --swap-api is not set" -) - -// this help command gets added to any subcommand that does not define it explicitly -var defaultSubcommandHelp = cli.Command{ - Action: func(ctx *cli.Context) { cli.ShowCommandHelpAndExit(ctx, "", 1) }, - CustomHelpTemplate: helpTemplate, - Name: "help", - Usage: "shows this help", - Hidden: true, -} - -var defaultNodeConfig = node.DefaultConfig - -// This init function sets defaults so cmd/swarm can run alongside geth. -func init() { - sv.GitCommit = gitCommit - defaultNodeConfig.Name = clientIdentifier - defaultNodeConfig.Version = sv.VersionWithCommit(gitCommit) - defaultNodeConfig.P2P.ListenAddr = ":30399" - defaultNodeConfig.IPCPath = "bzzd.ipc" - // Set flag defaults for --help display. - utils.ListenPortFlag.Value = 30399 -} - -var app = utils.NewApp("", "", "Ethereum Swarm") - -// This init function creates the cli.App. -func init() { - app.Action = bzzd - app.Version = sv.ArchiveVersion(gitCommit) - app.Copyright = "Copyright 2013-2016 The go-ethereum Authors" - app.Commands = []cli.Command{ - { - Action: version, - CustomHelpTemplate: helpTemplate, - Name: "version", - Usage: "Print version numbers", - Description: "The output of this command is supposed to be machine-readable", - }, - { - Action: keys, - CustomHelpTemplate: helpTemplate, - Name: "print-keys", - Flags: []cli.Flag{SwarmCompressedFlag}, - Usage: "Print public key information", - Description: "The output of this command is supposed to be machine-readable", - }, - // See upload.go - upCommand, - // See access.go - accessCommand, - // See feeds.go - feedCommand, - // See list.go - listCommand, - // See hash.go - hashCommand, - // See download.go - downloadCommand, - // See manifest.go - manifestCommand, - // See fs.go - fsCommand, - // See db.go - dbCommand, - // See config.go - DumpConfigCommand, - // hashesCommand - hashesCommand, - } - - // append a hidden help subcommand to all commands that have subcommands - // if a help command was already defined above, that one will take precedence. - addDefaultHelpSubcommands(app.Commands) - - sort.Sort(cli.CommandsByName(app.Commands)) - - app.Flags = []cli.Flag{ - utils.IdentityFlag, - utils.DataDirFlag, - utils.BootnodesFlag, - utils.KeyStoreDirFlag, - utils.ListenPortFlag, - utils.DiscoveryV5Flag, - utils.NetrestrictFlag, - utils.NodeKeyFileFlag, - utils.NodeKeyHexFlag, - utils.MaxPeersFlag, - utils.NATFlag, - utils.IPCDisabledFlag, - utils.IPCPathFlag, - utils.PasswordFileFlag, - // bzzd-specific flags - CorsStringFlag, - EnsAPIFlag, - SwarmTomlConfigPathFlag, - SwarmSwapEnabledFlag, - SwarmSwapAPIFlag, - SwarmSyncDisabledFlag, - SwarmSyncUpdateDelay, - SwarmMaxStreamPeerServersFlag, - SwarmLightNodeEnabled, - SwarmDeliverySkipCheckFlag, - SwarmListenAddrFlag, - SwarmPortFlag, - SwarmAccountFlag, - SwarmNetworkIdFlag, - ChequebookAddrFlag, - // upload flags - SwarmApiFlag, - SwarmRecursiveFlag, - SwarmWantManifestFlag, - SwarmUploadDefaultPath, - SwarmUpFromStdinFlag, - SwarmUploadMimeType, - // bootnode mode - SwarmBootnodeModeFlag, - // storage flags - SwarmStorePath, - SwarmStoreCapacity, - SwarmStoreCacheCapacity, - SwarmGlobalStoreAPIFlag, - } - rpcFlags := []cli.Flag{ - utils.WSEnabledFlag, - utils.WSListenAddrFlag, - utils.WSPortFlag, - utils.WSApiFlag, - utils.WSAllowedOriginsFlag, - } - app.Flags = append(app.Flags, rpcFlags...) - app.Flags = append(app.Flags, debug.Flags...) - app.Flags = append(app.Flags, swarmmetrics.Flags...) - app.Flags = append(app.Flags, tracing.Flags...) - app.Before = func(ctx *cli.Context) error { - runtime.GOMAXPROCS(runtime.NumCPU()) - if err := debug.Setup(ctx, ""); err != nil { - return err - } - swarmmetrics.Setup(ctx) - tracing.Setup(ctx) - return nil - } - app.After = func(ctx *cli.Context) error { - debug.Exit() - return nil - } -} - -func main() { - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func keys(ctx *cli.Context) error { - privateKey := getPrivKey(ctx) - pubkey := crypto.FromECDSAPub(&privateKey.PublicKey) - pubkeyhex := hex.EncodeToString(pubkey) - pubCompressed := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)) - bzzkey := crypto.Keccak256Hash(pubkey).Hex() - - if !ctx.Bool(SwarmCompressedFlag.Name) { - fmt.Println(fmt.Sprintf("bzzkey=%s", bzzkey[2:])) - fmt.Println(fmt.Sprintf("publicKey=%s", pubkeyhex)) - } - fmt.Println(fmt.Sprintf("publicKeyCompressed=%s", pubCompressed)) - - return nil -} - -func version(ctx *cli.Context) error { - fmt.Println(strings.Title(clientIdentifier)) - fmt.Println("Version:", sv.VersionWithMeta) - if gitCommit != "" { - fmt.Println("Git Commit:", gitCommit) - } - fmt.Println("Go Version:", runtime.Version()) - fmt.Println("OS:", runtime.GOOS) - return nil -} - -func bzzd(ctx *cli.Context) error { - //build a valid bzzapi.Config from all available sources: - //default config, file config, command line and env vars - - bzzconfig, err := buildConfig(ctx) - if err != nil { - utils.Fatalf("unable to configure swarm: %v", err) - } - - cfg := defaultNodeConfig - - //pss operates on ws - cfg.WSModules = append(cfg.WSModules, "pss") - - //geth only supports --datadir via command line - //in order to be consistent within swarm, if we pass --datadir via environment variable - //or via config file, we get the same directory for geth and swarm - if _, err := os.Stat(bzzconfig.Path); err == nil { - cfg.DataDir = bzzconfig.Path - } - - //optionally set the bootnodes before configuring the node - setSwarmBootstrapNodes(ctx, &cfg) - //setup the ethereum node - utils.SetNodeConfig(ctx, &cfg) - - //disable dynamic dialing from p2p/discovery - cfg.P2P.NoDial = true - - stack, err := node.New(&cfg) - if err != nil { - utils.Fatalf("can't create node: %v", err) - } - defer stack.Close() - - //a few steps need to be done after the config phase is completed, - //due to overriding behavior - err = initSwarmNode(bzzconfig, stack, ctx, &cfg) - if err != nil { - return err - } - //register BZZ as node.Service in the ethereum node - registerBzzService(bzzconfig, stack) - //start the node - utils.StartNode(stack) - - go func() { - sigc := make(chan os.Signal, 1) - signal.Notify(sigc, syscall.SIGTERM) - defer signal.Stop(sigc) - <-sigc - log.Info("Got sigterm, shutting swarm down...") - stack.Stop() - }() - - // add swarm bootnodes, because swarm doesn't use p2p package's discovery discv5 - go func() { - s := stack.Server() - - for _, n := range cfg.P2P.BootstrapNodes { - s.AddPeer(n) - } - }() - - stack.Wait() - return nil -} - -func registerBzzService(bzzconfig *bzzapi.Config, stack *node.Node) { - //define the swarm service boot function - boot := func(_ *node.ServiceContext) (node.Service, error) { - var nodeStore *mock.NodeStore - if bzzconfig.GlobalStoreAPI != "" { - // connect to global store - client, err := rpc.Dial(bzzconfig.GlobalStoreAPI) - if err != nil { - return nil, fmt.Errorf("global store: %v", err) - } - globalStore := mockrpc.NewGlobalStore(client) - // create a node store for this swarm key on global store - nodeStore = globalStore.NewNodeStore(common.HexToAddress(bzzconfig.BzzKey)) - } - return swarm.NewSwarm(bzzconfig, nodeStore) - } - //register within the ethereum node - if err := stack.Register(boot); err != nil { - utils.Fatalf("Failed to register the Swarm service: %v", err) - } -} - -func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey { - //an account is mandatory - if bzzaccount == "" { - utils.Fatalf(SwarmErrNoBZZAccount) - } - // Try to load the arg as a hex key file. - if key, err := crypto.LoadECDSA(bzzaccount); err == nil { - log.Info("Swarm account key loaded", "address", crypto.PubkeyToAddress(key.PublicKey)) - return key - } - // Otherwise try getting it from the keystore. - am := stack.AccountManager() - ks := am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - - return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx)) -} - -// getPrivKey returns the private key of the specified bzzaccount -// Used only by client commands, such as `feed` -func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey { - // booting up the swarm node just as we do in bzzd action - bzzconfig, err := buildConfig(ctx) - if err != nil { - utils.Fatalf("unable to configure swarm: %v", err) - } - cfg := defaultNodeConfig - if _, err := os.Stat(bzzconfig.Path); err == nil { - cfg.DataDir = bzzconfig.Path - } - utils.SetNodeConfig(ctx, &cfg) - stack, err := node.New(&cfg) - if err != nil { - utils.Fatalf("can't create node: %v", err) - } - defer stack.Close() - - return getAccount(bzzconfig.BzzAccount, ctx, stack) -} - -func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey { - var a accounts.Account - var err error - if common.IsHexAddress(account) { - a, err = ks.Find(accounts.Account{Address: common.HexToAddress(account)}) - } else if ix, ixerr := strconv.Atoi(account); ixerr == nil && ix > 0 { - if accounts := ks.Accounts(); len(accounts) > ix { - a = accounts[ix] - } else { - err = fmt.Errorf("index %d higher than number of accounts %d", ix, len(accounts)) - } - } else { - utils.Fatalf("Can't find swarm account key %s", account) - } - if err != nil { - utils.Fatalf("Can't find swarm account key: %v - Is the provided bzzaccount(%s) from the right datadir/Path?", err, account) - } - keyjson, err := ioutil.ReadFile(a.URL.Path) - if err != nil { - utils.Fatalf("Can't load swarm account key: %v", err) - } - for i := 0; i < 3; i++ { - password := getPassPhrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i+1), i, passwords) - key, err := keystore.DecryptKey(keyjson, password) - if err == nil { - return key.PrivateKey - } - } - utils.Fatalf("Can't decrypt swarm account key") - return nil -} - -// getPassPhrase retrieves the password associated with bzz account, either by fetching -// from a list of pre-loaded passwords, or by requesting it interactively from user. -func getPassPhrase(prompt string, i int, passwords []string) string { - // non-interactive - if len(passwords) > 0 { - if i < len(passwords) { - return passwords[i] - } - return passwords[len(passwords)-1] - } - - // fallback to interactive mode - if prompt != "" { - fmt.Println(prompt) - } - password, err := console.Stdin.PromptPassword("Passphrase: ") - if err != nil { - utils.Fatalf("Failed to read passphrase: %v", err) - } - return password -} - -// addDefaultHelpSubcommand scans through defined CLI commands and adds -// a basic help subcommand to each -// if a help command is already defined, it will take precedence over the default. -func addDefaultHelpSubcommands(commands []cli.Command) { - for i := range commands { - cmd := &commands[i] - if cmd.Subcommands != nil { - cmd.Subcommands = append(cmd.Subcommands, defaultSubcommandHelp) - addDefaultHelpSubcommands(cmd.Subcommands) - } - } -} - -func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) { - if ctx.GlobalIsSet(utils.BootnodesFlag.Name) || ctx.GlobalIsSet(utils.BootnodesV4Flag.Name) { - return - } - - cfg.P2P.BootstrapNodes = []*enode.Node{} - - for _, url := range SwarmBootnodes { - node, err := enode.ParseV4(url) - if err != nil { - log.Error("Bootstrap URL invalid", "enode", url, "err", err) - } - cfg.P2P.BootstrapNodes = append(cfg.P2P.BootstrapNodes, node) - } - -} diff --git a/cmd/swarm/manifest.go b/cmd/swarm/manifest.go deleted file mode 100644 index 312c72fa21..0000000000 --- a/cmd/swarm/manifest.go +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command MANIFEST update -package main - -import ( - "fmt" - "os" - "strings" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/swarm/api" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - "gopkg.in/urfave/cli.v1" -) - -var manifestCommand = cli.Command{ - Name: "manifest", - CustomHelpTemplate: helpTemplate, - Usage: "perform operations on swarm manifests", - ArgsUsage: "COMMAND", - Description: "Updates a MANIFEST by adding/removing/updating the hash of a path.\nCOMMAND could be: add, update, remove", - Subcommands: []cli.Command{ - { - Action: manifestAdd, - CustomHelpTemplate: helpTemplate, - Name: "add", - Usage: "add a new path to the manifest", - ArgsUsage: " ", - Description: "Adds a new path to the manifest", - }, - { - Action: manifestUpdate, - CustomHelpTemplate: helpTemplate, - Name: "update", - Usage: "update the hash for an already existing path in the manifest", - ArgsUsage: " ", - Description: "Update the hash for an already existing path in the manifest", - }, - { - Action: manifestRemove, - CustomHelpTemplate: helpTemplate, - Name: "remove", - Usage: "removes a path from the manifest", - ArgsUsage: " ", - Description: "Removes a path from the manifest", - }, - }, -} - -// manifestAdd adds a new entry to the manifest at the given path. -// New entry hash, the last argument, must be the hash of a manifest -// with only one entry, which meta-data will be added to the original manifest. -// On success, this function will print new (updated) manifest's hash. -func manifestAdd(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 3 { - utils.Fatalf("Need exactly three arguments ") - } - - var ( - mhash = args[0] - path = args[1] - hash = args[2] - ) - - bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client := swarm.NewClient(bzzapi) - - m, _, err := client.DownloadManifest(hash) - if err != nil { - utils.Fatalf("Error downloading manifest to add: %v", err) - } - l := len(m.Entries) - if l == 0 { - utils.Fatalf("No entries in manifest %s", hash) - } else if l > 1 { - utils.Fatalf("Too many entries in manifest %s", hash) - } - - newManifest := addEntryToManifest(client, mhash, path, m.Entries[0]) - fmt.Println(newManifest) -} - -// manifestUpdate replaces an existing entry of the manifest at the given path. -// New entry hash, the last argument, must be the hash of a manifest -// with only one entry, which meta-data will be added to the original manifest. -// On success, this function will print hash of the updated manifest. -func manifestUpdate(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 3 { - utils.Fatalf("Need exactly three arguments ") - } - - var ( - mhash = args[0] - path = args[1] - hash = args[2] - ) - - bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client := swarm.NewClient(bzzapi) - - m, _, err := client.DownloadManifest(hash) - if err != nil { - utils.Fatalf("Error downloading manifest to update: %v", err) - } - l := len(m.Entries) - if l == 0 { - utils.Fatalf("No entries in manifest %s", hash) - } else if l > 1 { - utils.Fatalf("Too many entries in manifest %s", hash) - } - - newManifest, _, defaultEntryUpdated := updateEntryInManifest(client, mhash, path, m.Entries[0], true) - if defaultEntryUpdated { - // Print informational message to stderr - // allowing the user to get the new manifest hash from stdout - // without the need to parse the complete output. - fmt.Fprintln(os.Stderr, "Manifest default entry is updated, too") - } - fmt.Println(newManifest) -} - -// manifestRemove removes an existing entry of the manifest at the given path. -// On success, this function will print hash of the manifest which does not -// contain the path. -func manifestRemove(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 2 { - utils.Fatalf("Need exactly two arguments ") - } - - var ( - mhash = args[0] - path = args[1] - ) - - bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client := swarm.NewClient(bzzapi) - - newManifest := removeEntryFromManifest(client, mhash, path) - fmt.Println(newManifest) -} - -func addEntryToManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry) string { - var longestPathEntry = api.ManifestEntry{} - - mroot, isEncrypted, err := client.DownloadManifest(mhash) - if err != nil { - utils.Fatalf("Manifest download failed: %v", err) - } - - // See if we path is in this Manifest or do we have to dig deeper - for _, e := range mroot.Entries { - if path == e.Path { - utils.Fatalf("Path %s already present, not adding anything", path) - } else { - if e.ContentType == api.ManifestType { - prfxlen := strings.HasPrefix(path, e.Path) - if prfxlen && len(path) > len(longestPathEntry.Path) { - longestPathEntry = e - } - } - } - } - - if longestPathEntry.Path != "" { - // Load the child Manifest add the entry there - newPath := path[len(longestPathEntry.Path):] - newHash := addEntryToManifest(client, longestPathEntry.Hash, newPath, entry) - - // Replace the hash for parent Manifests - newMRoot := &api.Manifest{} - for _, e := range mroot.Entries { - if longestPathEntry.Path == e.Path { - e.Hash = newHash - } - newMRoot.Entries = append(newMRoot.Entries, e) - } - mroot = newMRoot - } else { - // Add the entry in the leaf Manifest - entry.Path = path - mroot.Entries = append(mroot.Entries, entry) - } - - newManifestHash, err := client.UploadManifest(mroot, isEncrypted) - if err != nil { - utils.Fatalf("Manifest upload failed: %v", err) - } - return newManifestHash -} - -// updateEntryInManifest updates an existing entry o path with a new one in the manifest with provided mhash -// finding the path recursively through all nested manifests. Argument isRoot is used for default -// entry update detection. If the updated entry has the same hash as the default entry, then the -// default entry in root manifest will be updated too. -// Returned values are the new manifest hash, hash of the entry that was replaced by the new entry and -// a a bool that is true if default entry is updated. -func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry, isRoot bool) (newManifestHash, oldHash string, defaultEntryUpdated bool) { - var ( - newEntry = api.ManifestEntry{} - longestPathEntry = api.ManifestEntry{} - ) - - mroot, isEncrypted, err := client.DownloadManifest(mhash) - if err != nil { - utils.Fatalf("Manifest download failed: %v", err) - } - - // See if we path is in this Manifest or do we have to dig deeper - for _, e := range mroot.Entries { - if path == e.Path { - newEntry = e - // keep the reference of the hash of the entry that should be replaced - // for default entry detection - oldHash = e.Hash - } else { - if e.ContentType == api.ManifestType { - prfxlen := strings.HasPrefix(path, e.Path) - if prfxlen && len(path) > len(longestPathEntry.Path) { - longestPathEntry = e - } - } - } - } - - if longestPathEntry.Path == "" && newEntry.Path == "" { - utils.Fatalf("Path %s not present in the Manifest, not setting anything", path) - } - - if longestPathEntry.Path != "" { - // Load the child Manifest add the entry there - newPath := path[len(longestPathEntry.Path):] - var newHash string - newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false) - - // Replace the hash for parent Manifests - newMRoot := &api.Manifest{} - for _, e := range mroot.Entries { - if longestPathEntry.Path == e.Path { - e.Hash = newHash - } - newMRoot.Entries = append(newMRoot.Entries, e) - - } - mroot = newMRoot - } - - // update the manifest if the new entry is found and - // check if default entry should be updated - if newEntry.Path != "" || isRoot { - // Replace the hash for leaf Manifest - newMRoot := &api.Manifest{} - for _, e := range mroot.Entries { - if newEntry.Path == e.Path { - entry.Path = e.Path - newMRoot.Entries = append(newMRoot.Entries, entry) - } else if isRoot && e.Path == "" && e.Hash == oldHash { - entry.Path = e.Path - newMRoot.Entries = append(newMRoot.Entries, entry) - defaultEntryUpdated = true - } else { - newMRoot.Entries = append(newMRoot.Entries, e) - } - } - mroot = newMRoot - } - - newManifestHash, err = client.UploadManifest(mroot, isEncrypted) - if err != nil { - utils.Fatalf("Manifest upload failed: %v", err) - } - return newManifestHash, oldHash, defaultEntryUpdated -} - -func removeEntryFromManifest(client *swarm.Client, mhash, path string) string { - var ( - entryToRemove = api.ManifestEntry{} - longestPathEntry = api.ManifestEntry{} - ) - - mroot, isEncrypted, err := client.DownloadManifest(mhash) - if err != nil { - utils.Fatalf("Manifest download failed: %v", err) - } - - // See if we path is in this Manifest or do we have to dig deeper - for _, entry := range mroot.Entries { - if path == entry.Path { - entryToRemove = entry - } else { - if entry.ContentType == api.ManifestType { - prfxlen := strings.HasPrefix(path, entry.Path) - if prfxlen && len(path) > len(longestPathEntry.Path) { - longestPathEntry = entry - } - } - } - } - - if longestPathEntry.Path == "" && entryToRemove.Path == "" { - utils.Fatalf("Path %s not present in the Manifest, not removing anything", path) - } - - if longestPathEntry.Path != "" { - // Load the child Manifest remove the entry there - newPath := path[len(longestPathEntry.Path):] - newHash := removeEntryFromManifest(client, longestPathEntry.Hash, newPath) - - // Replace the hash for parent Manifests - newMRoot := &api.Manifest{} - for _, entry := range mroot.Entries { - if longestPathEntry.Path == entry.Path { - entry.Hash = newHash - } - newMRoot.Entries = append(newMRoot.Entries, entry) - } - mroot = newMRoot - } - - if entryToRemove.Path != "" { - // remove the entry in this Manifest - newMRoot := &api.Manifest{} - for _, entry := range mroot.Entries { - if entryToRemove.Path != entry.Path { - newMRoot.Entries = append(newMRoot.Entries, entry) - } - } - mroot = newMRoot - } - - newManifestHash, err := client.UploadManifest(mroot, isEncrypted) - if err != nil { - utils.Fatalf("Manifest upload failed: %v", err) - } - return newManifestHash -} diff --git a/cmd/swarm/manifest_test.go b/cmd/swarm/manifest_test.go deleted file mode 100644 index 01d982aa7a..0000000000 --- a/cmd/swarm/manifest_test.go +++ /dev/null @@ -1,597 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "io/ioutil" - "os" - "path/filepath" - "runtime" - "testing" - - "github.com/ethereum/go-ethereum/swarm/api" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" -) - -// TestManifestChange tests manifest add, update and remove -// cli commands without encryption. -func TestManifestChange(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - testManifestChange(t, false) -} - -// TestManifestChange tests manifest add, update and remove -// cli commands with encryption enabled. -func TestManifestChangeEncrypted(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - testManifestChange(t, true) -} - -// testManifestChange performs cli commands: -// - manifest add -// - manifest update -// - manifest remove -// on a manifest, testing the functionality of this -// comands on paths that are in root manifest or a nested one. -// Argument encrypt controls whether to use encryption or not. -func testManifestChange(t *testing.T, encrypt bool) { - t.Parallel() - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - tmp, err := ioutil.TempDir("", "swarm-manifest-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmp) - - origDir := filepath.Join(tmp, "orig") - if err := os.Mkdir(origDir, 0777); err != nil { - t.Fatal(err) - } - - indexDataFilename := filepath.Join(origDir, "index.html") - err = ioutil.WriteFile(indexDataFilename, []byte("

Test

"), 0666) - if err != nil { - t.Fatal(err) - } - // Files paths robots.txt and robots.html share the same prefix "robots." - // which will result a manifest with a nested manifest under path "robots.". - // This will allow testing manifest changes on both root and nested manifest. - err = ioutil.WriteFile(filepath.Join(origDir, "robots.txt"), []byte("Disallow: /"), 0666) - if err != nil { - t.Fatal(err) - } - err = ioutil.WriteFile(filepath.Join(origDir, "robots.html"), []byte("No Robots Allowed"), 0666) - if err != nil { - t.Fatal(err) - } - err = ioutil.WriteFile(filepath.Join(origDir, "mutants.txt"), []byte("Frank\nMarcus"), 0666) - if err != nil { - t.Fatal(err) - } - - args := []string{ - "--bzzapi", - srv.URL, - "--recursive", - "--defaultpath", - indexDataFilename, - "up", - origDir, - } - if encrypt { - args = append(args, "--encrypt") - } - - origManifestHash := runSwarmExpectHash(t, args...) - - checkHashLength(t, origManifestHash, encrypt) - - client := swarm.NewClient(srv.URL) - - // upload a new file and use its manifest to add it the original manifest. - t.Run("add", func(t *testing.T) { - humansData := []byte("Ann\nBob") - humansDataFilename := filepath.Join(tmp, "humans.txt") - err = ioutil.WriteFile(humansDataFilename, humansData, 0666) - if err != nil { - t.Fatal(err) - } - - humansManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "up", - humansDataFilename, - ) - - newManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "manifest", - "add", - origManifestHash, - "humans.txt", - humansManifestHash, - ) - - checkHashLength(t, newManifestHash, encrypt) - - newManifest := downloadManifest(t, client, newManifestHash, encrypt) - - var found bool - for _, e := range newManifest.Entries { - if e.Path == "humans.txt" { - found = true - if e.Size != int64(len(humansData)) { - t.Errorf("expected humans.txt size %v, got %v", len(humansData), e.Size) - } - if e.ModTime.IsZero() { - t.Errorf("got zero mod time for humans.txt") - } - ct := "text/plain; charset=utf-8" - if e.ContentType != ct { - t.Errorf("expected content type %q, got %q", ct, e.ContentType) - } - break - } - } - if !found { - t.Fatal("no humans.txt in new manifest") - } - - checkFile(t, client, newManifestHash, "humans.txt", humansData) - }) - - // upload a new file and use its manifest to add it the original manifest, - // but ensure that the file will be in the nested manifest of the original one. - t.Run("add nested", func(t *testing.T) { - robotsData := []byte(`{"disallow": "/"}`) - robotsDataFilename := filepath.Join(tmp, "robots.json") - err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666) - if err != nil { - t.Fatal(err) - } - - robotsManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "up", - robotsDataFilename, - ) - - newManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "manifest", - "add", - origManifestHash, - "robots.json", - robotsManifestHash, - ) - - checkHashLength(t, newManifestHash, encrypt) - - newManifest := downloadManifest(t, client, newManifestHash, encrypt) - - var found bool - loop: - for _, e := range newManifest.Entries { - if e.Path == "robots." { - nestedManifest := downloadManifest(t, client, e.Hash, encrypt) - for _, e := range nestedManifest.Entries { - if e.Path == "json" { - found = true - if e.Size != int64(len(robotsData)) { - t.Errorf("expected robots.json size %v, got %v", len(robotsData), e.Size) - } - if e.ModTime.IsZero() { - t.Errorf("got zero mod time for robots.json") - } - ct := "application/json" - if e.ContentType != ct { - t.Errorf("expected content type %q, got %q", ct, e.ContentType) - } - break loop - } - } - } - } - if !found { - t.Fatal("no robots.json in new manifest") - } - - checkFile(t, client, newManifestHash, "robots.json", robotsData) - }) - - // upload a new file and use its manifest to change the file it the original manifest. - t.Run("update", func(t *testing.T) { - indexData := []byte("

Ethereum Swarm

") - indexDataFilename := filepath.Join(tmp, "index.html") - err = ioutil.WriteFile(indexDataFilename, indexData, 0666) - if err != nil { - t.Fatal(err) - } - - indexManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "up", - indexDataFilename, - ) - - newManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "manifest", - "update", - origManifestHash, - "index.html", - indexManifestHash, - ) - - checkHashLength(t, newManifestHash, encrypt) - - newManifest := downloadManifest(t, client, newManifestHash, encrypt) - - var found bool - for _, e := range newManifest.Entries { - if e.Path == "index.html" { - found = true - if e.Size != int64(len(indexData)) { - t.Errorf("expected index.html size %v, got %v", len(indexData), e.Size) - } - if e.ModTime.IsZero() { - t.Errorf("got zero mod time for index.html") - } - ct := "text/html; charset=utf-8" - if e.ContentType != ct { - t.Errorf("expected content type %q, got %q", ct, e.ContentType) - } - break - } - } - if !found { - t.Fatal("no index.html in new manifest") - } - - checkFile(t, client, newManifestHash, "index.html", indexData) - - // check default entry change - checkFile(t, client, newManifestHash, "", indexData) - }) - - // upload a new file and use its manifest to change the file it the original manifest, - // but ensure that the file is in the nested manifest of the original one. - t.Run("update nested", func(t *testing.T) { - robotsData := []byte(`Only humans allowed!!!`) - robotsDataFilename := filepath.Join(tmp, "robots.html") - err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666) - if err != nil { - t.Fatal(err) - } - - humansManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "up", - robotsDataFilename, - ) - - newManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "manifest", - "update", - origManifestHash, - "robots.html", - humansManifestHash, - ) - - checkHashLength(t, newManifestHash, encrypt) - - newManifest := downloadManifest(t, client, newManifestHash, encrypt) - - var found bool - loop: - for _, e := range newManifest.Entries { - if e.Path == "robots." { - nestedManifest := downloadManifest(t, client, e.Hash, encrypt) - for _, e := range nestedManifest.Entries { - if e.Path == "html" { - found = true - if e.Size != int64(len(robotsData)) { - t.Errorf("expected robots.html size %v, got %v", len(robotsData), e.Size) - } - if e.ModTime.IsZero() { - t.Errorf("got zero mod time for robots.html") - } - ct := "text/html; charset=utf-8" - if e.ContentType != ct { - t.Errorf("expected content type %q, got %q", ct, e.ContentType) - } - break loop - } - } - } - } - if !found { - t.Fatal("no robots.html in new manifest") - } - - checkFile(t, client, newManifestHash, "robots.html", robotsData) - }) - - // remove a file from the manifest. - t.Run("remove", func(t *testing.T) { - newManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "manifest", - "remove", - origManifestHash, - "mutants.txt", - ) - - checkHashLength(t, newManifestHash, encrypt) - - newManifest := downloadManifest(t, client, newManifestHash, encrypt) - - var found bool - for _, e := range newManifest.Entries { - if e.Path == "mutants.txt" { - found = true - break - } - } - if found { - t.Fatal("mutants.txt is not removed") - } - }) - - // remove a file from the manifest, but ensure that the file is in - // the nested manifest of the original one. - t.Run("remove nested", func(t *testing.T) { - newManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "manifest", - "remove", - origManifestHash, - "robots.html", - ) - - checkHashLength(t, newManifestHash, encrypt) - - newManifest := downloadManifest(t, client, newManifestHash, encrypt) - - var found bool - loop: - for _, e := range newManifest.Entries { - if e.Path == "robots." { - nestedManifest := downloadManifest(t, client, e.Hash, encrypt) - for _, e := range nestedManifest.Entries { - if e.Path == "html" { - found = true - break loop - } - } - } - } - if found { - t.Fatal("robots.html in not removed") - } - }) -} - -// TestNestedDefaultEntryUpdate tests if the default entry is updated -// if the file in nested manifest used for it is also updated. -func TestNestedDefaultEntryUpdate(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - testNestedDefaultEntryUpdate(t, false) -} - -// TestNestedDefaultEntryUpdateEncrypted tests if the default entry -// of encrypted upload is updated if the file in nested manifest -// used for it is also updated. -func TestNestedDefaultEntryUpdateEncrypted(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - testNestedDefaultEntryUpdate(t, true) -} - -func testNestedDefaultEntryUpdate(t *testing.T, encrypt bool) { - t.Parallel() - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - tmp, err := ioutil.TempDir("", "swarm-manifest-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmp) - - origDir := filepath.Join(tmp, "orig") - if err := os.Mkdir(origDir, 0777); err != nil { - t.Fatal(err) - } - - indexData := []byte("

Test

") - indexDataFilename := filepath.Join(origDir, "index.html") - err = ioutil.WriteFile(indexDataFilename, indexData, 0666) - if err != nil { - t.Fatal(err) - } - // Add another file with common prefix as the default entry to test updates of - // default entry with nested manifests. - err = ioutil.WriteFile(filepath.Join(origDir, "index.txt"), []byte("Test"), 0666) - if err != nil { - t.Fatal(err) - } - - args := []string{ - "--bzzapi", - srv.URL, - "--recursive", - "--defaultpath", - indexDataFilename, - "up", - origDir, - } - if encrypt { - args = append(args, "--encrypt") - } - - origManifestHash := runSwarmExpectHash(t, args...) - - checkHashLength(t, origManifestHash, encrypt) - - client := swarm.NewClient(srv.URL) - - newIndexData := []byte("

Ethereum Swarm

") - newIndexDataFilename := filepath.Join(tmp, "index.html") - err = ioutil.WriteFile(newIndexDataFilename, newIndexData, 0666) - if err != nil { - t.Fatal(err) - } - - newIndexManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "up", - newIndexDataFilename, - ) - - newManifestHash := runSwarmExpectHash(t, - "--bzzapi", - srv.URL, - "manifest", - "update", - origManifestHash, - "index.html", - newIndexManifestHash, - ) - - checkHashLength(t, newManifestHash, encrypt) - - newManifest := downloadManifest(t, client, newManifestHash, encrypt) - - var found bool - for _, e := range newManifest.Entries { - if e.Path == "index." { - found = true - newManifest = downloadManifest(t, client, e.Hash, encrypt) - break - } - } - if !found { - t.Fatal("no index. path in new manifest") - } - - found = false - for _, e := range newManifest.Entries { - if e.Path == "html" { - found = true - if e.Size != int64(len(newIndexData)) { - t.Errorf("expected index.html size %v, got %v", len(newIndexData), e.Size) - } - if e.ModTime.IsZero() { - t.Errorf("got zero mod time for index.html") - } - ct := "text/html; charset=utf-8" - if e.ContentType != ct { - t.Errorf("expected content type %q, got %q", ct, e.ContentType) - } - break - } - } - if !found { - t.Fatal("no html in new manifest") - } - - checkFile(t, client, newManifestHash, "index.html", newIndexData) - - // check default entry change - checkFile(t, client, newManifestHash, "", newIndexData) -} - -func runSwarmExpectHash(t *testing.T, args ...string) (hash string) { - t.Helper() - hashRegexp := `[a-f\d]{64,128}` - up := runSwarm(t, args...) - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - - if len(matches) < 1 { - t.Fatal("no matches found") - } - return matches[0] -} - -func checkHashLength(t *testing.T, hash string, encrypted bool) { - t.Helper() - l := len(hash) - if encrypted && l != 128 { - t.Errorf("expected hash length 128, got %v", l) - } - if !encrypted && l != 64 { - t.Errorf("expected hash length 64, got %v", l) - } -} - -func downloadManifest(t *testing.T, client *swarm.Client, hash string, encrypted bool) (manifest *api.Manifest) { - t.Helper() - m, isEncrypted, err := client.DownloadManifest(hash) - if err != nil { - t.Fatal(err) - } - - if encrypted != isEncrypted { - t.Error("new manifest encryption flag is not correct") - } - return m -} - -func checkFile(t *testing.T, client *swarm.Client, hash, path string, expected []byte) { - t.Helper() - f, err := client.Download(hash, path) - if err != nil { - t.Fatal(err) - } - - got, err := ioutil.ReadAll(f) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(got, expected) { - t.Errorf("expected file content %q, got %q", expected, got) - } -} diff --git a/cmd/swarm/mimegen/generator.go b/cmd/swarm/mimegen/generator.go deleted file mode 100644 index 68f9e306e5..0000000000 --- a/cmd/swarm/mimegen/generator.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . -package main - -// Standard "mime" package rely on system-settings, see mime.osInitMime -// Swarm will run on many OS/Platform/Docker and must behave similar -// This command generates code to add common mime types based on mime.types file -// -// mime.types file provided by mailcap, which follow https://www.iana.org/assignments/media-types/media-types.xhtml -// -// Get last version of mime.types file by: -// docker run --rm -v $(pwd):/tmp alpine:edge /bin/sh -c "apk add -U mailcap; mv /etc/mime.types /tmp" - -import ( - "bufio" - "bytes" - "flag" - "html/template" - "io/ioutil" - "strings" - - "log" -) - -var ( - typesFlag = flag.String("types", "", "Input mime.types file") - packageFlag = flag.String("package", "", "Golang package in output file") - outFlag = flag.String("out", "", "Output file name for the generated mime types") -) - -type mime struct { - Name string - Exts []string -} - -type templateParams struct { - PackageName string - Mimes []mime -} - -func main() { - // Parse and ensure all needed inputs are specified - flag.Parse() - if *typesFlag == "" { - log.Fatalf("--types is required") - } - if *packageFlag == "" { - log.Fatalf("--types is required") - } - if *outFlag == "" { - log.Fatalf("--out is required") - } - - params := templateParams{ - PackageName: *packageFlag, - } - - types, err := ioutil.ReadFile(*typesFlag) - if err != nil { - log.Fatal(err) - } - - scanner := bufio.NewScanner(bytes.NewReader(types)) - for scanner.Scan() { - txt := scanner.Text() - if strings.HasPrefix(txt, "#") || len(txt) == 0 { - continue - } - parts := strings.Fields(txt) - if len(parts) == 1 { - continue - } - params.Mimes = append(params.Mimes, mime{parts[0], parts[1:]}) - } - - if err = scanner.Err(); err != nil { - log.Fatal(err) - } - - result := bytes.NewBuffer([]byte{}) - - if err := template.Must(template.New("_").Parse(tpl)).Execute(result, params); err != nil { - log.Fatal(err) - } - - if err := ioutil.WriteFile(*outFlag, result.Bytes(), 0600); err != nil { - log.Fatal(err) - } -} - -var tpl = `// Code generated by github.com/ethereum/go-ethereum/cmd/swarm/mimegen. DO NOT EDIT. - -package {{ .PackageName }} - -import "mime" -func init() { - var mimeTypes = map[string]string{ -{{- range .Mimes -}} - {{ $name := .Name -}} - {{- range .Exts }} - ".{{ . }}": "{{ $name | html }}", - {{- end }} -{{- end }} - } - for ext, name := range mimeTypes { - if err := mime.AddExtensionType(ext, name); err != nil { - panic(err) - } - } -} -` diff --git a/cmd/swarm/mimegen/mime.types b/cmd/swarm/mimegen/mime.types deleted file mode 100644 index 1bdf211490..0000000000 --- a/cmd/swarm/mimegen/mime.types +++ /dev/null @@ -1,1828 +0,0 @@ -# This is a comment. I love comments. -*- indent-tabs-mode: t -*- - -# This file controls what Internet media types are sent to the client for -# given file extension(s). Sending the correct media type to the client -# is important so they know how to handle the content of the file. -# Extra types can either be added here or by using an AddType directive -# in your config files. For more information about Internet media types, -# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type -# registry is at . - -# IANA types - -# MIME type Extensions -application/1d-interleaved-parityfec -application/3gpdash-qoe-report+xml -application/3gpp-ims+xml -application/A2L a2l -application/activemessage -application/alto-costmap+json -application/alto-costmapfilter+json -application/alto-directory+json -application/alto-endpointcost+json -application/alto-endpointcostparams+json -application/alto-endpointprop+json -application/alto-endpointpropparams+json -application/alto-error+json -application/alto-networkmap+json -application/alto-networkmapfilter+json -application/AML aml -application/andrew-inset ez -application/applefile -application/ATF atf -application/ATFX atfx -application/ATXML atxml -application/atom+xml atom -application/atomcat+xml atomcat -application/atomdeleted+xml atomdeleted -application/atomicmail -application/atomsvc+xml atomsvc -application/auth-policy+xml apxml -application/bacnet-xdd+zip xdd -application/batch-SMTP -application/beep+xml -application/calendar+json -application/calendar+xml xcs -application/call-completion -application/cals-1840 -application/cbor cbor -application/ccmp+xml ccmp -application/ccxml+xml ccxml -application/CDFX+XML cdfx -application/cdmi-capability cdmia -application/cdmi-container cdmic -application/cdmi-domain cdmid -application/cdmi-object cdmio -application/cdmi-queue cdmiq -application/cdni -application/CEA cea -application/cea-2018+xml -application/cellml+xml cellml cml -application/cfw -application/clue_info+xml clue -application/cms cmsc -application/cnrp+xml -application/coap-group+json -application/coap-payload -application/commonground -application/conference-info+xml -application/cpl+xml cpl -application/cose -application/cose-key -application/cose-key-set -application/csrattrs csrattrs -application/csta+xml -application/CSTAdata+xml -application/csvm+json -application/cybercash -application/dash+xml mpd -application/dashdelta mpdd -application/davmount+xml davmount -application/dca-rft -application/DCD dcd -application/dec-dx -application/dialog-info+xml -application/dicom dcm -application/dicom+json -application/dicom+xml -application/DII dii -application/DIT dit -application/dns -application/dskpp+xml xmls -application/dssc+der dssc -application/dssc+xml xdssc -application/dvcs dvc -application/ecmascript es -application/EDI-Consent -application/EDI-X12 -application/EDIFACT -application/efi efi -application/EmergencyCallData.Comment+xml -application/EmergencyCallData.Control+xml -application/EmergencyCallData.DeviceInfo+xml -application/EmergencyCallData.eCall.MSD -application/EmergencyCallData.ProviderInfo+xml -application/EmergencyCallData.ServiceInfo+xml -application/EmergencyCallData.SubscriberInfo+xml -application/EmergencyCallData.VEDS+xml -application/emma+xml emma -application/emotionml+xml emotionml -application/encaprtp -application/epp+xml -application/epub+zip epub -application/eshop -application/exi exi -application/fastinfoset finf -application/fastsoap -application/fdt+xml fdt -# fits, fit, fts: image/fits -application/fits -# application/font-sfnt deprecated in favor of font/sfnt -application/font-tdpfr pfr -# application/font-woff deprecated in favor of font/woff -application/framework-attributes+xml -application/geo+json geojson -application/geo+json-seq -application/gml+xml gml -application/gzip gz tgz -application/H224 -application/held+xml -application/http -application/hyperstudio stk -application/ibe-key-request+xml -application/ibe-pkg-reply+xml -application/ibe-pp-data -application/iges -application/im-iscomposing+xml -application/index -application/index.cmd -application/index.obj -application/index.response -application/index.vnd -application/inkml+xml ink inkml -application/iotp -application/ipfix ipfix -application/ipp -application/isup -application/its+xml its -application/javascript js -application/jose -application/jose+json -application/jrd+json jrd -application/json json -application/json-patch+json json-patch -application/json-seq -application/jwk+json -application/jwk-set+json -application/jwt -application/kpml-request+xml -application/kpml-response+xml -application/ld+json jsonld -application/lgr+xml lgr -application/link-format wlnk -application/load-control+xml -application/lost+xml lostxml -application/lostsync+xml lostsyncxml -application/LXF lxf -application/mac-binhex40 hqx -application/macwriteii -application/mads+xml mads -application/marc mrc -application/marcxml+xml mrcx -application/mathematica nb ma mb -application/mathml-content+xml -application/mathml-presentation+xml -application/mathml+xml mml -application/mbms-associated-procedure-description+xml -application/mbms-deregister+xml -application/mbms-envelope+xml -application/mbms-msk-response+xml -application/mbms-msk+xml -application/mbms-protection-description+xml -application/mbms-reception-report+xml -application/mbms-register-response+xml -application/mbms-register+xml -application/mbms-schedule+xml -application/mbms-user-service-description+xml -application/mbox mbox -application/media_control+xml -# mpf: text/vnd.ms-mediapackage -application/media-policy-dataset+xml -application/mediaservercontrol+xml -application/merge-patch+json -application/metalink4+xml meta4 -application/mets+xml mets -application/MF4 mf4 -application/mikey -application/mods+xml mods -application/moss-keys -application/moss-signature -application/mosskey-data -application/mosskey-request -application/mp21 m21 mp21 -# mp4, mpg4: video/mp4, see RFC 4337 -application/mp4 -application/mpeg4-generic -application/mpeg4-iod -application/mpeg4-iod-xmt -# xdf: application/xcap-diff+xml -application/mrb-consumer+xml -application/mrb-publish+xml -application/msc-ivr+xml -application/msc-mixer+xml -application/msword doc -application/mud+json -application/mxf mxf -application/n-quads nq -application/n-triples nt -application/nasdata -application/news-checkgroups -application/news-groupinfo -application/news-transmission -application/nlsml+xml -application/nss -application/ocsp-request orq -application/ocsp-response ors -application/octet-stream bin lha lzh exe class so dll img iso -application/oda oda -application/ODX odx -application/oebps-package+xml opf -application/ogg ogx -application/oxps oxps -application/p2p-overlay+xml relo -application/parityfec -# xer: application/xcap-error+xml -application/patch-ops-error+xml -application/pdf pdf -application/PDX pdx -application/pgp-encrypted pgp -application/pgp-keys -application/pgp-signature sig -application/pidf-diff+xml -application/pidf+xml -application/pkcs10 p10 -application/pkcs12 p12 pfx -application/pkcs7-mime p7m p7c -application/pkcs7-signature p7s -application/pkcs8 p8 -# ac: application/vnd.nokia.n-gage.ac+xml -application/pkix-attr-cert -application/pkix-cert cer -application/pkix-crl crl -application/pkix-pkipath pkipath -application/pkixcmp pki -application/pls+xml pls -application/poc-settings+xml -application/postscript ps eps ai -application/ppsp-tracker+json -application/problem+json -application/problem+xml -application/provenance+xml provx -application/prs.alvestrand.titrax-sheet -application/prs.cww cw cww -application/prs.hpub+zip hpub -application/prs.nprend rnd rct -application/prs.plucker -application/prs.rdf-xml-crypt rdf-crypt -application/prs.xsf+xml xsf -application/pskc+xml pskcxml -application/qsig -application/raptorfec -application/rdap+json -application/rdf+xml rdf -application/reginfo+xml rif -application/relax-ng-compact-syntax rnc -application/remote-printing -application/reputon+json -application/resource-lists-diff+xml rld -application/resource-lists+xml rl -application/rfc+xml rfcxml -application/riscos -application/rlmi+xml -application/rls-services+xml rs -application/rpki-ghostbusters gbr -application/rpki-manifest mft -application/rpki-publication -application/rpki-roa roa -application/rpki-updown -application/rtf rtf -application/rtploopback -application/rtx -application/samlassertion+xml -application/samlmetadata+xml -application/sbml+xml -application/scaip+xml -# scm: application/vnd.lotus-screencam -application/scim+json scim -application/scvp-cv-request scq -application/scvp-cv-response scs -application/scvp-vp-request spq -application/scvp-vp-response spp -application/sdp sdp -application/sep+xml -application/sep-exi -application/session-info -application/set-payment -application/set-payment-initiation -application/set-registration -application/set-registration-initiation -application/sgml -application/sgml-open-catalog soc -application/shf+xml shf -application/sieve siv sieve -application/simple-filter+xml cl -application/simple-message-summary -application/simpleSymbolContainer -application/slate -# application/smil obsoleted by application/smil+xml -application/smil+xml smil smi sml -application/smpte336m -application/soap+fastinfoset -application/soap+xml -application/sparql-query rq -application/sparql-results+xml srx -application/spirits-event+xml -application/sql sql -application/srgs gram -application/srgs+xml grxml -application/sru+xml sru -application/ssml+xml ssml -application/tamp-apex-update tau -application/tamp-apex-update-confirm auc -application/tamp-community-update tcu -application/tamp-community-update-confirm cuc -application/tamp-error ter -application/tamp-sequence-adjust tsa -application/tamp-sequence-adjust-confirm sac -# tsq: application/timestamp-query -application/tamp-status-query -# tsr: application/timestamp-reply -application/tamp-status-response -application/tamp-update tur -application/tamp-update-confirm tuc -application/tei+xml tei teiCorpus odd -application/thraud+xml tfi -application/timestamp-query tsq -application/timestamp-reply tsr -application/timestamped-data tsd -application/trig trig -application/ttml+xml ttml -application/tve-trigger -application/ulpfec -application/urc-grpsheet+xml gsheet -application/urc-ressheet+xml rsheet -application/urc-targetdesc+xml td -application/urc-uisocketdesc+xml uis -application/vcard+json -application/vcard+xml -application/vemmi -application/vnd.3gpp.access-transfer-events+xml -application/vnd.3gpp.bsf+xml -application/vnd.3gpp.mid-call+xml -application/vnd.3gpp.pic-bw-large plb -application/vnd.3gpp.pic-bw-small psb -application/vnd.3gpp.pic-bw-var pvb -application/vnd.3gpp-prose+xml -application/vnd.3gpp-prose-pc3ch+xml -# sms: application/vnd.3gpp2.sms -application/vnd.3gpp.sms -application/vnd.3gpp.sms+xml -application/vnd.3gpp.srvcc-ext+xml -application/vnd.3gpp.SRVCC-info+xml -application/vnd.3gpp.state-and-event-info+xml -application/vnd.3gpp.ussd+xml -application/vnd.3gpp2.bcmcsinfo+xml -application/vnd.3gpp2.sms sms -application/vnd.3gpp2.tcap tcap -application/vnd.3lightssoftware.imagescal imgcal -application/vnd.3M.Post-it-Notes pwn -application/vnd.accpac.simply.aso aso -application/vnd.accpac.simply.imp imp -application/vnd.acucobol acu -application/vnd.acucorp atc acutc -application/vnd.adobe.flash.movie swf -application/vnd.adobe.formscentral.fcdt fcdt -application/vnd.adobe.fxp fxp fxpl -application/vnd.adobe.partial-upload -application/vnd.adobe.xdp+xml xdp -application/vnd.adobe.xfdf xfdf -application/vnd.aether.imp -application/vnd.ah-barcode -application/vnd.ahead.space ahead -application/vnd.airzip.filesecure.azf azf -application/vnd.airzip.filesecure.azs azs -application/vnd.amazon.mobi8-ebook azw3 -application/vnd.americandynamics.acc acc -application/vnd.amiga.ami ami -application/vnd.amundsen.maze+xml -application/vnd.anki apkg -application/vnd.anser-web-certificate-issue-initiation cii -# Not in IANA listing, but is on FTP site? -application/vnd.anser-web-funds-transfer-initiation fti -# atx: audio/ATRAC-X -application/vnd.antix.game-component -application/vnd.apache.thrift.binary -application/vnd.apache.thrift.compact -application/vnd.apache.thrift.json -application/vnd.api+json -application/vnd.apothekende.reservation+json -application/vnd.apple.installer+xml dist distz pkg mpkg -# m3u: audio/x-mpegurl for now -application/vnd.apple.mpegurl m3u8 -# application/vnd.arastra.swi obsoleted by application/vnd.aristanetworks.swi -application/vnd.aristanetworks.swi swi -application/vnd.artsquare -application/vnd.astraea-software.iota iota -application/vnd.audiograph aep -application/vnd.autopackage package -application/vnd.avistar+xml -application/vnd.balsamiq.bmml+xml bmml -application/vnd.balsamiq.bmpr bmpr -application/vnd.bekitzur-stech+json -application/vnd.bint.med-content -application/vnd.biopax.rdf+xml -application/vnd.blueice.multipass mpm -application/vnd.bluetooth.ep.oob ep -application/vnd.bluetooth.le.oob le -application/vnd.bmi bmi -application/vnd.businessobjects rep -application/vnd.cab-jscript -application/vnd.canon-cpdl -application/vnd.canon-lips -application/vnd.capasystems-pg+json -application/vnd.cendio.thinlinc.clientconf tlclient -application/vnd.century-systems.tcp_stream -application/vnd.chemdraw+xml cdxml -application/vnd.chess-pgn pgn -application/vnd.chipnuts.karaoke-mmd mmd -application/vnd.cinderella cdy -application/vnd.cirpack.isdn-ext -application/vnd.citationstyles.style+xml csl -application/vnd.claymore cla -application/vnd.cloanto.rp9 rp9 -application/vnd.clonk.c4group c4g c4d c4f c4p c4u -application/vnd.cluetrust.cartomobile-config c11amc -application/vnd.cluetrust.cartomobile-config-pkg c11amz -application/vnd.coffeescript coffee -application/vnd.collection+json -application/vnd.collection.doc+json -application/vnd.collection.next+json -application/vnd.comicbook+zip cbz -# icc: application/vnd.iccprofile -application/vnd.commerce-battelle ica icf icd ic0 ic1 ic2 ic3 ic4 ic5 ic6 ic7 ic8 -application/vnd.commonspace csp cst -application/vnd.contact.cmsg cdbcmsg -application/vnd.coreos.ignition+json ign ignition -application/vnd.cosmocaller cmc -application/vnd.crick.clicker clkx -application/vnd.crick.clicker.keyboard clkk -application/vnd.crick.clicker.palette clkp -application/vnd.crick.clicker.template clkt -application/vnd.crick.clicker.wordbank clkw -application/vnd.criticaltools.wbs+xml wbs -application/vnd.ctc-posml pml -application/vnd.ctct.ws+xml -application/vnd.cups-pdf -application/vnd.cups-postscript -application/vnd.cups-ppd ppd -application/vnd.cups-raster -application/vnd.cups-raw -application/vnd.curl curl -application/vnd.cyan.dean.root+xml -application/vnd.cybank -application/vnd.d2l.coursepackage1p0+zip -application/vnd.dart dart -application/vnd.data-vision.rdz rdz -application/vnd.datapackage+json -application/vnd.dataresource+json -application/vnd.debian.binary-package deb udeb -application/vnd.dece.data uvf uvvf uvd uvvd -application/vnd.dece.ttml+xml uvt uvvt -application/vnd.dece.unspecified uvx uvvx -application/vnd.dece.zip uvz uvvz -application/vnd.denovo.fcselayout-link fe_launch -application/vnd.desmume.movie dsm -application/vnd.dir-bi.plate-dl-nosuffix -application/vnd.dm.delegation+xml -application/vnd.dna dna -application/vnd.document+json docjson -application/vnd.dolby.mobile.1 -application/vnd.dolby.mobile.2 -application/vnd.doremir.scorecloud-binary-document scld -application/vnd.dpgraph dpg mwc dpgraph -application/vnd.dreamfactory dfac -application/vnd.drive+json -application/vnd.dtg.local -application/vnd.dtg.local.flash fla -application/vnd.dtg.local.html -application/vnd.dvb.ait ait -# class: application/octet-stream -application/vnd.dvb.dvbj -application/vnd.dvb.esgcontainer -application/vnd.dvb.ipdcdftnotifaccess -application/vnd.dvb.ipdcesgaccess -application/vnd.dvb.ipdcesgaccess2 -application/vnd.dvb.ipdcesgpdd -application/vnd.dvb.ipdcroaming -application/vnd.dvb.iptv.alfec-base -application/vnd.dvb.iptv.alfec-enhancement -application/vnd.dvb.notif-aggregate-root+xml -application/vnd.dvb.notif-container+xml -application/vnd.dvb.notif-generic+xml -application/vnd.dvb.notif-ia-msglist+xml -application/vnd.dvb.notif-ia-registration-request+xml -application/vnd.dvb.notif-ia-registration-response+xml -application/vnd.dvb.notif-init+xml -# pfr: application/font-tdpfr -application/vnd.dvb.pfr -application/vnd.dvb.service svc -# dxr: application/x-director -application/vnd.dxr -application/vnd.dynageo geo -application/vnd.dzr dzr -application/vnd.easykaraoke.cdgdownload -application/vnd.ecdis-update -application/vnd.ecowin.chart mag -application/vnd.ecowin.filerequest -application/vnd.ecowin.fileupdate -application/vnd.ecowin.series -application/vnd.ecowin.seriesrequest -application/vnd.ecowin.seriesupdate -# img: application/octet-stream -application/vnd.efi-img -# iso: application/octet-stream -application/vnd.efi-iso -application/vnd.enliven nml -application/vnd.enphase.envoy -application/vnd.eprints.data+xml -application/vnd.epson.esf esf -application/vnd.epson.msf msf -application/vnd.epson.quickanime qam -application/vnd.epson.salt slt -application/vnd.epson.ssf ssf -application/vnd.ericsson.quickcall qcall qca -application/vnd.espass-espass+zip espass -application/vnd.eszigno3+xml es3 et3 -application/vnd.etsi.aoc+xml -application/vnd.etsi.asic-e+zip asice sce -# scs: application/scvp-cv-response -application/vnd.etsi.asic-s+zip asics -application/vnd.etsi.cug+xml -application/vnd.etsi.iptvcommand+xml -application/vnd.etsi.iptvdiscovery+xml -application/vnd.etsi.iptvprofile+xml -application/vnd.etsi.iptvsad-bc+xml -application/vnd.etsi.iptvsad-cod+xml -application/vnd.etsi.iptvsad-npvr+xml -application/vnd.etsi.iptvservice+xml -application/vnd.etsi.iptvsync+xml -application/vnd.etsi.iptvueprofile+xml -application/vnd.etsi.mcid+xml -application/vnd.etsi.mheg5 -application/vnd.etsi.overload-control-policy-dataset+xml -application/vnd.etsi.pstn+xml -application/vnd.etsi.sci+xml -application/vnd.etsi.simservs+xml -application/vnd.etsi.timestamp-token tst -application/vnd.etsi.tsl.der -application/vnd.etsi.tsl+xml -application/vnd.eudora.data -application/vnd.ezpix-album ez2 -application/vnd.ezpix-package ez3 -application/vnd.f-secure.mobile -application/vnd.fastcopy-disk-image dim -application/vnd.fdf fdf -application/vnd.fdsn.mseed msd mseed -application/vnd.fdsn.seed seed dataless -application/vnd.ffsns -application/vnd.filmit.zfc zfc -# all extensions: application/vnd.hbci -application/vnd.fints -application/vnd.firemonkeys.cloudcell -application/vnd.FloGraphIt gph -application/vnd.fluxtime.clip ftc -application/vnd.font-fontforge-sfd sfd -application/vnd.framemaker fm -application/vnd.frogans.fnc fnc -application/vnd.frogans.ltf ltf -application/vnd.fsc.weblaunch fsc -application/vnd.fujitsu.oasys oas -application/vnd.fujitsu.oasys2 oa2 -application/vnd.fujitsu.oasys3 oa3 -application/vnd.fujitsu.oasysgp fg5 -application/vnd.fujitsu.oasysprs bh2 -application/vnd.fujixerox.ART-EX -application/vnd.fujixerox.ART4 -application/vnd.fujixerox.ddd ddd -application/vnd.fujixerox.docuworks xdw -application/vnd.fujixerox.docuworks.binder xbd -application/vnd.fujixerox.docuworks.container xct -application/vnd.fujixerox.HBPL -application/vnd.fut-misnet -application/vnd.fuzzysheet fzs -application/vnd.genomatix.tuxedo txd -# application/vnd.geo+json obsoleted by application/geo+json -application/vnd.geocube+xml g3 g³ -application/vnd.geogebra.file ggb -application/vnd.geogebra.tool ggt -application/vnd.geometry-explorer gex gre -application/vnd.geonext gxt -application/vnd.geoplan g2w -application/vnd.geospace g3w -# gbr: application/rpki-ghostbusters -application/vnd.gerber -application/vnd.globalplatform.card-content-mgt -application/vnd.globalplatform.card-content-mgt-response -application/vnd.gmx gmx -application/vnd.google-earth.kml+xml kml -application/vnd.google-earth.kmz kmz -application/vnd.gov.sk.e-form+xml -application/vnd.gov.sk.e-form+zip -application/vnd.gov.sk.xmldatacontainer+xml -application/vnd.grafeq gqf gqs -application/vnd.gridmp -application/vnd.groove-account gac -application/vnd.groove-help ghf -application/vnd.groove-identity-message gim -application/vnd.groove-injector grv -application/vnd.groove-tool-message gtm -application/vnd.groove-tool-template tpl -application/vnd.groove-vcard vcg -application/vnd.hal+json -application/vnd.hal+xml hal -application/vnd.HandHeld-Entertainment+xml zmm -application/vnd.hbci hbci hbc kom upa pkd bpd -application/vnd.hc+json -# rep: application/vnd.businessobjects -application/vnd.hcl-bireports -application/vnd.hdt hdt -application/vnd.heroku+json -application/vnd.hhe.lesson-player les -application/vnd.hp-HPGL hpgl -application/vnd.hp-hpid hpi hpid -application/vnd.hp-hps hps -application/vnd.hp-jlyt jlt -application/vnd.hp-PCL pcl -application/vnd.hp-PCLXL -application/vnd.httphone -application/vnd.hydrostatix.sof-data sfd-hdstx -application/vnd.hyperdrive+json -application/vnd.hzn-3d-crossword x3d -application/vnd.ibm.afplinedata -application/vnd.ibm.electronic-media emm -application/vnd.ibm.MiniPay mpy -application/vnd.ibm.modcap list3820 listafp afp pseg3820 -application/vnd.ibm.rights-management irm -application/vnd.ibm.secure-container sc -application/vnd.iccprofile icc icm -application/vnd.ieee.1905 1905.1 -application/vnd.igloader igl -application/vnd.imagemeter.folder+zip imf -application/vnd.imagemeter.image+zip imi -application/vnd.immervision-ivp ivp -application/vnd.immervision-ivu ivu -application/vnd.ims.imsccv1p1 imscc -application/vnd.ims.imsccv1p2 -application/vnd.ims.imsccv1p3 -application/vnd.ims.lis.v2.result+json -application/vnd.ims.lti.v2.toolconsumerprofile+json -application/vnd.ims.lti.v2.toolproxy.id+json -application/vnd.ims.lti.v2.toolproxy+json -application/vnd.ims.lti.v2.toolsettings+json -application/vnd.ims.lti.v2.toolsettings.simple+json -application/vnd.informedcontrol.rms+xml -# application/vnd.informix-visionary obsoleted by application/vnd.visionary -application/vnd.infotech.project -application/vnd.infotech.project+xml -application/vnd.innopath.wamp.notification -application/vnd.insors.igm igm -application/vnd.intercon.formnet xpw xpx -application/vnd.intergeo i2g -application/vnd.intertrust.digibox -application/vnd.intertrust.nncp -application/vnd.intu.qbo qbo -application/vnd.intu.qfx qfx -application/vnd.iptc.g2.catalogitem+xml -application/vnd.iptc.g2.conceptitem+xml -application/vnd.iptc.g2.knowledgeitem+xml -application/vnd.iptc.g2.newsitem+xml -application/vnd.iptc.g2.newsmessage+xml -application/vnd.iptc.g2.packageitem+xml -application/vnd.iptc.g2.planningitem+xml -application/vnd.ipunplugged.rcprofile rcprofile -application/vnd.irepository.package+xml irp -application/vnd.is-xpr xpr -application/vnd.isac.fcs fcs -application/vnd.jam jam -application/vnd.japannet-directory-service -application/vnd.japannet-jpnstore-wakeup -application/vnd.japannet-payment-wakeup -application/vnd.japannet-registration -application/vnd.japannet-registration-wakeup -application/vnd.japannet-setstore-wakeup -application/vnd.japannet-verification -application/vnd.japannet-verification-wakeup -application/vnd.jcp.javame.midlet-rms rms -application/vnd.jisp jisp -application/vnd.joost.joda-archive joda -application/vnd.jsk.isdn-ngn -application/vnd.kahootz ktz ktr -application/vnd.kde.karbon karbon -application/vnd.kde.kchart chrt -application/vnd.kde.kformula kfo -application/vnd.kde.kivio flw -application/vnd.kde.kontour kon -application/vnd.kde.kpresenter kpr kpt -application/vnd.kde.kspread ksp -application/vnd.kde.kword kwd kwt -application/vnd.kenameaapp htke -application/vnd.kidspiration kia -application/vnd.Kinar kne knp sdf -application/vnd.koan skp skd skm skt -application/vnd.kodak-descriptor sse -application/vnd.las.las+json lasjson -application/vnd.las.las+xml lasxml -application/vnd.liberty-request+xml -application/vnd.llamagraphics.life-balance.desktop lbd -application/vnd.llamagraphics.life-balance.exchange+xml lbe -application/vnd.lotus-1-2-3 123 wk4 wk3 wk1 -application/vnd.lotus-approach apr vew -application/vnd.lotus-freelance prz pre -application/vnd.lotus-notes nsf ntf ndl ns4 ns3 ns2 nsh nsg -application/vnd.lotus-organizer or3 or2 org -application/vnd.lotus-screencam scm -application/vnd.lotus-wordpro lwp sam -application/vnd.macports.portpkg portpkg -application/vnd.mapbox-vector-tile mvt -application/vnd.marlin.drm.actiontoken+xml -application/vnd.marlin.drm.conftoken+xml -application/vnd.marlin.drm.license+xml -application/vnd.marlin.drm.mdcf mdc -application/vnd.mason+json -application/vnd.maxmind.maxmind-db mmdb -application/vnd.mcd mcd -application/vnd.medcalcdata mc1 -application/vnd.mediastation.cdkey cdkey -application/vnd.meridian-slingshot -application/vnd.MFER mwf -application/vnd.mfmp mfm -application/vnd.micro+json -application/vnd.micrografx.flo flo -application/vnd.micrografx.igx igx -application/vnd.microsoft.portable-executable -application/vnd.microsoft.windows.thumbnail-cache -application/vnd.miele+json -application/vnd.mif mif -application/vnd.minisoft-hp3000-save -application/vnd.mitsubishi.misty-guard.trustweb -application/vnd.Mobius.DAF daf -application/vnd.Mobius.DIS dis -application/vnd.Mobius.MBK mbk -application/vnd.Mobius.MQY mqy -application/vnd.Mobius.MSL msl -application/vnd.Mobius.PLC plc -application/vnd.Mobius.TXF txf -application/vnd.mophun.application mpn -application/vnd.mophun.certificate mpc -application/vnd.motorola.flexsuite -application/vnd.motorola.flexsuite.adsi -application/vnd.motorola.flexsuite.fis -application/vnd.motorola.flexsuite.gotap -application/vnd.motorola.flexsuite.kmr -application/vnd.motorola.flexsuite.ttc -application/vnd.motorola.flexsuite.wem -application/vnd.motorola.iprm -application/vnd.mozilla.xul+xml xul -application/vnd.ms-3mfdocument 3mf -application/vnd.ms-artgalry cil -application/vnd.ms-asf asf -application/vnd.ms-cab-compressed cab -application/vnd.ms-excel xls xlm xla xlc xlt xlw -application/vnd.ms-excel.template.macroEnabled.12 xltm -application/vnd.ms-excel.addin.macroEnabled.12 xlam -application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb -application/vnd.ms-excel.sheet.macroEnabled.12 xlsm -application/vnd.ms-fontobject eot -application/vnd.ms-htmlhelp chm -application/vnd.ms-ims ims -application/vnd.ms-lrm lrm -application/vnd.ms-office.activeX+xml -application/vnd.ms-officetheme thmx -application/vnd.ms-playready.initiator+xml -application/vnd.ms-powerpoint ppt pps pot -application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam -application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm -application/vnd.ms-powerpoint.slide.macroEnabled.12 sldm -application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm -application/vnd.ms-powerpoint.template.macroEnabled.12 potm -application/vnd.ms-PrintDeviceCapabilities+xml -application/vnd.ms-PrintSchemaTicket+xml -application/vnd.ms-project mpp mpt -application/vnd.ms-tnef tnef tnf -application/vnd.ms-windows.devicepairing -application/vnd.ms-windows.nwprinting.oob -application/vnd.ms-windows.printerpairing -application/vnd.ms-windows.wsd.oob -application/vnd.ms-wmdrm.lic-chlg-req -application/vnd.ms-wmdrm.lic-resp -application/vnd.ms-wmdrm.meter-chlg-req -application/vnd.ms-wmdrm.meter-resp -application/vnd.ms-word.document.macroEnabled.12 docm -application/vnd.ms-word.template.macroEnabled.12 dotm -application/vnd.ms-works wcm wdb wks wps -application/vnd.ms-wpl wpl -application/vnd.ms-xpsdocument xps -application/vnd.msa-disk-image msa -application/vnd.mseq mseq -application/vnd.msign -application/vnd.multiad.creator crtr -application/vnd.multiad.creator.cif cif -application/vnd.music-niff -application/vnd.musician mus -application/vnd.muvee.style msty -application/vnd.mynfc taglet -application/vnd.ncd.control -application/vnd.ncd.reference -application/vnd.nearst.inv+json -application/vnd.nervana entity request bkm kcm -application/vnd.netfpx -# ntf: application/vnd.lotus-notes -application/vnd.nitf nitf -application/vnd.neurolanguage.nlu nlu -application/vnd.nintendo.nitro.rom nds -application/vnd.nintendo.snes.rom sfc smc -application/vnd.noblenet-directory nnd -application/vnd.noblenet-sealer nns -application/vnd.noblenet-web nnw -application/vnd.nokia.catalogs -application/vnd.nokia.conml+wbxml -application/vnd.nokia.conml+xml -application/vnd.nokia.iptv.config+xml -application/vnd.nokia.iSDS-radio-presets -application/vnd.nokia.landmark+wbxml -application/vnd.nokia.landmark+xml -application/vnd.nokia.landmarkcollection+xml -application/vnd.nokia.n-gage.ac+xml ac -application/vnd.nokia.n-gage.data ngdat -application/vnd.nokia.n-gage.symbian.install n-gage -application/vnd.nokia.ncd -application/vnd.nokia.pcd+wbxml -application/vnd.nokia.pcd+xml -application/vnd.nokia.radio-preset rpst -application/vnd.nokia.radio-presets rpss -application/vnd.novadigm.EDM edm -application/vnd.novadigm.EDX edx -application/vnd.novadigm.EXT ext -application/vnd.ntt-local.content-share -application/vnd.ntt-local.file-transfer -application/vnd.ntt-local.ogw_remote-access -application/vnd.ntt-local.sip-ta_remote -application/vnd.ntt-local.sip-ta_tcp_stream -application/vnd.oasis.opendocument.chart odc -application/vnd.oasis.opendocument.chart-template otc -application/vnd.oasis.opendocument.database odb -application/vnd.oasis.opendocument.formula odf -# otf: font/otf -application/vnd.oasis.opendocument.formula-template -application/vnd.oasis.opendocument.graphics odg -application/vnd.oasis.opendocument.graphics-template otg -application/vnd.oasis.opendocument.image odi -application/vnd.oasis.opendocument.image-template oti -application/vnd.oasis.opendocument.presentation odp -application/vnd.oasis.opendocument.presentation-template otp -application/vnd.oasis.opendocument.spreadsheet ods -application/vnd.oasis.opendocument.spreadsheet-template ots -application/vnd.oasis.opendocument.text odt -application/vnd.oasis.opendocument.text-master odm -application/vnd.oasis.opendocument.text-template ott -application/vnd.oasis.opendocument.text-web oth -application/vnd.obn -application/vnd.ocf+cbor -application/vnd.oftn.l10n+json -application/vnd.oipf.contentaccessdownload+xml -application/vnd.oipf.contentaccessstreaming+xml -application/vnd.oipf.cspg-hexbinary -application/vnd.oipf.dae.svg+xml -application/vnd.oipf.dae.xhtml+xml -application/vnd.oipf.mippvcontrolmessage+xml -application/vnd.oipf.pae.gem -application/vnd.oipf.spdiscovery+xml -application/vnd.oipf.spdlist+xml -application/vnd.oipf.ueprofile+xml -application/vnd.olpc-sugar xo -application/vnd.oma.bcast.associated-procedure-parameter+xml -application/vnd.oma.bcast.drm-trigger+xml -application/vnd.oma.bcast.imd+xml -application/vnd.oma.bcast.ltkm -application/vnd.oma.bcast.notification+xml -application/vnd.oma.bcast.provisioningtrigger -application/vnd.oma.bcast.sgboot -application/vnd.oma.bcast.sgdd+xml -application/vnd.oma.bcast.sgdu -application/vnd.oma.bcast.simple-symbol-container -application/vnd.oma.bcast.smartcard-trigger+xml -application/vnd.oma.bcast.sprov+xml -application/vnd.oma.bcast.stkm -application/vnd.oma.cab-address-book+xml -application/vnd.oma.cab-feature-handler+xml -application/vnd.oma.cab-pcc+xml -application/vnd.oma.cab-subs-invite+xml -application/vnd.oma.cab-user-prefs+xml -application/vnd.oma.dcd -application/vnd.oma.dcdc -application/vnd.oma.dd2+xml dd2 -application/vnd.oma.drm.risd+xml -application/vnd.oma.group-usage-list+xml -application/vnd.oma.lwm2m+json -application/vnd.oma.lwm2m+tlv -application/vnd.oma.pal+xml -application/vnd.oma.poc.detailed-progress-report+xml -application/vnd.oma.poc.final-report+xml -application/vnd.oma.poc.groups+xml -application/vnd.oma.poc.invocation-descriptor+xml -application/vnd.oma.poc.optimized-progress-report+xml -application/vnd.oma.push -application/vnd.oma.scidm.messages+xml -application/vnd.oma.xcap-directory+xml -application/vnd.oma-scws-config -application/vnd.oma-scws-http-request -application/vnd.oma-scws-http-response -application/vnd.omads-email+xml -application/vnd.omads-file+xml -application/vnd.omads-folder+xml -application/vnd.omaloc-supl-init -application/vnd.onepager tam -application/vnd.onepagertamp tamp -application/vnd.onepagertamx tamx -application/vnd.onepagertat tat -application/vnd.onepagertatp tatp -application/vnd.onepagertatx tatx -application/vnd.openblox.game+xml obgx -application/vnd.openblox.game-binary obg -application/vnd.openeye.oeb oeb -application/vnd.openofficeorg.extension oxt -application/vnd.openstreetmap.data+xml osm -application/vnd.openxmlformats-officedocument.custom-properties+xml -application/vnd.openxmlformats-officedocument.customXmlProperties+xml -application/vnd.openxmlformats-officedocument.drawing+xml -application/vnd.openxmlformats-officedocument.drawingml.chart+xml -application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml -application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml -application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml -application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml -application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml -application/vnd.openxmlformats-officedocument.extended-properties+xml -application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml -application/vnd.openxmlformats-officedocument.presentationml.comments+xml -application/vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml -application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml -application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml -application/vnd.openxmlformats-officedocument.presentationml.presProps+xml -application/vnd.openxmlformats-officedocument.presentationml.presentation pptx -application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml -application/vnd.openxmlformats-officedocument.presentationml.slide sldx -application/vnd.openxmlformats-officedocument.presentationml.slide+xml -application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml -application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml -application/vnd.openxmlformats-officedocument.presentationml.slideUpdateInfo+xml -application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx -application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml -application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml -application/vnd.openxmlformats-officedocument.presentationml.tags+xml -application/vnd.openxmlformats-officedocument.presentationml.template potx -application/vnd.openxmlformats-officedocument.presentationml.template.main+xml -application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx -application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx -application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml -application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml -application/vnd.openxmlformats-officedocument.theme+xml -application/vnd.openxmlformats-officedocument.themeOverride+xml -application/vnd.openxmlformats-officedocument.vmlDrawing -application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.document docx -application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx -application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml -application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml -application/vnd.openxmlformats-package.core-properties+xml -application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml -application/vnd.openxmlformats-package.relationships+xml -application/vnd.oracle.resource+json -application/vnd.orange.indata -application/vnd.osa.netdeploy ndc -application/vnd.osgeo.mapguide.package mgp -# jar: application/x-java-archive -application/vnd.osgi.bundle -application/vnd.osgi.dp dp -application/vnd.osgi.subsystem esa -application/vnd.otps.ct-kip+xml -application/vnd.oxli.countgraph oxlicg -application/vnd.pagerduty+json -application/vnd.palm prc pdb pqa oprc -application/vnd.panoply plp -application/vnd.paos+xml -application/vnd.pawaafile paw -application/vnd.pcos -application/vnd.pg.format str -application/vnd.pg.osasli ei6 -application/vnd.piaccess.application-license pil -application/vnd.picsel efif -application/vnd.pmi.widget wg -application/vnd.poc.group-advertisement+xml -application/vnd.pocketlearn plf -application/vnd.powerbuilder6 pbd -application/vnd.powerbuilder6-s -application/vnd.powerbuilder7 -application/vnd.powerbuilder7-s -application/vnd.powerbuilder75 -application/vnd.powerbuilder75-s -application/vnd.preminet preminet -application/vnd.previewsystems.box box vbox -application/vnd.proteus.magazine mgz -application/vnd.publishare-delta-tree qps -# pti: image/prs.pti -application/vnd.pvi.ptid1 ptid -application/vnd.pwg-multiplexed -application/vnd.pwg-xhtml-print+xml -application/vnd.qualcomm.brew-app-res bar -application/vnd.quarantainenet -application/vnd.Quark.QuarkXPress qxd qxt qwd qwt qxl qxb -application/vnd.quobject-quoxdocument quox quiz -application/vnd.radisys.moml+xml -application/vnd.radisys.msml-audit-conf+xml -application/vnd.radisys.msml-audit-conn+xml -application/vnd.radisys.msml-audit-dialog+xml -application/vnd.radisys.msml-audit-stream+xml -application/vnd.radisys.msml-audit+xml -application/vnd.radisys.msml-conf+xml -application/vnd.radisys.msml-dialog-base+xml -application/vnd.radisys.msml-dialog-fax-detect+xml -application/vnd.radisys.msml-dialog-fax-sendrecv+xml -application/vnd.radisys.msml-dialog-group+xml -application/vnd.radisys.msml-dialog-speech+xml -application/vnd.radisys.msml-dialog-transform+xml -application/vnd.radisys.msml-dialog+xml -application/vnd.radisys.msml+xml -application/vnd.rainstor.data tree -application/vnd.rapid -application/vnd.rar rar -application/vnd.realvnc.bed bed -application/vnd.recordare.musicxml mxl -application/vnd.recordare.musicxml+xml -application/vnd.RenLearn.rlprint -application/vnd.rig.cryptonote cryptonote -application/vnd.route66.link66+xml link66 -# gbr: application/rpki-ghostbusters -application/vnd.rs-274x -application/vnd.ruckus.download -application/vnd.s3sms -application/vnd.sailingtracker.track st -application/vnd.sbm.cid -application/vnd.sbm.mid2 -application/vnd.scribus scd sla slaz -application/vnd.sealed.3df s3df -application/vnd.sealed.csf scsf -application/vnd.sealed.doc sdoc sdo s1w -application/vnd.sealed.eml seml sem -application/vnd.sealed.mht smht smh -application/vnd.sealed.net -# spp: application/scvp-vp-response -application/vnd.sealed.ppt sppt s1p -application/vnd.sealed.tiff stif -application/vnd.sealed.xls sxls sxl s1e -# stm: audio/x-stm -application/vnd.sealedmedia.softseal.html stml s1h -application/vnd.sealedmedia.softseal.pdf spdf spd s1a -application/vnd.seemail see -application/vnd.sema sema -application/vnd.semd semd -application/vnd.semf semf -application/vnd.shana.informed.formdata ifm -application/vnd.shana.informed.formtemplate itp -application/vnd.shana.informed.interchange iif -application/vnd.shana.informed.package ipk -application/vnd.SimTech-MindMapper twd twds -application/vnd.siren+json -application/vnd.smaf mmf -application/vnd.smart.notebook notebook -application/vnd.smart.teacher teacher -application/vnd.software602.filler.form+xml fo -application/vnd.software602.filler.form-xml-zip zfo -application/vnd.solent.sdkm+xml sdkm sdkd -application/vnd.spotfire.dxp dxp -application/vnd.spotfire.sfs sfs -application/vnd.sss-cod -application/vnd.sss-dtf -application/vnd.sss-ntf -application/vnd.stepmania.package smzip -application/vnd.stepmania.stepchart sm -application/vnd.street-stream -application/vnd.sun.wadl+xml wadl -application/vnd.sus-calendar sus susp -application/vnd.svd -application/vnd.swiftview-ics -application/vnd.syncml+xml xsm -application/vnd.syncml.dm+wbxml bdm -application/vnd.syncml.dm+xml xdm -application/vnd.syncml.dm.notification -application/vnd.syncml.dmddf+wbxml -application/vnd.syncml.dmddf+xml ddf -application/vnd.syncml.dmtnds+wbxml -application/vnd.syncml.dmtnds+xml -application/vnd.syncml.ds.notification -application/vnd.tableschema+json -application/vnd.tao.intent-module-archive tao -application/vnd.tcpdump.pcap pcap cap dmp -application/vnd.theqvd qvd -application/vnd.tmd.mediaflex.api+xml -application/vnd.tml vfr viaframe -application/vnd.tmobile-livetv tmo -application/vnd.tri.onesource -application/vnd.trid.tpt tpt -application/vnd.triscape.mxs mxs -application/vnd.trueapp tra -application/vnd.truedoc -# cab: application/vnd.ms-cab-compressed -application/vnd.ubisoft.webplayer -application/vnd.ufdl ufdl ufd frm -application/vnd.uiq.theme utz -application/vnd.umajin umj -application/vnd.unity unityweb -application/vnd.uoml+xml uoml uo -application/vnd.uplanet.alert -application/vnd.uplanet.alert-wbxml -application/vnd.uplanet.bearer-choice -application/vnd.uplanet.bearer-choice-wbxml -application/vnd.uplanet.cacheop -application/vnd.uplanet.cacheop-wbxml -application/vnd.uplanet.channel -application/vnd.uplanet.channel-wbxml -application/vnd.uplanet.list -application/vnd.uplanet.list-wbxml -application/vnd.uplanet.listcmd -application/vnd.uplanet.listcmd-wbxml -application/vnd.uplanet.signal -application/vnd.uri-map urim urimap -application/vnd.valve.source.material vmt -application/vnd.vcx vcx -# sxi: application/vnd.sun.xml.impress -application/vnd.vd-study mxi study-inter model-inter -# mcd: application/vnd.mcd -application/vnd.vectorworks vwx -application/vnd.vel+json -application/vnd.verimatrix.vcas -application/vnd.vidsoft.vidconference vsc -application/vnd.visio vsd vst vsw vss -application/vnd.visionary vis -# vsc: application/vnd.vidsoft.vidconference -application/vnd.vividence.scriptfile -application/vnd.vsf vsf -application/vnd.wap.sic sic -application/vnd.wap.slc slc -application/vnd.wap.wbxml wbxml -application/vnd.wap.wmlc wmlc -application/vnd.wap.wmlscriptc wmlsc -application/vnd.webturbo wtb -application/vnd.wfa.p2p p2p -application/vnd.wfa.wsc wsc -application/vnd.windows.devicepairing -application/vnd.wmc wmc -application/vnd.wmf.bootstrap -# nb: application/mathematica for now -application/vnd.wolfram.mathematica -application/vnd.wolfram.mathematica.package m -application/vnd.wolfram.player nbp -application/vnd.wordperfect wpd -application/vnd.wqd wqd -application/vnd.wrq-hp3000-labelled -application/vnd.wt.stf stf -application/vnd.wv.csp+xml -application/vnd.wv.csp+wbxml wv -application/vnd.wv.ssp+xml -application/vnd.xacml+json -application/vnd.xara xar -application/vnd.xfdl xfdl xfd -application/vnd.xfdl.webform -application/vnd.xmi+xml -application/vnd.xmpie.cpkg cpkg -application/vnd.xmpie.dpkg dpkg -# dpkg: application/vnd.xmpie.dpkg -application/vnd.xmpie.plan -application/vnd.xmpie.ppkg ppkg -application/vnd.xmpie.xlim xlim -application/vnd.yamaha.hv-dic hvd -application/vnd.yamaha.hv-script hvs -application/vnd.yamaha.hv-voice hvp -application/vnd.yamaha.openscoreformat osf -application/vnd.yamaha.openscoreformat.osfpvg+xml -application/vnd.yamaha.remote-setup -application/vnd.yamaha.smaf-audio saf -application/vnd.yamaha.smaf-phrase spf -application/vnd.yamaha.through-ngn -application/vnd.yamaha.tunnel-udpencap -application/vnd.yaoweme yme -application/vnd.yellowriver-custom-menu cmp -application/vnd.zul zir zirz -application/vnd.zzazz.deck+xml zaz -application/voicexml+xml vxml -application/vq-rtcp-xr -application/watcherinfo+xml wif -application/whoispp-query -application/whoispp-response -application/widget wgt -application/wita -application/wordperfect5.1 -application/wsdl+xml wsdl -application/wspolicy+xml wspolicy -# yes, this *is* IANA registered despite of x- -application/x-www-form-urlencoded -application/x400-bp -application/xacml+xml -application/xcap-att+xml xav -application/xcap-caps+xml xca -application/xcap-diff+xml xdf -application/xcap-el+xml xel -application/xcap-error+xml xer -application/xcap-ns+xml xns -application/xcon-conference-info-diff+xml -application/xcon-conference-info+xml -application/xenc+xml -application/xhtml+xml xhtml xhtm xht -# xml, xsd, rng: text/xml -application/xml -# mod: audio/x-mod -application/xml-dtd dtd -# ent: text/xml-external-parsed-entity -application/xml-external-parsed-entity -application/xml-patch+xml -application/xmpp+xml -application/xop+xml xop -application/xslt+xml xsl xslt -application/xv+xml mxml xhvml xvml xvm -application/yang yang -application/yang-data+json -application/yang-data+xml -application/yang-patch+json -application/yang-patch+xml -application/yin+xml yin -application/zip zip -application/zlib -audio/1d-interleaved-parityfec -audio/32kadpcm 726 -# 3gp, 3gpp: video/3gpp -audio/3gpp -# 3g2, 3gpp2: video/3gpp2 -audio/3gpp2 -audio/ac3 ac3 -audio/AMR amr -audio/AMR-WB awb -audio/amr-wb+ -audio/aptx -audio/asc acn -# aa3, omg: audio/ATRAC3 -audio/ATRAC-ADVANCED-LOSSLESS aal -# aa3, omg: audio/ATRAC3 -audio/ATRAC-X atx -audio/ATRAC3 at3 aa3 omg -audio/basic au snd -audio/BV16 -audio/BV32 -audio/clearmode -audio/CN -audio/DAT12 -audio/dls dls -audio/dsr-es201108 -audio/dsr-es202050 -audio/dsr-es202211 -audio/dsr-es202212 -audio/DV -audio/DVI4 -audio/eac3 -audio/encaprtp -audio/EVRC evc -# qcp: audio/qcelp -audio/EVRC-QCP -audio/EVRC0 -audio/EVRC1 -audio/EVRCB evb -audio/EVRCB0 -audio/EVRCB1 -audio/EVRCNW enw -audio/EVRCNW0 -audio/EVRCNW1 -audio/EVRCWB evw -audio/EVRCWB0 -audio/EVRCWB1 -audio/EVS -audio/example -audio/fwdred -audio/G711-0 -audio/G719 -audio/G722 -audio/G7221 -audio/G723 -audio/G726-16 -audio/G726-24 -audio/G726-32 -audio/G726-40 -audio/G728 -audio/G729 -audio/G7291 -audio/G729D -audio/G729E -audio/GSM -audio/GSM-EFR -audio/GSM-HR-08 -audio/iLBC lbc -audio/ip-mr_v2.5 -# wav: audio/x-wav -audio/L16 l16 -audio/L20 -audio/L24 -audio/L8 -audio/LPC -audio/MELP -audio/MELP600 -audio/MELP1200 -audio/MELP2400 -audio/mobile-xmf mxmf -# mp4, mpg4: video/mp4, see RFC 4337 -audio/mp4 m4a -audio/MP4A-LATM -audio/MPA -audio/mpa-robust -audio/mpeg mp3 mpga mp1 mp2 -audio/mpeg4-generic -audio/ogg oga ogg opus spx -audio/opus -audio/parityfec -audio/PCMA -audio/PCMA-WB -audio/PCMU -audio/PCMU-WB -audio/prs.sid sid psid -audio/qcelp qcp -audio/raptorfec -audio/RED -audio/rtp-enc-aescm128 -audio/rtp-midi -audio/rtploopback -audio/rtx -audio/SMV smv -# qcp: audio/qcelp, see RFC 3625 -audio/SMV-QCP -audio/SMV0 -# mid: audio/midi -audio/sp-midi -audio/speex -audio/t140c -audio/t38 -audio/telephone-event -audio/tone -audio/UEMCLIP -audio/ulpfec -audio/VDVI -audio/VMR-WB -audio/vnd.3gpp.iufp -audio/vnd.4SB -audio/vnd.audikoz koz -audio/vnd.CELP -audio/vnd.cisco.nse -audio/vnd.cmles.radio-events -audio/vnd.cns.anp1 -audio/vnd.cns.inf1 -audio/vnd.dece.audio uva uvva -audio/vnd.digital-winds eol -audio/vnd.dlna.adts -audio/vnd.dolby.heaac.1 -audio/vnd.dolby.heaac.2 -audio/vnd.dolby.mlp mlp -audio/vnd.dolby.mps -audio/vnd.dolby.pl2 -audio/vnd.dolby.pl2x -audio/vnd.dolby.pl2z -audio/vnd.dolby.pulse.1 -audio/vnd.dra -# wav: audio/x-wav, cpt: application/mac-compactpro -audio/vnd.dts dts -audio/vnd.dts.hd dtshd -# dvb: video/vnd.dvb.file -audio/vnd.dvb.file -audio/vnd.everad.plj plj -# rm: audio/x-pn-realaudio -audio/vnd.hns.audio -audio/vnd.lucent.voice lvp -audio/vnd.ms-playready.media.pya pya -# mxmf: audio/mobile-xmf -audio/vnd.nokia.mobile-xmf -audio/vnd.nortel.vbk vbk -audio/vnd.nuera.ecelp4800 ecelp4800 -audio/vnd.nuera.ecelp7470 ecelp7470 -audio/vnd.nuera.ecelp9600 ecelp9600 -audio/vnd.octel.sbc -# audio/vnd.qcelp deprecated in favour of audio/qcelp -audio/vnd.rhetorex.32kadpcm -audio/vnd.rip rip -audio/vnd.sealedmedia.softseal.mpeg smp3 smp s1m -audio/vnd.vmx.cvsd -audio/vorbis -audio/vorbis-config -font/collection ttc -font/otf otf -font/sfnt -font/ttf ttf -font/woff woff -font/woff2 woff2 -image/bmp bmp dib -image/cgm cgm -image/dicom-rle drle -image/emf emf -image/example -image/fits fits fit fts -image/g3fax -image/gif gif -image/ief ief -image/jls jls -image/jp2 jp2 jpg2 -image/jpeg jpg jpeg jpe jfif -image/jpm jpm jpgm -image/jpx jpx jpf -image/ktx ktx -image/naplps -image/png png -image/prs.btif btif btf -image/prs.pti pti -image/pwg-raster -image/svg+xml svg svgz -image/t38 t38 -image/tiff tiff tif -image/tiff-fx tfx -image/vnd.adobe.photoshop psd -image/vnd.airzip.accelerator.azv azv -image/vnd.cns.inf2 -image/vnd.dece.graphic uvi uvvi uvg uvvg -image/vnd.djvu djvu djv -# sub: text/vnd.dvb.subtitle -image/vnd.dvb.subtitle -image/vnd.dwg dwg -image/vnd.dxf dxf -image/vnd.fastbidsheet fbs -image/vnd.fpx fpx -image/vnd.fst fst -image/vnd.fujixerox.edmics-mmr mmr -image/vnd.fujixerox.edmics-rlc rlc -image/vnd.globalgraphics.pgb pgb -image/vnd.microsoft.icon ico -image/vnd.mix -image/vnd.mozilla.apng apng -image/vnd.ms-modi mdi -image/vnd.net-fpx -image/vnd.radiance hdr rgbe xyze -image/vnd.sealed.png spng spn s1n -image/vnd.sealedmedia.softseal.gif sgif sgi s1g -image/vnd.sealedmedia.softseal.jpg sjpg sjp s1j -image/vnd.svf -image/vnd.tencent.tap tap -image/vnd.valve.source.texture vtf -image/vnd.wap.wbmp wbmp -image/vnd.xiff xif -image/vnd.zbrush.pcx pcx -image/wmf wmf -message/CPIM -message/delivery-status -message/disposition-notification -message/example -message/external-body -message/feedback-report -message/global u8msg -message/global-delivery-status u8dsn -message/global-disposition-notification u8mdn -message/global-headers u8hdr -message/http -# cl: application/simple-filter+xml -message/imdn+xml -# message/news obsoleted by message/rfc822 -message/partial -message/rfc822 eml mail art -message/s-http -message/sip -message/sipfrag -message/tracking-status -message/vnd.si.simp -# wsc: application/vnd.wfa.wsc -message/vnd.wfa.wsc -model/example -model/gltf+json gltf -model/iges igs iges -model/mesh msh mesh silo -model/vnd.collada+xml dae -model/vnd.dwf dwf -# 3dml, 3dm: text/vnd.in3d.3dml -model/vnd.flatland.3dml -model/vnd.gdl gdl gsm win dor lmp rsm msm ism -model/vnd.gs-gdl -model/vnd.gtw gtw -model/vnd.moml+xml moml -model/vnd.mts mts -model/vnd.opengex ogex -model/vnd.parasolid.transmit.binary x_b xmt_bin -model/vnd.parasolid.transmit.text x_t xmt_txt -model/vnd.rosette.annotated-data-model -model/vnd.valve.source.compiled-map bsp -model/vnd.vtu vtu -model/vrml wrl vrml -# x3db: model/x3d+xml -model/x3d+fastinfoset -# x3d: application/vnd.hzn-3d-crossword -model/x3d+xml x3db -model/x3d-vrml x3dv x3dvz -multipart/alternative -multipart/appledouble -multipart/byteranges -multipart/digest -multipart/encrypted -multipart/form-data -multipart/header-set -multipart/mixed -multipart/parallel -multipart/related -multipart/report -multipart/signed -multipart/vnd.bint.med-plus bmed -multipart/voice-message vpm -multipart/x-mixed-replace -text/1d-interleaved-parityfec -text/cache-manifest appcache manifest -text/calendar ics ifb -text/css css -text/csv csv -text/csv-schema csvs -text/directory -text/dns soa zone -text/encaprtp -# text/ecmascript obsoleted by application/ecmascript -text/enriched -text/example -text/fwdred -text/grammar-ref-list -text/html html htm -# text/javascript obsoleted by application/javascript -text/jcr-cnd cnd -text/markdown markdown md -text/mizar miz -text/n3 n3 -text/parameters -text/parityfec -text/plain txt asc text pm el c h cc hh cxx hxx f90 conf log -text/provenance-notation provn -text/prs.fallenstein.rst rst -text/prs.lines.tag tag dsc -text/prs.prop.logic -text/raptorfec -text/RED -text/rfc822-headers -text/richtext rtx -# rtf: application/rtf -text/rtf -text/rtp-enc-aescm128 -text/rtploopback -text/rtx -text/sgml sgml sgm -text/strings -text/t140 -text/tab-separated-values tsv -text/troff t tr roff -text/turtle ttl -text/ulpfec -text/uri-list uris uri -text/vcard vcf vcard -text/vnd.a a -text/vnd.abc abc -text/vnd.ascii-art ascii -# curl: application/vnd.curl -text/vnd.curl -text/vnd.debian.copyright copyright -text/vnd.DMClientScript dms -text/vnd.dvb.subtitle sub -text/vnd.esmertec.theme-descriptor jtd -text/vnd.fly fly -text/vnd.fmi.flexstor flx -text/vnd.graphviz gv dot -text/vnd.in3d.3dml 3dml 3dm -text/vnd.in3d.spot spot spo -text/vnd.IPTC.NewsML -text/vnd.IPTC.NITF -text/vnd.latex-z -text/vnd.motorola.reflex -text/vnd.ms-mediapackage mpf -text/vnd.net2phone.commcenter.command ccc -text/vnd.radisys.msml-basic-layout -text/vnd.si.uricatalogue uric -text/vnd.sun.j2me.app-descriptor jad -text/vnd.trolltech.linguist ts -text/vnd.wap.si si -text/vnd.wap.sl sl -text/vnd.wap.wml wml -text/vnd.wap.wmlscript wmls -text/xml xml xsd rng -text/xml-external-parsed-entity ent -video/1d-interleaved-parityfec -video/3gpp 3gp 3gpp -video/3gpp2 3g2 3gpp2 -video/3gpp-tt -video/BMPEG -video/BT656 -video/CelB -video/DV -video/encaprtp -video/example -video/H261 -video/H263 -video/H263-1998 -video/H263-2000 -video/H264 -video/H264-RCDO -video/H264-SVC -video/H265 -video/iso.segment m4s -video/JPEG -video/jpeg2000 -video/mj2 mj2 mjp2 -video/MP1S -video/MP2P -video/MP2T -video/mp4 mp4 mpg4 m4v -video/MP4V-ES -video/mpeg mpeg mpg mpe m1v m2v -video/mpeg4-generic -video/MPV -video/nv -video/ogg ogv -video/parityfec -video/pointer -video/quicktime mov qt -video/raptorfec -video/raw -video/rtp-enc-aescm128 -video/rtploopback -video/rtx -video/SMPTE292M -video/ulpfec -video/vc1 -video/vnd.CCTV -video/vnd.dece.hd uvh uvvh -video/vnd.dece.mobile uvm uvvm -video/vnd.dece.mp4 uvu uvvu -video/vnd.dece.pd uvp uvvp -video/vnd.dece.sd uvs uvvs -video/vnd.dece.video uvv uvvv -video/vnd.directv.mpeg -video/vnd.directv.mpeg-tts -video/vnd.dlna.mpeg-tts -video/vnd.dvb.file dvb -video/vnd.fvt fvt -# rm: audio/x-pn-realaudio -video/vnd.hns.video -video/vnd.iptvforum.1dparityfec-1010 -video/vnd.iptvforum.1dparityfec-2005 -video/vnd.iptvforum.2dparityfec-1010 -video/vnd.iptvforum.2dparityfec-2005 -video/vnd.iptvforum.ttsavc -video/vnd.iptvforum.ttsmpeg2 -video/vnd.motorola.video -video/vnd.motorola.videop -video/vnd.mpegurl mxu m4u -video/vnd.ms-playready.media.pyv pyv -video/vnd.nokia.interleaved-multimedia nim -video/vnd.nokia.videovoip -# mp4: video/mp4 -video/vnd.objectvideo -video/vnd.radgamettools.bink bik bk2 -video/vnd.radgamettools.smacker smk -video/vnd.sealed.mpeg1 smpg s11 -# smpg: video/vnd.sealed.mpeg1 -video/vnd.sealed.mpeg4 s14 -video/vnd.sealed.swf sswf ssw -video/vnd.sealedmedia.softseal.mov smov smo s1q -# uvu, uvvu: video/vnd.dece.mp4 -video/vnd.uvvu.mp4 -video/vnd.vivo viv -video/VP8 - -# Non-IANA types - -application/mac-compactpro cpt -application/metalink+xml metalink -application/owl+xml owx -application/rss+xml rss -application/vnd.android.package-archive apk -application/vnd.oma.dd+xml dd -application/vnd.oma.drm.content dcf -# odf: application/vnd.oasis.opendocument.formula -application/vnd.oma.drm.dcf o4a o4v -application/vnd.oma.drm.message dm -application/vnd.oma.drm.rights+wbxml drc -application/vnd.oma.drm.rights+xml dr -application/vnd.sun.xml.calc sxc -application/vnd.sun.xml.calc.template stc -application/vnd.sun.xml.draw sxd -application/vnd.sun.xml.draw.template std -application/vnd.sun.xml.impress sxi -application/vnd.sun.xml.impress.template sti -application/vnd.sun.xml.math sxm -application/vnd.sun.xml.writer sxw -application/vnd.sun.xml.writer.global sxg -application/vnd.sun.xml.writer.template stw -application/vnd.symbian.install sis -application/vnd.wap.mms-message mms -application/x-annodex anx -application/x-bcpio bcpio -application/x-bittorrent torrent -application/x-bzip2 bz2 -application/x-cdlink vcd -application/x-chrome-extension crx -application/x-cpio cpio -application/x-csh csh -application/x-director dcr dir dxr -application/x-dvi dvi -application/x-futuresplash spl -application/x-gtar gtar -application/x-hdf hdf -application/x-java-archive jar -application/x-java-jnlp-file jnlp -application/x-java-pack200 pack -application/x-killustrator kil -application/x-latex latex -application/x-netcdf nc cdf -application/x-perl pl -application/x-rpm rpm -application/x-sh sh -application/x-shar shar -application/x-stuffit sit -application/x-sv4cpio sv4cpio -application/x-sv4crc sv4crc -application/x-tar tar -application/x-tcl tcl -application/x-tex tex -application/x-texinfo texinfo texi -application/x-troff-man man 1 2 3 4 5 6 7 8 -application/x-troff-me me -application/x-troff-ms ms -application/x-ustar ustar -application/x-wais-source src -application/x-xpinstall xpi -application/x-xspf+xml xspf -application/x-xz xz -audio/midi mid midi kar -audio/x-aiff aif aiff aifc -audio/x-annodex axa -audio/x-flac flac -audio/x-matroska mka -audio/x-mod mod ult uni m15 mtm 669 med -audio/x-mpegurl m3u -audio/x-ms-wax wax -audio/x-ms-wma wma -audio/x-pn-realaudio ram rm -audio/x-realaudio ra -audio/x-s3m s3m -audio/x-stm stm -audio/x-wav wav -chemical/x-xyz xyz -image/webp webp -image/x-cmu-raster ras -image/x-portable-anymap pnm -image/x-portable-bitmap pbm -image/x-portable-graymap pgm -image/x-portable-pixmap ppm -image/x-rgb rgb -image/x-targa tga -image/x-xbitmap xbm -image/x-xpixmap xpm -image/x-xwindowdump xwd -text/html-sandboxed sandboxed -text/x-pod pod -text/x-setext etx -video/webm webm -video/x-annodex axv -video/x-flv flv -video/x-javafx fxm -video/x-matroska mkv -video/x-matroska-3d mk3d -video/x-ms-asf asx -video/x-ms-wm wm -video/x-ms-wmv wmv -video/x-ms-wmx wmx -video/x-ms-wvx wvx -video/x-msvideo avi -video/x-sgi-movie movie -x-conference/x-cooltalk ice -x-epoc/x-sisx-app sisx diff --git a/cmd/swarm/run_test.go b/cmd/swarm/run_test.go deleted file mode 100644 index b68a1e897c..0000000000 --- a/cmd/swarm/run_test.go +++ /dev/null @@ -1,502 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "context" - "crypto/ecdsa" - "flag" - "fmt" - "io/ioutil" - "net" - "os" - "path" - "path/filepath" - "runtime" - "sync" - "syscall" - "testing" - "time" - - "github.com/docker/docker/pkg/reexec" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/internal/cmdtest" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm" - "github.com/ethereum/go-ethereum/swarm/api" - swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" -) - -var loglevel = flag.Int("loglevel", 3, "verbosity of logs") - -func init() { - // Run the app if we've been exec'd as "swarm-test" in runSwarm. - reexec.Register("swarm-test", func() { - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - os.Exit(0) - }) -} - -const clusterSize = 3 - -func serverFunc(api *api.API) swarmhttp.TestServer { - return swarmhttp.NewServer(api, "") -} -func TestMain(m *testing.M) { - // check if we have been reexec'd - if reexec.Init() { - return - } - os.Exit(m.Run()) -} - -func runSwarm(t *testing.T, args ...string) *cmdtest.TestCmd { - tt := cmdtest.NewTestCmd(t, nil) - - found := false - for _, v := range args { - if v == "--bootnodes" { - found = true - break - } - } - - if !found { - args = append([]string{"--bootnodes", ""}, args...) - } - - // Boot "swarm". This actually runs the test binary but the TestMain - // function will prevent any tests from running. - tt.Run("swarm-test", args...) - - return tt -} - -type testCluster struct { - Nodes []*testNode - TmpDir string -} - -// newTestCluster starts a test swarm cluster of the given size. -// -// A temporary directory is created and each node gets a data directory inside -// it. -// -// Each node listens on 127.0.0.1 with random ports for both the HTTP and p2p -// ports (assigned by first listening on 127.0.0.1:0 and then passing the ports -// as flags). -// -// When starting more than one node, they are connected together using the -// admin SetPeer RPC method. - -func newTestCluster(t *testing.T, size int) *testCluster { - cluster := &testCluster{} - defer func() { - if t.Failed() { - cluster.Shutdown() - } - }() - - tmpdir, err := ioutil.TempDir("", "swarm-test") - if err != nil { - t.Fatal(err) - } - cluster.TmpDir = tmpdir - - // start the nodes - cluster.StartNewNodes(t, size) - - if size == 1 { - return cluster - } - - // connect the nodes together - for _, node := range cluster.Nodes { - if err := node.Client.Call(nil, "admin_addPeer", cluster.Nodes[0].Enode); err != nil { - t.Fatal(err) - } - } - - // wait until all nodes have the correct number of peers -outer: - for _, node := range cluster.Nodes { - var peers []*p2p.PeerInfo - for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(50 * time.Millisecond) { - if err := node.Client.Call(&peers, "admin_peers"); err != nil { - t.Fatal(err) - } - if len(peers) == len(cluster.Nodes)-1 { - continue outer - } - } - t.Fatalf("%s only has %d / %d peers", node.Name, len(peers), len(cluster.Nodes)-1) - } - - return cluster -} - -func (c *testCluster) Shutdown() { - c.Stop() - c.Cleanup() -} - -func (c *testCluster) Stop() { - for _, node := range c.Nodes { - node.Shutdown() - } -} - -func (c *testCluster) StartNewNodes(t *testing.T, size int) { - c.Nodes = make([]*testNode, 0, size) - - errors := make(chan error, size) - nodes := make(chan *testNode, size) - for i := 0; i < size; i++ { - go func(nodeIndex int) { - dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", nodeIndex)) - if err := os.Mkdir(dir, 0700); err != nil { - errors <- err - return - } - - node := newTestNode(t, dir) - node.Name = fmt.Sprintf("swarm%02d", nodeIndex) - nodes <- node - }(i) - } - - for i := 0; i < size; i++ { - select { - case node := <-nodes: - c.Nodes = append(c.Nodes, node) - case err := <-errors: - t.Error(err) - } - } - - if t.Failed() { - c.Shutdown() - t.FailNow() - } -} - -func (c *testCluster) StartExistingNodes(t *testing.T, size int, bzzaccount string) { - c.Nodes = make([]*testNode, 0, size) - for i := 0; i < size; i++ { - dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", i)) - node := existingTestNode(t, dir, bzzaccount) - node.Name = fmt.Sprintf("swarm%02d", i) - - c.Nodes = append(c.Nodes, node) - } -} - -func (c *testCluster) Cleanup() { - os.RemoveAll(c.TmpDir) -} - -type testNode struct { - Name string - Addr string - URL string - Enode string - Dir string - IpcPath string - PrivateKey *ecdsa.PrivateKey - Client *rpc.Client - Cmd *cmdtest.TestCmd -} - -const testPassphrase = "swarm-test-passphrase" - -func getTestAccount(t *testing.T, dir string) (conf *node.Config, account accounts.Account) { - // create key - conf = &node.Config{ - DataDir: dir, - IPCPath: "bzzd.ipc", - NoUSB: true, - } - n, err := node.New(conf) - if err != nil { - t.Fatal(err) - } - account, err = n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore).NewAccount(testPassphrase) - if err != nil { - t.Fatal(err) - } - - // use a unique IPCPath when running tests on Windows - if runtime.GOOS == "windows" { - conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", account.Address.String()) - } - - return conf, account -} - -func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode { - conf, _ := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - // use a unique IPCPath when running tests on Windows - if runtime.GOOS == "windows" { - conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", bzzaccount) - } - - // assign ports - ports, err := getAvailableTCPPorts(2) - if err != nil { - t.Fatal(err) - } - p2pPort := ports[0] - httpPort := ports[1] - - // start the node - node.Cmd = runSwarm(t, - "--bootnodes", "", - "--port", p2pPort, - "--nat", "extip:127.0.0.1", - "--datadir", dir, - "--ipcpath", conf.IPCPath, - "--ens-api", "", - "--bzzaccount", bzzaccount, - "--bzznetworkid", "321", - "--bzzport", httpPort, - "--verbosity", fmt.Sprint(*loglevel), - ) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - // ensure that all ports have active listeners - // so that the next node will not get the same - // when calling getAvailableTCPPorts - err = waitTCPPorts(ctx, ports...) - if err != nil { - t.Fatal(err) - } - - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - node.Addr = net.JoinHostPort("127.0.0.1", info.Port) - node.URL = "http://" + node.Addr - - var nodeInfo p2p.NodeInfo - if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { - t.Fatal(err) - } - node.Enode = nodeInfo.Enode - node.IpcPath = conf.IPCPath - return node -} - -func newTestNode(t *testing.T, dir string) *testNode { - - conf, account := getTestAccount(t, dir) - ks := keystore.NewKeyStore(path.Join(dir, "keystore"), 1<<18, 1) - - pk := decryptStoreAccount(ks, account.Address.Hex(), []string{testPassphrase}) - - node := &testNode{Dir: dir, PrivateKey: pk} - - // assign ports - ports, err := getAvailableTCPPorts(2) - if err != nil { - t.Fatal(err) - } - p2pPort := ports[0] - httpPort := ports[1] - - // start the node - node.Cmd = runSwarm(t, - "--bootnodes", "", - "--port", p2pPort, - "--nat", "extip:127.0.0.1", - "--datadir", dir, - "--ipcpath", conf.IPCPath, - "--ens-api", "", - "--bzzaccount", account.Address.String(), - "--bzznetworkid", "321", - "--bzzport", httpPort, - "--verbosity", fmt.Sprint(*loglevel), - ) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - // ensure that all ports have active listeners - // so that the next node will not get the same - // when calling getAvailableTCPPorts - err = waitTCPPorts(ctx, ports...) - if err != nil { - t.Fatal(err) - } - - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - node.Addr = net.JoinHostPort("127.0.0.1", info.Port) - node.URL = "http://" + node.Addr - - var nodeInfo p2p.NodeInfo - if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { - t.Fatal(err) - } - node.Enode = nodeInfo.Enode - node.IpcPath = conf.IPCPath - return node -} - -func (n *testNode) Shutdown() { - if n.Cmd != nil { - n.Cmd.Kill() - } -} - -// getAvailableTCPPorts returns a set of ports that -// nothing is listening on at the time. -// -// Function assignTCPPort cannot be called in sequence -// and guardantee that the same port will be returned in -// different calls as the listener is closed within the function, -// not after all listeners are started and selected unique -// available ports. -func getAvailableTCPPorts(count int) (ports []string, err error) { - for i := 0; i < count; i++ { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return nil, err - } - // defer close in the loop to be sure the same port will not - // be selected in the next iteration - defer l.Close() - - _, port, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return nil, err - } - ports = append(ports, port) - } - return ports, nil -} - -// waitTCPPorts blocks until tcp connections can be -// established on all provided ports. It runs all -// ports dialers in parallel, and returns the first -// encountered error. -// See waitTCPPort also. -func waitTCPPorts(ctx context.Context, ports ...string) error { - var err error - // mu locks err variable that is assigned in - // other goroutines - var mu sync.Mutex - - // cancel is canceling all goroutines - // when the firs error is returned - // to prevent unnecessary waiting - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - var wg sync.WaitGroup - for _, port := range ports { - wg.Add(1) - go func(port string) { - defer wg.Done() - - e := waitTCPPort(ctx, port) - - mu.Lock() - defer mu.Unlock() - if e != nil && err == nil { - err = e - cancel() - } - }(port) - } - wg.Wait() - - return err -} - -// waitTCPPort blocks until tcp connection can be established -// ona provided port. It has a 3 minute timeout as maximum, -// to prevent long waiting, but it can be shortened with -// a provided context instance. Dialer has a 10 second timeout -// in every iteration, and connection refused error will be -// retried in 100 milliseconds periods. -func waitTCPPort(ctx context.Context, port string) error { - ctx, cancel := context.WithTimeout(ctx, 3*time.Minute) - defer cancel() - - for { - c, err := (&net.Dialer{Timeout: 10 * time.Second}).DialContext(ctx, "tcp", "127.0.0.1:"+port) - if err != nil { - if operr, ok := err.(*net.OpError); ok { - if syserr, ok := operr.Err.(*os.SyscallError); ok && syserr.Err == syscall.ECONNREFUSED { - time.Sleep(100 * time.Millisecond) - continue - } - } - return err - } - return c.Close() - } -} diff --git a/cmd/swarm/swarm-smoke/feed_upload_and_sync.go b/cmd/swarm/swarm-smoke/feed_upload_and_sync.go deleted file mode 100644 index b5ffc43d20..0000000000 --- a/cmd/swarm/swarm-smoke/feed_upload_and_sync.go +++ /dev/null @@ -1,291 +0,0 @@ -package main - -import ( - "bytes" - "crypto/md5" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/ethereum/go-ethereum/swarm/testutil" - "github.com/pborman/uuid" - cli "gopkg.in/urfave/cli.v1" -) - -const ( - feedRandomDataLength = 8 -) - -func feedUploadAndSyncCmd(ctx *cli.Context) error { - errc := make(chan error) - - go func() { - errc <- feedUploadAndSync(ctx) - }() - - select { - case err := <-errc: - if err != nil { - metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) - } - return err - case <-time.After(time.Duration(timeout) * time.Second): - metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) - - return fmt.Errorf("timeout after %v sec", timeout) - } -} - -func feedUploadAndSync(c *cli.Context) error { - log.Info("generating and uploading feeds to " + httpEndpoint(hosts[0]) + " and syncing") - - // create a random private key to sign updates with and derive the address - pkFile, err := ioutil.TempFile("", "swarm-feed-smoke-test") - if err != nil { - return err - } - defer pkFile.Close() - defer os.Remove(pkFile.Name()) - - privkeyHex := "0000000000000000000000000000000000000000000000000000000000001976" - privKey, err := crypto.HexToECDSA(privkeyHex) - if err != nil { - return err - } - user := crypto.PubkeyToAddress(privKey.PublicKey) - userHex := hexutil.Encode(user.Bytes()) - - // save the private key to a file - _, err = io.WriteString(pkFile, privkeyHex) - if err != nil { - return err - } - - // keep hex strings for topic and subtopic - var topicHex string - var subTopicHex string - - // and create combination hex topics for bzz-feed retrieval - // xor'ed with topic (zero-value topic if no topic) - var subTopicOnlyHex string - var mergedSubTopicHex string - - // generate random topic and subtopic and put a hex on them - topicBytes, err := generateRandomData(feed.TopicLength) - topicHex = hexutil.Encode(topicBytes) - subTopicBytes, err := generateRandomData(8) - subTopicHex = hexutil.Encode(subTopicBytes) - if err != nil { - return err - } - mergedSubTopic, err := feed.NewTopic(subTopicHex, topicBytes) - if err != nil { - return err - } - mergedSubTopicHex = hexutil.Encode(mergedSubTopic[:]) - subTopicOnlyBytes, err := feed.NewTopic(subTopicHex, nil) - if err != nil { - return err - } - subTopicOnlyHex = hexutil.Encode(subTopicOnlyBytes[:]) - - // create feed manifest, topic only - var out bytes.Buffer - cmd := exec.Command("swarm", "--bzzapi", httpEndpoint(hosts[0]), "feed", "create", "--topic", topicHex, "--user", userHex) - cmd.Stdout = &out - log.Debug("create feed manifest topic cmd", "cmd", cmd) - err = cmd.Run() - if err != nil { - return err - } - manifestWithTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) - if len(manifestWithTopic) != 64 { - return fmt.Errorf("unknown feed create manifest hash format (topic): (%d) %s", len(out.String()), manifestWithTopic) - } - log.Debug("create topic feed", "manifest", manifestWithTopic) - out.Reset() - - // create feed manifest, subtopic only - cmd = exec.Command("swarm", "--bzzapi", httpEndpoint(hosts[0]), "feed", "create", "--name", subTopicHex, "--user", userHex) - cmd.Stdout = &out - log.Debug("create feed manifest subtopic cmd", "cmd", cmd) - err = cmd.Run() - if err != nil { - return err - } - manifestWithSubTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) - if len(manifestWithSubTopic) != 64 { - return fmt.Errorf("unknown feed create manifest hash format (subtopic): (%d) %s", len(out.String()), manifestWithSubTopic) - } - log.Debug("create subtopic feed", "manifest", manifestWithTopic) - out.Reset() - - // create feed manifest, merged topic - cmd = exec.Command("swarm", "--bzzapi", httpEndpoint(hosts[0]), "feed", "create", "--topic", topicHex, "--name", subTopicHex, "--user", userHex) - cmd.Stdout = &out - log.Debug("create feed manifest mergetopic cmd", "cmd", cmd) - err = cmd.Run() - if err != nil { - log.Error(err.Error()) - return err - } - manifestWithMergedTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) - if len(manifestWithMergedTopic) != 64 { - return fmt.Errorf("unknown feed create manifest hash format (mergedtopic): (%d) %s", len(out.String()), manifestWithMergedTopic) - } - log.Debug("create mergedtopic feed", "manifest", manifestWithMergedTopic) - out.Reset() - - // create test data - data, err := generateRandomData(feedRandomDataLength) - if err != nil { - return err - } - h := md5.New() - h.Write(data) - dataHash := h.Sum(nil) - dataHex := hexutil.Encode(data) - - // update with topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, dataHex) - cmd.Stdout = &out - log.Debug("update feed manifest topic cmd", "cmd", cmd) - err = cmd.Run() - if err != nil { - return err - } - log.Debug("feed update topic", "out", out) - out.Reset() - - // update with subtopic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--name", subTopicHex, dataHex) - cmd.Stdout = &out - log.Debug("update feed manifest subtopic cmd", "cmd", cmd) - err = cmd.Run() - if err != nil { - return err - } - log.Debug("feed update subtopic", "out", out) - out.Reset() - - // update with merged topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, "--name", subTopicHex, dataHex) - cmd.Stdout = &out - log.Debug("update feed manifest merged topic cmd", "cmd", cmd) - err = cmd.Run() - if err != nil { - return err - } - log.Debug("feed update mergedtopic", "out", out) - out.Reset() - - time.Sleep(3 * time.Second) - - // retrieve the data - wg := sync.WaitGroup{} - for _, host := range hosts { - // raw retrieve, topic only - for _, hex := range []string{topicHex, subTopicOnlyHex, mergedSubTopicHex} { - wg.Add(1) - ruid := uuid.New()[:8] - go func(hex string, endpoint string, ruid string) { - for { - err := fetchFeed(hex, userHex, httpEndpoint(host), dataHash, ruid) - if err != nil { - continue - } - - wg.Done() - return - } - }(hex, httpEndpoint(host), ruid) - } - } - wg.Wait() - log.Info("all endpoints synced random data successfully") - - // upload test file - log.Info("feed uploading to "+httpEndpoint(hosts[0])+" and syncing", "seed", seed) - - randomBytes := testutil.RandomBytes(seed, filesize*1000) - - hash, err := upload(randomBytes, httpEndpoint(hosts[0])) - if err != nil { - return err - } - hashBytes, err := hexutil.Decode("0x" + hash) - if err != nil { - return err - } - multihashHex := hexutil.Encode(hashBytes) - fileHash := h.Sum(nil) - - log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fileHash)) - - // update file with topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, multihashHex) - cmd.Stdout = &out - err = cmd.Run() - if err != nil { - return err - } - log.Debug("feed update topic", "out", out) - out.Reset() - - // update file with subtopic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--name", subTopicHex, multihashHex) - cmd.Stdout = &out - err = cmd.Run() - if err != nil { - return err - } - log.Debug("feed update subtopic", "out", out) - out.Reset() - - // update file with merged topic - cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", httpEndpoint(hosts[0]), "feed", "update", "--topic", topicHex, "--name", subTopicHex, multihashHex) - cmd.Stdout = &out - err = cmd.Run() - if err != nil { - return err - } - log.Debug("feed update mergedtopic", "out", out) - out.Reset() - - time.Sleep(3 * time.Second) - - for _, host := range hosts { - - // manifest retrieve, topic only - for _, url := range []string{manifestWithTopic, manifestWithSubTopic, manifestWithMergedTopic} { - wg.Add(1) - ruid := uuid.New()[:8] - go func(url string, endpoint string, ruid string) { - for { - err := fetch(url, endpoint, fileHash, ruid) - if err != nil { - continue - } - - wg.Done() - return - } - }(url, httpEndpoint(host), ruid) - } - - } - wg.Wait() - log.Info("all endpoints synced random file successfully") - - return nil -} diff --git a/cmd/swarm/swarm-smoke/main.go b/cmd/swarm/swarm-smoke/main.go deleted file mode 100644 index 03e2cc2c48..0000000000 --- a/cmd/swarm/swarm-smoke/main.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "os" - "sort" - - "github.com/ethereum/go-ethereum/cmd/utils" - gethmetrics "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/metrics/influxdb" - swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics" - "github.com/ethereum/go-ethereum/swarm/tracing" - - "github.com/ethereum/go-ethereum/log" - - cli "gopkg.in/urfave/cli.v1" -) - -var ( - gitCommit string // Git SHA1 commit hash of the release (set via linker flags) -) - -var ( - allhosts string - hosts []string - filesize int - syncDelay bool - inputSeed int - httpPort int - wsPort int - verbosity int - timeout int - single bool - onlyUpload bool -) - -func main() { - - app := cli.NewApp() - app.Name = "smoke-test" - app.Usage = "" - - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "hosts", - Value: "", - Usage: "comma-separated list of swarm hosts", - Destination: &allhosts, - }, - cli.IntFlag{ - Name: "http-port", - Value: 80, - Usage: "http port", - Destination: &httpPort, - }, - cli.IntFlag{ - Name: "ws-port", - Value: 8546, - Usage: "ws port", - Destination: &wsPort, - }, - cli.IntFlag{ - Name: "seed", - Value: 0, - Usage: "input seed in case we need deterministic upload", - Destination: &inputSeed, - }, - cli.IntFlag{ - Name: "filesize", - Value: 1024, - Usage: "file size for generated random file in KB", - Destination: &filesize, - }, - cli.BoolFlag{ - Name: "sync-delay", - Usage: "wait for content to be synced", - Destination: &syncDelay, - }, - cli.IntFlag{ - Name: "verbosity", - Value: 1, - Usage: "verbosity", - Destination: &verbosity, - }, - cli.IntFlag{ - Name: "timeout", - Value: 180, - Usage: "timeout in seconds after which kill the process", - Destination: &timeout, - }, - cli.BoolFlag{ - Name: "single", - Usage: "whether to fetch content from a single node or from all nodes", - Destination: &single, - }, - cli.BoolFlag{ - Name: "only-upload", - Usage: "whether to only upload content to a single node without fetching", - Destination: &onlyUpload, - }, - } - - app.Flags = append(app.Flags, []cli.Flag{ - utils.MetricsEnabledFlag, - swarmmetrics.MetricsInfluxDBEndpointFlag, - swarmmetrics.MetricsInfluxDBDatabaseFlag, - swarmmetrics.MetricsInfluxDBUsernameFlag, - swarmmetrics.MetricsInfluxDBPasswordFlag, - swarmmetrics.MetricsInfluxDBTagsFlag, - }...) - - app.Flags = append(app.Flags, tracing.Flags...) - - app.Commands = []cli.Command{ - { - Name: "upload_and_sync", - Aliases: []string{"c"}, - Usage: "upload and sync", - Action: wrapCliCommand("upload-and-sync", uploadAndSyncCmd), - }, - { - Name: "feed_sync", - Aliases: []string{"f"}, - Usage: "feed update generate, upload and sync", - Action: wrapCliCommand("feed-and-sync", feedUploadAndSyncCmd), - }, - { - Name: "upload_speed", - Aliases: []string{"u"}, - Usage: "measure upload speed", - Action: wrapCliCommand("upload-speed", uploadSpeedCmd), - }, - { - Name: "sliding_window", - Aliases: []string{"s"}, - Usage: "measure network aggregate capacity", - Action: wrapCliCommand("sliding-window", slidingWindowCmd), - }, - } - - sort.Sort(cli.FlagsByName(app.Flags)) - sort.Sort(cli.CommandsByName(app.Commands)) - - app.Before = func(ctx *cli.Context) error { - tracing.Setup(ctx) - return nil - } - - app.After = func(ctx *cli.Context) error { - return emitMetrics(ctx) - } - - err := app.Run(os.Args) - if err != nil { - log.Error(err.Error()) - - os.Exit(1) - } -} - -func emitMetrics(ctx *cli.Context) error { - if gethmetrics.Enabled { - var ( - endpoint = ctx.GlobalString(swarmmetrics.MetricsInfluxDBEndpointFlag.Name) - database = ctx.GlobalString(swarmmetrics.MetricsInfluxDBDatabaseFlag.Name) - username = ctx.GlobalString(swarmmetrics.MetricsInfluxDBUsernameFlag.Name) - password = ctx.GlobalString(swarmmetrics.MetricsInfluxDBPasswordFlag.Name) - tags = ctx.GlobalString(swarmmetrics.MetricsInfluxDBTagsFlag.Name) - ) - - tagsMap := utils.SplitTagsFlag(tags) - tagsMap["version"] = gitCommit - tagsMap["filesize"] = fmt.Sprintf("%v", filesize) - - return influxdb.InfluxDBWithTagsOnce(gethmetrics.DefaultRegistry, endpoint, database, username, password, "swarm-smoke.", tagsMap) - } - - return nil -} diff --git a/cmd/swarm/swarm-smoke/sliding_window.go b/cmd/swarm/swarm-smoke/sliding_window.go deleted file mode 100644 index 6ca3d3947f..0000000000 --- a/cmd/swarm/swarm-smoke/sliding_window.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "math/rand" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/testutil" - "github.com/pborman/uuid" - - cli "gopkg.in/urfave/cli.v1" -) - -type uploadResult struct { - hash string - digest []byte -} - -func slidingWindowCmd(ctx *cli.Context) error { - errc := make(chan error) - - go func() { - errc <- slidingWindow(ctx) - }() - - err := <-errc - if err != nil { - metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) - } - return err -} - -func slidingWindow(ctx *cli.Context) error { - var hashes []uploadResult //swarm hashes of the uploads - nodes := len(hosts) - log.Info("sliding window test started", "nodes", nodes, "filesize(kb)", filesize, "timeout", timeout) - uploadedBytes := 0 - networkDepth := 0 - errored := false - -outer: - for { - seed = int(time.Now().UTC().UnixNano()) - log.Info("uploading to "+httpEndpoint(hosts[0])+" and syncing", "seed", seed) - - t1 := time.Now() - - randomBytes := testutil.RandomBytes(seed, filesize*1000) - - hash, err := upload(randomBytes, httpEndpoint(hosts[0])) - if err != nil { - log.Error(err.Error()) - return err - } - - metrics.GetOrRegisterResettingTimer("sliding-window.upload-time", nil).UpdateSince(t1) - metrics.GetOrRegisterGauge("sliding-window.upload-depth", nil).Update(int64(len(hashes))) - - fhash, err := digest(bytes.NewReader(randomBytes)) - if err != nil { - log.Error(err.Error()) - return err - } - - log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash), "wait for sync", syncDelay) - hashes = append(hashes, uploadResult{hash: hash, digest: fhash}) - - if syncDelay { - waitToSync() - } - - uploadedBytes += filesize * 1000 - q := make(chan struct{}, 1) - d := make(chan struct{}) - defer close(q) - defer close(d) - for i, v := range hashes { - timeoutC := time.After(time.Duration(timeout) * time.Second) - errored = false - - task: - for { - select { - case q <- struct{}{}: - go func() { - var start time.Time - done := false - for !done { - log.Info("trying to retrieve hash", "hash", v.hash) - idx := 1 + rand.Intn(len(hosts)-1) - ruid := uuid.New()[:8] - start = time.Now() - // fetch hangs when swarm dies out, so we have to jump through a bit more hoops to actually - // catch the timeout, but also allow this retry logic - err := fetch(v.hash, httpEndpoint(hosts[idx]), v.digest, ruid) - if err != nil { - log.Error("error fetching hash", "err", err) - continue - } - done = true - } - metrics.GetOrRegisterResettingTimer("sliding-window.single.fetch-time", nil).UpdateSince(start) - d <- struct{}{} - }() - case <-d: - <-q - break task - case <-timeoutC: - errored = true - log.Error("error retrieving hash. timeout", "hash idx", i) - metrics.GetOrRegisterCounter("sliding-window.single.error", nil).Inc(1) - break outer - default: - } - } - - networkDepth = i - metrics.GetOrRegisterGauge("sliding-window.network-depth", nil).Update(int64(networkDepth)) - log.Info("sliding window test successfully fetched file", "currentDepth", networkDepth) - // this test might take a long time to finish - but we'd like to see metrics while they accumulate and not just when - // the test finishes. therefore emit the metrics on each iteration - emitMetrics(ctx) - } - } - - log.Info("sliding window test finished", "errored?", errored, "networkDepth", networkDepth, "networkDepth(kb)", networkDepth*filesize) - log.Info("stats", "uploadedFiles", len(hashes), "uploadedKb", uploadedBytes/1000, "filesizeKb", filesize) - - return nil -} diff --git a/cmd/swarm/swarm-smoke/upload_and_sync.go b/cmd/swarm/swarm-smoke/upload_and_sync.go deleted file mode 100644 index 7338e34737..0000000000 --- a/cmd/swarm/swarm-smoke/upload_and_sync.go +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "context" - "encoding/hex" - "fmt" - "io/ioutil" - "math/rand" - "os" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/testutil" - - cli "gopkg.in/urfave/cli.v1" -) - -func uploadAndSyncCmd(ctx *cli.Context) error { - // use input seed if it has been set - if inputSeed != 0 { - seed = inputSeed - } - - randomBytes := testutil.RandomBytes(seed, filesize*1000) - - errc := make(chan error) - - go func() { - errc <- uploadAndSync(ctx, randomBytes) - }() - - var err error - select { - case err = <-errc: - if err != nil { - metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) - } - case <-time.After(time.Duration(timeout) * time.Second): - metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) - - err = fmt.Errorf("timeout after %v sec", timeout) - } - - // trigger debug functionality on randomBytes - e := trackChunks(randomBytes[:], true) - if e != nil { - log.Error(e.Error()) - } - - return err -} - -func trackChunks(testData []byte, submitMetrics bool) error { - addrs, err := getAllRefs(testData) - if err != nil { - return err - } - - for i, ref := range addrs { - log.Debug(fmt.Sprintf("ref %d", i), "ref", ref) - } - - var globalYes, globalNo int - var globalMu sync.Mutex - var hasErr bool - - var wg sync.WaitGroup - wg.Add(len(hosts)) - - var mu sync.Mutex // mutex protecting the allHostsChunks and bzzAddrs maps - allHostChunks := map[string]string{} // host->bitvector of presence for chunks - bzzAddrs := map[string]string{} // host->bzzAddr - - for _, host := range hosts { - host := host - go func() { - defer wg.Done() - httpHost := fmt.Sprintf("ws://%s:%d", host, 8546) - - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - - rpcClient, err := rpc.DialContext(ctx, httpHost) - if rpcClient != nil { - defer rpcClient.Close() - } - if err != nil { - log.Error("error dialing host", "err", err, "host", httpHost) - hasErr = true - return - } - - hostChunks, err := getChunksBitVectorFromHost(rpcClient, addrs) - if err != nil { - log.Error("error getting chunks bit vector from host", "err", err, "host", httpHost) - hasErr = true - return - } - - bzzAddr, err := getBzzAddrFromHost(rpcClient) - if err != nil { - log.Error("error getting bzz addrs from host", "err", err, "host", httpHost) - hasErr = true - return - } - - mu.Lock() - allHostChunks[host] = hostChunks - bzzAddrs[host] = bzzAddr - mu.Unlock() - - yes, no := 0, 0 - for _, val := range hostChunks { - if val == '1' { - yes++ - } else { - no++ - } - } - - if no == 0 { - log.Info("host reported to have all chunks", "host", host) - } - - log.Debug("chunks", "chunks", hostChunks, "yes", yes, "no", no, "host", host) - - if submitMetrics { - globalMu.Lock() - globalYes += yes - globalNo += no - globalMu.Unlock() - } - }() - } - - wg.Wait() - - checkChunksVsMostProxHosts(addrs, allHostChunks, bzzAddrs) - - if !hasErr && submitMetrics { - // remove the chunks stored on the uploader node - globalYes -= len(addrs) - - metrics.GetOrRegisterCounter("deployment.chunks.yes", nil).Inc(int64(globalYes)) - metrics.GetOrRegisterCounter("deployment.chunks.no", nil).Inc(int64(globalNo)) - metrics.GetOrRegisterCounter("deployment.chunks.refs", nil).Inc(int64(len(addrs))) - } - - return nil -} - -// getChunksBitVectorFromHost returns a bit vector of presence for a given slice of chunks from a given host -func getChunksBitVectorFromHost(client *rpc.Client, addrs []storage.Address) (string, error) { - var hostChunks string - - err := client.Call(&hostChunks, "bzz_has", addrs) - if err != nil { - return "", err - } - - return hostChunks, nil -} - -// getBzzAddrFromHost returns the bzzAddr for a given host -func getBzzAddrFromHost(client *rpc.Client) (string, error) { - var hive string - - err := client.Call(&hive, "bzz_hive") - if err != nil { - return "", err - } - - // we make an ugly assumption about the output format of the hive.String() method - // ideally we should replace this with an API call that returns the bzz addr for a given host, - // but this also works for now (provided we don't change the hive.String() method, which we haven't in some time - ss := strings.Split(strings.Split(hive, "\n")[3], " ") - return ss[len(ss)-1], nil -} - -// checkChunksVsMostProxHosts is checking: -// 1. whether a chunk has been found at less than 2 hosts. Considering our NN size, this should not happen. -// 2. if a chunk is not found at its closest node. This should also not happen. -// Together with the --only-upload flag, we could run this smoke test and make sure that our syncing -// functionality is correct (without even trying to retrieve the content). -// -// addrs - a slice with all uploaded chunk refs -// allHostChunks - host->bit vector, showing what chunks are present on what hosts -// bzzAddrs - host->bzz address, used when determining the most proximate host for a given chunk -func checkChunksVsMostProxHosts(addrs []storage.Address, allHostChunks map[string]string, bzzAddrs map[string]string) { - for k, v := range bzzAddrs { - log.Trace("bzzAddr", "bzz", v, "host", k) - } - - for i := range addrs { - var foundAt int - maxProx := -1 - var maxProxHost string - for host := range allHostChunks { - if allHostChunks[host][i] == '1' { - foundAt++ - } - - ba, err := hex.DecodeString(bzzAddrs[host]) - if err != nil { - panic(err) - } - - // calculate the host closest to any chunk - prox := chunk.Proximity(addrs[i], ba) - if prox > maxProx { - maxProx = prox - maxProxHost = host - } - } - - if allHostChunks[maxProxHost][i] == '0' { - log.Error("chunk not found at max prox host", "ref", addrs[i], "host", maxProxHost, "bzzAddr", bzzAddrs[maxProxHost]) - } else { - log.Trace("chunk present at max prox host", "ref", addrs[i], "host", maxProxHost, "bzzAddr", bzzAddrs[maxProxHost]) - } - - // if chunk found at less than 2 hosts - if foundAt < 2 { - log.Error("chunk found at less than two hosts", "foundAt", foundAt, "ref", addrs[i]) - } - } -} - -func getAllRefs(testData []byte) (storage.AddressCollection, error) { - datadir, err := ioutil.TempDir("", "chunk-debug") - if err != nil { - return nil, fmt.Errorf("unable to create temp dir: %v", err) - } - defer os.RemoveAll(datadir) - fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32), chunk.NewTags()) - if err != nil { - return nil, err - } - - reader := bytes.NewReader(testData) - return fileStore.GetAllReferences(context.Background(), reader, false) -} - -func uploadAndSync(c *cli.Context, randomBytes []byte) error { - log.Info("uploading to "+httpEndpoint(hosts[0])+" and syncing", "seed", seed) - - t1 := time.Now() - hash, err := upload(randomBytes, httpEndpoint(hosts[0])) - if err != nil { - log.Error(err.Error()) - return err - } - t2 := time.Since(t1) - metrics.GetOrRegisterResettingTimer("upload-and-sync.upload-time", nil).Update(t2) - - fhash, err := digest(bytes.NewReader(randomBytes)) - if err != nil { - log.Error(err.Error()) - return err - } - - log.Info("uploaded successfully", "hash", hash, "took", t2, "digest", fmt.Sprintf("%x", fhash)) - - // wait to sync and log chunks before fetch attempt, only if syncDelay is set to true - if syncDelay { - waitToSync() - - log.Debug("chunks before fetch attempt", "hash", hash) - - err = trackChunks(randomBytes, false) - if err != nil { - log.Error(err.Error()) - } - } - - if onlyUpload { - log.Debug("only-upload is true, stoppping test", "hash", hash) - return nil - } - - randIndex := 1 + rand.Intn(len(hosts)-1) - - for { - start := time.Now() - err := fetch(hash, httpEndpoint(hosts[randIndex]), fhash, "") - if err != nil { - time.Sleep(2 * time.Second) - continue - } - ended := time.Since(start) - - metrics.GetOrRegisterResettingTimer("upload-and-sync.single.fetch-time", nil).Update(ended) - log.Info("fetch successful", "took", ended, "endpoint", httpEndpoint(hosts[randIndex])) - break - } - - return nil -} - -func isSyncing(wsHost string) (bool, error) { - rpcClient, err := rpc.Dial(wsHost) - if rpcClient != nil { - defer rpcClient.Close() - } - - if err != nil { - log.Error("error dialing host", "err", err) - return false, err - } - - var isSyncing bool - err = rpcClient.Call(&isSyncing, "bzz_isSyncing") - if err != nil { - log.Error("error calling host for isSyncing", "err", err) - return false, err - } - - log.Debug("isSyncing result", "host", wsHost, "isSyncing", isSyncing) - - return isSyncing, nil -} - -func waitToSync() { - t1 := time.Now() - - ns := uint64(1) - - for ns > 0 { - time.Sleep(3 * time.Second) - - notSynced := uint64(0) - var wg sync.WaitGroup - wg.Add(len(hosts)) - for i := 0; i < len(hosts); i++ { - i := i - go func(idx int) { - stillSyncing, err := isSyncing(wsEndpoint(hosts[idx])) - - if stillSyncing || err != nil { - atomic.AddUint64(¬Synced, 1) - } - wg.Done() - }(i) - } - wg.Wait() - - ns = atomic.LoadUint64(¬Synced) - } - - t2 := time.Since(t1) - metrics.GetOrRegisterResettingTimer("upload-and-sync.single.wait-for-sync.deployment", nil).Update(t2) -} diff --git a/cmd/swarm/swarm-smoke/upload_speed.go b/cmd/swarm/swarm-smoke/upload_speed.go deleted file mode 100644 index 047ea00925..0000000000 --- a/cmd/swarm/swarm-smoke/upload_speed.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/testutil" - - cli "gopkg.in/urfave/cli.v1" -) - -func uploadSpeedCmd(ctx *cli.Context) error { - log.Info("uploading to "+hosts[0], "seed", seed) - randomBytes := testutil.RandomBytes(seed, filesize*1000) - - errc := make(chan error) - - go func() { - errc <- uploadSpeed(ctx, randomBytes) - }() - - select { - case err := <-errc: - if err != nil { - metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) - } - return err - case <-time.After(time.Duration(timeout) * time.Second): - metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) - - // trigger debug functionality on randomBytes - - return fmt.Errorf("timeout after %v sec", timeout) - } -} - -func uploadSpeed(c *cli.Context, data []byte) error { - t1 := time.Now() - hash, err := upload(data, hosts[0]) - if err != nil { - log.Error(err.Error()) - return err - } - metrics.GetOrRegisterCounter("upload-speed.upload-time", nil).Inc(int64(time.Since(t1))) - - fhash, err := digest(bytes.NewReader(data)) - if err != nil { - log.Error(err.Error()) - return err - } - - log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash)) - return nil -} diff --git a/cmd/swarm/swarm-smoke/util.go b/cmd/swarm/swarm-smoke/util.go deleted file mode 100644 index b95f993e8e..0000000000 --- a/cmd/swarm/swarm-smoke/util.go +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "context" - "crypto/md5" - crand "crypto/rand" - "errors" - "fmt" - "io" - "io/ioutil" - "math/rand" - "net/http" - "net/http/httptrace" - "os" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/api/client" - "github.com/ethereum/go-ethereum/swarm/spancontext" - opentracing "github.com/opentracing/opentracing-go" - cli "gopkg.in/urfave/cli.v1" -) - -var ( - commandName = "" - seed = int(time.Now().UTC().UnixNano()) -) - -func init() { - rand.Seed(int64(seed)) -} - -func httpEndpoint(host string) string { - return fmt.Sprintf("http://%s:%d", host, httpPort) -} - -func wsEndpoint(host string) string { - return fmt.Sprintf("ws://%s:%d", host, wsPort) -} - -func wrapCliCommand(name string, command func(*cli.Context) error) func(*cli.Context) error { - return func(ctx *cli.Context) error { - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(verbosity), log.StreamHandler(os.Stdout, log.TerminalFormat(false)))) - - commandName = name - - hosts = strings.Split(allhosts, ",") - - defer func(now time.Time) { - totalTime := time.Since(now) - log.Info("total time", "time", totalTime, "kb", filesize) - metrics.GetOrRegisterResettingTimer(name+".total-time", nil).Update(totalTime) - }(time.Now()) - - log.Info("smoke test starting", "task", name, "timeout", timeout) - metrics.GetOrRegisterCounter(name, nil).Inc(1) - - return command(ctx) - } -} - -func fetchFeed(topic string, user string, endpoint string, original []byte, ruid string) error { - ctx, sp := spancontext.StartSpan(context.Background(), "feed-and-sync.fetch") - defer sp.Finish() - - log.Trace("sleeping", "ruid", ruid) - time.Sleep(3 * time.Second) - - log.Trace("http get request (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user) - - var tn time.Time - reqUri := endpoint + "/bzz-feed:/?topic=" + topic + "&user=" + user - req, _ := http.NewRequest("GET", reqUri, nil) - - opentracing.GlobalTracer().Inject( - sp.Context(), - opentracing.HTTPHeaders, - opentracing.HTTPHeadersCarrier(req.Header)) - - trace := client.GetClientTrace("feed-and-sync - http get", "feed-and-sync", ruid, &tn) - - req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) - transport := http.DefaultTransport - - //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - - tn = time.Now() - res, err := transport.RoundTrip(req) - if err != nil { - log.Error(err.Error(), "ruid", ruid) - return err - } - - log.Trace("http get response (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user, "code", res.StatusCode, "len", res.ContentLength) - - if res.StatusCode != 200 { - return fmt.Errorf("expected status code %d, got %v (ruid %v)", 200, res.StatusCode, ruid) - } - - defer res.Body.Close() - - rdigest, err := digest(res.Body) - if err != nil { - log.Warn(err.Error(), "ruid", ruid) - return err - } - - if !bytes.Equal(rdigest, original) { - err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) - log.Warn(err.Error(), "ruid", ruid) - return err - } - - log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) - - return nil -} - -// fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file -func fetch(hash string, endpoint string, original []byte, ruid string) error { - ctx, sp := spancontext.StartSpan(context.Background(), "upload-and-sync.fetch") - defer sp.Finish() - - log.Info("http get request", "ruid", ruid, "endpoint", endpoint, "hash", hash) - - var tn time.Time - reqUri := endpoint + "/bzz:/" + hash + "/" - req, _ := http.NewRequest("GET", reqUri, nil) - - opentracing.GlobalTracer().Inject( - sp.Context(), - opentracing.HTTPHeaders, - opentracing.HTTPHeadersCarrier(req.Header)) - - trace := client.GetClientTrace(commandName+" - http get", commandName, ruid, &tn) - - req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) - transport := http.DefaultTransport - - //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - - tn = time.Now() - res, err := transport.RoundTrip(req) - if err != nil { - log.Error(err.Error(), "ruid", ruid) - return err - } - log.Info("http get response", "ruid", ruid, "endpoint", endpoint, "hash", hash, "code", res.StatusCode, "len", res.ContentLength) - - if res.StatusCode != 200 { - err := fmt.Errorf("expected status code %d, got %v", 200, res.StatusCode) - log.Warn(err.Error(), "ruid", ruid) - return err - } - - defer res.Body.Close() - - rdigest, err := digest(res.Body) - if err != nil { - log.Warn(err.Error(), "ruid", ruid) - return err - } - - if !bytes.Equal(rdigest, original) { - err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) - log.Warn(err.Error(), "ruid", ruid) - return err - } - - log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) - - return nil -} - -// upload an arbitrary byte as a plaintext file to `endpoint` using the api client -func upload(data []byte, endpoint string) (string, error) { - swarm := client.NewClient(endpoint) - f := &client.File{ - ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), - ManifestEntry: api.ManifestEntry{ - ContentType: "text/plain", - Mode: 0660, - Size: int64(len(data)), - }, - } - - // upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded. - return swarm.Upload(f, "", false) -} - -func digest(r io.Reader) ([]byte, error) { - h := md5.New() - _, err := io.Copy(h, r) - if err != nil { - return nil, err - } - return h.Sum(nil), nil -} - -// generates random data in heap buffer -func generateRandomData(datasize int) ([]byte, error) { - b := make([]byte, datasize) - c, err := crand.Read(b) - if err != nil { - return nil, err - } else if c != datasize { - return nil, errors.New("short read") - } - return b, nil -} diff --git a/cmd/swarm/swarm-snapshot/create.go b/cmd/swarm/swarm-snapshot/create.go deleted file mode 100644 index 434561a491..0000000000 --- a/cmd/swarm/swarm-snapshot/create.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - cli "gopkg.in/urfave/cli.v1" -) - -// create is used as the entry function for "create" app command. -func create(ctx *cli.Context) error { - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) - - if len(ctx.Args()) < 1 { - return errors.New("argument should be the filename to verify or write-to") - } - filename, err := touchPath(ctx.Args()[0]) - if err != nil { - return err - } - return createSnapshot(filename, ctx.Int("nodes"), strings.Split(ctx.String("services"), ",")) -} - -// createSnapshot creates a new snapshot on filesystem with provided filename, -// number of nodes and service names. -func createSnapshot(filename string, nodes int, services []string) (err error) { - log.Debug("create snapshot", "filename", filename, "nodes", nodes, "services", services) - - sim := simulation.New(map[string]simulation.ServiceFunc{ - "bzz": func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - hp := network.NewHiveParams() - hp.KeepAliveInterval = time.Duration(200) * time.Millisecond - hp.Discovery = true // discovery must be enabled when creating a snapshot - - // store the kademlia in the bucket, needed later in the WaitTillHealthy function - bucket.Store(simulation.BucketKeyKademlia, kad) - - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - return network.NewBzz(config, kad, nil, nil, nil), nil, nil - }, - }) - defer sim.Close() - - ids, err := sim.AddNodes(nodes) - if err != nil { - return fmt.Errorf("add nodes: %v", err) - } - - err = sim.Net.ConnectNodesRing(ids) - if err != nil { - return fmt.Errorf("connect nodes: %v", err) - } - - ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancelSimRun() - if _, err := sim.WaitTillHealthy(ctx); err != nil { - return fmt.Errorf("wait for healthy kademlia: %v", err) - } - - var snap *simulations.Snapshot - if len(services) > 0 { - // If service names are provided, include them in the snapshot. - // But, check if "bzz" service is not among them to remove it - // form the snapshot as it exists on snapshot creation. - var removeServices []string - var wantBzz bool - for _, s := range services { - if s == "bzz" { - wantBzz = true - break - } - } - if !wantBzz { - removeServices = []string{"bzz"} - } - snap, err = sim.Net.SnapshotWithServices(services, removeServices) - } else { - snap, err = sim.Net.Snapshot() - } - if err != nil { - return fmt.Errorf("create snapshot: %v", err) - } - jsonsnapshot, err := json.Marshal(snap) - if err != nil { - return fmt.Errorf("json encode snapshot: %v", err) - } - return ioutil.WriteFile(filename, jsonsnapshot, 0666) -} - -// touchPath creates an empty file and all subdirectories -// that are missing. -func touchPath(filename string) (string, error) { - if path.IsAbs(filename) { - if _, err := os.Stat(filename); err == nil { - // path exists, overwrite - return filename, nil - } - } - - d, f := path.Split(filename) - dir, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - return "", err - } - - _, err = os.Stat(path.Join(dir, filename)) - if err == nil { - // path exists, overwrite - return filename, nil - } - - dirPath := path.Join(dir, d) - filePath := path.Join(dirPath, f) - if d != "" { - err = os.MkdirAll(dirPath, os.ModeDir) - if err != nil { - return "", err - } - } - - return filePath, nil -} diff --git a/cmd/swarm/swarm-snapshot/create_test.go b/cmd/swarm/swarm-snapshot/create_test.go deleted file mode 100644 index 4cd78f35ae..0000000000 --- a/cmd/swarm/swarm-snapshot/create_test.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "sort" - "strconv" - "strings" - "testing" - - "github.com/ethereum/go-ethereum/p2p/simulations" -) - -// TestSnapshotCreate is a high level e2e test that tests for snapshot generation. -// It runs a few "create" commands with different flag values and loads generated -// snapshot files to validate their content. -func TestSnapshotCreate(t *testing.T) { - t.Skip("test is flaky. disabling until underlying problem is addressed") - - for _, v := range []struct { - name string - nodes int - services string - }{ - { - name: "defaults", - }, - { - name: "more nodes", - nodes: defaultNodes + 4, - }, - { - name: "services", - services: "stream,pss,zorglub", - }, - { - name: "services with bzz", - services: "bzz,pss", - }, - } { - t.Run(v.name, func(t *testing.T) { - t.Parallel() - - file, err := ioutil.TempFile("", "swarm-snapshot") - if err != nil { - t.Fatal(err) - } - defer os.Remove(file.Name()) - - if err = file.Close(); err != nil { - t.Error(err) - } - - args := []string{"create"} - if v.nodes > 0 { - args = append(args, "--nodes", strconv.Itoa(v.nodes)) - } - if v.services != "" { - args = append(args, "--services", v.services) - } - testCmd := runSnapshot(t, append(args, file.Name())...) - - testCmd.WaitExit() - if code := testCmd.ExitStatus(); code != 0 { - t.Fatalf("command exit code %v, expected 0", code) - } - - f, err := os.Open(file.Name()) - if err != nil { - t.Fatal(err) - } - defer func() { - err := f.Close() - if err != nil { - t.Error("closing snapshot file", "err", err) - } - }() - - b, err := ioutil.ReadAll(f) - if err != nil { - t.Fatal(err) - } - var snap simulations.Snapshot - err = json.Unmarshal(b, &snap) - if err != nil { - t.Fatal(err) - } - - wantNodes := v.nodes - if wantNodes == 0 { - wantNodes = defaultNodes - } - gotNodes := len(snap.Nodes) - if gotNodes != wantNodes { - t.Errorf("got %v nodes, want %v", gotNodes, wantNodes) - } - - if len(snap.Conns) == 0 { - t.Error("no connections in a snapshot") - } - - var wantServices []string - if v.services != "" { - wantServices = strings.Split(v.services, ",") - } else { - wantServices = []string{"bzz"} - } - // sort service names so they can be comparable - // as strings to every node sorted services - sort.Strings(wantServices) - - for i, n := range snap.Nodes { - gotServices := n.Node.Config.Services - sort.Strings(gotServices) - if fmt.Sprint(gotServices) != fmt.Sprint(wantServices) { - t.Errorf("got services %v for node %v, want %v", gotServices, i, wantServices) - } - } - - }) - } -} diff --git a/cmd/swarm/swarm-snapshot/main.go b/cmd/swarm/swarm-snapshot/main.go deleted file mode 100644 index 4a1e8b4f59..0000000000 --- a/cmd/swarm/swarm-snapshot/main.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "os" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/log" - cli "gopkg.in/urfave/cli.v1" -) - -var gitCommit string // Git SHA1 commit hash of the release (set via linker flags) -var gitDate string - -// default value for "create" command --nodes flag -const defaultNodes = 8 - -func main() { - err := newApp().Run(os.Args) - if err != nil { - log.Error(err.Error()) - os.Exit(1) - } -} - -// newApp construct a new instance of Swarm Snapshot Utility. -// Method Run is called on it in the main function and in tests. -func newApp() (app *cli.App) { - app = utils.NewApp(gitCommit, gitDate, "Swarm Snapshot Utility") - - app.Name = "swarm-snapshot" - app.Usage = "" - - // app flags (for all commands) - app.Flags = []cli.Flag{ - cli.IntFlag{ - Name: "verbosity", - Value: 1, - Usage: "verbosity level", - }, - } - - app.Commands = []cli.Command{ - { - Name: "create", - Aliases: []string{"c"}, - Usage: "create a swarm snapshot", - Action: create, - // Flags only for "create" command. - // Allow app flags to be specified after the - // command argument. - Flags: append(app.Flags, - cli.IntFlag{ - Name: "nodes", - Value: defaultNodes, - Usage: "number of nodes", - }, - cli.StringFlag{ - Name: "services", - Value: "bzz", - Usage: "comma separated list of services to boot the nodes with", - }, - ), - }, - } - - return app -} diff --git a/cmd/swarm/swarm-snapshot/run_test.go b/cmd/swarm/swarm-snapshot/run_test.go deleted file mode 100644 index d9a041597e..0000000000 --- a/cmd/swarm/swarm-snapshot/run_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "os" - "testing" - - "github.com/docker/docker/pkg/reexec" - "github.com/ethereum/go-ethereum/internal/cmdtest" -) - -func init() { - reexec.Register("swarm-snapshot", func() { - if err := newApp().Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - os.Exit(0) - }) -} - -func runSnapshot(t *testing.T, args ...string) *cmdtest.TestCmd { - tt := cmdtest.NewTestCmd(t, nil) - tt.Run("swarm-snapshot", args...) - return tt -} - -func TestMain(m *testing.M) { - if reexec.Init() { - return - } - os.Exit(m.Run()) -} diff --git a/cmd/swarm/testdata/datastore_fixture.go b/cmd/swarm/testdata/datastore_fixture.go deleted file mode 100644 index 6a147a6a48..0000000000 --- a/cmd/swarm/testdata/datastore_fixture.go +++ /dev/null @@ -1,1390 +0,0 @@ -package testdata - -const DATADIR_MIGRATION_FIXTURE = `H4sIAJSqh1wAA+zbBVQcXbow6saCBZcAwd2hm4bGCe4eIFhIA427SyAhaNDgFtwhQII7wS24BQuu -AQKEQPC/Pp3vrHvWmZlz78xdd93ZWQ/VsmvXfmtX7ap6V9oW4e3q5uiC4AH96wovLy+Ml5f216UA -/69LXgj0t+XvhRbMB4WCYRB+XgEILS+YD3gJouX/F/bpz+Lu6gZ3AbpiA3dwdP0f6gHVLCz+h+9/ -j+PP5f9Hiu0f46/zWJqLC8ILFuLi5eMCQx6DIVxQAS4oLzcUJsTHxw/EZMDFxQuHg/mFeCFCFnAw -n4UFXBBYmglYWFgIIEzNEBZwM4SQkLkAHPpftwGsK/A/jT+Mn+8v4w+m5YXwQ2C8IFref8cO+P/5 -+PvSw83NXRCurvTC9P/o6NJz0pu5eDu5OdIL+9KbWTtZIVyAteEIV+C4EeQyc3P5pcKvH7shvNx+ -adgcAbWAAW1C+PnNzfihvKYIfkFBPgic31xQyByGMEMIwvkFwQIWMIQ5FCogAAbeQc0QpkJm5uZC -AgjeP9tzgrvA7V1/2ay1B9AuxEJASABuBhWCmEIhCFNzU0FzmIAprwA/P1wI2JwAvR8nva25BVDT -9dcO0//69m+NmNvaIRzohfkgnPTAAiIAAUOhnPRO9MJgTnogJEFOele43W8BwAQsIGAE2MICZiEE -NhUQhID5gQUYCoMCJ4eQBZQXym8qADMTRJib8cLNITAYUBMCBvOaCQrxw/h/6Yg93AxoCWYuaAaD -geGCEAteCB+fqaAAHwJqagqBWAhBBXj5EEJQYO/D4IIwM6i5AAIqiIDz8fHCTKFwXqggL4zP7JeW -rM1/iZ3PHG4KR1hwWQiCTbmgplBBLiFzPjMuoD9gC/Nft2sGxOuBcHG1dvwlSL//dvxdPeEu9v/K -yR/02/zPz/+Pzf9goCIvGAKF8f1n/v93lN/G38HRHOH6LzsK/vnx5wNOhf+M/7+j/Db+KurSyv+6 -bfxy/YdC/8H7P9iv4w/m4//P9f/fUX4bf1Mfn3/43u6fnyb+6fMfuLhCwf85//8d5W/zP/Ak8C/a -xt+7/wf/X85/KC8f9D/n/7+jmAsB+10IYiYkBEcIAHtfUFAQbgrcrwvwQYC7WLApAoiaDwyHAXf2 -gjCIgClMAHiUFzIV5Dfnh/MKCoD/3+7/f8r/vfK/mP+BM8ENwfVr1oDb3PQfuBz88/M/lA8G+8/8 -/+8o/4vxN7Nyd7D9Z54W/vnx5/t1/v/P+P/ry/9+/H+7dHPbOVr+vW38j/f/ED5+Pr6/jL8A7Jfz -/z/5v39Tce5INScFISH9/vaXJRISxj0ndxdrN+8Jnj0qMlQk5D++RPoFCsafKyOj/wIJgAxAAaAC -0AD3AOgADAAmAAuADbgPwAHgAvAA+AACACGACEAMIAGQAh4AyADkAArAQwAlgApADaAB0ALoAPQA -BgAjgAnADGABsALYAOwADgAngAvADeAB8ALAAAiADwAF8AMEADCAIEAIIAwQAYgCxADiAAnAI4Ak -QAogDZAByALkAPIABYAiQAmgDFABqALUAOoADYAmQAugDXgM0AHoAvQATwD6AAOAIcAIYAx4CjAB -PAPAAaYAM4A5AAGwAFgCrADWABuALcAOYA9wADgCnADOABeAK8AN4A7wAHgCvADeAB+AL+A5wA/g -D3gBeAkIALwCBAKCAMGAEEAoIAzwGhAOiABEAqIA0YAYwBtALCAOEA9IACQCkgDJgBRAKiANkA54 -C8gAZAKyANmAHEAuIA+QDygAFAKKAMWAEkApoAzwDlAOqABUAt4DPgCqANWAGkAtoA5QD2gANAKa -AM2AFkAroA3QDvgI6AB0AroA3YAeQC+gD9APGAAMAoYAnwDDgBHAKGAMMA6YAEwCpgDTgBnALOAz -YA4wD1gALAKWAF8Ay4AVwCpgDbAO2ABsArYA24AdwC5gD/AVsA84ABwCvgGOAMeAE8B3wCngB+AM -cA74CbgAXAKuANeAG8At4C6Wl5iFHISEgvRf5g5MK7idnaMnAuFQ6FHNNwZCQv39e/Rfvse698ds -AmKPMFPaYz7s0n6HO7RPO6AuM/NznEZwSi9chdYnqE/tHPxHTV8/JGCG+XPaQaID/b01UTpfvkTC -xPxjDbY/t/n3VvzL9IaEhIT6l9d/bh/piqENJw+EhP3XsP7y9T/WPSTQ37r3t54i/T/aU2Sb9Y8j -o/hIhP91AP7cbDEtH8K9Stuqt+iFnI6DmbIBkV1z0qwxl/lGA9VCybJxTCEI/7eqd5/vVkD4SnKK -cr9eBBSAf6C7VVCkrJc1cE1UVQWxA5UwQGhIhCCUX4+EX64UFCC0348KJaSHf77WQmL9vQ4Qaqg1 -CPX3zw1+75XC7+9/W6JkI/2txWzkP2qjgrJR/niNJPBrDw9AghpWjm6OrlaOTrR83LwgQSlFVVTU -3xr99TXTry/xp6gi52JAVai7LzFT9n9K+d91gggwkARQQShIwFWEAAmFAOmuG0QDNIyG9Gv5vWMo -yKhIaKB76BiYWNhAhS584MgHPkNBvYeKfg8V454rcJ1EIUAlpEMDE9Hj35PUhBDDnRnQA2hjpUhy -tPg+MJrykna4jEvHQV9hrGo/YjJ7wH8U75qrIVMVeMz8WMA8wa3z2URQHpnTGossDFGt456f2BV8 -Minn8XJdXteiBhOLnIKVjV1QSFhBUUnvib6BpZW1jaeXt09IaNjr8DdJySmpadkFhUXFJaXva+vq -GxqbPnb39Pb1DwyOTU3PzH6em1/Z2Nza3tnd+3764+z858XlL1ECexfpj/LbQQEEgYr2tyiBizMy -ECcKMgoaMhoyKmooMG4EKPiEdKi0YEkiNF56iCbxo3t8DHApEmctaIAGY2yO9AdSdFN+7aNxpmcd -Mqsuxw9emQk4Mcs+jmPJnQCaJfs1DhgQiJw8EIqO7i/BmCMsfonH1c3d45eYXgYGBf8WV3xC4m+h -5eX/HlxVdc3v8XV2/RHh5B8hrq3/HuTJn1EugKRBaCioqKgoaMAfNDQguPsY6EDBw8bGvE+AR0hI -gEdAQERK+YCImIKEgICMjoyCioqGhoboAT0jPTUjJTUN9S+NIAGrot9Dx8XAwKUmJiCm/qfL3Tzo -Psqvu48A2M/Hi3ZN6A81nE+REa04xlmrvA22X+D1hLgTrapCwqfbRYwn+y9PajJaaeSgLheZjRJf -L3Dbk7PV4F6H39JdwW4d3xUrmKojC3IU87IDtWqZFAbHEwvsqx+SW23yGz7Y731V/a46KGBSpXDY -OMKIwHTgNgxtc5teJygwqvdVSzEkaUNDwYeQll9Ubq93S1u0mV/KSJmNmXBe1LaYWXc4jqEqkAVG -4uTG9lgDTppbN1ie+2T2CXOckFLCQfjekLDqieqBzmE4gxrxRjZhvgtbVLCIqcDn8UJ2Frhp5LAK -IYZ9kVm+9ceDAkN79jkDjZ9T9qeZzCnTfETKHsNrCQd5zXcgiVNxtRA7zhSGhc51KooU3DBSIy1C -mfdIJMxRQsqstD9Gi6QfvM1I+G6rWqHLarMq3a3CoJLz6I25ItZEgTkJtvWCtpoYjsrHK0vbp7uZ -hIaNNdU5tbveHooGW87s5hoaGTMtwwPkDk6pa8YKLTdi7E0kh2521AEfiXW6Xz+2GOns0BCUE16f -hvWNcvjBbJOTWco3hHxQNTvBpZw/z5tgpw/CTt4WxL9TVIGMrblhJpSoBBYyF2rlCnx+Pc5oT6RZ -F7RfILjurB1REkQuZMVZXDxvEcz8uEQ1DWUzjWXn2riuXJg1Oq1Ruwaunuc9mn/8A2JmPkA9xA0e -zwtIwgiWRpUklILUsnDIphih2O1jvN6em0B9ZmOU1jjxVa2n93FcItY0+8S7V9mRhJr4OrJ5rqWn -B1k1274cQxxZ8qEpnp4i69vIbfAtH/4PNk+mG148kRq7YNQL6X6MqFES0mgYJ5QTEQN5BLEfPEpB -+1yja1HAWrEcIPD688JFXkb17k/tmCyLwljmaK1EOlLGvIBFEDSYNclMMQkSITP5XtiMgI+w00yS -iC3FOtJ6nF5rwhwhlExW63IFui/04Smkr7TYIf0Qnz/gULiU/PKLs0y+TdTZvGWRTQaRssv0YN08 -mnjGlnhJ3+TT3q6k0ac9H1vRbPxNPl+fPxeCvn1+gxxc8MptWO4tNm/Dvbn2wcXL/OI0MdkuLK+6 -kdjsLt66MUR/EttIwl7ndHP/q+nXz24zhi0cP887jdRv79jOMcC8hM+sywdZH3K4Y2487Kt5QMh6 -9nIdyfiCnRvkKuzjVBksL754WITkH6jB+nBaQ/VpWZZG5XbGY2GuURkfsmxKYaKT5Mh6dMzvGNgv -kd8WWGZrwasKXVIV0KNqZawDZHaeFc8F7XwSmCdiS0tktqpIE+058GEfSU4nfMZ/5hU1POf6lMZX -IEXMsP9xFHom/6Hi0lBnfCukPdG+FRcHXGrBz9Vlye6h2YFeeYH+ztmt8Y3Qxo7OHUiIsxXG/oS+ -QYDWOo0Kp8sbOmneoiF688IkBToanxRZnd8lXn0a9eGktNLwuw5/r5PRD0y4KRQpnzopNts/+Lml -VcE4vjE+5Tflvu+HqcXsezsoL8cLcNgh1oay9qx0ijKJXyt2fLAZVEauf+yyXpyvgnR9GhXmJSEL -P0qFgt1PFXWZlxR+YNQWTRuhYTopj/iccl0FCHdjtgbyw986fvCQ9P8UQMppDE9WGf6wreVkM04B -JcrjzSB7nbBWOpCWyKCpNINUYzPOgUBTY5EybYnEyqHg6B/UiQVd+C8snNTNF9kxCTpsEI98rJwR -zZpoaLLL0MpK9pyvyl8yOqIeKDRqaFrl76vfN3wYG/32vtCNC5oFqtWuoZIli0FvLQ8Xq4LkvJBF -QfZFT7MRGMTMrIjCrFnqhzd8w8mRV3wQQc3XtOY8HwrT3rN0v3mqoy/M/NzemFRa2kxtK6seK+Wx -3ZrUeIVfluKI+5MutK6h9ExH8wEf0cu6icpcre5HC9Vrvu8+vroF3984yjfKMh5wQ5JTiy4rNXyW -Edjx41roO6fvrQFxUiTXh53NxohMs/Guxq8/h6LlTg3a2Ioc6T9vWM7W2Ou6SWOOo7LLy+y+aITb -Z5k05EDORRJ3Tlw7H8fE5b8Gg6koGPIYycNeDqopNCSeVviZwIIfJmdPJPiFtzOrtepb9zs0amy0 -kqZ9x8necx0tV+efOckQdG3XuS77oZf3UTIZkkfweAkxBbGnSfDxiThUKzM1vcj4OegaARvVYN63 -S7F7K6zAHSKWaKId94Er8F0M2cRIvad66YVJZW6rq0/998Z28R8SPFv765tE7UpX4hxVj9so5rbj -g4e5vyKGtVpqK1XMF61TZsUnK9d8IuXl1KxHvIRKHsnLP9C2156hzWFl+/rzcKeIz0rbjPP1vhC3 -SeTpKPSbXL/GyFB12XO9Wm/NRtu6H43kC/NuDJ+rlDBiOz1GlTzCS2QadFXeFG+EjoeaR5HtiZvk -bQtD8DEyDyUHarAnXW4kmA91+b87CrGhaQRpZuNjPtMitw7iGKGULVhi0dnz9td3VbRPWrwD5Xh/ -M6A4zLm8qF+5xA5VzwjbrBe/idHfkFS5Wuby055MxJuW4L6R3T22F5qUGzMIKk6nl7xYaNlsquRo -reWrE23V8ZvNOsevEcHpq1TtEoFPxuDSo3yI+Xxs/MVKd4nJppII7+I2RL3QOyYHUSRjU0/5qU05 -fwvaKBQ2nrx7azJV6i7mST6yGpPnfKi/I/RqVp9Fh/4ZFbSi/PB6KVR9wG1xXkhbikIqiG7T+lDo -piMcOUTdvsutSCSHIOteDMeSntxoalPh/nDYif7MQfyAz77glnXI0DJfxtuvacTxFzc7CegqlI/4 -cvLJAleKy8V4NPVmR8dp0banE6laxXdY75+fEKKW8mj3u7fMi2iRDIyzJQTGsxXPI4WNQ3O10gof -cr1szoSN+9HAOg5sDh4ocexxBxQ3W9yBcLgG9PQGJicCgw7OehQMrNzrlfe3Vm5zLup3qY6YI2UG -aV+pKHCoVeJsF1hTyxfWRX8FT5hotZeh8Ikj7JYE4NvTniRt0Tw+I/JlHdG3JXCb0qXqSUnPa5oc -CyO2pW9iQxMeb984sEEyQ0zkR0yK9xqfFkUaNUFcZoNckk49pW2eUQnz29bf29nc8Ym2zP1+SZXJ -edFDJP/DsUjok9t1Vll3PU5gE/l32tIz8NPt0d0P5X5PKi4b+Y29n6UYoDSX+SVleLHEfvxBl2c9 -mZULLfQgKe+jmXS51HmzVVQWmC0r5JL1IHFHdeT07ZVDpv87lUULe0Tg4nJWaaOJhZtTBI4zonlE -yDjUbMgtNXSvAjFaOwsb1/7w/LC0h8nc3DooH7JAgl1O5BDu25h1iffwswRPSIMI8nR9jSf7WaV3 -s4Px7p7b2ffKsedbc9yfWjwdLpKT9gw9Xb6byP60VE/KDFnovTiVUC56ZU+j+IVLFS+HraU5TO9r -70xgcuFiy9eok52PmRIRRVNo2z5U1dz6veEnjZVy+/372DwqnSEDyiqfoxkKtrM2222texvWxIoy -zzK9QQLVfpMF/OWypcbqb88oi+RF3UVFMiC1vsNt63sDI3IrHwrt57pmT2/1xk/cfV4ofrykiQ+l -kRw7WXCfdBXDwSsf/BTVRP2WDbIYfrDJoziUndpUZGx8X21BbrDSNEPGiOGFREkJCj6Pdxz/8gPH -r450w27PqvS2K8bOI+ZKqJp8rkOkS/mAGw2JPchyuGbg7Db7l4AvVDzpOXVhXUUI8zRw9qm6KEOp -WLJkyC2Nob3mbO8JxTyBobfbrcE25WS0Q8SN3JiErJLAkrdgY4GenFif3NId6F6b+4CPunBejMvU -ZZO9TTwbSlCfMCXBIkFwsjpXHgwnw3aHa+fiDG5l+6m2qMxP1ZjJ/oSKbc/HZ1MsGeY8ud2eLK86 -mhCeskfFOr3PmXKxGYwIUR9srSl/voAFkn21d4nmE6mfeTzI7uWHCnl4OwqNKrfXLOmw+hyQITVq -bPSjmePBPvXXJPi8i3VBwFwsVTW0T14ksCbBlybf3/T8qT2bl62lEXWo4PxM8sRK+Q7oKO1larsj -6sLYZ4vz76N16/siGdp1HnJ4T9EQJF2RIt4+h5/FREVNfSzSLGWe9kUTpcvJqHKVdc/Gz1rozhh/ -4fd+W5M8fqGs9GagIaflYGXm+bAJTD27ppFFvOUFbPGirszuMHRS2yEgVHJVyBa9UsKEJP8lW5GD -Iy/f5m78lgOf7x6D8By7cY13aZuhL4l4u+aYNwtpd6nNmE4Rprs7DjftNLcrg3t3Wl/td4dzO3uN -uaTUJiLmsDXvUQaq5kP5yYb7wrYUQnjyFDxCQ0anB8pDzbSJJC/zP89C3X88dQnMoc+w72bBVLm3 -gz+2Ql76INSY/dXF4uGb+xSzFd+rt/wI60cndqc0IWqpc1gdudUIOm7mL42Fi9/2XKwZ778fFCx9 -8KZQ16EoZqJod+dByKeyioeX/iLYAoNIyOigvyY4/l7eAKUTCflvWQ1ktj9TDn9vxb9kNZD/ktVA -/ktWA6VgVattFB+J/L9mNf54TEcupt0h3GP+ilJCqHmM56Dq+/m5ZBlRs79Dx1VgHh/zXMezj39k -NUi+iT0NIb1nbdsuITE2k5VcohVV+Ox90YukGVVHIc76vVR+v0oR/6z0/XDd+lMfFffvMzfqPLlR -iWGvy2dkdYuFaXmXYMnA4/XhpbfiJ7eWOfJ+X1FhwQ7jqRTjZaxaR6XvVk6aJeGhuPal3HC15cp1 -aZA5La3H0v364XT3Jh5+Z/XnUeMTwvBtj4l7HX3qEoI15OGXuA7fBFTpGZ5jRMZhLx5nfK/kMTQz -yANVGljoRfp8UC4dXy0PJOHvU51YGmh9dOsrtbhYrI2Sh/rqnm8FUaOx0IxuLTwKw+1z7Ddhfoft -ZNM3ytP1H/oK3yKkdh/SiobdKA6F1v0wWBJqtHQTuPjBV9K+VZOO6HPMxHBaYFZQIxFjEC7SwPgE -Gvp2fV77XSwd3d4nqGHvy3ns/ndnfViu4JaljrFfRN9IcW2wu/8inLZEUfMb+z7ZdEBnUf8AuTfs -q7xZp3fG02RxnsnL69ZRvOkf+MeGEobH1z7bUhdXZWSpYrdKlULneDE5PLH3k+spJbwG+lzFuz4i -poGHhStTPhntuLo2RPnuwVvJUOw9I1ob4mZEZt4s9qx4RC5w/N64qsG5W5lIAnkkahJnF+sugg5G -Lpamgtfs9TMC8yI9arsrc4Zwl6kfDvhFBKIn7l3cFhVxw1M/6nOZzLraYynqtNIPb1phFzh0Nrq8 -RY1UZrUFp9bDqumdFrcSin0vVM/GMvge+scnfvUWE35EFW+RU6CSGbgIfm+kNb3FsV3jnzzQsEEO -91xpyZBVYcNmFPy8A1PVfRMi29NuPeTWQt3VNvTqAMLTbfpte+z4NgmmzkTzbqTxSPeGrHqifsTP -5mPWPT1FnfGRIDGrtIX7atCP5YkZj1ero42v1Pn2GvypkjZzW9WsfUp9vnFIfR05128xTGXvcZjN -Cy//GkF10TS3ny4hgvL4h8CQmQ1sa724VUjqBHe0Uhtr24FYjzzx0XxX7APhdMuWdTvPU44X1Ht1 -GztWYsKb3y8ui3bbRUfzejOFHKPrjZRc8znR4AJwATFaM0f1QoWGwh2PzR2/9M2JoUOjrLRc8YFP -TiODmeNluG/TwCkbu5MEMmoBpribAQ8NdGONLY4rxF/qapfVpcft9uhGFD8XLPhBHZXZhph05wZP -JIx6CXKkCxbZNSY9yKhM4eHbB2+TUFRWXEyTCb+PLeTXWWVTJGbCfxTbpk6E3dMvNSqhxF3KedGc -POPyYE84rzrK68sWR5EgO4fR7iyvQ2yXJWf2ejNC2Ctc5FCvjBT2mEpcjMQixPDZXm9eznfhvYv0 -eepIHbbMd9+etFZtHlSIwATPWtyNVhkkF3bD9D3EHSd7dv1YQkQX0ncetKG7hc6zjBxi/Sgt/fB8 -kOQ9F3EGL3c7u2wMQQxiYUS3+Z2b7rSAoXOStHsliW09sdOhTcPudz/8iRXXpCt7Z6KZ6NwtRK/I -x3dS2VzUkx7OJfM0iGwRauWcWergsjPD1a7v59CyCpX9mmBLYkyPGgu1hHo9RGkU4UBphosvpwO3 -+XHd64UjJs17LMVed6CC9YZ3c1OrZd/4k/bfk0vyEeS+S32VAHaMRSY+tfjQYB9fDk++p6E7KMmK -MZE/ov5MrsLbJ/IgL9O/dk7HLdtNGblmK6kCGYN0qap2SEDaTaETXTmCWvbQp83+Q4OWOGLPuzSI -wbyu1vTrVmu4j8N64uGG+YeG/cGR29zlT2cUVHj3aqOoddyOjdhbbUaE0FUuGzB2U+t7BiFzBnN6 -9QOXvv7ESn4hCx3L2F8Wf7ru+MhjGBrVfa+jThly/pj+njSdNzOmcPf7daHfSO9Qx5eWiiP/qhQm -efmkCVOPrTh+MGnMw/atxVGNVVlpUqVlhgbs2qB0BEnpzgWMyuibUN4sd9jrN4iPnB0WmdE7T/3X -px1xNmFLn7CqJuCK7O/G8FKFK2wrHNJOxRzEKDnODqp2W7cSjVwS4LsJufJgiAURGN9Q/pGbzU2A -G17ZDHuw1KniY7ZplASLjbct8ybTn82qA+thMK3maKLq4MGuaLmxXNB8RzXWsX5haZpxgarIEEu+ -xqzxYxxhf7yx4UqJiLLqDWHwJJkeTNTmp2eFcPxMK5shzadzHZv5Ln8HsxivyeahaiZI4onHbIYy -ZWqHIY2MCAyj0ILC1Xyby6pCv1ErT3p/UZlat9aLHcdPXaXtaAFl3Y+MBteghp/0u3hI/f1Wf0PG -Utjmw/dpAofzEptzC1EyFwb1FQ9M+MdtpqKcBj56n9qpyzUsS9B47rExBDa1qRgKy4AaVFSKZbBl -GCG5vMnDp7zqtN+zg5VQ56c3Trl6medK8VtdlF3qOZ2VZGrpHpeoEQbJJD7L5bCbxKKSKVFl4VQh -yNVIyDZIaLZYJb/82Oaf6/78hRz3+2x62dgBbMIxqRlKqT4Ic3k5wvAtfwLveyd+AeutpkcPB/r2 -qD3bOOPCxo0KFuEf9sOj1TUOORZ2I9R8s7OXE4RZ/K0WdMd59T9aau23kryZiTTaNt8ZfivoUETJ -MbDJJmNcP8DczZUlLvVBS0ikShu73Cypb1KgOrlIRM8uq2pBxOFrfM60Tg9pAz6J2pXQ048pFPYX -Q5Qe51pHS51ItFYpxfi73SiaK1i5OWCSAl5MRhes9z84WLC8DtsTOYahrIvwIe91XFPnSimBN3OK -r3XfpsAGqecqmdy5aVl3OSyDIMp15kqxjMohvXrvUxaX+OxVTlrRrLjxclx0IAVk7AYKqZSvbSlK -NPEl6ZhQzaUwXBYkKbHxZDcybEgj1dVsPH96FoXt/RypFCO3Ws4kTUUTfhaVoxFfLxKoZClDpExK -XlOOpbXVmTuuNFQvPhxyIlkkWS7sZObuqvZuhDDTRFKTrfQkyoc2Ka5e5EEUlfDpKHX71sLbFPyn -MvLojqL4lq8vKdLb/IQd0rNaFCVF/JC1c/niGZXelI7HMTGbIpTMNXNN83eCID7ToZjGY98domJ5 -oVGElrZSr8JJU+PBOfE1qPR4MtqFFSWqGfz3YapUb5qusI6tUhAZ2Q+9lS58+sD3xcBDes/n2Zkx -5umT48NSxpg2BrDCegcVkvW4VEg/WfcPyURJD+xEXoQqFdva2ppIeivObic2v7SOw+AP85Xm1tLB -pO3/WI01Tjrww+8eQZX1kx/UKAHi9/LmtUypQQbMHR/T0aXv5kEYSEggJDTknrWnTGtHXqQMPG+K -BrQ3Hgxoq02yqSyYf6j9rJDg/zotK1f5oYbVAp3yYk40eNke2rwmNj8nRwZ/LUunSD8Hg+H3cDpJ -p+7TJCd/UWpbOWtNvVIaaiDR0lTkaq3x6/EF34HCu64KazZSSOLYN87gN5+WSjd1UK17cJ5+kmgI -PBfbuplSUKyrKnl9xbHii/fluMEy4Co5QsVlbtC8hRGZsGoioehQ76LbyTL0MkD0eXPfVfMXIv/t -E+ixp0fnKsdCEY5HMiaCHc/hDvTwQM/bKDx3s8uShY10sYBe9Ym/iS+zSs0o2Rhwd1+TBD9VFGIa -7hYOIqLdMvQ/ZjDwyGNQ4K8OPKfK283IJL0DNTac+SpXLtbdgR4Enht/ZYy7jWB7BSUjoqjGIlF1 -UVhZd74DRVaNLi7GFQwgzGvYaFlajV9kyuP9IDRJdvN90PZpuYmm2Yq2su3d+7DO5qUrjxfrivwu -ORwqxWzOA1LkK6Nu4e22H1ZeOGVgN90M1dx0pS+IcvsVxH4jLRBdPbgZUj8WlHCdVyUdgvQnMcUq -7VcuR59lrR35f2uoa0j01OS6z5zuRaxMSdTRbSSxjjf6fuok4aOSsa/ejTQNuvoPDH/jyf0vV4S3 -uxKNToURtxbfotp/DpLIkeS+1EgkSyEdveeLTvjaQCx58w6ElIYbQaIiv3OQOK3b7qBSFQ2lK7TV -o2rRWp7cbU5kFOGyW9MkmJGPPFQopBP4TlpmLS3yhNHeucbw1XApRZDSE9nqzrlVu4mGCSz7TIHR -h5aOxISqhETEnh67DdEcT+gjvKu62figwVNcdFuhEt/qumauP5bG2ucY4Mcp3oE0o8dxTyey/LRl -kpq/mt+cVp8T7S/775ks5Z3jCm9fDy8EXiMC5Y1JkePy35jpaoZ4ncWcl6wu3CJ/6Ok9uAP10pwv -cOiM1ByER2Nja1QJfGZw6XBiOfeeC0A62Z/XdqDWkijyGvlka/Oqgj1sSt2taoLsm2hplHFuvdEh -bvDVKXGWS91rWSs8HwOxxV6KXGcrKIKVJx7Nm9X/oFgjkk2mSp/zRXGgghUu5qsvXwrUkN00zD31 -s7OcGrbSS5IuwjcrQ78oSziL8oSOKe7L33KXU8YmUFhf96wHXlu+hx5AIHJwdhxV4WLBdp9MqtCf -Rb4Tsr2TVxt97GkB0etWSmiVvinfExZ6uzVDQAeu36iP51SOlIaJa8HF7vylaY87M9VZ4gc2xtke -YSHlmr4qQCNeIs4DqwSWSWUaR6B6sJvPNgF3HsUoClbK2NHkXPvwlybSgvX4bKyJxLaWNS0sdyBK -vKuJ1qyWrAay1Re3nLlxKfLHVrkj+mdCpI1rj7VegD07aY6jd1eS2UFG7CNM4P2GO9CvHc3SRxDG -H55a19djRSuJDtjOrA2uJ8R4qzGv6jQMyoQzocG3qB1haakGqUwlcavTaHmf/e31nAv8bx6en0q8 -wFtebi+4uqRpz7k6VV829b8gOm8wae0cnuL5Andi49jPQjwXyVyPuXwJbXbT6bEnh3PmC5l5SkVL -Dbi7ODUBvVZ63K3ctTSTcx66SClr7Z84YGNfhLukeO6X9AWMsrzjqMAdefO13fSXvq9RHg9wHukw -OZ409G/jmtG+DwKnd6y8UWXld+92fTzVXqTS+zpRHbI3C1W0aa27f6h7qruT5KlIvujwGpbMbpPp -cqKplTl8yzi+L/HpsL1XHn17o9JaRWJ4i8qNs52res7qTK+rlvwwk/ZFMYr0hzwsJUKHZ7jGnXM4 -vhml8a4upI8Llct0KxfX+w06KeBhvOjLlL5F8zQunadSEUMjJRqkBTKfbBAcbrHjDuEHeYvJyn5t -OtxbWU42miSdQQt+S836z4IZ5bBzFDZfTWPINneI7qclzvMgzORfwJhN/BLTh0JKtrQZEyazna8r -v0Odr5cz1BF3IGKrM/KzjOWfYy/ir/ZqXJxNaPgOjjTOXrCtFIpFVUfEzJlUz0dJZvZTPQnJr77+ -qUPBrUS1tDGJ581UsWkjawyUF2+p4nvdUBOuVJzN0zaeqiTpmzc1hT6d5kxCpqJHYHg9eJXZA4o7 -CfiiiF8XWzBdRiKa+dimMZhL7yiktUPNsDkY6kvgy3729PhqrI/UL6b/DsSghz/+KP9K//5M/qzp -HYj0ly5GtEn0uWqXZukIvxaR7WtSXL3KjrWhaWK6SqM4iKZSIRmLU6u0Y4Hhj5sVZrxye4IIdQjJ -aONNXdGIMru4PO/gBElMMbSVUy+ok/pVnJpDkuSX1Gk4IwampzsguY/TE06YZUvU1M2NupEr30z7 -MRhPISGjI/0tw0AH+nt5A5ROZJS/ZTVQ2P5MOfy9Ff+S1UD5S1YD5S9ZDdTKpAzwKD4S7X//n2VQ -imljXAmKGswkeGzCmMMuf5wF5YyRlXdfmlbkCORJHFWuU/+R1SBQCSqCv7bg1AbRdyMPBljZ10P7 -j9YHvSKSLD7HH5ysHx0iqy//XJrhimVI5uzYRFXcreqjBbcZJeEsNJDe62q29nxSdzBU1/CMczKe -Coy7QkEoF3Dq1+blEy39sqHlfRaThCcnQs1oUUNSWm1i3CqEj16S0tzFHPxC058o6XFkEb3loDle -Ep+z6QBDG0NocWKaTAxlFbf2Wb5fXWS7JyefTBpiPWjjND5a6kv+zb53L3m03XtQvNpSlwsfOTpl -GDSlV7ZrZqVTQMgSiae601WoyuFoHbqS8GHUy/n5s4WBrVQzAr8v5J2M4GGZV32H69JhPqLfQFV9 -F5CTOYwB2Wh5L9cfjP6kVDKjefFHyTRv1iU/G3fQJQfx3qdVzCm4tD5Eliirn05IobZfRMrN2s03 -NY/Uui98sRb9kYiBwWHuQm37UFxZ8FZFtJGWbvVckVqbQ+A15J5ZKKeMKYizQOtkSuBoUzwa2SEe -gpAkv4+NFbs5RABj9GBICHe+OBkt7adrJDWu2RpumDJ61eA0eqCIu7b6sMByfDSuhXaWs6BF5F5c -Bn8jgyPGA8JoDOddRVG+o5dRn5hqFsTS3YJenryN9esqOHieU+3AoFlHtJhAOzSd0OgRZ3K/5Wjp -zM2P/BPMBE8zbG01MS6a3O+TnSIh+CgZx2FziJ1b/5CTgDH/s3PU4j2NBLdRXPvOEE26oDO+pLWk -8SFZ+s/dPdzzOIZRNRlMOUmf5zzJwaucpojVOS4USshQt1EKImYkv2Fdsy5+NaGVkG2XDw/tK+Sj -18k8YUBRd5/zG/9HQ1/oGC4l7EVKGDSWioYmaRpHsTZP0qljZGXi+l9RZmqvBtX7iMlsYiyiJTu9 -maqj9Ncy7iAqlKGRkxWnVCwxtjHtbtVJeUl2qzAhshRcSD+MKsdbLDvIE9QdWClL9knT5SYuf0D4 -6Yj2+cOJ8ZFEx54X3ObJldtMu3QOnWG3Dk+6rlhp0tnzj4vUf37JfZomJyPY7XFTMfzu2CE+mbzX -qk1fnqb2xq0q3ue+kMBhBXUWTbMb99uUIDsFL3O6HbfdD28bUZ/an5peORcJCHb7lRy9OcDtb9hP -32eOTWLadb5pW3XdOtup3rOEOY/9tIuW5owb2NYfAXNuN4fURr+iFOMKLcmdNI4LY0hA2VmLZORW -k8S3Ydo129u6tlSLL1yEKRJuJpS/zv0hN1wnJl1Dg9lrAK+73aZ+7nURJHTb0iqvKfr5+kMSdwiM -7GaTnHcjcsSk5g70tppKIoD+iqDsC03Y6yTD69SLCfSETCKW44fqIfBkbjrN/awQwQ42Wrm3k5Gr -BuuoJ0T+rY34FOVm+Tih5EWcDfaEXmwoClVRuITYBwvRebjkfVcGbu8ZaDh3ICmnnNJpeow72I2r -2b1ubMN8cbrRgZwFdZn5B0mTNJTg2NOIsXVwX9NT5VhWP3JUrFVxqjYpaSr7NoKuAemDdOfTlQv5 -z5RVSwu0fSEyGWaFDDvdVdtVQ5siKbeovfOFQ/enO5QJBUJcBTaSdg2/pZUridzLkNkMLSIQL0de -7VVZnpZ3/IH46Rb2Y5KzLtSZtf/5gwhovwkCOpMw5HTUJXgNWU1SuANZNnzVPZB7c7Jsb32IP/go -GrpgHWVN09jtP8+tH+E6jdv1mSB/Q2EzJpnSVl2VYVtl/P00LSmXpnVhM4cWfky+W0wGuj1/NoW9 -X9Mz/yOjCvt7RQq7NMLakHXK6PHNmq/4o7uKVJuYYzcq/k2ovGFfhoc3Wad2RHiMexZNfn2IQSZA -kkCqW/AUeTtXgFUolC/l87rt9A4Eo5Y0qsPOOmaM64S+9jGxFyGXS/F2Qf2wGv58FzWn6IrLVoLi -auxNtmYX7frJ5klAb0pLNf3PiaWlcfVxYfenkaIso55n2jQa3Ycr+ZpTx/lpmwPUVO8KaoNeixPl -U8goqx5N1n7uN/zQMembqe/GmIarwnwvgnYNV/KcvzeAOf0SlF8/VyU/+X53+pL3KItr2fHMregY -Rz2KKecaR7BJYVDgidsYcjyBPYNxlzSLkye6k0ze84bvV/5kP0Knh5IXE/OjsIw/qXO2BWUstv1k -Djx0edXN20dxNAufLD11/gmP3EgUei9P6XVAE/qEgk1JHre3HIyJSReqzRqupnXoSTrkoyXKVHEi -aDo6EnA/dhl2T8JTYEFF2KCCMuXRoIwoOBxZ+A2yT3u/B5Vw9SpatDQKXEglhjXe51vO4y8ply9c -013NyEYpDMwPlW8y8NyJL+SDLjySbUz1FaSPxa/JHgcHyaXiklVzRhAeFmqbfTFzrH5gLq1qrQo0 -98EtLI8gNvs2nuHSKKwj/sSv8VZtwF9xYvzNJRUbpnUyUnttTLKVhcdkPGd3GMYAZG2gx/4OJEyw -CTxAIjWPNYJTw/F2zf1MxrOGQyQcSHKO5pYkh9oIF3iHO+77T19WUzZ+cunG6E2Ri333DLF6I5o1 -STOcKVbYFoS7kvrSo9El8nnyD4KyF9roAgojJeegkxVgYv8BuSLUVyRyTBAy49nPQ93cRG5w+Qmf -HHlyLni92xPhuhVCtNr3Ru1hxlnodIpMAVINHqeZeh4XXdymun5Lvxz1E2Ra1JacCqqWBda5qrce -vcQvo+QwrSe9Z2EJ56vc8PPQUlJBeDOJA67KcYJ1pBd8Uu5Q6ksyej2w5be9bzVLF39o9pmY0lpH -gpIXVpH2MKMh0kEpvSIpg3NBa9V2cgmcYgrvXskY0jQ/CAKxdGEsvrSMcGS77yxzwT0Drgl1XHDA -yLhulfHfQs5GvtewguGB7iICHt0XmJwMz2y8UktXjhjK6ndpVVlnPeojzudkIegNxWVTTip7n+b6 -yj6SxShEc4Kpj67ubde+M17n7KJRSPzUAXEf84GY9FRvF6VLiHCc/OLH8TotiAuRder157jT3HXE -UPSFGTUh6JP1J/GNR2+mXmCzzuJymvobPQlbnTdVbZUjomlKWX8dpX1AsDkQY716dt534jFVUsot -Yv5kcLGlGRPeJXgyk1lxKwT/+XYxwtX/AbMwUqRHuMs639HKbmMjI4TCgcK4upeJMNP5RWpPkPqg -sLhdXmHwyZUpXg17xH1fr/u5m+AF+SHOh+8J0XnU8TbmMHI2wzZDk5mpxlaT1eNEkxgSzNqk04vW -nVxMM346u1CS0qnso3fknx5HlicgbTbKOGVmMd5u8cbSeCZTUzh32ca9bbakKhiYpvewPmuUCeN8 -b0zWLKO625IbiYm7vtfXJZmAdP/9rXqd8oRbbNa6y2nK6saHa6Pm61ejXazfMKIDR+IR3ND5n37V -txY3ZF2Z5HJxmKQEN27McfpuC5sIkIx2M9nqQwnYwel9pouqo/XUrOSF3LAxBVcFs9csJz4apkL3 -ZWNw+jON4KMEupFS79q+rIysfoRzvWNq7lRisttLWb33OI2yOcAZnuPifLLVd/7E+xGudJ2oYE7D -gkIU6QSZ2SLZEHxzqWXO3EbhgV26o4plUqdH1cMGeNPFhCZLJ2qWnTiRy1i2U1bvUNDNp9wr51Mz -JAX6mhiGpLI+S+2pSKMH5ESbYdmZT4z0NWPYwpJSHR1xBQ9xBe2JN1aYOU3QUiuUnYXhyXmJnKrV -IVv4BCQFLCFj1m+DUgp1NbsEJJFrMM2oJrIP8I9GE6x9vhGYic1rMahJW9QiLTvYuff7GGmlbnc+ -Q5YLyrkAO+OpdiMzvoA6MgmO0wuKJSr4dFzXZ++pjNazvAkXr9R+jopM5iUNrrlw1pTwlu3Oq2YJ -QrdWEzHF+OHcNx2T5E9gpqF1msBon7XVv6PgafVUndXONmUq5YRiCuea1o4k537DxO7X6BWQ0y0V -HVfBebzEQIiUaP0FuFle2D30QvbnJ5BDZgjoAvHs5LCOKLvXMOTl9wIPRF+Cl4xLz8MbuVTLOtRs -EDS+YSHa/ELaB/OBmIzGPvKgc7+Q6IGMPdlHa0jh+I0mAQ1OvuDRoOniE7/2hvz6QsmvOcncDk/u -LewHfVLHXd3bgKAfmLLoSp+Qi0ruoplSWA4b3ZNEUaFsmzvlGhSXgtw7ZQkREso3h5AwMyTImcTf -Wm7UddFQv3PLikJZ0X7+gZP1Abjxq51oER1eqWBSo4L86UHXJp/n0+rj/D7Oz/fiSUtQ2/TxBoLa -oQrg0fdCA5mmyoG8X5z9DSwTR0NYA35gOvdZSY71fKYq2OTdGmc3fcFMyP8znm7vaTXrgHDMy76R -YKYlRdhw/dChFyvbWM0Ss8EDL8u0FomoII66exHcTwJoMCZ8EPdfibDCFOazOM1NA63DXE/ptc9p -rbLzXXrpU8Lx6ngehRiHPkq/v63p12ZCOPGUcDXkgp6AOvKDCdg7x85c2u9sYGmUNbLVN6S55Auh -W1ZI/GorV6uAIdlsBmyS/HDCxFaix07S2eTZPtsEQ9Lze1qtuMANfVEi6aTKmJ21j4nTJYq6WNxx -DqXHgk+o6+Eyar7fOyPpGmtw/h0I2/79/eHPB8mrSmL4SYiO7V28bKLiy+DkDCxGFfz145wZYeXe -GgqKMSuJ35OZ9ySQr66l12jwf4bggXH4Y6nkIsugO18/Sd8c3YHQbq9uNn+Q8PwQPFKgNnEWFmZF -ppYj1tvYC3sTuIeSQ4KnEnajc9ES3tT6fE5qS6lTHWn7XGLo1tn6lJvf5/ScKi4gdtKAV8ZaoSx5 -SyKg7Er+kCZe/YxCovpzwSuvI7HEE+sL6B3IzlPrM1XMQN4VFw1PQ2U8UGNnWNWnWa9/x3+j6MJk -ap2G77xDoqo3YZdnfecymmFMDP1qA6iaFR9x9WJq9iYpK3lRXRfqY+o/+w6xh2F1FVtYhGIQfuxW -9JGpjA2Lo0M8pjTHX53k+ES8dfSs7bzjlIXn9codiGWlc9cksHg/0X8m8jLqiV6lS97GhE6PKkb3 -nlG7mclZzJL8GYW48ZSEFWJJwpZmgWosS8cPeIKv6lt8LEnoFxD/jVW94lFIzsSHp2zaxWhvJiq+ -3s692PD72SnJnKmeUmvqhzJ58x0P6NxAz01de7z60AfqLE8NaqOa2UP5s/cv4nw11Un28JCPTT77 -cmyfl3p54/bkXWdu3I60vjydbNL+WhaxtSauY/szQD0i/uqFh8R+zXVzb+Wm9vG3cJ1HvcosT3dv -B67CLiSAO2q8RaXc10pFFPxMj0LpNvNnqZSeoIQi8KSXTOYlOqdvAs6dqeTHxAvMjvDyX7QFnFwF -bqzffra9gD5vZr28A/HTzPedqftQSXfvxX9sITkjbW88sjmdyHKm2ThnmC7a2KCh3si/outt5LoI -eGoTf5ki4/FzdpzuXSDPOA3/RWN77Y2Jqw7SWcOtCksy04uqO5Azy96LJoWLkj0ziunjML/K87Br -KpWioxcthjd7dyDtm42sMD9F9qKO2683q7fbvxlDRj8zdrqRvbhlupJ5kWCgwaRbmLlAkPfSK1P8 -nRyDIg1Bz+vsHoZPmkeRN+Wyz3BEI9ZusmdvCtuTnz9ivETX1/nrb2VQkOhAfy9vgNKJgvq3rAbq -n79AQfl7K/4lq4H6l6wG6l+yGmgH6NXjo/hILP/9L1BQi2kN8/UZ9UPs0ip1q7aR3Tvao/V/kAYT -w2wjIk+U+oXD+//IauyhJhJ8zKBYNGkOssqZlG/1v4B6o6dkB9tECVQ94xwifSnh8cjXYxJnTVTa -DC1hihyfj1Kvz/RmyOBC9/r4k8ZUaIO1v6B3NE2q66fiyO8JyHvGyiUMVyurW37llecl9+kQ2CHm -/PTRUWy7S5V+0xa3a4p0U/ZhxJjErfKyfbW3P7tO9mPso/m5lHQNgzdm1k97+gkOJJ39wzgPCKur -F/ntzu32Z9/tnx8YGv+06DyFDlDroHrgRt7LZPekaaIKpWGswaq14rtfsnC7R7yTf5rQeiChKL/l -l867Reh6ET6UUqg0hBl7yKaleJZ4UBTesE/TrODURRfrsdfdaaaUuXs7RfTZ2RkvLy/HjafkB7// -tYf4zLx/5rKOoVQylI2tVY7d+fZb9+t3A+EqK2KYbbzdnqmfLC43FTkqv0OWudhhk9WeTsPdm6mM -PA46TIq3/vOdvsFGT5Qd8nCokXYuHO+x751aU9k501VGH3y8Il1e+zpww3EpP6vUv1eIeeAUU/j5 -DtRD9ow3OQJF56jpZmBFObrUgDaP4OVHpCX/O1Btyjt66mfn/gYF4TH+NMqbW34ZVSa51xvs7apS -JRM4H30HqyRSn877FRwDk+n7V+uNAbj2nUtsSVvkUkNL7X2TfQPiC4ky9scKVWfubApNN9M1cjLl -ZEI1Td8towIu3QZe3zC4JHN/hYbFHSo+VSVyU3011xM3lH1r3tSYQORUoq8V5sY9qvimbykvL298 -d0FeT+MMRbmdnDkZn4kj0WPJikSg7oMi13BUFUKA9NFVcICZba227iThExw2i3lZJtNKj5VK0+Xr -pxUV7T4HNL11MjeYOKKEFFrHcM69wxeuLCSCeJP00DYNq0eYrerHFQs698FFUigNhSJ3oG8tLaMf -6grDGlapmmbWw7rPxw3tHh+Wcj2fPmCY16MKOq3B0QuQgyIOl9cHzu5A7H71jgSZXwz9ZergtKNX -Ga8Y08X2RLkr7kC97Xzc/TcSi2UDG1+vh5fObHQWy1J0wxGLd6DIOHIxsfKY4wRS4hMe+r0i7S+B -3/bnVdehfqjCapUOsDoVuuZFej6qZWoFX7yfUy2EZ90ytS45hV/vW/uOvveLeHHsJ+IdLcZD92VL -Yj2T6sOoQ1MM2lOjh7Zujsoeg1syOQXvjHq+zLMke1+lCpZ0XZ08XsNydl7UrVF1dr6fNDIole61 -Gatl9EN0VnVbX8RbkvShaFPpOBjjnNpwMYoz1kmpnmYpk2MsOJ/NyIP+xLsl1ZDp8A60brYgil5n -3HjLJWrtNM73qTJXaVphgLV9Yvt7defk+U14bYlZ1EBoAvHXc6i78gAP7Yln0nvgMYBxNC6VqaI2 -6xqeZe7ktOsSTeN1BwLXWok+fVuXf3ualClwgqoWsaPHTHr+4Ta6zmPGqYOxbajE1qgmulhtU+sB -AX7HLc/y8Nbek7JGmq9RNScdZpwRmk0vFxdwCi3tT5229dICjeLZ9CQak+e5eZY/mhEtq1vzLtAT -qbfL0C7FpRXMZ60dlyRC3p+r6iwM2RsMIngYlIUmahyIBfDxGZfYXq87dxhpuc0JfujjzlsA+kam -+dTdbIGNQ0THLOR86avDi0jlq4QMrgdpnjzL79ZsS87s+bNY4ll2Rfyf9BeqWl5EVC4ZLhQK5Uo+ -cimh0zNp4/d577bnTLOOsXq9tvWaCVspODrp6tI7nXbNL9SkIDTXPuUOVL5ylhxqNr8luvgDM/D8 -XqVeGdLa8X4uYeoKZJjYpvOJMZaZSni5Ae675qxFY6eI+ZjzydbWuUFN5r1qpmv/fo/2tf6xPVns -xY5vm3VOJrVI70S8L5XvQMcYP5dv94/f6owlUfen0QnWFEIuNDXhSMo8Pij3LaTigit00ProI5K0 -yQOzmNKIc1zBorXUEbgPs74xpbisCvsrS58Oa/XGqU/QH5IooyoavgkKK6J32mpMibCtMJ2fSWBm -y0ucHnV1H31lWjzlkmZMjOPLvYSNwIpSyXDmBE9CBD0SveQKHMjmVCzrryY3B+vfZ1q8afZNIYpe -8Ih2mG/FvJn42SXtzujeWCXfvLBo1If6oiBW3a9pi85ai506imBro/61unOQ3Ood6EG2G3GuiSoa -qJ/X5px/9VnmE9JkE0XuTXNSh3HaoScbA9lf9fScr1J7lDTlYr4sHlUziiB0fb8dN0SEng+ML8Q/ -pk34pBO9dQeCxS9gs+xybagzf7lhXjs/V4R6NnUaLBKQ6/C3xEblXevjIukNCS7i1h5/ae8h4lHI -sAabq2pg8ntgxy9N3vJLHJqT5/KfEDCmcg+wxVnnGDnw65BuxcVtBSEID83CDYM2zdxHo7VP/c+H -PCZzvQ6i5XboGQv3YnMfq61oRLuUCm1iJTMVKvOXYfecDIeX2SljXeofkNbEyj4hZnbvozzcmzf0 -JnCoZTVPFuukk/JE1WNMMCyFpDiYYn8zabRXUsh/+FJiRkT7LUxzlQLH1KTW9t3XN8wrrA8aVYeT -orByZJEptHXzAtMzy1I5P4bjLRotStviLvs5+pHoc5ZvTdgcbtW1vNrbWzpwnV80Vmlf5/30eK9n -s8FIeeZ2x1DarNHSnvskmL8/mNXVVkmhtUM5aUR+ql54YxuLE78hZAA68TC93SOw8ypqc7/5tHdi -GrZ1MFHFWs7ha5elLBqMY4z9Dlc/VhQZh7vdxSCjaSKYnLiobpAWg/ujeSmWSaS5/qzPHYgonNoc -O7K75jv+LK22bsi01JMLJWYZC2GtmZSpYPsbwt6wVx9YjYySH9TrMYYFv4iz02FKlO1r3XTyOrDd -7DlNyKAT8WSCE8rlk8VFMqe8FkhXtnPkLJRdamAmnyZ+XZVEXGAgboyz0YttdWDh/DlHsbnVuElp -o6lh4WzodcZSY128s45DWgUjrzRbmB6DrTu92Ss4vaRN7CnbwEQJd8JamlIfBX2IjNlqef21tvdu -c9jp0NWQCgf7REn8OP5sfWxbQ+HcN76lzmwd5nLxT0uK8881kTmfa7YWOesu+PKXzx3LuGX15EKX -f1ZsbY2aL/McMIszLSLnZHh4VncxDQRwBLosRhZeTsiyI3xR271TmLTYPSnCNWPAHKo4Ca+jJ3bd -E1kzNeIazHXWiBxKlKbjZLy5rfaDkqq+Za354y82PvBnawhcKjd/GfEkmWvpplSKej6z7ELKePOx -pMd3stEW5TiHyGJuqEV6AtmUrlJSgZ5tU85CvbJXPZZ1C4VS7jnDpzohGSZ9g/LSfDlk7goN4rME -VrYNmziNwR4COu5Dl0Rma4qZAhzp6E3E9xJvZ5dGX0MV0zirg2evBjGKVGayHsWGE0ilu9Oy3zin -s85oOTyIrd2YFPx0tsHMNO+qmgQecKZl+aIxOhmkGjhC6Cn7RL3ekIOci7G5Frh7JmLwULihZVfP -CGJ//L4jrphBSldr0qm0dFXR/6SmscIlhDobf1AjqGJH8b297m7mrGctxIglcrlNMvuk7k0J4djg -E5eVlZhFgYNUOemn+W/1kic4w6bZSBbWhgmJHm4R0dubScWncTNFSea2dBcrHJ7UtLS0NiZq0mm2 -e2kp/dCyn4X6f3N2YFR9Zx1N7bHMUlcwzm+jo5/wuPCDXt0CxUyq3qCnJ3ZD4uIis5s8M6QLHGJb -ouOUn88qz4uRyKy/kSg7vbBOfzPjkq0AVWcTrXd7l/R1nELnJZLLggxt9TKjZkOiHqKLYpfepJnt -c/6si5yeohh/WfQxIVkY/cNmd0wpmeN+rGTMxqzTx4fQ7AKnYtYiwvfvvhTVGUjT54Id4hPHmVIf -h6SSxjKGJ4ZEFyHQ3tfLxOWksuf7os7/H8LeO57N9+3jjipaWkGt+iJVe5fSmok9YsQesUqp1VpF -UaSoqhlbaYkdo6hVo0gVtao1q/ZWYidGSMTjfp7nvu/vH/fr9Tuv/HmdryvHeZzH5/yc71xXLp7p -wlGz6lFZWZtrpqEqjfer1DwzqhSV27Ie3nMVe/kb+/YpDhurzl9x9WbrwbVsxdJLW6H77Ie9lXC2 -GPMJP//9vtbWL8bqOx9LS3GcoQ8/gY469tAhc2JOSccGzqQSCDQjnYXN4vUhl21d9qM/McOVMx/M -f0D1+1P8tN6NPjigkiCcFjZLZIjSL2rbIb1zzOem4ND3uY23dZONFbZt/CTNOe/NaN6NftFszDmj -PFq1/CUtp4S31F5SW7ausOmrTIK5exgzg9f9inWNFDP4LHRl2it9pEHryvFM5AVAe9bo+R1VO3vN -vmS05eOsdt07A4slpnBbHEqJn++YqsCAtn/HppvpadMLVb/Ht9lGe5jCtjRhFCYuGkJ5aoUG7IE+ -q19a9uNGWcRnv77L8eD7bJSk8Yu5nPL2ZFzctn694KFjEsJnFU4lYA7vvdN7PWw2xh0ktGZu+3GZ -0/fbszSvN0YN7x8riLnECjPyWCdS/bVrTByo8jINflow9Nl0/tbTqpbKqSmW243NjDNWtoYuGQXf -bYcjM6nLRcP3P/G0yCbftbx748mfBHG+7y818M5zxuT6p9K99DPPg/f+Sdzu3vW8tIX8DqqqLFay -OrIyPtB7f3rE+UNNBzRd0mSgPlrD8k0vqxcKH69JaP4ozOcAmhmp3+WdrfSK7554mb9uB2OOvV5Q -j8kbsrBBtqs321e9EK4cSrOfcWbFFz5dzpzWlSdWbPkAPWW0WoqNoFWuUs1eBSkicM4snzuzXrHA -BXSey3FlJWt9til/VVHmDi30CwuT3EkVu4yJJtTMLgfXMMtQ8Fzt1O+Lhh5j3k9dzVm6V8VKn0LK -1ZzivSahZ8o5YoXGtEn/RA3lbJTf4bjKL+kayS+/lHc5UTkXS55+9bHl0VdhGndj+mxuFYFVS+SV -NavwmLjRwG829BQj6p7i6r0sPk/3RTqVI7W4QWZcjsXqoc4tquHr3ZVt0st9dLoJBZdub0jTRrd1 -ObHQqdoCoetXs2JCxuOSrquiJU1pozpVPk5+/vmxqiRz7sa8zf1gyhzCoxbm+lRcc1tt3vQG+r1I -oyVl0b05dXfqiS/yH72usL7uLi1x2+b77v28id4lgMqy0X5BPvqFpY8OTwrnzk85nMjoPFNtsg7P -qj1cmEYIm9ohtSkpKfooslGM+WPjQKPWuJVrfOq8zhiHR8V4lhdDk7dHhLdf3DUv5yZok02d82yN -Lxvb/aIs/wlfeVfpMbXt4bi7cVm1Mo+rF1ybV2e9esBrdo5A5nqjYyqVYsO3r4N+RnszDvlNMG+4 -m1okZfhNOaVRUAGKRRSkioZUJwWTHYuvODZBj7OfukqZJQ3C09NZ6VqUvr06eqksTxb8rG+gshJv -+GqsQbSny6vI42257zMzCTJObyu+xP/WhP+1+y8R8yZcdUaPW7MZMoQ+RjM3jpS+1Zp7Wp7YR5fG -aK6l4Z3sJqx+t+ttfvRwmUiB4fKU8MzOg/a6l8++2jwjOm6/3NlMPZuwaKJrNUyqMvytfqPpVi+F -4W50L8LHNfeayYRIsJBCYCkayVw5pWZRQudlsl1WftVYi7+RSSSohX8kb4CFXji5zEv+kZO12/Hn -nhUXrlYvPkWDFqadQJ+Wj2M/4nrY57Q0AieNv7K0aus6aaAl3iENXtpyvxZJ1i5ch6/Gco97VfHP -/Jb3Mv/3EyhXKXgA/4kbUH67SvW/VIPqf55AufqfOv6LalD9i2pQ/YtqUEetA/G/GCgk/m+qQVV2 -x+NKRvCmXfX9tLDHY6UnU0kv19oVkxQ2BzdXWsYSr/3zP1TD94p409tiX11vHxbOzSfrQUnYjF9B -93VLqCiFdG8ZJ919t5Ml9W2ldSZ90tX1/nvXenFF/44t/vYNNp+fUbNsFtwZ+0NfowIX7tbb4Rod -az6t1O0+UAxrA/NlupfUfUr6G2D3ocBrY1TUCqcYI5n2kL2Z987YQ4k/533GP+wSpKpokYSp4eGU -Js0fzR+e/JRjKY2wymYb5ULFmCpxvssIVNKUmOFewiws2KyV6NU4ljckP0tafsyjwMZkpBEv6hDW -qGPXuIjlmWz64DskWv+Hz6ax7nPDPz01bRrM1u/fvf6RHGth0dFtnkunwMyqkJNo/Xi6Xkaz8KBV -94VUodX6dIGPXdy8nZCk2oZ6QmfGtFiJloZMFd5t1d6AVwNZzGLCu5hEo8Wh3CCS7J2Z0vlQ2T3Q -pvGHe/2CUdPVz5YS66O/UjIYYhnQ/Cr2pbl3C76FtGNZCq3Fv91pbRv4dsOup9E8HDq9LLyn3bl9 -fOlDRPZzu2balFumvNiIfIXrz1rPePk81JfLPsblbKcNGtQWPo8t93A0gCtGrzcXSaxZ6wlefSn4 -9Iv5qzLtsMJ5xdzvEOCOcand559CTXRCfPtn47qBxrgqCcRLo9tQoUJs1/76jLRliHhVtdGDrb/t -z5Tiw/yUt5euJXBEE0UWU1ete3efcTjM+xfAO25CA8KZ1Vpkghq1uLec3q2vlkgsXtU9YZa+CU9j -13vnt7Lnuc23okA3UU7160ruXPE39Ru/qnolnLhDOGcS50hsgXXTVa9Tvw4TfXOZ2JfuJrlL8B6O -fPzn5WC07axigFNLqmPeP1MU5hPfqia+PuF8Ur3MCeXouVnol+Nw80/Zn22GGZjf+3+Ctk2v9gk/ -n7b5KfFA1Jqzg42qqMtSfmeGKrf+5B+15Uihr/RJJ74N9Q/teVL6W3dFUsU3hDshb9CM24oa5a37 -Hzz9gmx8EgfrvN56NjQnvvAzsuk1FV7rsm8kXj/mh48fAJiv0HLzlOqbLxEndhW9VjyV+uYfXnsG -+jKzIO8EZxMPG8daVtq11XYHNX+DXgCg09+zTxoYz+yu3d/FizE58zHoRSqtZdpWrSwJ7oYemMQV -Wc6aQO3niwuXt6rlU8vmVVOX1EreezdpVhXVeFbq2UTvBR5n/i4GbJ243OQSxuepi3Uupa0eaVSx -2pUP3KF5XCkU+pmBg5aVDSDR6w1Ned4000+/2QDz6IC/FtdVGq9I4GJFV9hrThNf1Pkdd3QlLScl -UcvX69tKuem84DIeSOEouWaipMz6spxeZ7V0kc9meuWNqOzj6aSkpNz1lqaIWe8vTy2G7eG7Hh2s -xj3+VxmHEmA5MfWdj8rFT8QbC9wcvNltmUux0Pf306VtdkpHamLWpMpnekfLHNTlfn/nsYvxN3jz -V5kklLQX2NScCCrkMXu/HTD7UM6L9e3PB0aqz7yDn4tP9D76XcIkJ4Ot2DTtU3qsLSxo45Oa9cFF -KNGF2GKax1zKHycKtbayG+D5UySw4NkQaVPprOsbrKTCPJE8ypW59Pzp9ougv0+W8On2mnsP1ZYX -zwda68tSzE17NXhL090ndBWEd+Kr6sywWMWR+TvFMz9iIxKcWcTZKmcDf7ezV3xwrfjHnTX6Sqyw -Vr3q0wSeuQySZfuS7ox4VUtE0F+Od26uMxnUwa6qq3TZVQZvLgDSSzFBEYb/VAar3QOFWC/H9jfb -xCDAa2JG4tTet2zUXaknmnUTf5sMBfi0pT2TGRGZvip3zyT4fTXzHG+U1/wk+4HziEHwzWLPfyKd -oKbd+2K0DRtHARLGmnxMiBcUsuYoQh/LZw0PUyELtdE1InROon0d0Rx0/ElNv8lCT8+g9V3CHcOQ -KgOuxraga1/d6RPiEtFemuc9n8duFqWYm195rJOiHdDxkOmxStEJU4V8jbNdoVc1A3PjQIlloxUk -wFbbsRMdF8R0HOCv0PbOKqCSYsVYmu3G59HYwuUD8WtqyFixFSZdF1+Ox2nXw3bvSEhopFznYPnQ -xviFO+ngOz/Hcg7e72rkKPpURcfcpGw9jV8DblHcXN3H+r6AWnzZZ3neUUJ0y53dSKJaTy+YD2oU -ITwW/EaeJZz17XC1/t0Al2fN323vVxT4xU7cfZbzUKzIrheO1pMJTHt8Y0AUHlbi47vvOFKm6EwT -LKGpJI4I43RN4btGPz0vozxg8hqqQ7NLo62tlRAVh9NovHRgVQMeK79FXSy0ghK57Oee7/7zG9si -EEcXUIDWDg5zpzMXKTqp4NxAvtMB3hnI3rO0X8g+7a3gsNpplEiL0SquwxfdSh4J5Bpf1lD1abbG -fDGtx0jdLpWuPtNPTYXSeJhnNZX0hUgwuXKllTcZn2TTq7Jr1ZWxet1du/c5ykK5kphkS+vmONGX -8I3VaCRYVGstvml2xWe3iaK3rbwo4LPpyftgzSOM1G7mqN9fS21naINcExXOstXQoZ0lHaDTaJKK -vi0ntVNezi+S+GpAhrGxNMlXKXAT6655lbFS+sOzxS+FTkZwb/HTZAOOFWKU6eBketMAxWHz7Afj -ct/pWVtF8TjbhzZCnwnktWn5wt8uL+u8GAoQIe+GC8ftrIkD9sXH+s5xgTWzHOkHSo4SVTek7apS -GUaMZF3EdTx1d21j75SZn6ryqLcdm/Iw2sMHn6IrTWuPBY4DzShZdlqr0D7EQCla0UjDei0JWsn2 -ac0h5ix17Vyu8eyBLt3t1HUDOtoyOBSuq6e5NsD58nVz0fOEZu9CMdsqNdiLlMFnn69aW8ElWKys -157q635OmnZlnS+5//mcEweFxmt/vgB0hAezDcHZ4u5WXeN/LT7DT20wgF0+s+bVuq6jt2XabO4U -YTiv+RWDSHSf49dPsdX6UCvJmqbJb2Z5ry1+YiZa2OfpCV4RAeQRWPBqiI6YeRE1/3nLBX8Hl4pl -lqnYXftToci+1N5mO/laW6z7VoY1Ed3WMflBR8dPrDGQa1D7auN+wtG9Lok/vylOWDOL7//ztS7y -d+SYF59ZYIbFktfbZ72f0rVlS9c+6z09kAR8R/LHfJ6/O/dQKfZZ7U0OAcYEebmBrLvj/C8Lkjwt -b0zckoiF+HDPqqUVaRvdjflZzGBSaOQWV/I+e/QG1iYJOj1jQMv2DCFiq9j+NbDpw/helv1WY+p4 -LwvRYYGm8bRohV1CqgIa1T/XI+KSKJ0y6DMTXe1GTtJhyIyLUOPszS83LFksPChI+ol1Ze1pFu9c -6qUfauoe4eCl2Q1mkm7WP54snV5Wd2xSy+hLLxFdvZ4WrABf4y/LSJ3o3X3D1XWDzaFZUfKVu+ur -R+P0xOCqsgCxQLHWKwN0wpJRtDeZrpzE+aVsdxLjlH895d2NLhfiuQCEJAZ/G6N30oimm6CaO66Z -u3GPIFr33X0HxH4dSMFr5hE0Mn0X8oKKqUKVTy8J61+4EDbr+Hxh3l5QYoQo6nGMpPg+lS8jjBbh -d/tILfr2o5EEm5hSdkE0/TV/adG5wrf/2MgMpOZWk1eLul6I+BB8rzPusF7Tf7CvfoKcmwvce5n5 -c/6c3tNf572679X3uODv6/1SGky3OGOM/+RhnMM2wzIV3U/MuvRwCnKNOgE79Tlfwbti9N+RDPAC -Z3GJIxedJg1DphtP2wc9b7UwNU9OV3GgOe52H4p9CXbz5j/jK73jzN5/EsWVsS3a4FEAvzJ3zc13 -v9IsTpw/WvhHXn6xgSOtx+t8/Jdut3K5yvhXFi+1Xq0Y+SbjTNZOWk7HynrkU1+2uKa4P3jo+1xi -8+zhk8Y4USaYR2tr63GNxzn+zyu15OKW369FPHtmJcw/BKX2Pza3wITuj0wc7KbXZfqFTP6QtpYA -tdSLGvX62dnZwUI6JGzcVn2nC8T5KJJdHDPYgl1Yxl98roeLv9KLddewWt1+WpFtVMxtd2UdeV9M -9YdaCbEzqbNGjd1NUvMmnMaAS5GvsaZKx/BBhpDlLIyl7nuiQHyD+02Fe3RmkffvDpftZJj1MsbO -8juW2zbevl87vaafKToy8f+3yT3LXUJKmAI/33qpnjEibXAvT3lY9A+o+G7Nj0DJAW7ejvEK2wvA -w1W9SqrJTzpcJVAXA/L8s3SmIdpnR4GjIz/z63lb5H/N5wruJuHplyInfqf80yNWkC7rtqILX460 -Hvogrf3ZcpcbrG/aiGJuuHfC8dxAuiEr3blVy3R2UBQ80SSl7t6aKczqIYLtD7hs2y8td1EtHZqW -EpWUatbKGd1mrS9qZh384zAi2LCGFppZXNTM3pM2L0r0LH3EWONL7OaUMJ9IebBStqk1LdtnVRq+ -kt48+LhixkjqgBt7gDLSpzec91ejreAniUZEii48sbHkR5LbzQzM5nXBGfJyM9L5oDQuMPTZjnNG -9ahVbi9do4CMkNGxjlvsnzv8xt3R7wMsZH0l2itPRLZOkqob+bN8kpt3n53ya73K2wzl6NhjhRMC -YXWkyR5Otq5fn9yHTxJGdRoTwrAnNR6tx0nmVD8q+uzsrJVrxJmoMq5IEP4evhA5k/GokaVlzQkU -e8EV477BltbXmsn66bQO/BT5nne9X2c9U/bmpC9wvlqEzyp0CvRAeygFz4f4f2/moPyvmzqnuarH -NRTV45ld1jLZIxMYwt6F6x/gvzmpx+znAwbUdJFVgTPtr3fE8+szl9PKR+fWMC3zARwRIVebf91A -KsC+yZR+QY5y+JM/ko4TIQ3fHd5L2b7Z0/PWyXnhk1Ag3U6BUcgbZKva9HpKnlao1RcQEHMXEHxz -KB72kivKEDWBSpe1w0yPLnx7qZUxwJmr8bpM+pf0s4TmZ+2eKkwc7n3Sln8Gr3/QugCItTr09yIf -FbvJCp1RVDMmw+V/B/M/y+tEw7D9H461ZuVL7ms3kMVdljhm3BRMla5ojby9qvrH4WnHTL1ajGeD -onqDol31eElS9GV37BOV/Lc/zpQfLBHePzsWKyrlbr/8LpO6KjrGjylANwOf1T9zTwP/5JS/0atg -yq43/oWjOHhY4wWTDNh4iQnt94QmU5ppfxRWCIVabZh8e4TumBvKPPpMpM6FVECfAJqOGMII4EPI -w1nkemwvXqsUUFCaPLNGHvNaTuu69dgAHbDrDmYaUBtZUcmmWDuJWSWu4DRO9NTW8r4uDrWnCesF -yFNI5XddLRJtOIaqgR2CwMTbf85ug6dM7njMGs0TqY6dlyOQ6d0tCNqXIYie/Oscu3+z5ihwaaqZ -z72Eb9+UJjz+h9sU1PpOrThrBDeITlpV0fB5fd+FW/wWQ3QW58dpaxlgplRC6E1x5Zh7Y5BE381n -n6NK2rWX6SW/Hm7efdH4RlhjWi85O6SF/3hMYtYYnIBcXbpPHrvbzSCvq72s+0Vi/mqyXeG2QMNg -nxbET/bp4zqzyNXMP6krAy5dLfK0znbjkX3vn4RPMi7R7D7LzOZTfZG+IjP45vCzMfH98/CbjtMy -td4mS0py83nSNJmmCaFFAqstfho+eS8BTWxFrZD3Iauxs3Tnpa6D58lJ1r3uGkHt0uFs/6YaVBQ8 -gP/EDSi/UVH/L9Wg/h+qQfWfOv6LalD/i2pQ/4tq0BjMuyX9YqCQ/b+pBnXZndD4hNHXQTp7Rzeb -be86PzYwm/vw6+NkGPxsYfdbZDBA47+pRljtoqmdg3FFTplwjS/MwKovTOTI8oQjHeF2AaBxQnZG -HRR4MJcA2Szq1w+d2kTGi7eModxAFoFXreOsqbfsC2DxJqqnzeslbh59yhT2uvgA/FGoJz4g/4bI -tfE6GSOg/LMJZC481VIlJCbbzfZOcnq4Quu99H2uhm2XGkrDaVm/MVM7vTNVNe6KTU7uRFmBMhW1 -cNVI0MMK9GB/QoaKUk4cXzWvaezI69JX6F/R8PV8nSJCYA/cf6MPTXMQ8KuiTejMogIVzSVa6L8T -GyDOo81RdmXlNWckA1WYdTcRDLMV3uA4TbfMS1KRqek54qBh1SvjAMYbw6aP/P1NoGZK00nC5jRF -uJuqIhvVSRHLGfyCy5d2AdmZorKprTbuy2tpaXRTEc8QcEOQsXLEDMLG7wFMKzRTHycqv3KHpwJe -WzQeHjmXHZV5eGK/mX4NXLd1vul/t0Y0YHLiQKxMrHJ9PJSUS5vLt3xmHodw268p0pjUSqWM4E7o -YqQ2d8ftpK0/NleYnQSJc0lDIhDtOiH6MTtaVgyaV98ance1svOqEgRyO4DMdUiVRVA9ByICPY4I -mEV4nmU/wF9hhgQYmIx3kvUIwhvqZcSXrg71DZ7KKkVHjWHtdZzqQxA358UKy5FcuUwT1f4QYITr -p8FEUJYjv4j2ltOO39slJWWzAzhzhS+2aGBKm7miuXwsgkyDHW+JXeOFAqVPfbQYUDGPmjeuNEdg -+0w8cnwIdVAjsOrhp5S13r8z8Vt2rJ8UwhTfjjPf9Ewrg9aCaHrOOZlAdciaq2GNYXrwCQJYquM6 -CZ5i9rpSU+DVGj4EgEpbJisnMyWQmYPqjGScmaOpfcsOl05Ehmz9DO4w8cvVrN82UjKwU6k00hbr -U0rPeSNStgXf4I63It7+rtIIEgPut54dV0oLbZwKKaDc16pBXfvuWxVIxs0paaFhvolDDpSAlhlv -vFxejQCfJa0H5VacnVK6NE/6zNdPRZ1QnD+fUUcD5UFoy00hNwfWj815VAeLB1Uvzcj49V/W4YOc -3efMubJ8Acqy5SFxgZZdFtmmXXigEZbuNyoqK5OJWXbpT2gOdcqqnKhZeYVeCXOBshltDVCrRaoU -KpCXc8LLEYlHDr7dBunhwmCWNcC7EyYfY+rI7NgjjsziM8CkDLYHQJbQS/AZ7D/AFYmFvqtJDiht -owMEf8qhl61B+TJlasrJ06Orc/FgreqYh9vpMX2ZcGeRSGX1dWDjX+hYFBbeMcQdW35UuTUOvDuw -cRoieFMoj/lRVcjIByc+S5NMn3KRZTt4C5TZkqHUspBZxshpeqGybwvalgmwRKNn4cWJIimC+BDp -iJut7t9SGv7GRUDqO8dGG/cOWx7vH/kH6Luh+w8KCB08WAc1uIm/LrGAh3sSlXZ2I4Nf+J3YOeNA -epV9biPk5ZTkUInDY5NxGeMQKhDOYTeLTNdvXGapwrLe42sAvimfvrU5o45HMJ0CgKgQoPSarf/f -K4AagLItLqPs7UZyjclYwchipKb9m4TN8uB+d+bY6tdvPhZZKKmza2ZV3aqc4Jf9/Tpw3QWO6mr0 -nGUgVW79UbBIdJAgmR+zqZWEKy8aW8Ti3RsS5UUKoHb+XK0RXBVyHU8g0AwfHE8KaDfzygq5/1GG -qfaokOIwUSLGqJ+F54i2uAGaYS5h6BSpa4hi2qcpVmibInKAZmbsuGPFzIxJitxP3zEWmp57V7v1 -Tm8IwJYP0xW0ihzSsNYStZM8ZUVqVLNK32RvB9e9zcgqx/nvXS3QEUZN6chK8rpKnprB9rNeZz14 -0E2e66vBeiRKXweAhxfDHZ4zNfKLDo9M0pLI2MNq1SiUZZqqydeJCv23/kDeQnshZvr2M2cj2DGK -Y9KwXzCKCchb2ZOex/tJVRkSJKyK/eXCH/7BwRDD6m7hUwKWNHQgSLQNy+J0nPXkrxuPaE9Ex6az -QG/8LDiCCRJg/OvhASGsT9IPeQcnyh8ZWapunghY4lIPcKaUEfAuo1Nl+xzlACAlj1ZxBpUHOU6T -BSE8flU4v5Qhg/9IA51kdsTVKc03ObJxYDTc2m4lKRY+rWxB03dcYARi+q08R9vMFTpeiZvARwO7 -fjVf3VCkgQeODMFxE2zmVL6yzJD4xmsKfj/zchpCvxjFnaDTKlJVTlnz/Smh9Z5C1B1D9q4llFOw -7TdqQYGqYG9Scm9n5SKHh1K2hsxAa+VxuGHFxAaWSln9V1xbB4j1HeNd05FMPRdBWw+a7lYOaV98 -iT2S/xAJe6CSjwfmb61bXT+aqGzzSKSlYlwvGcPLlT54m8V35UYu4tuuYNw8s98KnzFAwZdYIgQP -jlTIqaVmL8vx8PffzQYnoVVRNOkPbTe3yvUfZ46lC9HhD11sb61yC+kaE2S6NmSJJZlMKalIgCz/ -SkAqS29mxMT511O3aKnvVDBjY7FXKM94k2ahLDVVMCpMXsgiqYzSTiaYYmy28IM1NF1TmbsUtp9r -dl0X7Mew+ZQRWRIEKYWy1mz/Rha6jdnzlX6M1uc/LIadiIhVzz6qkbsAtJz3wnp3y0EN2tjH69+1 -mvedz7tggj+brE2CymksD98SjS4T5QMr2uyBVfTTbHvmMixlMZPsmNNOArabvage2aOh2E3OYWAM -jelVUcLIJkfKeYaUvtEVljjkOqIdijH9aSR3ClqXHy1+99pZbLSBOqfZ3Kn5lGlySoHyHGbITCwj -C7D5wMwqOWk6S4V3VhirnOIO6TX775kFTwjVpKmJR8gsF5WAYYDBvk9ConYciE+KHCSr0orefWKj -EhVXdyrICZx+lrpPuyky3AHUDHW3rLkawGqSKn1Y+VU05hZ2A8sV9lLAO8iYlqVQZaTH2cM4Bdo4 -jvFJ6hdl8KcSgXUdyXYKRTNWxpmgtpzPpyJZY+sBZrQ3byvEbc3Em6weM4iEgyMyRJGz+ndW7qS2 -couhvryWqtAMAWwFSFAem5aT7HjeCq6sO0hDFnhjcDFFy/b24c+gYP1yW9jsJIb2k1KqYox2L/Kp -s4FqGJNO8qmpOW2VrEciTQzT+aURAHYelTvlIeV2TbIRGaWwxaNQLuEpyMP1X792RVeHYdNjMiLX -9DFpP6TKR8ahOtzQiaSnTqiGKMvRsnT4j7c6hgqX9SSRkzS+U0n9gR26kmB6HkOeszJoEKLFw1Wp -Xmsq/Jqx4G+1Kp+EPSh55d5TIaNNOAjZXIjCjq13G+fKVdn6hrGlCJGM1N8svmyLVWs8M+T91T+r -6+380Vcukdbcnjks8CEv+ZYgATTKo0Me1Qk3UOpZSa6h+eAHirZvhDzezCe+O0YXaR9zWLet0cM4 -624gW7xvVHyX7WMqsnzbWDOk0fguHxpiO9mxB2orqryXw0WnYLqzY7rTPw6Pwi4SJncFNp34evkQ -npSzzpnm3ELDrDStxq6rzKefj4xozMb6SR1/23TJOuTPYP0XvSumJ4+JVpa9u7/4ZUQAYT9d29QB -af0evZZjAS4XAC6K5GwmTByLMam3yXSdw/g0YzwcC+vF0NiawNPTb1kSM8j00SIkdlBRBr/MBJ53 -ZiclqV0LU477dVdGFPpayUIGZ7T40rIvEOad197sPrONEHCxRAGzvKOMdEvkwBWiBKtYk/4YTt0Q -5QD6pI7q3CJV0iB9rYTVr5+Yb2Mi6BQXgXJcUeGzlAzRVwCl87GsGiqj4zMrI8y7MBE4mFN7K4yJ -d7/o2ub184pPJehswZ4LQLwmma7Yt4RyUXFFJhdRl2Ky+QwAw2V6nuWFH2MyqCA0eoN0Ninram5W -+plln2VIfd3ABqWqgQNIrRTPb9HNsX0jqnPOT4OEki1Ph+2cTwKRVlvYvClWvUok8YZMftnKgQK1 -Co8ZHhh/HDWhOgG2FRpuob/PW+rwnnvvgeDPmrnd7Wr+/ONKDVS8SK1MGpKP6LBxntDLo3ZtxbyZ -b3iNfZEM9p5yz4QVQXtMsdUrvBqTFrc4+O74jCZ9KDY9hSI03vGSu5+ei8UcKbzuoPmku/R3hpSp -6G/WDvXczMQ8LzMuedLKCjgKSdpMlCmXGW9eMmzAH0GeyxfSmgvDMYVxqWIjAmhYfLkscSI4ZH+7 -HLiu3IxxozHst+zEgv/SdKYkMsvFFBQx5ykAe95NHGYccSglpza3h7EbQsBTwYFAhl5zh7p+sIF9 -xSYxWY/ohl66ANBjt7ZOAIRW40lAhuDYD7nQg4ov/rrqB4+gmrUcVOnrqJ7XsctZv/j2Q0Dr4Bwz -wXV4ya0n2tcIwjDCXI4RwkPag6P4je4hKQ55NuuZpt8L1JJW0lRf/jbxpZcW40LXqa+W+O02M+RP -hmSJCumLppucaJWDK/2E3YDjpH5Uv036QBrH603osfaxnaLOdfJxRejC+wn/CwD/hucx2BVNndpo -cluBjxDC9kMt5S4itfRxzqgsekQvWGBA7E1+dQCHwpK7g2mlNEtPhhx/uSveh4Kc2mboPsh+1/Kk -h4RI5UBnB4tfSsuE9sEuxZKFP4dUakdvEYCot9xH6KhLdz+Nv367hshz+D099Cz+TLPcwXOD/ZjD -OMmWDzhtkXB7vMV8I5dSo7bnd1RJkDITrwhsymhAOHsH/ejd6gYoHcvNhL4OMQ6hn3Uw8NU2CEO8 -IwC/dDUTwnbFYCDGnv3Ctq4hvgKHBu66C0BbjLkZaSpzNnTk/OeSZD8Y3ubC2UgumlkmyN3C6hIz -i36Ie1VQJ/DRGgUrvADmow/cxxbtfXSMBcseDfAK/uo/KtE99y41AzVupCOz5q9YXxH9Vv1WJMX+ -7Y13Ravov5VmD8cq+PpPSbmtjhYuUFlLFDWvVNFV8hP90PrkJcuEEVWFlC4+H9/KuW3+pHTd7jiF -f17CMmmINRs7z/y41VjlmWZKBI9NE0GKh0nM+LSSogXXN1aT21UKoENbkVh3K0ZfmvG2YhailRpT -rvJtV0zNc5UNOcyr7UTl0I4bqLULgGkfLyxtzCE5+J9gX/Igw1me7NJBGIdaxGvdQx3yI/NzjjpY -zxGYo4G0cGoW0FvmFu4d46cMX4GP30BkgL1qbWjJk0zd7g4/2ilkJlbztacPDEwiDpaPiN1PVBcd -DLqjSGhr1pLQwWPMOC2sd2+4tQh3+qn2uJ27NXROvox401ZancuszqQm/mcsOJ81Y0wE4lXOewCa -A05VoKgZkUMbOzE44P55H05Z6DeScJuY4Thiy5Eudws92AQdz/otivNPWkRGhKnSIXSiBY86slMP -lVtStbO50doa/MKn9BMlN0NzGOGF7RAayxSFWq7Rq+U4wbdO08IKCOHQaKxqqAVSDfWgAVcGu/5N -hfcg+EljqMWmw+Sf8SRUPN8F4L4JN++rnWPQort+DuUdR2FmWFoZx1kbRWkD/8dhn3xISPuh5G0F -FPfXRtLUBcBJENIUsdPb9pDDqSOahCQ6FjxYRjWtnk3+ia6UJfc5R/w9+TfVoKbgAfwnbkD5jZrm -f6kGzf9QDer/1PFfVIPmX1SD5l9U41rdWxWBXwwUSv831aApu+NlCDpvDaprLuM9OsK6+q5xSiTF -6crLiw0B7j2Lrvi7+99U44gFuIGlzL8AGKUfLxLCfhZPHBbGc96WMq3sJ4YoSFZ3uKyrqZJ13Ky5 -3BVAUUpyyuFLDpWHnvAgdXZiNLdVLS6Ao6yOjaFmC8i3WhzSDrJ8SjHhEFgUvwnv7WtnBh7n8r1F -pm18yCcDddXI3tV3wjWPnFG1hz+yjM5zhifGVmrCmB2kXEQzREegIU5xZ+BG4H5ucBzv6ZWanPRq -KTs/rkTwGvM1COMcBLz0hP+uLJEW3YhzPqWfDmEVdfA+yzEXBEIUFEoCaEaqZLEiFbqnsiWPok58 -qwxAaeMnAkjDBXXaiYNSJKG7gAVnWDIjIbaZJ8I3iZxj5LUG1qV0N3dfysR1LJq2tThynKHgBy4U -kY0OReLNiIXqJpj3ywQUxjKZaCd0YO42rF1pBPBgF4immxDhOkIwFslODJTQrhVJke2FwUVN/bHI -BoSl12tUJ7m7661Yl7SZMHZygL14f8cCNt/no1xrST/Hh0wbNQn3NqNi/I4sF4Fthd0a2yk6/oYa -nSnQP7+teqpUDGdSNhviQ29v7kjd7IlLj9ju54Sfd9QU/oR9ZgIRGtxAAzfOhaHlpyYcoy1x3+2Q -PrjJmOxK5t4V4ymZyXIs3Zk5rjeFd+itBHMach3IDYz/rrDqz+xoVliHBbGahM4Zue+HJDB/B9cU -7Ids9NyG+L2l0h65W10qxQ7ZjF6T7YRcpVUovDo5Ac/Da/6Fotc52PYD/GHWBEiBlvARaM4ztW0q -o0jnXkXMiBgzp7U1HgFsd/hizqA3FoNX380nQbIXsSIgaG8/2btJK4FKIduRTscEGkCVzVuxdO5+ -ejyxWXQ8uNaXSrNDbfEpo1f/ixiJA8BtF6kNiv9u/LpoynRd7PUQKwo8bjx5GqeQxPXJ8s/mdJH2 -79wwE6xCGpY7B5yBajyS0d7iIdOMd9TEb3xo9zUt18s0q2QZfXvarki5kMid2zjW8fEg5PgreSAz -vLcmBRjNZVkmuUie7DkIpSNgCj9nOKwqP9ZAzNicvaypvU7eOv917wIgNjEqw095yrtnVGbxQeTv -5zdiZ3Wwr2w25VdoCsgrsAf8ywWjjdJCgNKaDwm64McEq48fuDUOQvZ3YO2GXecaqHVSJfY8h40L -4lkHqf8z9PTSCZH/zplQbFoy/iHpQTu4Uhvc8s+iUtSjEe/RKXvJK3/nP6ZgyUjk9gXAd4wqHGhC -CW8bFuGm5aHDgbXXBwzdjBTeXEs///i6QrLxhgjWCaP6lQbtnTU/sXFEH/3I3Q4ea0GrWwKozGEZ -UlPOlRX7FgDWXvxrLAJSKSDRm60ZlY3TDFW0SVVq7zB+SzTGsYlYyGwoKBDLXwdT0Uzy6Zx7b0pM -ktVUgnA/UDPmDiPqHGBd8lOoAJw1RWNY9vqv+3YiNYKaxaCI5W+0CZ9JQmHFzeLDjcYBCuFPpAR5 -Dh6VhQ1gkGfFSCQ+JFAF/PFJEUxBZtjdQDH7USEfnhvqQqcLjUkhNnjACna0YZbFj/c9QKD1ynXw -mlb01olyCaipUVrGsZyJQ+9aBXBH8Dj8l8Q4xP9ERaxdr0RRZJnTpHWsXDagOVEQypQC7fCTsygz -woWuRPq6fx0tKs/3ST5VVmq1ff6IuU7uDFF2FMClWmrPnmstXKbOIoHxw4R2UO5ORg2f40+YUX+D -TFeP4PFoepId30g4lFP9u3HBsZkc97SSL5U9utYaDGPq7E9nAYRLWt8iNAr5CJ62Ih5iudTH+n+j -XmzvAouUCW0WAEucQ+P6BG2qWYZZTCo9uLU1JyB4ojhqnAOSIZqUZ8cXAjoSMxKM+4kRhPGchHsv -kdbbwEvkJ3kYrDpnLK3qMl1fwPcgkHZlvuNw7ZTryoko6adDAIQeElrKPlDLYq6Us24GvS4NYNbu -2hPcFW2qeVRbnS7Rct9EFi8pbhGuQFM+NlZnIjz6MZc1L/pgYvJcl3mhvgg9B8IWo46ok2J2mcvM -QJYfAoQOD0MUiqXWpjE0FkB8OrE4cKzRToUvlPL7/G0+40NDVLxBqbqCq6zSOKKZ/fPdWF1S+P5p -/RREwEEXNu1gknbMmj4Jg8SvpXQrhP2ULE+Bulugus51TILYdlzINbChYhIElb9I/tXmgiz9oO34 -53we9PMgRAjz9L+O1if2Oim6kCsXgF7BC8B18ikifkST6PL/HReAi27AfYb/eu/Vlf9qlP/1ZqYr -dBSMAB4pVWNH34iUgtrO/RGGpYM791SMHvm8Ss7/9HV48b//lRHCg0olxu+KkTLt9bZFuPWS8WkX -gDtVGfK8aXMTCYxgkSuMyrOcmBxtzPrpx55fBDzclDfmXAxR+/XvBaDz6w2ksouTX6ver/dD/Ty8 -rBaRhlp7/HtHRodtgHDGuXDD+xhCAcC4vAZyMBRsmmNKfvBUvl9HV/gCIMUqA/4HzKq3hzxly/qG -j7/BoLP3/YEHKHN/RAfRs957Lk80Bq+Q7EJhyyUPpYNCZXU7e6cczbIaTfFbscPrJElv1ejddFnc -iRqy7wsCtoy6AFy9hcdChAPT35bUkC43A+KJ+ohd8q0D7U5EJVnZHkG+bjMv+NKF4RodYM1HvhWT -Hj7z/Rvu+Hyq3bomMfsymsGlWq0OMcTp5Rgnv1xhm9wik9+gDoKNT1E9wG6ymDEm5rRc5Xa7t7DC -usP3hfklZvLecnqR8u8WITmnfK2kWw6qZtc/ZMc0nZuscKtHbA05a4HpIScOBITD2QWgBPJX7468 -TQeixETnnVyG0U0p5Iswgsbrp8YrkeRgUZEgkMAoXcQDaczv7s3YCgEBlOdt69suzKdFOMmJgSZa -VktYD4QPwRx+M55txCn03QXAsvJHCOabPYzgej72B2IDI7ybI+kR7pM+QzasdCIfwMQffPfTPWnw -/eV/f471CvsocbVj4D0+CLE+sZ4Dztqpt8QHQ8g04N9Al3+SkrSQNGvZNvcvAAzWR8EXAPwV5HyP -PmIVcUpzAUBmIOBHILwbiRZBQ3AjLSyT3xNqdfSLEOJ6rMpTrNeLVgsB3Ay10DECooRi/m74wJ28 -p1cIL0UxfaDDcRryAgxDcIg5N30/gMJnHjj5rCyenl4AIsNFIP1YDCbHNCsdVInscmhY6CUrj+FH -CZBv79yW16mvZPycXslzftsrZRjOduTUE5eN0L4AKIgOEfxRVyATW2RQKl23CQNv/AWA+5/OfVQ9 -uf4XyRt3XhleZiqIA45PnTEGO6yTfjj+3mFilxZFPEABCZf102pc6OVgibOuocVfAOR4l/jbi8GW -eNf9PPsFzFmoR80F4INVG+aBaDwLhMQvDLsAgBT+fr0AtJsSxi8AuevIfrLkBiKeBb7Dc3wBuLQ4 -iXqskFWHKTIbCVN5uE0qrtI31MLEXl9AzxlzI17UvCeijwy9FR+GLk7UC6gB2aL2LmPPrSGAoZlu -SunvNzItgrvCJSH9T+Yq7gvR8OPTedeLkR9cmG0jUqtHePi2jnrZQEtLJr2k8yG1/Zs/7jyBPAgF -byAC7CFfCUU4av6lHKtXL9LOjSHRE3GiE9FZB8w7FwC2nigiZL9KQaX8MfYCcGh2Adh22K/QwL+y -NmsWbXbwqSHrtsTaNjyNitynLGF0omyaJqygQGaQWdAE8zIF+paOhukF4MlhWhbeVNMKj4fLjAl+ -1bPkDH64h57w3eQmh07yI/5SXQaCB10ArkmARFiFtS5Fo6vnvN8IQ5ZbCwoFkSkI4wsglDZhzqqt -a/Gg8QKQchmE+wVAnpRBhk2SXvBT8iKXq2+bp94b2ZuzYJfHIc9y3lmT1ecgX0gXgJ/lZ5AUG9Sp -FBnqycuYXqKbGJy+l1B8W+mr9bbWUGY7rc1d2XjXrANOTYe4Y8kdTDoraHVvGd++GoN/9OrcmmRh -G7ZW9xwPOrH79ZuWEo/adFr7JkKPJVaaL+m5C5LzKfuRhDgYMDTR+XFC/1evpgR+wqeUVwLqC0nu -d3m7R2mdGbjjIcAla8W4eSsL25jV4t4ftF52e94TNkRtvMtVw17JoaR6DALsGchUFDyPIV3OzHTj -CwDnZKR76LQs4Gvnw8vROUIR8GwFLofFDRot8I+pj+9X/HZ3JV4ACKf2oEMhkubl5ki4CHcphZQV -XUoEpXlLXb69bl+N23ozFwATDBm0egEQgQwdXKbibJfka+ItONOv8bcTZifjG8z8NeDFadkFQPTz -5Xbs8lLRF4B/Lk9HypZcmReUq7un9y73/aDpIM1ub2yVLs1cWJ171wqZwfECIBNQdgdijmjeinFg -ppewl257g/2J+PFUVj1TqJ9nvWuVZB2PLYlWuwBk3FgJe0gqvYxrHHHiuHZau092S3ggxy/3NL24 -ZN5mO0cV9oPDbX7tR3uU2LX7cadioWIwT9DN2wL5HUw/A3RWPC+nkCHmUoU3aD06a5PXng73ihcF -ld5jnPGDPiV7R2uTYCR6MGytuTcLZ6wEITRbhIMkLwBv2yp7L8utLQ7B8vZHXLFUNei94Km1I1FL -qUyZQTMR+zRNnx+acQHY1yZBUkg1pygH8s0zuQtAjCEv5FKqvN/JnLbFgafjEMBTb0GCN0lSjE3p -1hxq/vYFoILapPeW31Qoo7/J6hrxo0rnlmSJr+y8GzTLaJCJtcPW4tN8/O1GbprylQuAl2/3c8R+ -fKI2+njqSHsIZPljQY5YfqIi2zay+wFT8rIW835urmpJB5LfITlgj/ljtbpl07srearJVnSZL10e -kuQEqXIn3PLyqheAWNpwdTIH6ITZkuz757JoBn/mihXWtsI7zJT0zMeNgh98wOzI7MUvwR633jix -HPK2rxS9RU23cJnO3CACYl7y/TVUNWQu4HP+6bjP+UdW5jfcYmaa21GTJOA2zU/ChL3Q5XA0kTCe -Z5gusjapBxfPGNKZt71wR5BnQcA+/eNHBiHBoGm+LAmKIUru1wtzgb9wF4A5xisQigfeeGOSw2Z0 -pHl6Vu4ts0WWxIHY3hlHP5CF6XvTmdMistmldDSUnN+MST6iSqMkzjKZTuhBjMTqqJxEoM+rDW4E -Tl2e0POPKW5+A6l+GWhwsNvemuuhl3bPRjkP/gnT5SqvfVwDfgDK/csCW8aFVwxerrLfHU16LtMR -hzjtCciAtme5sIb77g9dzbRnexRyr4w/M3AJzhBbIfjEO/T0YQTCTInyAtCXB2abY8TktwEJ4qCH -T1xFnISHYleiCDWU7tZbGgUbYX/P7OMvZWMXQ7z0SFEXAHP6RMe9fQNrxB0jZ56FIcgdH0LdgeNl -au4mGQ5KmVFeywuPG18Q0sWhs4HScTZCIfwqFwBmufyr9RSw1X8yba79cmI9UBsT+3u3cKcnAUXQ -Pam1YHw+g/3gUFcPuJ2jC12A4uO2PWP+eSxZKR820YQakgv3Sgle6LSMIQz2iaJMybRZ/6YaNBQ8 -gP/EDSi/0Vz7X6px7X+oBs1/6vgvqnHtX1Tj2r+oxnUPSc7HalevqP/fVONa2Z1rrW+4bp6MR9DN -oKZ9r7FE3X1LkdUWP8CwdKw5MUl2sP1vqoHEmZ5PvnYHIMqR+DATvrCamZo+xD2wg09oDuQzR4cB -iGfKnOwhiTqSuQA4n/+A0UQ2n7K2HuCJ785LKlfBy5B+Yhx3nDhiiqvjd5v2e50yPrDj3VeNImJ1 -4Ao/p3QjlPRRxvVT/qM50QMKbIkkqdBBsxayCn4nBObfT4A8o1zNIk6EA811EAOPEDLJ73A1XEEv -HMQsb6ltrWeEf87VNcEI6fJ3pxo4gz9wV+gQHUSHtGriMN/CRy+XRRWCslHasTIv5VrRiB7I83wT -3b/8ivJyXS8fX0Wv3oSWohBZWYs/9ZS4/MBjsMHTCBwxAk109zi9FJg6RVpRc/fCPMyPHjy5FLWN -+oJukFM4FQobOGsMjSK+RK+CV2PLS+DNo3lIHUuC8dHmcWuBeb85xFc7p9Wyr13V8sfExmsy18qa -0LVL43FEbDXd9Q2FhQOjFgmBcuOWiXTDvgHQ9LR9iUosuCR9hJbmOM3ScNaa+AExocsU7sfEEclA -bT/Zs+LC9Lx/RN2hA7ONweUg6klfiRFRpFqS2Ih6VDyRpwgtHnSvQULGaJLVqFYTuO5EnjySCUXO -ol2iuvpL7ItqSYqgNCLMFxcmJbozMtzPATLDvAr2SzXHBoQEmofZy4xEjeGoUumENeq1WHbC+K0M -gsCSQ/uhNF6SscSiXSGGqpuguiZiI2ROmLxBljzxRHyxOWYlSO6HshAgQwSw4H74JPbyg2i7kZ6D -PPIRTRThjdYGrocvbHlsKnEJG4T+4Y46jTiBBJYavZ20U8r7VENiYzcp8+W0QmkK7Su3IpwtTy/N -beO5Ach7/noilTO6v4KfVlhkGxyWhMlI5sUv621l8y5mERsliTBcCbaRrVB9ZaE/NcyBfvZlgE7E -MWaBEhfyJLx3jLZj9DAWEk+KImURR8Gqwz8wPeQDh/jxLLLxtiL3KOJZJhdHeFh6F7r3ExF9Ducy -y6fpIR9JmluunlnW9G+e6Fag6i0LKZdIX3fBiBeZtei0M5bqjgK4dIkFevnQpHf6AhBUM35eQABf -k/wDW74AvCCwbYuTHfF67GVmwsVCUb17GuKpbekVbHxjfI72d/bDEVHMdhCbcXHEtAwwjgFMccQE -f6Krhf7D+fK5Z5Xwyc+MEH4eov8pzcdKkn2F4PpL+q5dtuNjyDQxpgEz4/oJwX/vV/+bcMfLNaCU -7oYscD0KpIAoa/CHJ/H2J1J+pagBHTFss6aN1phWgsBdu/uhkOzyWNAiZm5s1T7OKkQsrGBfl+gw -itYoLWrIZvBf7PU1hnMkzbodJStfQf454yXpHR+cUoMdggKVYxz/tBuA2OAxO9SYnfOuaUfYjy2V -g9GkRhaMKTMp8cZVEE358pjfR58SzzQROSPgzOOy+nGHBgftLdeoZRkCRFDLc/achKQoDyW36Aho -RPy1uG4oOHau3bkBGVf/VO5+mnS592WNNoqJdi/FsJl4XNrUIBDUzAEKcN0UxoVpoFBzsMHdg1B1 -POl20WQxyapiahxzaG0pL9SNFVrRMHExNt131VIMS3K4tLuWLrpq7hvLhnRnqvact0+Ps/6e28X0 -lyPfM2QIfZcTaFWinUTSOp9nbcdsx0BlQ6cQ3o+njL+b8IO/gp+Fzl7RYd/6OytTlJViVEmp8UYR -dTKKerfXcyBOddUT+wtKnyhyEh0Xtw/UQ53ElHyDfEV0vD2PJhqhGjoYEW8uAIFROJtLaRFcVf/9 -G9ZJPoDED0+eRi1su5xXo2jUeyqHcjkgdbd3a5KJKTkh8rSamg6fQFeTpl0IMi4OTXUvEanrlxUa -2CdZmjd0G7uy8Q0aV74elDdIVORd/d07hCyAdkieXCc57KYQMHPog/BvCLbtkrJQ673jY91uF+zZ -K6NdVNpr0jUyTSZ1gjSjLRJVVAodSIpLTjkguxVryYBrcMBaMv5I+YnNb80LwOuJmqyzVwL3ritx -30/haKc77jrGmK7MIGdhP8K+jeA9TtlAx+qbMqEml9ZyEfQJwrYd3rR9nAb7WbPkSV7A0zRRA/Kr -kVOV5zP4m3bpK+S+J3w1mfUT8GDZAAlDj60ujWPLY22/g8Ihf4KsCScyu/+/fuY8Lt/kpIgsf6QZ -Dqw4k8LR8z8PjoJz97tcAC6DH95mMgiHTTksYtMISQOn1HCOd6d1qmg9B3g7ylIAKrgOh4frF59e -pm3vuJ29sIE7YkQErreFfgQyotqgCQcN1UCxh8whqS99/AkI2W4wJJDmCvmqkvlZnlAaSQD1Lqg/ -i2DAeCSY3akJq9AUXEcX/yU9HFO43Ohu/cw6CqyscOZI1tRO61fiAD9zmJKAbMd87aDah4QgTjwu -AIs9A6g1y70N4OKgcgo+fBiRS7xKmo0QPhz2/NOMqQMvkbvEpFfA5c9j8sUfJfF04snobVTnTNQG -IqbOGrHa0vFz+pWdvPseWWf7NsJTX8WsjEKrbICJWUbG8zrz0mqX2mF1QZrx+O1dyLjVd5c4lDj8 -8ZulR1wiFb4h2JfV7c0vQIKdREjVPrD/IHwkFLYyE7PwioSomqk5RUxMiYsJ60C/50fL1ZrTmhud -tX883EbUzpq9Oi9ui3xTBZkml9ZsZ12mExdu10hsAu2uXQA641OgNXsiEGr1dX4e+MjWU8g3dzvh -5Jqn9vaO5Xl95DH2rPFV8lgz4zgL382bHKacd+/HeUiR5kPqltHbMeY6+aNq4zohZVlkPTHpbb7S -EtD4GpEdC1v+TqcL9hcXPc+kVgqXkGz6dFo/DjqVcKjfA24nLXh7N6JXRzXKzTX9xR+JtPPWuRUV -YWWJUbs0PVuWh27dZ5N7vsB4fCjdMXz8Xcgm2ni502qTGwESJEctEzLDHZ7Ha59F3iKVZoR/Gzv/ -jkpTRXj221Iaxi/CqLNlhXG48H6SvVuVu5biMMOmBeq9scyxHpLIcwEovACMhCJsVsiHBHLTGqED -GNWqo1bGb26+1rPEEedR0Vq+mEFReY7lYAiNVvQvQ69iW+gjP8Czt1HvfPEwPeRcVqaSv4eqTMWH -2sQQE4SpSaU+lftWjdtl3v+ein0aVBHhoyhKR/CPC7XJm5kEVbTZdyTKLiX7jr35KPUH4TKI49qa -A02FUZy319IWrem0HrmN9KUpKzR4kL+SuTtriPqhedoxs4sEqVlkFAdNJyQGLxdVkciRZG4YWocS -UYLiQJltLz3ywb8hdQSMe0y3jOdf0hHLXfUKM7pohwEJxCpa8muD1PF9PGLnTA4rOlxw9gHhvX8B -uCdbZITrbkA4Qx6uX3piNrtLXb71p1zrla+nyXVh+Hg198eCxxF7vbs1q5NTkMfqNlm31OhSoOPD -shcA1zOi9nkydvOP+9of6dHJ8zeXRSHRtb5ymsm+Damb5CFNg4ER4QMYNn2IzeIIv2wV++Yd0XFZ -p8iaZEdRZhmE5zUYN0RAooSF1vg2OMcja9//5uPlMVxom4cVN8ov2p1mvXcI1xrZVsFdVwB5UM3J -4WSiCbyi6MqJ0MY6iIeGfnEuUjljsR+ggBoAAWO590sLkKvI37bj58mYBoVjeIJ7Of4RN7dd2RHz -NnIH2Fwy2hzXEeiP/3qvkZabZq8S6JGjMCEEYlWI4WDzqjEXJdj2nZfB9iG4dx6nmTkNw2MMY4zm -7vvBFehh6vBYlVOl04r/h7C3imqz69a/QymFYoHiGtwLxYqTYsXdKe7WIi0tUCDF3SkOwb1oBSse -3KWFtlhwJ1AggZD8eQ7evZ9vfHuM9yA5utfIPVbmuuY1f2uOtcBALkrZIUh4MdWNxW5QUiJoCfgb -HF+herfg0DafITQ7K04mBUK8WTZyjk54tGVMfp/4ENuRHg3qrHCCMeuHpWvIYBg6Nxq2kNxUXJPk -wr34E6GAIZu5bTh4c9QTAoxXkovXBC+66JckWhjOf9DmNyHRHWsGfzZz2P5BkRjCuemqIgtFWcXX -ggT7b7Sl1EqTUx9bVlOm1Iv5zbdrpJ+y/qgb9IgyB8zaoLSi+TSSuibo5u9i3KQ4TTKIzmFrkSBd -0e+Tf+fmvm6KrJmZql7pPrvwJp2rWUnn3mlA6VFDOs92Uek4YGa0Wl/W7D4V+cD3QFfav+u/Sg8D -jBYWgjRq+naBmeWl65VOLAEHl2I1Ig+ZVeAqRHTc1jgVxkMqJDzW/Dw/9RX3jctt9OYWNrt7E6qV -dv2lf1Yk823ibjKHgYHb9wJqxpn83Ev8KmmcG7aEMMQzu2V3qwXiZIahFz73wMy4ooQNYUKqY+iq -owbg03v+pEx/3XuEDA9U2bbM5Tgykw+jnAv1Ikg5Mp2+plTzGpO8Kd24XgX9QHfTbP3yMHOJU+et -uffFPUGZAqOUrz22P0SZJcHzhtNa6YP/ZeXT6B+5wlZ00lQYo4Uxjr1KofGA5tBXnbo5d374Lom9 -9UGBe8v4ZA2t5CwzKozWTY1y+SdqBeW9Epm0/Xc3t9VMUjWMt3lTZ8Rfq3pnZHCyRN6fO7RXVs2R -xjGN2yCwCKbDWfs8kxkB4chKM0wdCjdji0CJ1URQ5k6LZYCs5EBf6SGfh5ycrPxFac+BqcIP9cWZ -4ktBXl5n4TVU1XAmqksahVI8uApINTPDwULaJNmCRpvWLMUoiK5XrPrMv8pI3MOoEC/8V+Who9on -uq0bwc/iDzm3FkY1zAfoZT1qevXmZiIBrkG/VD9/RoCfknJFwutzv/NURqfSS2vk7y9Q8vL/tQ1o -Fxru0pMztssxCN0zMYJ67s6WY95tZZVq4dFjZs4dqy70Q0941VDilbJDqe7MBW3iexhqN432dIM+ -YncrJjdFEoIjg9BLORJ5T1RwQzFbolFf+cd6BcMdU/sGg1JkFmEX6bp8RfenVHRF95FYrWVVX23/ -80ey4T+7pDiCwik/vmHSBD9QPfvsFLapW6MZxVCm0zbLo/FsYYhS2I7R+buluo/2Q2ODT8+kybev -PbMwtLbxjyDrOqRqxd+o98GrFI/VbrWt3AsI6SuM0y+/uIxYGFdIzibx2kkPuMd90RbSyKoJU83x -Xp9/Tek7em9Qo6rosdSjNy5biyxajak9Im2mxpxiJBb5uumEpgCxo8wyVGfpuVuRGr6u2wLHJu3D -5PquO79u0KBrwqb240vAj6LdoumGpdT6h8ZqjjqqOvdlIJX0F1y5m/R9Boasxn5/3TVIgLVE28Q9 -5+eHOfynbnjWlsyBhaNicCZfocziTx4m9INJyWCJVPFa8mor7gthz+6pipBn7Z8veen3wZFlqluw -+Sx6Ex7dvF6jaVRzkT8QVu1kdFa6YVKsAWQ35eRRmpYXykztneNDLwPxYRFCNvHblFs6OHPRntFj -h7aDJgGlOhVlTmy6PQifElYutfrP8L5gOrxc+ttPxnCdZMXponW9j8a8+5W1GiqkipFb6JL5Jm7Q -qEVGDZCLZ1cbdObe54i/NmNdoED01/fcQERtbnufwvB5nt/zXIP2xk4Vn/X9na0bqQB5pi+6G6XS -BtAHpbtM7nj+jYQ9zJ/fEN55TQPg4i7ew42Vz9VvL7uOu0tVT4CEaEZnlU/qt7m7xwah85H0oght -C8y/4QYBDivgv+ED3D6Ch/8LNx7+D9wg+G8D/wU3Hv4Lbjz8F9wgJH63rTxFhqPxf1/w+rCKBVtp -R44/yhp00BZdmx7k/endiYKOxdjrZjlH7biTSkra/8CNpCvVO5eUI7PpAUPQyBtet3KHnclBYLfp -JoWjB6f1ss9rQVEHa5bBDCNXoI7kVPvYG8MOal4okohqNe1DLOeHK4eSboztDBaQZ3VEv917bq/K -Rnd8uvFAoNDzn1aYWc+lFhcsYGjy4rQpocks+pkN9Ka7HuPaZbHiTkmWGyjQaclrKKvXdB4Mi84T -I6VPfrLUDMw2xwIahS4fePzhx3whJKUDlDzG/dDUrTU/Bv/+8Vx22hBtTuJjlhOPCKi4dsZErRuH -vW+MJfzcBYWBvmDc9bttdjtroVFTYPEQmRE3mGwyEO0t/2ru5LqZAPiWUI9CVHzA3tm5n41xgQuS -DV4bmkKD0zHUEkCwSjor16wQBYxmjbw8gv5PI/p5T2+1hAMpmIpbFT586QBzhK5XvM7+venSHz8O -6ylK/w0b2OaGubjbwGEF/yB8N0FNJrGXxGfcJZmPXikPguJC5z/67Q/8xAJGBZZasAAShZp9V1qq -FheMdt5Tz7vpQZx/DwLD65+R2Zxau0E8MK8NMSqQg9LqO1uyrOvBG2dhzXugdFwrKKo0aiaMBeDZ -W5xbqm8fpM98Bu96AMMzPRu7aEsCdOYsNWcXm+4qytrf8JMNLIDa9Bzi39pId3BdRfjhyjZesU1z -QVWh8OGP5gfECrDY6VNDxbkLB6XH/KnUX2XPTV7bfQiSxAJEPrG8RYhGpSOwgGQbIqReWahUuGsv -HAjMuvUOMYdoor3OdcfBW0yQQf1vA9BeRzwSI9WY2nVdlGVrLMIadFc84KPBFZ1yWICJu/u+Ie12 -47Ch1DuB5XqGL/sJS3qTTmREgZ3hE0Ylbqx4/GQ+NlgA2z/RseCJBfzEdCMa0C+euv+zVTCdevcG -kN4ALCAxavEG45p1bhyVK1uVEwNlMh9KYrb/PrWIBbz73mVz81233PrbdHftvM236yIMDiR17KZs -6rA7vi+EKTV8bfHCYYESC/hgnw/eNlMBh10E1RcfXHfehYmegp+fXUJdSv4DqhVz0l/c6ISGS6tV -brTms4GiJFK3Kfg5emkpwrcMvTTPiWrAuNeO/LWO3z80FpVl+2SzZW2TfIwFSB/AsYB+SdkQLEBU -T4klffjSiDX5hLaCIRnh854Zup0spDnQ0r0Fw3NUqMy9/gyDYeQsIbDrJreV2D8S4HO61Q60Cfez -e70fdxMFiB2kteTdPnntCQA0B1FVyEdUIQKGyKZOYgZzuYgPL2/rnVQfvwBjqL8ZNn786XPTvQyJ -7u3+TdDZc2MVt3qCBZBjAZ8gB3cTiosFSPIHBrQucjGVPRWKg0nz8fR/lK8m/JCg+25RQ+Nuob/D -AkjlIWsMHlsQGnRWPIYBRhS952CjY01Z5n4XwstwJtXl/RQe29arIuJ74GIs4AHkDz8V+HTeNqCW -2PfspyRhrCS0Y72bJubxDhIjpA0JhUwwGhlHifdpp5Y/2y8wOrAtg/DfQraVW3HLWOu8PeaoBYus -7yK9mYLpCFLDwgzaqmBfi8dTewJagETe/sAC0rexAL7uM+ky3yV1q74zkAM+ONfOkJmQrx/CesIw -h/58a3MKUVFUI04Ma6ha/ogvw//aAVKT8ejzuB4WMEDKd3VhLS+g/veTBP/EhuujrKjXZSHHgytx -i1r+/Pp6cFdGoQYkb/s49xRa4G7BnbYv8hntc2ifSZwJeAr3B8eVX65AMfeNPOuOpTzuqqcQwujc -GyN/N7jXMPTKgMBpVpcklOC5OlsZsxoq3yDTAZ3xhNeQfLuAUy+ctAlk/NeoN+HbLaCNB6m7P0j6 -Coz8bkJKzBCp5qniMred88a6OjkPbXPKLIQ6ocy7pckPiXsFVsUC4nF758JEb/Hi8iHT9ua/c3vO -+qDDlkGJRxg/+28fK0vcNm3w9IJjrby4cfsXvJ27B/tWz3iCBHTimVHtSJtl0AgWoJTSK57hdoAU -3Oc9NcqNgEX5DhPExmte2yx3r6G6Jxvxv103z3LgR7WGnryFyWABsqs7E5s3GK+zLyF8iL9FrsWy -c/akMNKmecUclJADHSj3OYtgiGDI+5XvaMiYy0LBnVhxY7gkjMtrsYB1MHyYF5EMfcuc98AAKVmW -ateQKzLZ0zt3XYYFbKXz5Vv/xmWvqnyABUhMYwGhSBtTLCDj0/NXutCJvwLM4A1rvqXutVsh5uOQ -F7eWYKqXm5gGlwgPMzki58lYqHhvM8et6HXjVO09IEIierv5FUnhi4GlSwNHeaO0ZPLbBpQuDdo0 -7iAx0PMNhB+H8XZRGmSoLCrIfNKN6aRpI4DLbpYvUrrr4MUB4d0XmuEE/sW21kaO3ttzzBEYr2OJ -my9DAxUaFGIcX7K4JnLMfMQ98lpImbt4X3rjRvO8lj3Kkac2wwLOKhunuU0nhUX1kofF1TEBXsbL -DPYWDN/H6xn6bwUl1S8/9aT0qXVINjpMmk1EUmFsOnoRZh9jqovANybyJsDzcywAsN+6Xu7U2QAe -Xz276QTxo98lz17Jecrx0IPEsjjqgn/GHxeyVl3YaOxkFgRFuu3sY7b0/95JpeePD4kNd9Luwifv -GdHorovmtGtcRNYEoH9uB9GgudEEWMCFdY0mATLYmDOB957fIe+O9CbGA/phYbizm1pXIJlK9KNW -0u11pxEW8B0yeHonBCaJql1YAOdVHHrqstbdq1mQdea2aoLDBha1tulPk+eLzodMPEtd9EBnvsgS -b6VIKEpb7Ba6/jHsBjJFZ8VV7L0WLY/FAn5Us2epqHOGmDB8uF14HL2sEnNoewx+F9GqCgtpRrWY -Hb+4e8a8iAMRWPfWYfSXOSP976ceNx+xgMfGNLY6K69i7rN1A9qDF4QBNMsOiyA2yhP0Mezb3Vpn -em3HCUd97LmTzxtztN8MLREs7w9oge21ldgex1bD9aKVb3J2+2oqqnbpMYaw8QoLeChvbLOGajGi -asr1lYwf9ZjYhBRUb+JL6T9cqmlCBKRc19DaVDQmb5UwYMh//bPhvjr81O4HELYVaIgTXBKa2mcM -zYXg2Jx6YEiMHLqRr62uMpURl4Y9XXgq21tT+Og8MTeLyXu8U93z8/T3E9VGbk12JaZlhfzg/Zmn -s4uJ5WtoU8ZuqvZu8SzVhTBzzrq5LCyg50cnZHAi96sz8GU895xqe+vEXvEh2torMuQgeQL9g2gR -M6PqrYhqmID0MPTfxQcIqUlNKxYLOZVAX8VxQr8AMZmyrvEcgXm/UV66O1hA9AeDwvhpHXxKqFgd -Ny+bV028QmkAoaCSyendmrox5uBHZ5wfGTmMOJ3j8f0pHkP4hyTvmaKuNOogZ9UEpo3bbhKU45kd -vyFfMNJ3ecDvENQfcgl+eTd326Mg8Jw1BjrxG9LHgZ8nzB5nLy7AESqrkpWFqm+Btrs2Ng7oJd1D -D2OK3RNnCwpPmvmen8UhHHxzbUS3XNLEyb99wRGFezFH+0jkpj1bsegz691IEuKLWrUtFPheJw6x -HwgBbn9iQczpc9L/OB2MRn38QEnU5TFA2raKHID16i7nAI5lWhymxmeyNyZeESMBwy0sCJK/Qvvg -5O3tRAUMc9x9RmnTqG/NID48Dh9Za5GozkVHhR+LKrMHN3xNq6jFUNzWaltkWOyImWRqrcnEnUv4 -FcchF3ru4BhyuXrqkne6dFtFRfcQSnrnCmzWl7EApu1U/8qb5lNmZhfe4a97pCcizji1Lo9E3ZVv -mjRLbYT0zbcfityAYDbcCHN17o9xacwHPDe5TiIihcC4fsr9chgoS9Fr60+ojYxZZMGFUuQD7/dB -4Dcba7xvjyXF+G03ySLwN7weu3CD4nBvM6KVW5G1F0775fBrfc04DveNrW+oVXgT2YQW/SGVQM6d -2uPsd+1iAfeg96LjQ7mXnrp6+xsw+fg1PIY4+QetdElcMEi0Qt40q4z7fJPvcVoNyZMfYBfYhqP4 -sQAc2E5QXWfvPA0l7Sj8/NrYHKo5Y9alEmK8t4YF+NE5W9BCKQ2ehsV2HbuvWC7vms+mi0wUbnP4 -CFM4+qVwfUeDc2WJOxdHq7IEedY0OS5je7zFjxxcyt2CObEAjuPtP5aEhvU0Uj1Grxw14SUqLwkm -q1kQxMtc8b0YIm4bgDvChVaZX+6legp1ELOAN3XiSkYoyG+65zaeIjfZ7F4Kftj8jdt2VdXB/Ymf -bElCCUWE66rx6ytBtWWcBlxBRmouHAirSnUhyrPyNS8+elHH6ZkP/vWCphpS4k98/5xve41WKz2W -r8EpIh7Z78aPlKxZavlY3WLiWE1LRazu7/2oOHTiWiIcJUHr2C1q42hzzuwOPbouf+ITLKpFyd5n -HJHm8q0byT4mK8v5YPqZHGQEz6xf1ni1dY0vnGBoAQuggyPCfKs/McKRkPV7cicfJDTYb+u34tmG -wn32U5Xx01SPP3oTmJWdvnvL7DAzgzBOQ2iczNGH/LAei67IdD5TDJ6FCz73u128f18BCktlZzEl -3o+jaZ3REB60GQ2n/iIg58emDlx4IR8UZyvoovvWljIcnIs78kD/0/idZ3IYeseSZt3wuBIuYqdk -IlpNXrKlqT4sAymHdw6jDWcVYpWnW7U/nosZyLH4js/wjfC6p9NnQ/BeY3SEgB99iLa/PPvuh3Ci -rnuswEU8fGfrPyUFWdcKGPCrvCgZeRB1zF9/Tjj0qpfy1e5suHPSXo532n6d5FJq5xjeCQO3bKGO -oHFlWqNeP2UEacDaBFkz2Twl7oQwiZ7Gk6Um3P7MxhNpdQJTWHn66wQWeh/efOb3nkYzI7sVpyWL -0eTgqG4CPPJHjmA+5yZRyqehorKqT91BT2G5mw/klkKyq2H5n+YTWro5lGb9nOYmyFX2vR++kOuw -5/G7wkdtf8nHuVxgz/Ftnuqg8JZ85/tK2J7ZtUBSDh+voNzly0ecgeNmtDKYwjkc/vpO8ajUSBNf -DLcF5M1PP0Ega8qymSyfp6mFUDpw3ZjeY60WCZsKsWtwlUUpDhm/PTWMwgLs9Xh7OLopkZsgziE4 -hG3te216ilLr+5Lj9fwmU5/JciFuG+TL8DjGA3vFRZFA1S4eQ4fLl1Ifgel6oU8oJsbpA6OB3Pp6 -6XP3z6TXogpOaXRSJX332bnSnQMeQQhlKDkI3wqj9g+inuGuNSfX5semp67TNX2meKV2LJsJ5HiO -qzqxsrayAjFUerJLvIYREmfPWvAV/bVXsKjnj09Yc+89IUsFMSJoOt5X32nIKDz778fgQB4R59U8 -dv2HswWLRtLqyqry0LGJp44/eJEjryLOs2r5sgHShSG1u/b9K5yhZRSVO3BwWCR7gk2I6ouJj5Rd -emUpeFl48MFAzQWmSk5ilto4hdSJfn+2O4GP8eR4v+3TgDPNnoDbWStvVIF730AkfWK2xDLrl7O7 -/3DWR/05emaepevq4Ab48Vx0bUbSbqSCTG2EhsyT/MWluuqn2Wu/ZFRQvP++4PUhDivgv3ED3L6H -hP9LNQj/54LXh/9t4L+oBuG/qAbhv6gG0c9ndL5TZDj6/3fLBmEVC7MGAZmfIpmgPITLo00KWJpD -PxV1GOigX/u58U1WPib6P1RjXKPcDn+x3t1Yop0c0OGEbmvUU6Rq86TsM1J0kjgLrTYbR7INdGd1 -9Kpq95XmvPabD48IaDvdEQh6yiZGZ4fhfTgHI2Scb61Q4nnflKB5JOoydXiumnNPyvIX2yP8SAsD -Ed/n8/FicmOqJr7eeiyh0RPWr57rwazxKT1Ep2fcWfP1f8zo2C5ZtO0WPIoBfEO4UKQluSyfk8ku -U7oSPBcnexQsdaGMIxSXJHluyCTn7soGF4EcGYg4VfTG2V6FrBlqXVuDbRCAJyWgZFMv2gUznCr7 -WxoQ1zgh8Fdx8RCNYXKtzO6OG6NxaC8Q5YOfcvvRMdHDhKx4FPnpGTPe+oROpLQ8QZSGHu7WbTC/ -qcjQdFM1sMLD88gM4IwXlNgiFA0PgzerVcltzXgKDMEL41Knlqy9JQe/s4aP+tcrddJtrG6vbRAN -Ud9ffoIFCFrk0x63tw7Iyyzwpo0z0sganSVD48mZHYl1iX1MuXG9FQhrXAo5dQU265Keob///BbP -ItUmcdsbZDbD7A+RsrNyM43gMlAXi/Ecq8YHiQ+l+AQ8uP0L/Vq8BFzW5Hk4S9Uryli6HF2iVbqF -0A+gwmPGJ8iCPmZ58IDGMm129+nfPLocUdFkGFcrfUka7clNS93pXEnVIVm3nwje6cyzWO/jAZ4k -SWrGGmXxc9w8wFz4r3JR3Y+5be7Z+v1ZkfER8L4ddUL89I8RlvRXFiLIGuINR9Q+9PHbGlP1zhpP -Zkn6KGs3OGLmdCU6JsmVYWh9nt/oc89TeLPFn0UzceFs/cr7XYI+IddT5spTGKOpvsvyrYdZVGSq -hhNsGviMxraZ4mHuYBqi++iqRo1Ay2a0Ub1KBJmiRoji50hp6aDE7YrrCloDNacD72i5z2eyrw2c -BnnJCNX8ZuPJqcmTwPJuyQRX5/WpknqPXFXUpQvff9pWFLPHAtywgPr4oWHQRUAbsjN5lOhpTX7/ -UsY03p/RbbpfI0Jls4FgscD3BFbACa3ghkvMsegiRMOOpRexd3hyfHRzpw5VzK80Xscuc4/Pwy++ -20fF7vDQ3B/QUkQMKM1KvTL2DyQa59WCvFtUzLA2VkMg+Ug5dcKTJ5zzkYg7nwqlAvTpcDVm8RWI -Ss5XS+aw3lIs48IAHhf+dTg7p+cSqkLjf1sGA5zyW9P6JyhmtHD9fu9MZOdSobXPbuo++jatIkz8 -eH94vjowr0wMOHKUIZQHTjxA24cWXKn7edmjyq9sl0rhjLn7FD/OlQLo8rsf66XepJ+aerJLkyRJ -dmRWcta7TvHQZf/tKG0ntfRUITg67vOvLtVlM/9tED8lXz3Mjd/t54w7oc7srwVc8Pv1lFmqjvgq -HnBbh2sr2Kq7nFqSwQhI12KpLqdhvcsx24PIXjNRvJFbweE3FSz7JY4HzwVomU905fxljTlwEt5+ -+ilHSlgpO2kVx1onQaxfyE7ZkkBk5PCHunwyoPKIwpn+RXeLGD6JaodYZh/Tojsz/YWov2b4gHnV -pOWfBKCf/uuRt+Zd8nzvqR9VwuEAoe37WpiGNtsh/Li+yogl5c+2W8+n0kTPYGIxwWZNvMercf3k -6y3fKrCAcsm4Z+ohpBRT7TVi72tSdE7I9WYHOtNBHUK/fVwyKdRyB051E84VMYCSnXHNZ3g7TWOY -Ku7eK9iTzb9XDu1eI7qEUawJ52CqN8dYgIYHPicA//rUsvPpZRLwTUJiqlSMIMk9xAWmXnUDKcSu -PFi0v21SpBRxIytBh1S5NmVm1I0LX+uL/YP7saNI4scXOw67YJvVbZS0hGcK9wOEfWUBLkyLzNba -rcSWnMHnEkLpraQR04Uf2yn43c7f7ZAvytVxzgsoKiC5wmjLCsIxEsWBmvgS9YT416XjxQn+DqkK -fUOZfivGTTEDJt+fqu9QhQc2GP5SisvKrc2T31tYdUzdSBYPNy0VnUjscQH287JsBRWCTXSRkn3g -GTu5ykG0yGzbqRFxaZjRqaH54kgzqXMkAgFbae0uv+T7gJccutXeedocdKIKY47ViyBo0RruvX+B -BZBT0syYscC9fi8vPBwQeLyx39Sf3m18RBEhGtf0fe+blB3cyY/YZy6I8auvL26pbrb8z46bUqJo -XYmUfbODfFXom0ZjYIwHNIfx55NzUwuOI+pxoto4JetH8TSzdcUPkGh9G4lRXRIzjpXx1sauZ8Hz -crz3Np6VMPp83rwrLhziSfG2mcdEt7JD2A7tdfK/yBtdxy4IOSxnM/9clhQk5nFaWMrqF2Q7rBhL -coh7twAWdCdc89FJlmBHHDd0HI/B7GKP7IibhiL7bmZDu30SoEsXAUkAUi+zkJ3jiWz3t1hAZOZK -NxV53nK4st2E3KxCFsgUoJX3l8r3nmaAvxF+b/dWIO/Edj7KecEntUIZqv6Ma4pPhTv7vX9z0foQ -emE8pegKpbt/dTFw/l3/4kXGNV9poTXlqMLANJHvitLCe1ZYnZtGoFDxlR0kfMHQI5tiwQSy3DXZ -QBo9hozrrqSD4tRz94KnBGsOs+fvBObxQ0lk2Ueumu38TrPCuh+JxA3zn0mSt3RzpMjFVPJ3D7uq -GF8PQN7F/nwcXCI3P0kSWVCagRHi4LYjVzR+l+muw/hFOUUGL5QuH+lnT7zimlz21JLRNJ60Mrch -fnbLyrLkTMlb8Qrec07iwYrz3VpCFJe9SdU1b6W3WyXT15Pw9D4WIO8pBSU2SrPHAUa8u4B5j3BT -+NpJ1ygnwRLVP7zjPmri8jL8lnlVeFqWJwzkW+qs5QzUHaMq23HpeKTIIpPYrCrSfyX2fmdC6bp2 -HkQ9594IKmMW6H39nW2iMLBex6zSJa6bYlg73Xu8uGFhlj3IjPYTAS/RKl+7euNGTXHysh6z50qh -tABt5YfOomh4bAoaj9xO3dZDEt4nSiIEPD5lE/ILleVGj/w4XBBQsLyyvVJjHR316fgwDcQXYlp0 -TMdXdJTz0K7MsDqdk0gpbaThe0/3TW5KWAXfvXz9uLH019DCdOvO1KWeL/D49jKHEdyxuiUkP77a -lPiGKtpo9QUrd+W3jicuW13sLkALH/+iXGvoBn9jxBztzolnPkt/aXKdq14ZQi+fQE6P6m9DYssm -FmCKf5/luA8YIyj05HsmC+LxQED92wiR0DPzVViuxGO9aLfGTZwmuptyHBECG/B5pHazIeBNkl0i -QuIDN0eIUYfvk9n2gIrMeyEhq0bsacqq9ZzNs75WnYVVknhhGDcvgrjSvZax5f0xPiyAMtKZpum+ -NWuyMd8pHpHgs1BblM1he2yan4hJ3KDlzYWTOefHSodQv3ap36MgpMEg9LzGNV7ZMR/6a4r/CguI -7p80ZAmuko64MTvHR/v4WJPg3v6YmnKr6f2u7+2PrOgvH2iB5aQvsh8Xh30vM+4fEeKGnl34X42W -b0NB4POnoExj3M556hn2Avwazz1nLRsndUeXc++z3meyBbd6sckxaLNvO/37HfN7PHiv29dGytA0 -yCIAmLJ31U/nVVEjj6z5Q6Q5x0WGogPIMJ6+fxK03q1v57n6B3//44MnXHr9t2ZGWADxXCt3Rt5d -lelfSrKuUz056fgdCHMlfDP9iFSd5IDra0hDpsLW1yeBZMYpqNoPjdoiGggJVnncoYs31eXx21yN -mWEy3t/nUk+s/hL8prj8/HAfC0hzin08flhjOHW1qOyvkUjs0bOBBRhrghHfORXSfAaDDMbtp/i4 -D26a7AhQImMjSHh8UOQkuIP6rpQ/tSwlVEtHleJDLwjvme4PdcgfzjhV/aaUC2o5t+0xywYMQim5 -eotZ15kzJfA5hUVHLuBNXkJGhvYj+/UzD2WLXaYLejmnZOfrGpSeezGJDY22Jv/BAn5hKsosAuGT -M7pIzmJJuasRCmRRytuBMdiWM1fd71rcX1jAVpjEOyxA2JnnBDo8C4sGpd/yihH1sBhInZhXa0pk -xZMyBq1wa6iKDVumeZ8uqp0LnEkeLLwwY0G2VfQxCRvwn9E/Cu1/44WZURvjZgp3y9gbs2siUeOo -0lephg69YzBqVB2TutIhugWLV4L9GCmuTETwNLZ5fMUv/HaPtCVNuXz8rZUCY8lPG86oSbt0bZYX -C9Ym4tL+gI57uWTx4XvILEjcBqs/nfILQO5AWVAGj2COqYNLrjbv/QqoQInQNm9zwafsuSucc3FS -tbT09QWReH0uGNwhyqYPAf5y09jFwO7KzI0wfEVRAtoxoUG6HqdIspR7K63NDybzV5HlKwZM8vcr -FYC+pPRhAXhCz8rhdGUcazoZcnE4O4i30b1x6gSyw+YMFHvdmT1j1uLn8IFJlYAu3bMZIhVdWh/S -M+dCTbmfUJQ4w30yh52Lq9d9okK623XEWgMnlqs0pmuyUyrW93NpXiP0BsA4P/cRnVorocFSAjVC -D8IWpDYwIqkczsTSqlf+TAmjF00uSGIz0GsJU7iJrsB2mC/KIEfqnX/j4rq8u7rGHkSiwHkz4zd1 -Jpc/FoBU1jsHDWal0Fq+fhDtsdZgfbh3TfaS6eUc41z7bJK18qyj1E5OySNFCK6Ox2sMCdgO5hMT -R3bPJM3Xn7jm6r48affmUnNEDmWQlZr6cqSVzahBrMq4KuUJSeMEykHNJ0YSo2G07qh5KnFumEJx -hta0nwzAKAYbl4FFBl/Xhh17AfYv8+knFNxB7cnUXjVeQj0d5lq9iOmWlNlH4hM6aRqyfooPSJn5 -Qp5XTM/Z7RqtxlNqDLfU/JFxGOjV1fzWiZf6s7HhYH84mXgt28B2pOFbfnILZTl8IIShbQAJodLu -SulGh9Sb/8K5k7yH9UjTlG6268IomhBey5RYMIpwT/QIDLxypAOfb+pxreAjXDFVPTEx4SOwmy52 -B2Rfeab+dPK0ARSRnGu9CrrlPaLUVN2J0/+YzdsyZaoSkIkFZB3VCGgRNUI5zCiAxcV/hI02zqY9 -P8wG9skF/+m5x/Z6aunzlpo6l9v2m/55T0P4im7x0NhpcUURGYZ+fIKoz15gxVijZYeQSQcoaWCY -6S0bnew3PyXGmUG8yQ0x5mBkuW8CpcO0TwgPsaOaTetUpDfPlmNsHPPww7MG6pLvra99NwKnJW88 -X0ekB0bP3oJ33lmT7j9Lg3ud1pfGSfE31KakThy/kFVf8H6dTaU3aDPuedPYokzV+wSWtZuaLG2v -eNaNeOo6892mXXwjLk0uvWuPlrjxzZsQ8Jo0bHHkBEMT27jj90eoV/uet5lNdF1K9rFABNQ9Gjyd -HahRFkAA+dWq9/rb2O18KGHuqwABa5aCJbFGhKMYTUuNMiiWn0rqfV+dRMJJIcTmtB4PRds1z0P6 -3JOCYFNv1H8/7Cx+4G04K7eI4/xwYwOzoOziIwXuHsjZxsTsxQPNBpYsa5/KP+Zj7TbRmbEy1OC1 -Zsqic7HO9r9uyCKJyEdywHPrGhmh9oe1jJVd6ePg7/WiVSdntQSqNFG9hKHrccgOEYqtkZo4NTgW -IPHvXg1CHFbAf+MGuH2ERP9LNYj+p1eD8L8N/BfVIPoX1SD6F9Ugpidf954iwzH7v3s1iKpYhk4K -j0P1wdLaLy4EmT2Y+Ok+RYkbvUCsl2oYVmA5fV/+h2pcMkNRf9xXHJXOu43lGWJ3njs3KmdzRzNq -mZ8k1AqR3S6l7tGksll9miDtjbR2tjGiHLkUsy2d5Jultezw6AJV3tL87RL4yKasX7+EBcSLpDbn -4l2uiKIjU5eZ47l3PhIZeZR03CYLHX0RMUTKMtdiAU/mZ0N+cLR6iD5mhVnwrZTDz54PsMRLtKx1 -7zvJmvvGjCaEJtEPM8pyb9X6WjWghQ48cE8trR6YCQwz7rnYjGyPKR4kn0BMyDy+3c5LPgq3aVIY -V4u2OQbHE/+R6r3S0NK/jJM7qaEPBg1eXNjJEtJhAdp0P5Dk1vsRW8VvC7z4KifynuLxkclas/cY -XOogWym3Cyiffdle4srklqcSYDcrkbKEN88/n7XNuaGpyh0iQXeHuJIlt9NVNdHXluVHI9FmgphD -lVk+uUhYyxIz6dfR5FCXRbFt3G1X0anTCtGyXOiOAbgbCZn620HWPEhTyA1H4FDxEJ0bB0ykn5t1 -c26T6+KemZlAwmHC/XzCZ7JgExyJBeAc4K58i//SHVO3qpn24uyFX4uRQPplofyrUbt2YrpUZVp6 -6hc472lzzkktBZsiQdD9M60+onntvvll7uMwXF9xzEmMO2cg7PcoFw+4+tbA7pMaamCoBeFCadXf -i9ZrBrZCjFrn7kne5J52VwcEm7CEeDLK1iXRfjJKAb5Z1Oh4EI76JN0WxPr3bWsdFrD+LtdXg5bo -TED0g0a/oIAP2Y18ZOy67UYsagcL6J/AAqQq8111/4hVB8sulYFkLhCl3xKhj1Sv3jxQ7aZdIcJQ -w1bum+28tTCdeoFeIUN377yS1clSjRdBJ3wlVC3JIvwTbIAF1PjrqhzEnaDp45z4FmJif1ShFzDu -rgmKJzDfLbsAd1Ih8ZxOg4mduEnPrQR5fli+p8bN4e4B5Qv+3Po9fHHZxaelia7J3sjGZ7L4Fccc -aNNcEIcx/aQ6tYuWIvcjcFh15MN0zzDc7HO/xYGAU3kefw7Zro6bT30b2zDktvEctK0Y3w7UjYb0 -5d90crqfvdgd1f+5/8GLpibr3cM0e8xVmYCLmxMFMDOkjsPkqZwUsl27YHUUCtHm+YCMfxTELGAC -JSIRcZR7CnzjpaCFYTRLDVKwfGfiumdJ8OS9Kg2lGqijBSqz1gMc/PkV7gehc3YjZZK/vNaslS/0 -QMnhyfYjOwgpbCE3V2aE3D3xUcrmi0wUoL16rW+559aYOs8ktvJJ9dgShMtes02sog38XNkgNe92 -rI9IZp5COeqJgeJvkWEaX60Q3kYt0rdnUCzgwW/JUzeV12xeCQVXBsPX7T/kH7wy1pHGwQBB52Hs -+xHC0lcaEx2qRRgnlxaXDIY2mf3+TnMtofdX8NLxR7ovHBvEsYCWZ7q2AU2rIT/+ECIrWvbrq4S1 -uiKWfPz5Epn5NYDm9j3uo4hnxyOdnp01AZbXzWYrsNK3SOHnLBNaI4tLgqy1do2d7xm13W0PTtFz -APSTkF3vhPSPI0Htb2zPDoveC5DT/mGgCzCEJIbK8rgNB5FiAeDTknvHTCCnjdOUEqo/R54ARjhv -mqKO/8Xbquu1jowfWvNBVN5Mxl+ceLpGjr+GZKP1hvpibmeiv/DyzA1Getjqhvt3/eL/BfbFCLEG -C5gZTDVfctjz23Gsm5dycPw8w2fWFJEQrpCFiKsEjyj/UJjKc2Lbs2KmomAO4KgRiZkV/oneLvfm -tBbQK42gN5PmvZxA0GukstyaP2p8J55eWCU/igMKSxk9nufRzBq35NIL/hEJWqrUkaLy/3aoDDbX -6KdF3zmfezg6YmGN7+CJ2clvNin0vM34qSgahW1FoMZX0R2PiNaBI2OS/tw3kkWygiZDBxrnIfxY -wOftthHEolRpWJycwnJ0OrLFTo1Zbibn512l8iDrtkDnBPY2n3Ikw3p7YqN4ZrvdjdvHScOkzead -McwoNbiBrzSOKaOaYCdUWQFKojK1jQWE3VmwUPLfEibsUtvF9sVrsAVT880aozQjYSmhhG92F3st -+SGHc0zGfnFtmtGmprEgbuRP55qwnCyL9nITOR4SOu9Rl5o83Ahy8Q5hXOhbVypO5Oqyl1ulewuQ -phsV2mLriwWcK2ABkcN/g4xYZ9bP/T5expPjbfgdXagXetpsFF/XKEMp4fh/xFzkLixEfHFdjNXn -2M3Cgc+6mwuddruizwQ4dtCxAhwBthhCOi02VvAbQj8K8gRIH+AmNzWPU8raKbuwdnhF/Dbvvma/ -Bnm6/ZgmWa+j7V9LnvslhZTDQBkHVJXCtX6k5uDSA2e+4ylC2k0VdSLJqbzfG4FgziT7a3Ow2GOt -2LJXckYy+pDm5KafE2cUNpzWNefO3y5p1lrU97LByp/7wCoo5woeyI02qOaZmSYW4C0EZQpaFOvp -6LPyQS+BHaaNDD8Lw2WvHJd7yXAnejqg4hPGOku8fR89dFHTfpBoTIAMjxZJF3QOtq460vVufwxG -A5M7sCSBuWDIOAXdR2O6ZqjUtOkRCs1+KvtZ7RfWL0FgNoM5ZjMveDHZUM5zwRfSU7XXGe+ykVSr -TpA0uSU588n5zpPexhRyCa+Mpe79/va7WdY1HQ82Q7pa0rI/dfFjIFUu6VFGYQG55u+rwpfhnVuy -vbfL4GvQNYm4XiawSdaUj0Peml9ks1Oxt73tEaJ0PUSHXmxgFX9kwWEKDsMMZiSGCL4Z91KoKIlQ -eJQMoya64gwDTRoBkiva3E8rbCjTjH6GIOPEjzvrQH0vwvYc+7jcv+jf2PDbrnHWWFCrtW0wv5Ao -rCIoQhuC3/oeBw4OwB5aP6SIqo5ApdsXvY9+iksndrxgPUF11Qa7T7T7zlrsJiXEjNdXtQRyf2YL -PDTxXOvV6gU8C0FMQ9mS6VlLwFwRrZ/laPLt8VAqJsgmkChrd35im41/kFFf5Nd9OmtVM2tmPmEh -AiKwvKUq+uEg4dW6ar1Fhy5q4czmQQIEgWdgHoQF9F1D5pJ/oukqHWzAZy5vdH4jxhvA6zyrqMHB -fJzaQJ6OUkG+mWeSRy4VqjIGKmBUpQ0lTiFN5B95pZ/df5sdnCfsP0vKafPkoV9GSPn5I3TE20eC -59abJqqCndyM4G0W5qV4NqfrDT2OqOomZHnExun5eywg56/p68+uOCuQdWSX2uUBzdXj1OXu+9oR -uvGFDcC8tAdpj8prV/lvKEDL8RbjLv2ExRiqlVfFKw1SrVC09GHh50aPxs7aWaURi6xswYYv3orR -gvQsAQItPgU7n2/K34wB298GaomSpd5ahVkyZ2+naV7qdsRkpIfoI5DVG4xkEInXh6vTjbApVmhb -RWoyy93fTAnaF8ACfkwY2iCfurpMEO90vS9mzVSObs0bQ8GSXTBmjIci8oX9/aZrtgpzWMAX8VWL -SDqtlh+E5/ao6keX3+cwoLNX0E+ljjeNufMRbWbMbhLuX5rI3wdB+hVV4P7ucUaranO8oFN33gAd -SJ9Q7nfppPb6EUPeWEz9pEsHnO++LhBvrdjDWvv17d2ryirposSbGP4s3Dv7lvaWGn8H490rVJ5E -fat4F7znWACzGxYQYIoFEPeOcAZD7/JNihdmK+ceQ1iVjUTStBgzDRZAwxhKLpvl8Lkkw6lDEKN+ -Q/Pi1cNUsClUpa9+Bx2Kc4oFjP+5UPogdFNDOmmu3tSzsxDNaOp8DIgK8S1xBj2jDnRN/Wcjc+xJ -+alIQ7cx6ld/2XjVs0v8HXdShvhT2Ebu8HovzWithVtFJYYGw3Fu0nArNHrlMOiF6aM6iXpHphpH -rjYUd8+J9LpoGAvI/hpbGf6C5cYFzevfviLEkF8mEPiTiluGh9xpkF9Ll9mVWYBHYO6jj53AwN2L -vZ18+YLJsqbleb8LfPKmGnQut1XIZK1S+oUmIpmymsXb5jwuRLz7gMf2GRYgXJ60AB7Y2P/kQORg -KkUqL9TsDCdea3itw9OGH2AnFkGIaM5f6sUCXtx97qJ9p3YwVlYwBuG9+lLb8sKAjQ69sMlZYG4g -QHL/O9lSzvY44/yyJJDOlG+p9TtY4uueuPaW085FzdxMXImr1uI4vyQ9/ozMM8+eN5PyVRRwBy0s -oMAER++YFYmpHz7jVJDjCJ5WS/lL9MWt4lfwIWR3fqnFeQotaP6PWZ/O/87DECkh3WnVvT6UcAXf -EI20rqd7h5kIaFW9fTucT9hVCls+Hryy42DtrEKYoqVcGpC53+BqpZE8XZ4zGxitu5R2byvOUZDy -LkNlmdBUNHF17R/BRcMFSIxLkRJ7oDjaKGTLbiEWsP1E+PkrLzfNWxf0AeaR9/FZA+gvFlBY7T/U -r+V8ZZUk75rNdwZuqCrznSbh8vRqQOUlquzx2+N/rA5WpFi3sDD/Hb9zJOSHM7a4umFEOfVFCFJ7 -FhPFzDWa2T5Ku5oCiwLEYAGKcNW1jrf3vBVhsUvJph2bU36VGHwsoAfXcMCad8sI8fyTuxCJxZKw -r81ymj4tFpA/sVXzbLdRwQ30Lskzaw7jgwWwirpg1OK3yJms5mIhA9HtWwKzmUApe/AmDNW1HxYB -6fvQEDaMbLkLeAp1z0DzgMaAVz6Zqk5T6BG1CkfaH8BhG9TYMcg0JCBrYeDXcUJOI52PgZDLq1j5 -YMjkC3sWD3/D5GvHj/uJCqZ+rMk2p9/lPQYKD45KZ6uVMqUESHfM2QbOvUIvp5ZfT2oi7mMBdwKs -5OgOOaB5+qUYVW2HRxn0zuUQul8N5gQvQO+ny8ZWcebgQDFEbk/futsUj/Oo9CvsNy05Fkxwff5q -4mZy2owFJD/1XGpTciq3OcUZVnrhv0ID7UbNnaDzu4wGLuBVIiXzyagn5ne/hI8W5EFoJW60k4BO -hfL6PpHmSuT+UC237jF/bt19uFT+OGc/BT6F1sjTl+gVmD8jzJO++GTi0zQxMndhq1aIbMxm2xL+ -kpwUw183nNiMjx6RBaNZg/buQhyfKn7U8tR0iuZPJ9tN9+0NFrB8970BzjtKVlH+EG/M38AvXlZU -WdB9y4AFzHTfvsAClrqxvwDEuDiAe+S45AAAWdwJcqRufo2oEnZOCi/oF6u7uqUAUVZRKHeBbF6B -kWV1js3RzkwNVtJOS3jEKjtP3Xfz+rpLuWQkZbzdxGwzNiKMnz91l7r17nkhd/X5Uf/trcRTA6NR -2rUw8CtR9Kc4F3YS8bfu9cRIh3Mz8sBO0ww7h1Ul3zjh5FmPqAK37MXvTtoepxUKraZt1G3uNsqC -05ePLGm+J8lD1PgSvwQMhmjJ9G81xtil4L3/aULYP6W4/IDmE7AleA5fJFJUlzSQ3fLBWIDRN/1K -RP1o5ZORNtFI/eFpeJPfkkU4FjAcKv3H+fdtblNzhmlCu8GmiA5lcsoWnkrblF8fkOiLeYF9uvwz -H1DnXwUB8/bT9UmG8v0A3ZGp+zItqfsRjRCiT3g3oj+pchahVMSMR0tTTc9VTdKJ8MaF+C/uqjnq -f/dqEOGwAv4bN8DtIyL+X6pB/D+9GkT/beC/qAbxv6gG8b+oBgngtenCFBmOzf+XauD+59Eqlm+f -j5omrDct91mrwJY6RlvVtExfXDJmeP5SLhK8epwa+h+qsSsK6rKKlH16yjjs6SW4au7PDZKskuVL -sHWlErgZbCP9cTtQ+3acfrWdF/nZlaW+T5CqJTsrJI1lMqpdMyrseD+4EaX6Jau6MMFJyjNO3NiG -075DJe4yme3b7Rte2qcJeE9daGW+kiMiru6x04Gr728+yFXm43hew7Eg3nfGjFodEOe26td8t98s -F8J+SrC+6qcu739UAft5pjrtWmGFUR7Fc7M+2DXgighzmzDM2j2eumAneGb8ivQXZ8FGec+9gjS6 -gmj31rxwofIAlunNJQg5Qv7XxdcKOuAWUIQ2lkzCeYQPn68XJWCn9dIdh3+Y48yKSDqFPuq8algw -5ij5CHIoVCQn3RP05Cw+nYbghkXm6zhsp1muSPMERTnu+qY2NvvgMc7Yn5gghXS8JA5m+Tr2KUGG -X1YvLxNV4r5ONLS0CNW1UkTySZn/jJV9M7P6fJgP9DmFvu6cvZBoNyz9xAX+jAhfhsgzJry9yHfs -kciT4ZDP9+MI9+mV1czY92g0Mzz+lJwh13l8crNVw56c23h8/U3dGx1c84RcZUjCgFjDpVnpLcen -CGq0lN3O+LQ3/Ep4JtMzujPDMpodbmVYJcI3w5A+vvw+c01YMBD3s2czS5a7Y9pkFkmboKDdRYZ4 -MsSjjYzQFN9Ck+HBA45gIoR2S45tmujp9w0oYUHtHGmTU0sJs6hGa7wwA1u55lo7AAvQmwRATZSf -4LPi+7f+0p32PVOGyDDc6xmCTwfTez4P/ibG1Gv40oT+DefW2l5gwa3EUknx2qmjTQwtoRYVt24r -HujDdkLeDoT5zpsbFoMdfbSK9QNjud7yl1uLH9kefapXyonO/ln5khIOsfpuTuf5IG6wgWrzb/QD -WFry439OFSTHwfnnXEGce3h4/5wViPMQB0DOKkymoG/H4nOaGlrcNNO7jvj/nSr4z41aZAlmHzdv -hEMdNj9sCxfDFslQ2q6PshnTvStJUgbsRWfwGVIZWZmcZteizH/TvvkaeVP08ufLDtSfEXWxLIqN -aYZdFVLnhfigVVXyNX/lm7nJFXK4NIIAX5/SkOuubATMCpJXTjA4LTfRPn+0Y5BFB2T+/Lm1MRss -slGoykAtSmKGpxNS+JShPKWgix0uDtDqDvdMIxBhjRreggbqfhiW/NiLFmAISLwhX1/95NCsvFPU -xA0sq1qV/RT5Jd1b8+uRxu7q91OW1wVeF3BGiYnetW8cyG423Tr/jN/y8syMbpkEuOpZRGpLSlkT -aPynTYcZyO4PsgxS5AQir0RKCduAkl9iPxGpecUfKWUwv20nA/U8EBiJsnr1zbs9wAWW1edd8yLS -PlBnaf3xxy7N0zctiVEDY3BlrocG5tQBNMC8PB0Sx5g2O+UVD/3NyL8m94dMzt0iY7ePj9tZYMnl -/QK/rd67NYbUGtZqtVs5DKmLCco//or69lDXd0pAO7oXFOh/ivBMs3mCBYh0iciDOiPXm0cea0dQ -K9DhjpfA90HKthqc1+Yef9tRhe9V54An7GwqCWICA6oDZcqeQEOCF9q/mMxag6aIEvzYDr8qPM60 -0RuVz+J82UUsj9A1fC3ZpvILRHGJBbx3jdltre1uuzr1QRd9Rjz2JfgC9nmFf+AqIvk7iplA5vnL -VhrFo4ijWWd3vQBPykPN6jNPBWrCcKHx8oSsB6sEOnJTD7UmKoH41MxclopmiJhSFi/9wcIShY4H -5HWcTwV2Y4Bl9fl/GJwZnDdgOaAMvHbSd07MXbQBg0/GBJPDrluSnkgmxXQKmQ48yrzO0YaY24Oo -ax4TC8aaPGuUcqQb+kF9NDnTbMqJKW4MDx62+J3Oxc8nwEr4Xl7WG9W0FjU4vn7zjePrriXvBRZg -kF30ShPGnrptpvYBlVocmOFN/sBcOToypdhCVi0AiuufJTQqvL3C4Ku8v1foLCwo3X9vWsa8cZuG -WsFhW9eJ3tttykaNg93bk3Xm2pzON/IUXZ5VejEvgZ8TUOkiYw9gwKufvpdyCJs2UxVImPjzVX+S -IzzoEBZyctWoX6jdFZFR9btlaPtratuYHa3rRM4AdBMLeF2hQysVgbOttiK6J1O8P+9y71VKBPf2 -TZZANIo6NMmxgP1hADehZDQpx8mWE2y4n3bU2z8t5i+9Y0yLoMZhWNY9Hy8DxcgVZkl011lK5fLL -2AEgmy9z2wffF0ljlTPDMGvNPcRdBt997XOalZ8WBw+QT9AlYxfcmlaa47iiBp6nzqF09a57p6+t -ljCwYkkib82HNGHPGRcvPHOb/rqWZvlyC/i1zF3kZK/3LeF6ajedh1/fmmeNRHgrBSVWWsroF8TR -TMX8zvcfmgxatpAZmfM34xxrbWWK2WLHBxvHWDRhBJTz1NbaQMmoLC2nt+xMxPLQ+rqyN8Bw0af3 -1JMpG5imRvBAb01zBjaGxhmZqH2u/xQjfGxGJzo87O4r7/dXa+6lu54zanov3fp427lfSft4jJxG -sRn1NZvt/UHC5ypju173j9Z5kgp97yYfK/R2xAK8KjS489Po+J9PcXeQMztQvXN7xftkquzG4gW+ -ZpZIbGcwh/nrtwMdHPV0UFHJLNYRP8/nRMGyMQ6eclOJLbEClouDh/FdorWHL0CU+GadXBZtB3mO -14HvSYbVpDzrzJjNVMJOYQzLV37hhXorThu5SnCukNWVP8ySmBm0Kjy6J3IzqzcqZa7LTE9KEtW6 -d+spViolKCUfIG/pqdSEKnQjzT3nMmcRj9orfNzy5JXWt10rFqG4DRlyuChHS2yWpqABEtDUE6XJ -OQnOL3jnQpH1mmJ6MuRQGsJRNNk58rhYPs/AYtzvoWvR8KkcAlhexahbl0NqEwjOqOMBCjSu/fk5 -OfRctzhpU9I5vQyd0FaoJU/E6LB64hzAMdGxejwE9u+DpMtLHFzeDAO8V79e4GIBmla9XaJojKpA -tXl89pnZ0ydD2agsWUapuCwTlyLjDzMxKihIjhlD5WXh1tTozELoiyjBg4TL8Yj3sUzLrBFaCLTW -sxF3tCZlmyYHQmKK0ntWrTOLk5ptp1EBIYu42Cbhptb0yw/pWE/ODec5BkvIL4/AQypv8fGvovkB -m0j7wOgsvaGLgQSPHOjIefL5nPeb1QzRa5nbDRvjAyZIJTK3IfoKTtdQd+HIvTAk28iQNq2LE24m -MsSzyrSKS0a+dI1ZQQzp6z2YegryYrps9u/wt19k97YUeHw6RJy4GWnH+ErH9p5IMOY+OAK3+Ovb -kxNbD28btRdp0dRdL4Oz5rJUOXtPyYvxQ4QlvrJsFeYkCcn6nHutLtv3Q3F+BPkgrqJxg+rp0jwp -h5MJnqykHgJOfZ0pOajKOuNb8HOmLcMy7RGXqMTQGeanL4tZvXzbRyR0ZXbuw9X5AnDloY/eCA4Z -NRNt9xamSsZGm/OeDLgSJ9PJyjuzZ26QSmtNlmHuzc2LBrJKY9SOKzN3b6AXGM+mma1Ck4H3mumC -IniwSctesoiR+XibE5lkmzY0+KAtnyAmr3a3yyt+V4M1Opl30DhthC6avCegiVHARdDl7WJPkBZz -nxqBj+gpUQVX4PKr55skMfHSty+z9J2bvc1U/h9hZx0Uhdv1/SWXbpBeeinpFli6u1GkEUSUlpDu -ku5aupVSBES6G5WUXBoRWRakNl6fd977vn/vzDNz/3+dmWu+c536zJlzVbcO5+Xv9c0hAWzRo9Z0 -HmLUJNNzJJRjD1xFxjuZuKdvcwPVczMfTt4O2VOiwBd22B4haKpNrsgEDp+9ZJSV79jB7JO3tAtZ -9FLE9ceUwO3j3d2hsVm0oujpGbgLSQ4VfXARyD7sHzve7RCAxP/tWYh6GRpCd/9po+//1gzY/1Mz -LDaaJBvbmci8awbe6U4v+LJoWLG3Whv89oI5cr5tn14vFe4qFCyOJuXMF5gO0g7ZmZmLI5hASTnv -ssWndt3pMCe+8KicfFTEa2erT0Wov7XtMl2d63p+jaj6efGmgybnTYd7Cv0t1wCCPU22iyApu9jG -QPqiXYj48/bZ4/6DpTH1th8zt6fWbh+6+zsAIGsFDpvZ9Tl2OdlPiG3THWCB83qpwq+C1Kg0zeT7 -2tGQMh8OBdkmZPJ1YrfUCeJTMaw4vu9hMyPKQUAEkZwpG+9E9vtL6NQvuw/HNy0fmXxYBYvXFJ7u -hXya1357HqgMTBTs5bA4s2/qeEi/i4u1jZD/tbO14fTZ3gt4MeC6zRRCRc5KyUB4NueWSKfS4poY -LtiXBqpbu/vx3oC5+/1X7CG5zp9cYoO3EfY/hFykudv38mwJ0kw29V5gTZEH3Ekj11OQ1ioDK6JZ -wYrSxS2opdyBgxUItcXUn/OEMCHFNhavrU25h1+3M1UuHxceTABsXpbYtHYOvH5Z3OThzZwWu/pQ -+BFKRJR09oJNIpwutG3Ru+Nsn6arq+mlaxur2BvcMJItoNChyCtiRZ9wih93sWP7huXQL2ljV5Hr -9xNCy79wZbknynex9Xy8d+K9vkXxeuZSyklNI9sxgP42m9bKz2fhn0zCa+8+Bk4POPCxeO6DlhG4 -eqV7P3YgYPszOQxAIDX4i5IVg4x1ytE1vwhsq+UWppzCFhXAtlEVsklQ6pJrDTv6gZhWXiCT9f3T -+x460um95qzqfx3CrpIrtT4ag2+EfSfm25cKLupSkjhZ0jDY4Qqwhbi9ynFyHkj3YcYAKJ4yaGV1 -HBZByuLJfx4EShSIYQCJFCcqx3VOt8jBfRGsjSl+1EbKhq6MMh17YHee+C/vLtIxn48fS0o+lnRS -HVTTR1uAzmyARVoPJlFmc2tHrJBPayGB2rDV3/CrGwzgE970bbqij6hHZyhx3/JUZ4HDz9ndviVW -2aG5M42s1yKoJuPMb76HaZ8oWXECg1sSsG7kzmZIdlGlRlakM9SdSgxkIO0BiCwQDNF+a+wDjyWN -Jt/Udc9b4CLHm8vnIDSyACZ2KebNRWd6ZA24iuFXj6SPpmOvf9sM/ywPp3/hSA2m6FT8aW8lYVPo -ujewftDv0vaORgvU98ce8MRZD84vEzW39bfsiQNJMY6OQ1xRWiq/CX7STwd4OADobagoonNSuDM+ -ga4VF+sEPz5CTZUKZkQfIrq50J9T2xPEjsbJ2GCngt+C0yXeOq1P7zGpnMKUvYt22WZ0LIfkZzkO -dU9g4nB75Ud45RmEuYevi3WYV/hw3WXvDphC+75y3wnqwJ9XfuYsPq0hO3XlTnKYaRkt+9bXDk2D -cfuG9c3AmVq6HeoMmFJsUGcmzMlMAaw8ZgEC79Cc0SJkLOkfNrIh7z3fvw9d3+PNskauv5N9M71r -t0Y4vA9zg+XpyYCORUJN3lwY9jqx1Dt9ZrZOKJ6mpsJ2YuCx5soLqCLODNIMVfdDRTHdUqneGO2w -hovRqzY/MDJccp0CWOB0kYtS+f/CqTVmZhn3LJZmbZ/2eJDveHf5qJx9fziey+uPlYxjGk+6N7iG -g1uuO3I+LByIwJJVRHj+uILjR1HnPrvmQJuwU37LlFJUfb9HmhRTvLSmjUjYJpmt7At6+MpHudfV -J3f+URdYLT6O6InUuc0BwlVezHLiYSlU9+1dnokyFjbwH7SBHfDfuAHOIAnpf6gGKd+/kcN/M/wH -1SD9B9Ug/QfVIJOqengxR4H17H+f1SCtY0PJGKQmNX3/CO92pz71XLVXNJlNf9Od2PUSjAYNpE3M -/Ytq4NRJdpPkTd/LOqoR4ghtDLG//jXx7o8WZ7T888bEbzDlpeDDxizroTyR6wwOQkJgw1Tgj84Q -2ZbulxFK9BuUsHVZakCJ+kxsO4JOWxMf8tXGmYJ5lrNQhDLubOgBjLp6QDoZP8pvtaDkuVOJyKEg -k7BrxOy2hkjR+6lSV+FCuyz5HjfmFrFnQSRE+ufEujksVi6FK3L91gscNzzEO94WlJedbbobyO5B -sjMEPh3t0h0WMElIC1812f8lOAz0PkSMHPJVG7rshSPq5yErO5UieasqANz/ZOLNfi44VpQ+pbG9 -8mbSp8jAUpgOx/YXgsDT9MW290PrPizPlHv2VYem7vpD7pGNUhEu2eSUg5Gq29U+PYS7szBE6o2y -/QHHviCEOgTSlHlZEj25wOcdiIvdJwQ604eBY7jCclZGysl8qOU+R9I/ntZogthJE6aVJM78qWFT -nvkK03OMf+Tz0qlHq2QrcpxbFJyv33b/HSdKiG5ZVzdaK+HEdgJ9sVjT+64bKVc5aP+a52HCRayv -dR8dvc7ueyXkj+u86xB1xNrfQOdKKREK7qBRsVd4jFSWeb9oY8Psh+YhIngQf1dBnjl1dGcnEke6 -xT77jFqk2QIBiy04o2/6kad3Kz+OL+xDBoZEXtryBEcvrviwQA2ZvZbuMiQ+9CQQ7vJeFD6XA3Jv -Em1ZwqFhsugOlay8l1khoOnbZ+djPXlfW48/HeIbkqgW2Dh1DsGb98OPBkMSuhH2x4QvRyJ87mxE -HhK6/8CK0FjTumGGiazeELcdQoI6Pr22Pos52HsWyGIIlXui5UDRH3LjoB966g/mZNQ9fej1za5v -+eLZ4bNN1KuoOaEdWNdQUCIsUMrTdCLjp8NE68uLIcXxSFhILTbhgL9IvCoW1uyw7+HLDutcUR+a -s4WBtEvPknY2JDMLoqR1IuZkAVFiMMQuNUz4eo4zUbG6ZrRb87bGBtokTSw5/rvqdBMcJ5tKSTcA -01ksegTHW3nZKStWf9UlP05nG5Ze+lp1N+Rlx4/DcDGeH4ITz8UbTljOf37uYmVe9d+2o2uqX48u -ir0cbhC/7v3ZlXg15OP5dkmnw4aJ4I5O7fLJ66fyD6gm2nQmPp0rKga0L4X+3IbqXYfYQWJ6hQ4z -J1YOPnmyd4+VVP74fGrn+LOR+Jed+7+/dKDAAErwos77LhJEfdTsE8y3LO11l+ZgtdVHixjAVGuJ -bHxaL6/9IM7hVViCh1iAgtn6E1Ilw+TFTJ4A8Eic2mi0Q62psoxTfjjH4QBuxO2vAGkjaoLF/dBP -HOGz/K8C0MflkEMpTl7xqUxD/89FX+P3KvjSRVRZOxtt48yqHA2j8vkHOF2pk/62KsMHjiGGsSts -fnlKMsHrC2cDVtM3MnlZ3wITW/CxsGDlWTmEn3K2w0HXasgHco1oX/66R+W0l/6O6ZojrB7i2RoT -DH+gn/Pn9l1uOc/ii9/JkD+rjreAf3LG8tNSBSXtEwNI5hiYFJ8rn6L4Io9Aa2VlJhMH4Tj+e/1d -YKc7O0QIa3T6gkKKxJEW5ZDqFVdp4Z85Vl4dR1DNnAKokXpg5MKcuPDdsXObnv6kfWiHZRBxu+UP -aSHBsT2IPq6yMLxJfRuaUu/k7rGydaOugjtIox/Yar6nbcOYY8hy44pa/WM9h39BMp1Tfxl9afwj -KyztT5ckAWvjzwVa2Lv8phBObDNv1MoC18eVQ7ir5Lqsnd2PnFUF411kIHJ+C0qe8eIxlH/IgniB -PLdRx+7upci78N3qo9aN+AP0q+Jmh1R+q2rijahYgtSjStdd9CGKjmNeNvFw9ENpq9wgRPPPQiYQ -R2/uqEFzCXJ4aYQBJA88uyzUAu0QgQ68mr/OoDXOjO3e0CTqLdsxaQl/DX9tTj0Rr1izg0Qhm2/s -+AFpN0J0rIw3K1b2UUVMJsi3L7cD7hBOIDaFV/qnygizFJekC5Ch+B9TTnpKeOAlMngo+K75GK2D -Z5Ipa270sqhBRaeM78Eg1xaV7qU6hzaLQlDWTeW+TVmTTPHvbmM9CBlXYFtrRwgNBvA1Tgw4qzI4 -KTaX6bFhpb1LB+EUENju103gHAAummpGkUSvr/M29Hejxpfbmhsu6RxSMYARv+c768k/UU9zos1K -QUcYgOqNGZE82BL+WpHIadRug7lrJnTDDj8sGTmYeG3AIRjJnGi/cowyxWNO226AwLwftE5JaUV3 -w2maXqfSF8t6eC86vBHdZo+EvX2lYXKHcBnlAQ59uxwpjFFVBEK63pv0LKJlKRo8i27CF+OL2FjV -fTZ/YgBYgXyLJPkfyNmGHeWnBu6brQwqND8uNcaFz07amb+KdHn8oeobmtWxDyFwhQHICMYs2VMT -pR98+r4yJ2nBcaWbocPsAtntfRa3+X4OWYiEdQ5sqWEAL29ldzEAyMZ0sEz4NNJ2tfU3BtA3koxs -EoImKXu4DqHcTyKOCC7fgaSF/S/biuNPviTeVlD2cvVIwNXum6vJYcnlxygTCYV8Mwf6vZ26qiy2 -wVvWIno8JQrFeKStIZ1X2xAGcP4mABGwTJP2OFxuImSBiD+94rapp/g6EO4pE5+xdd5qxDJ30223 -6/ZMLxLFy3Ng11F0V+i1iyTHAF7NZYeWodQD4NpkEWheDvbbDUi+WbpYp2HcK58nUfnea7rzNP1J -GsNZrLr5nHf8HzzdbAXPHnEkFllBh42ndjAAbFqtJvpezYumkIpEUFxncpmo+CM6X1Qkfa4ZBmAJ -ovZLhchDzu7ABxMx0EJ59tta8Yowujg1PdroSUnqT7toJRlzo1Etat9Z/egIDkLtQx1D4eSRQGlu -IxkG8tKjeWwyygdvKZkUC0AHxSk7XxQ9dPtr3bX7rvgT1qpCZ0x63fQJhDKfyY9pdhCx79Mhm8nr -b8sibfDC1N9Rj9Ip5SXTEf7ZNO7S8cUAFCFHIwefXqgkedWSSaKMv1iUXmnT+4fScowV5Yrdmm9E -q7/6trHaKXH7+RN4doH6eurKiU1mJe0namEVHIpAofmz5OJckRhAABjJ9llP85J40cYlEAPQubd6 -uMIC6gqq98MAJrMpVbLnLcx+HvXAPRFP2LThcLhSCbMCVCK+2IsKIXUB3XbamnnFd+gXL2yoAA0o -UYA2hLuzv/mRUuNRpnN0lpNvNK4qf+/oFja3V25aWTPaWzfxCoUuqlXpc3lNpTmuhT4poQSXoSeT -xlF15vTsKnEVNvJGbfAQgqP4wFeRXyt0qQQn/XWHuDLEnCPcNCE051RWt+8TYVHxMgu163kXrUo8 -aqvcLWwNHD6/oi5sA+3DjlsJ7xSVreBO+yI+P9PoWONYH50LfUNuvbSyt/p8WxiEq0me1vAieYFo -h0zfbkD1Cbu7rZr1ZvjuInWb4Tks8RvyixHqXJC1XQAu8i55aqywCPoYfUJ+qzkjE9hvazXx4q38 -ktUj260A3qyRsoswQZcU/CgejQ4yyWL2QPud7yHm6X/63vIHOxFLvlCdkXML65MkC3uYMvtdI58B -23StqZwBxqfv0QYC2t5UsbRp3mwRKp442cTh7ft8eYck9He2Kmio8De31g0xla1m9A2SxQDaJapj -rH8sEnH3haZTI2mCP7/Plmu1kmtGnhTlKgsAP3/7rQpJyjDTXoDIWz+f+bkhivZo1foSkHcEv8cA -zAflFSHeA9eWQcvQ8N83tfSXg+HQkfH/+fMkL23vFefWeYcLBsBr7eS6MX5EVbmoB7uAZW34O6YV -CdOuBf/tYl+kXbyeEhVvn8n2hBZGPo3ZPQ02lB4TUQGTt+4hjlv4ItQo9oKDer7YvoS7KKzcmIDI -NW9hechNT/bdWxqp4Qq52tf9YwI6rD5TRRtf/eZ+3NfwPiQ5qmZWDQtyCFSqIcCBNlB4YnGSswmA -/VRsCJT34Nlkae+W/HxCV4wH+Ng4iNtnigpP0N7Ak8jlbeJLfYZ38lSK2eYJh1iocmMSAvKvcaMF -kLQ7AXrZA02EPo54+KKlcEY6JNZLlMo64tpKSGHhLciSALxYFKHosT9KHlYvOmD/V1Qz7t8I+7Nn -fTMRA+yKt7uLeqt1dsh2BLA4mis41bYu34D+Kfs97xk7Txm+ygCv7kHVZGQiI0WgbEs0HqU47LEn -ArvQIMjz8CcquXKFHGJjRU+iZG98d+NBH68DSeLOywrnEpL+3heVboSgZAUcTpvzh+Lm5UzetsWE -sIDMqw7OC17vr13MNqlKNJvVogys26yvn8ga3n4WcG6mVkExFtMUaLKETQmsUsVmn8pLFpNxphGb -2SRFjhD4Owrh5bytFKPnwqa9P3kXJXGN0/HoXU3SU6aUz6sPzFet1yBSz3LV2seQzsJU5PC/D2C+ -OG35Du15+NfPH/Wh9DEA1qN6wO6dlOnfgO/xe+tSsInPvsuWqFw8CuDKmPGompCagCBv2t+k73zx -basUR41xquyX/qUinYuLFguC7HdMFCMm52krYbAjAtmkeHJDxLPsUVMYLCmD1COpK1y1Ek6nF/T4 -7QQGsPymItEQVJEoYEMz7pHZl5PISMumsY1Pkn6Q/lAG1ZWdHWavJ6NButrBrifKHBLeTxHhR/mg -j47TlMj5XCXcL20wYMfjmSXFPBuwjChYtniBTUk5BGsvKvgHweAtrC88WWKyEkC5ZqVDzfyeC0JD -3S72hBgvFWiLWlx+fq0ezpGNQM6P8pNcVE9P5rfwAwuLu368UXkk8EM8v5b/yyeOYXd1ssLIxAuh -m3Z1bIsoMtvU3pB5bA4cwDZZ9Mg9tHB2npBFuKKaUbksaUQVlS0W61qYxRAEN3FJU2f53gOcSbSj -2UV3YgCxjLXJUiFLkL193ofiuRrulbwwssTsyPs25n3CO9na2V6PLRFH0Tey/Tm1HKCeug2aKCGN -Fp96iMS8a5JqEkkUS9O0kWBmv1Em5IupCq9L37lggOaMeFcfUdd6OcIbHWpKFhjGiQqXGL7EAKCH -0lWn62NjN+VGhOb9sZuz9LYNDkwoOQr6394x9214NENIxtllm6Fuz4aLoBqF747D3k4yNQ0WuRnP -Luwa3sKGrepdZhuoIElx2MwDlSATlPV6hGr/MPKtcbx5lWhCmBX6SIZE0PZnfCUG0DEghSXE0kxr -MKKchRNxcDMxb7gbrsN/se98bxJOu52+tWb+QvFV5pa4RnwSDQTv9eudxOdsbf2+8RaC+fkiHlD0 -R/rQVxmL1EOFGoGsPfoeke0VKZHzcqoNezcuGpE0zeEZ7x09rR7kmlvBNQvcJSBYIbYhlul3mfVB -dpIwzSkrLmX681VKmjdhdPi0htWgbmClqAtaB1urtjCIxBdNqo1/M3Zf2ZIXdFLLwAq9empYDvnc -Vsb8+/6rdsEX6EGWGmsG+nfjz/j77mQE/wfBVP7wwb4kMbPw+KTeMkU19HsxD23Z99Zkt10gPwWr -ikQMIAJucpMXmwIrXk7eQkItHGdXfyieXj/Lazw0aNqhI6D1++esBikWO+C/cQOcQVKy/1ANsn/P -apD+N8N/UA2yf1ANsn9QDfL+iJQuJiysl/871SDzn2jg8xJ6ZMHxpYWp+9VQGndqv9k5tcTkdlZr -fyeof7FG//+dlIQvmjzIm4kr1D82xSNuv9Ij7MLBc5ww3Ks7D+6b9A3XMyOnjRxAhs9OPHYGMxLQ -ZjRfefWokfC/vwpN4297x7qFNYWWZ4UcdK9/w6z+UyGyvwr9t0vgDJKR/0ch8n8rRPbfDP+hEPk/ -FCL/h0IUEZZeOHMUWH7/++YR8jq2wG/bzBfBMlP2ABpj3JcbMjcdPbdpRpwYpadNJr5xpZP/4j7I -wbkf2aQzFBGDBl4NYGYan62vT8uGowdc8QaBEZP137CweN042RE2iSRqqS7kLIsHPnpAmHRcaeoM -MQ55Fzf8mZx3x5jh53FrvRiZ2dsmfVk16EFcL5VSxu7Jh4o51p77d1mkTyi12FMf1TkvFyk2chvd -pvIZcDIPGfNRE00zDzzZOT4aT1uUTx8fZrXaL/1d2r+9HJQtU0uj2mQQgloc8yoOO/51ykxdcjHP -6vFoOBlvINSsn6Tr0TwBR2ChmD8VC+XsrCKvYSWgp5X6sYowKbxLNX+9RCdtEcdlncp8pdRYGFYq -h0fuqNhQrLVEESHK+HbYkIh8y6yJOOeA4H72phZxxS/5DWpK8Wweq9GZ/ysJNYiwrW5HhKXPVTO/ -nE6Z/7TX9rSFoXYOMjK9nQwUjaf+PWIeuKBoowt3TSCrjD9/N2kYhz6u1jvMDtOhQVaim6lJKFfU -KdygYQJqt2ZQnX28aUreX5wPMo2zCsbozCpt2EvNb6of4ve+qfwqJlqJHu3UixX4II91fzKhTS/m -V6pN4k3W8LVA+KiBtf1CykXJTW90ZVJFFHnbpDXeppVTIA+CjDyJb1BSFlUVeS2BbQ/JcBYKp4ge -hdry6yjcHcGvnFc4I8rxiewdA9uJYypFv61aBfInZgnBaxFm2JzWWMLbYplJGVhmYK85ax0DlfN9 -WGY+Inh9lAzW9n1cJa2Zzkj5jQpvKJ43jvL9Wo9Z8rCWw3dT0YiXRdD0mHVL4cbpO0Xv8V61VfEG -2/EGfOZSMGrBKzsmQ/yH3omZnQwjNr97a/qc6myFraXAD3vBkBnzzPToLCBFwZ83DYzHsonWqyTw -5e53spSc5B1RlAbvods31UXA6FZ+eWYQeeFHujcOfV/70U3ykaP0ZLrVmVgNJr1sNSRx2ggjNiPx -L+PT56rbJ3OmfzKDnOatB/AA/uCKD4wFD4BVjU+/2A2DZg4GleX3GEtzqg+fczUPm0Zyp2PTZp9H -pabw00Zp9cRq44JoZlWex7FglWIAElqqBe/UMp+0kVOmYADd4d1cm1nHB5HxnN/ubXxWSTypRVa7 -YenqtgeZt5/xP9m44xuThBjBLh6mk4i9MD64re4dBPYbFvGTsnY8L2uxeKYTtF08wKXJIwWycP7q -PLJqafzdmi6ijz2PAXx+nh4vT0tUpEL1eoAQaGkmx6pYz/JoxbhxG9JtQuD2eTL0/grh8OTgMJOc -v7Z5JIarhzVb/vNhYct8uaGFxGCN2OsuxmKq3lLI67DG3GbeOYlx3TSqnmtlvkSv50aB4Blbx1jO -r6rHjd6L6kHOd+q2nIknVhgAN+Nj9yjVqlUuj4nN7yaiojtjOxWZahzghnbeqKwapLzNnVIxb4Tk -T/ufi7iaDe7ez4Hx0RIJFgxxCvpBTKe8UMkdO2x6l/SdNh7Rni1xY7IHudZQdeGmJnmkoRQuAavg -WNRdF0q/hHuhpLZ3zmG/HpdDD37TGPFeXfPKBgPoyZaUOS0snx3O7vUGria0DwEjCvyeDb3xtkKR -DtKoxzQmBehmz2kX9JIYNlaR+1oC5hSfc5XJejYEkLW/SdydWJbME2sgnPJFSAR5MZLo6ddYE3fE -ETSlT4Ik2fV07BXA0u5sfuRh9Cf1UUoF04/tJd5atLFNZGyastXkPd/prBMMzDu3YdjKtXyYZzny -VhuQ14Ed3FgyU+FcHtHp3Gl91ygTwYAL3oMky8XE7guyiivqEh5SBKmi63hdH7wFgmOGfWYocgnk -yOksnmuwXSFOPnzf1SYsllQf2gANercQot6R8A7Z01sVUn+qKFLC5nICzxUOgIdS5G+IJa0lxRCE -H36VbUfUvdFUaPqwr0VfOePzSCxnQXVM9JnKy37Fvs9/6Cd+yrSfOKdXpZS8PUyqSqKqrZbZPJs2 -WIkBeClTBNaKyNFMgvKTlumPpAtUwqRKH2IHZfIEOYmPSXAqir/w4CT+zM4lFm5ewJ9C/1VfI91Q -XJ/VCracH99Tk4GryC1iaSduZp63oVqGtGYUnlL/MbiVkfQQ91NmGf9jwgL4hcRXmdGnPpE0nxKb -fEzzvDgQLTy8SbofsIsImdUYmAPOzaIfbB23DLGo3AcVnn6gPrhytuJWZ668r7c50XVIvOkerJCL -vTISx9t7Zn3WwoXLEWKuS4jjOsO4F7rgqXbfYRCBFqxS4APjchEymz7D5i2/UN2SUhpYNxGcUT7g -G0zNiJw68B2ZyGv91eCQqL6UTWJW/FxnbIOgn5W2uZZiw3UvyVZkn57zkIgjBI40dlauSp84+lZw -ElXyaphZqcY/UnyEfYDJyK2yWr2Wu0olQCxhDtxG66aXz0OJXH0g2rtYVZrIye562td41nDrsRZ9 -9VoPT042rbM9WVFGT4tCWFGuLBaXT8kZweNFuqTIG0eGAXjrpUQnhNy31AnJPkigVxspVRu4Mkiy -MVXDevvWK+760ngiYpiXPfcp/3jMHx7OuSTiDXO8I7hYqI1fWuGsvoyo6BtxRXclO06TNBPqogjA -uRGVVtMbovHEjAvx3wZ8mUorhiaI2zasyAyC3OAJ7KFz06rxQ3wi1kXcGq13RXFEcUqu6Wt7TTCJ -Simnk9NemR8H6jG1UaGtuSYyNDY0enIsEFpHVDoVKKArgoq7FZ/B6RLkL1+jJIp4kmiXwE8PpJrr -Np7hk56q0LqAeltGQcUcPWt/3K8MRsm6fZYHfoLr2Jl7TijvJEkkRTadXyBz9WhZxNIIP4hLErAj -RHdnUrO61tMhkt750Rzdde10DBPRn/j3HP964t5kBw1NlIJR+6DvKfDGLeGe8jmLDzQ4vCEyM48s -Ie3sI90DHnHU4pMDbE2UhbMBpSLt5gtLZrre6RYwPZQV/VhEbMB6ENuRKtU9+s9ZN4kOo+rhwWxU -YOeAoxarOorOzZQEGh2IxTO4bBp5UdrRpqOmQx9U0Ih/RXL6J0xQtGGYETLb/Cprpx2fiWq79Ft3 -8v7aMBYhH5ZQbWFHwGS4HoRO6Y6tdx3Y6Z7x2IHFLvJt4o4gJMH4Iml4R3ENdsfiK7+pYjZ+sPeN -pznkw5Egc65VIzt0Mr+ght3GL4Q4WhPf3nK70Hk9uewp1+7sJ2MDxTGqr83Xh7NXy7j6JjFtpKHv -PDplpc+D3Bmcp/pceqLwXQ52shUe+lVzWhJuEG8x1/fj7B1MfOV7/lbyvppBLVF+Q1lHLcHwbFJO -Tb7Osi6/KabfbKD1Qz9x4g6fWx2kkeDFj6/sjxSfXUUhv8dAqrkAva9qHSY5RAgtwfLGisYjBxN4 -DHhvuXhwsRToXhokao+wap5Nlu9JNHs4vFZlow8wfCCmoxeswxaE/fF2Y0ELJ8r5WorkmXAsgPlR -nGS1HRdJgg9VwqprYOEka//OeZSqai0fPSiizChehrh53CpaRnyihrlauychVUsR/0vp8WRGEYAf -aVU6wTTcN/hBWxxYTnFLfXOtSt+JxdV5+ZCK/siBPbwWNk1rorVzi3BkeyMDHSHE2WczFN1QSFI3 -pcxySBuRbU58L6RJPYpcIGdQwgDO6F5hd7DKBGsrPhliyklbWohpLFNOE3qR4zBjIETdSBWVbqW9 -3HQyQzled6vMsIN4ymj63vnaMHWCcSCDstCM5zRJTX64EyIlRrwKvt2IFgHmgU8KgYza3/vLz8Qy -DpmjuAbFZNcvTMQCh4H2GVNOvt2z+izcBdCQT4/KZmkisQH9J52RgtRjGICgeJlhqtkALut0NStz -xeXVDJfvD+r8Qb9M7O24ISyF/bFDGX/KvLdV8blV84mGI1hR4+L51yY6fZCT3Xj+wYC9hFDpwWIt -zo/owAZBeI1eWE60yraq/f3wbd2SjvnfgMGIYpiSxSldTMcfwHKcSEGSX+uRoyhdoneQ/BL0lOVv -CO0K3IsSmv4IAb149aUZ3KvosFayM05zbt80EJGnah7OcAW5Am7lyVO76wTXBCNXfpnIyzZ8pKHA -q+MvZYXSscbmSPA+eh20ZvKyRAwKvK/ipimJjbkm3wDg68gaSpQZ6YSwaP7ZODkmLVZ6dFMnJ/6J -sOwSUlg5MJd9HpLzh0RB019UHiShVoP/+CWpkVU2Jy55hUwjgVaDKV9A1DUWkJxjmIZ6RTIsqD5r -2ewPXCdiPOy9K1eX8ljsyvEUUzqloGCN0tiVlksJWKsirCkiqIF7PvtKSWF43gGe4tpLBCFxBWud -t4PaIlXURgIp+l5JVWA9w9qacLmJ+kRLMQYLof6RAyAiT5gIC08myWAZnhsJdE3IQwRFvjLO6qCq -N3KVgyxSYlEN1Qj03VizRj/uUqC/4X5J/jxOoidNw5SKzbdf4SWd+3Ne6NfPsOTKhZvKD9vM8p80 -LGLF/OE66hqBTdjD1Dapl2nczN+YPTw4KcdVJLu8tikWkQ9i/5DKo+0aqkY7NTEA3aUya2dIkoEK -QQqU9/v+DI/hipDoNy5BLJKwt8NiQ9REDU0r550i0QAEn6ms4/1uO82YYXZIgLNcnC6rA0L+p5EQ -pwCqKdSo+DvVaR54S3jh+6kPjizYyIXJ+L07i1W7sVgF7mc0HbBymxHyMuiAeVQT4m3ZocLa4JpS -Dc5l74lcmissdwwqYhdMRFl9dcbKmLr8rvLF1URBWhUOK4iGfuAHDS9TONeTF7zMFt95orYqiwHE -DeiIAdJFsEiCHnQXOwGzNLwCbB/HhDZZmSTMDWw2aqQPZ6nVZQ8d1AU5CZkx5rtu+OD2gyJINwXa -hCeUxZDRYTphTUWMavZKk4eq2Y0DG/yQbrWWfGRAlHe4RIwyJ8I0EU77wViozfJK60S+NHwCZZ7B -DX46X1mxGLeTiJ3o+HhkA46rgAUEEM091JaJ2KAUva9je+ur9N1QcoKS8eO4o60Hi3lJgM4Ql9+U -FtHCpi7Mo1hP7aW0SQLxJNsJGZs6U7VBDMEgp6QRDFzl6LO/wVfWWWUEl4ObUA9l1Q+d1d7AQIvy -zcYK+gP4aXJioSveOTGBarq/ozu6wSFfFtZvG9yblRmdCcvLwOcQ/4cZ9uylQXRVLgNy1N/fmMLN -vgPfax3el8HT24DzMsGgNwYagNYSxYNwWqnklmfOXhVihrQvf8eZ8v9hYUHopfM4zGiVfE34SIBT -vlSmzKsVVHeV78ZJMCmdXWepaa2iwn5911ZGpiRYNGX6cVpGbxi7OEMh5V2XG23JSLE6CLj5S2E9 -xU1Bh/q+WR4DaNu2CE0Qu53n9JnQjqLmawtdrch5nR7+a5K75DOO4nEwq6phMl8MufK8n7VYbubz -tTCBadeDtvyYPRVWezJYgphurwD+dmsENb3kH6oqlitpDsgw56fIXyozrBsOO2qhwIO5D2SBLO87 -xKvFS9VL758q5lYwOKlTBxpmpZlz2uNuhyAl7lvHXiz4LSTKBPJzZbkFsvKNs/ejFXmpnh9ThbnD -NDIKfUKMin/JKN/05EuGcedd7Evae6EfaJ9NV5r+fN1WljrL0NSi4T9v1/2tLrqgms7gn5tHyLHY -Af+NG+AMklP8h2pQ/HvzCPl/M/wH1aD4B9Wg+AfVoHR4AX4GIcV+8/9TDdx/Ha1jKw/L7h0HTL4W -s//ODard2TL4JC4+mvEcl11Bixq3fGP1X1TDvpxdBBwfVJtzURhz9NWIfYiGCt8o7+Ba/9y6d5ly -zj6kvps7izvGYpovoYBzyuF1jNbx0TUGANhFQ/pufDEAqbcn4dBbA4LDGwxAnrZbTALULcPFDLKt -h3LRDZe0kff2RQ0IZ0ayE3y1/0yhF8IagObFclO0uY+pCLIdRJqdf09m+T7FAIGPXzbLnKPzPg/W -1r2XPkm3JfXelDXM09zgjCQSxdW6sD0C7/iCfcLiijGAKSo3wNMguHnkKJhmVgctWCOMFc4HaciX -U9PcwQDw5jwiyX9G9UVHQhKs9gh/gC9++eCHzmNrK09wjeZhB8VWRhSIlpgRYu29gOEsPoK68+XI -H5gfgGNRy1V1F2juA6cdtOOexLDqleTMh7J3KDNfNtwMxaWIeTnOfLgFK7PTzRrP83a3+3dleQJD -Z/uchmtvFT1yqdNYf/J7tiNXDqXEvEBTXk4i4JNhP+Bp8xnxpXTfMPQ3BiBUkGQ3aCdgbzhlNKqF -0lrQEoUWCuouhyZqe70mPG2IE0n86Z5CZu8GHl47eRSebZfYN44B+FdCHjLdCr4k1CH4PPIVKbz2 -ifSgnlu/fsKWH+229XkZKVtdgAHEWury7iQVVDzrLa7ghVKtvHbuER4xZChpCWrOjWbGAAKyqZ8V -3FRcdJuUYPdyjVPsQx9k3zI5JLyCLTjBIjCAeHnb31tI2ZZaBvnwObRx5Dbo8ObpTuaRNAagkgcj -h2Wq42yks8tuLpG4lTGezj1dzmAn6QkcvFBhDTFnqLsrfr9JqCB9Wwim8YusuwEdjmBz2e0fzM1V -+tHBjrfGrfyMt1XPPxEq8oTBeNdl2LJwZp5hEfCE0Uq5XBnJhgmGmn5MxI0EF5ZRikSkAXBzXC8W -JijodfsJ9laSJGUQt1pJvHkmvpkcKbkIlBJKSjKjzTLCCnzSr8gK6Y/qfEDFIYU1QA13eXJbZyOe -jSMf1HpuddfYD/JjPXNDnZJHvNDay5EdGFelHVh7HRQmtKRKiJwxoUwJe0r5BGjar/qrjIv0+YGA -24xhT5P+VyYJbHZGLFN/rWDgyRfPC/fGGC1a9TU/ly+Jt4KQIVQekZMdZEZTV+0s3oTaLbQSQn6t -OQ68coZvQ43tqQ7vsnGF0lYtFBdsAlfDpVxS55FPczWPLI5ZiCr/FIXqgQ8xAPc4hEBtFC1l+qBi -tk4QGs+l1VyBv+233QwtW8HTPP8pohkB4HgOv0HGXKx1ayYGIKnpc97+5JGre/XB9MKTRxapGMA3 -BO8F+4gPH72STJgbzGnCWtwJzEvVsqsAYQ2sT91YsTE222+c+ZsdV8OH1irRXRiALJ/ts74Ks3R2 -kR4957v89k3eOjYOQIYMrmBxXuw3pLvROctyzI72jyp1E5HgXve7XqNFs7QZmcXbmnw/BfCiCwag -c2EUBjyInrjtKQ+ETurD53QMp60o0eLfLG8SQKvBA+eQ2rtmPgQuWvctV9n8o5WC3ZHIWFwKc+2X -sey48u/Us/es8AD7QsGRJ4Hh/uy4IYuxPoJRb1nOi24EHcTRhMnsjDDNIwzgNS2XI6WU7DPkTvWN -dQap4Xy8RCulGvQDNLPrTYKFzmeik8+jKpDX5j2bhiBkN9CF9TelXVp5/TH5UQ0Ltgut5w92SmsZ -L135FRbGzZ55ZZGaBQWrKBm7mZRNd6jQTYB2vUzpk8BrFf1znfyPRNS+ZscI8zK/p1JchQbqrSyE -rKFG5awkqiSa4KIuoBoJrQszq32L3WtXa7Nx30D1F65joYp1HSk9aQ3vaXSiizW7q9hjIFkSkaQx -fsiF544Ek+FQCy8qkhtj0Zw8YlbWJqtz0ExsA50zWZOToK4zrbtDi3cFmmh5yFmL/ibizes/Sbbc -/qcNu4do5ib1OVr31fZWl4YZWzdhgdnGpNre58wWXA8WI3GO6hC2y78sGmcsC0dz75c3pzGAub4b -76CrsOCbmjYG2AgdbzC/DwaA5ZAOLbojYtInFUoyNDNNnsvJo41PUnmJM5KXcW0zIrvx2DsUeJI4 -UdaNrg+mnWSOvEudknAvaP+dFhdULqNhMzazrCQLoeEfWGte3Luexrk2OvNxvZmcttIDWt+ivtd7 -i12WnvJij2YNoH9mNf0KNy82oAhVB8FubF0o0R9q56LPaneeDa+yBq4MCZmZKKTn8PjO5GjZV/mp -6wQLEwSTS+hScueHWFBMboJqPCEK/CoRnCx9x0rtXwdUtOmPx7gnbjoptKfkcmhiOLSPKkk205L8 -AR6oDt5ZDGCGnuyhnsPHyJDxhzI18C8DsM+vZp4/YQjfMNX7fU/7E43dEyLuSP3jdlUmlSIirfo3 -zgHaWbORtq5x00znvP2HEDYD6gHpSR55ktFW3hkGEIMBFHdFJVKqLTjBXWfdvsvYxckvGXkswY7b -RfYgjaPQdFzCAxdBAboxpxCkuaKaz6KWUoLes2SPYVmk5cQCdybLFQYgTFtUnAMTcN04E5R9Xxey -sioPPqlTHtn2YJIuGnxh6/4FAxhsPPibj4gQoTkYQJZhoSmbJ3zRyhD3rMJHfP0b7Fc3+m3Yc06b -klV6yAsChBl+bl4k13Mt3+keapabcnxGK7aB0t/XpWi8HDQX/CW0Ez1lJhWnizCy7kJ8uniQW54U -q0D+N4XFa477z9DT7oFWnfN7iXj3r11WMIBohJHwa2Hcb+S7KCkKLNYvZmfD2drnyOWd2U8y4xAd -OkcZgxnHKmXRrC/wXC2xtHteynMcl4a/htud+dG+57Z6Xw0nrAp+jyh3ERow4ffM9ror1sItNonv -y0b3Y4rjbhgH9RMpRI5gFapUSu0kIezoMwSyD+9NfZjryeTdKr9Xi/cluqFYHmLu8gvZeIkBfK17 -kna3FOLriMepTpexFZNx1jFLIcGpwnV4khVGGBUQkdeJPW0sXRP+Ltzyglcz60rU6g66uDdnuO89 -r+UycPITCbyrMnbgVWWJSoDfYgAnsUJ/1NG8B7IIuC+5vn8oJKlMETph4koI0Q5EIXwz6c0c6YMn -ZRzZB7cNyRCaEbGT+gpWffsuueb5EmszPPRqwboKVy7V9I/yuMcd3qjOZKXBcMftZCGFDhiAI29p -beGCSwgGMFLfXrzaaGY2a+zyzMQhMUKg62b5oozmzvDC1jqEfJu2AIEAIVxODc1tMIDFdIbCRoNX -GMAC7yEy0LqRnNbdfWR+nuz8y8C3janHo9GDHjzy1tQo0H15FPt43Slh3oiB8dmG9p2ZK3GEkQa4 -xnCENCGs0FEHyH4MG5I+/32Ds4QBWPLblGEAbzcxgCJ4yzq2+MPjOi3tHcG5a/uHepGJWc27jbg6 -bVqcDRrCopdpSRp8spkMXXdrEjiT/DoKtjpXwOiKFhuC31XM1rHqyWDuqxWmjRjRIZV+3YGzTwIU -E0vGJ6fnARbY375jkc8EXVDB0ijijtBnSqWdvN/1igxepMWjFqY+Gz56clnrBe6nDtEVvT6p973Y -xtceKO55h20uRczYFPrxRP7ocEP4+0rAw4X0AHunZJJhJUemwwSZNu0la8MN1WlmOdrPvFlhibTL -OcDwF+oFe+z0ojh9sK68DFPwjbpNUdpF4+RNi8+aFd7DtBqv28Bm82I8LRLPh7wH7whqyhx8DtEc -4ZYW2AhHSIDDHrrhsBku0bSkVOi13kalTV7qAXgmwKE5kw4uT3IIGWpvdc6QSHuEWofknewuuUNc -VlMy7oUrHvzBALoDEj/S8xh+LsQALKgdcH5kDcx6EAid4ly5bPKxi2RnvU+pRrkRlT5/2GwSIjVx -0DTFT9je4Zp8/eCsTG+jq4mtpTyL3EklooMHpWZDQeZGY7xxMgcasvaw2+PPrJZgIjRfdfG2OLnF -r4xg/cFUfVnVYphkoHxtDPYLzWGOP+vJxZP+iVpQSqEwTnw00syd91D7rIkzm4QqkZ23lDmaPhV9 -vOqPQzY28nRHYVpb1FitjNsQSLyP/Xtx58Ew5MJsL2TUn2veL6E2iQCoZonjTJEMjKgcoMFS6fNc -zFUXqdt91Csd/yt8MGiZ3vDuDyDpjTtohSM645fxX2eBK+Hc4bwbxnumAlqE0r1O5nJwTSkfmlHG -tuYnYZfEd008TIMNHaF1MIABX68Q6I4jBLT6VE5vSHixCMoOKWJ2np5B/jRytt8LHnoFiCPxwAoA -7ddQgm++iwdE+Fuu/HT8qJXH6mERDg+HcSoO8EOjPiwoNPHR4WPz6rlppr9e5efhSsWfbtok9Del -DqNlyzGKqSFWeBF3jWb8HByeY40BKAhEgs4Ef0AkhbhTUudm9qajCN4kHDSWtw2cvUtsNoTMeJ5B -MqExkIAzINw2NFyS61qLivldaPA0iKs4BzpCXyiK2LAJJvvCbaOhrBefy3S8meCDNHozgKIdREga -zi82Hwyymt9DdhqLl+Q/Js6wqTcyok9Rq/f1lvZGbQzpOLgzjx/l2t2UrPcEDiwVO/ePz0nEyJ+J -QPNdixgvKYYrrU6q2aqsjDKPgmg8wE27LlaKJjXeTfDFfB6nZW76EwoKDKDAnvlLRS34f5Yv7gp/ -bDhHmqJPhvtvPELvKNBNPbVreXJh5kdIWjKsc5OeBnYMgNMMWYwCbXA25Z1gZy0VoFXGXa1QfYtG -+igx6XgMgBJo+lXkraXnV3bi6btCOxrAvkp4lu68b/4hY/tacDVamGbU9oi6sL89CPAM+qsBqhs1 -ZSYnGvLzDrWFYPXHhaYtZcP0n7sQRUoXd4pQhtmVChSUm2i64SzpErjz8tiK/o0pHiy5imZotxE5 -EQqlW27fcaMOHqv6hsAlWfwjDrl89IvZHfEKx9PiCRcBBof445rHTToDhGgi7r+dXx+sZ5E/PIZO -LYvwvvXPc8CmYL6yMJH3nlZLYFtHQ/w0b2jiwhrXJ5J+0rKVfXFRCcJD4K86I8hSmZU4L09gT02d -kXTV291CpYzp5Pu6MbPiea9rdB369Z6JRv+NCh7SSoZND/5XUnM/3m4gk6PDAoVefoUXqcgsg9M0 -zYR2mLB4vuaxxQfO0eTzlSjKxKB9ZQd2dIOIIfi8jNIoYrPiPc9lsYU+bRA1iv9hH2SyDoJ3/x7U -bgY5/0GjtWnQUm19FAuWZ8KrpopMl+ROjH80ZW2tI5j0NJ6n5+1jTzxe08q/yT0Hbe7xQfsX0nrL -sUua5asQV0ppY0XANh7fuptGOK2QMi+UcVG1hHfOz6D5fesiiC8w9qrs/MuCAD4xbHoHbYQ+y4dm -2cjGT5OBg1xH0nmtxtUyGmRgY+XW+Vuq991DNzh33Xv3S9xPi38XrpJDCivC0HnZSRW8OvLKWt+q -JC4alleD+qTcD0dkQj62IIKEJwfnzH1qQEUfv7qT/q2GMIDGpEmy8Ch+CJfmLgYgQOGQ0ushTh+W -JEaTzx3ZabZsP5TyBVGt+YzQgCg/bEpCaThgvLe/LL39Dfm5Ued7dXBSML1aBlcazd3CtAjE/NVC -/+tJLGzgP0ADO+C/4QOcQQrK/8ANSr5/k4f/ZvgPuEH5D7hB+Q+4QUWonPd6jgIr6v+HG0T/OlrH -Vv/NKMHtJfZKbP7AFcFgIL7U4IagHQsT0jxHEfzicVH1v+DGBMVGXo4DJ+j4Gx/H05Jkqp7hvsGh -ne+XJjiFzrroJqUjL5u+d+VOOflk4c3SaomxEIQlDmuAbrJblk1KEyk++FWZIDY9tvg3lCUXcjA+ -BW42GlylNTcPd0na2S5nsAGb1mlxkCcPSRq2/Jbk78ALm4qUC5+R3zrnJxzd6jgAPul3XmD3qKLj -TF/32GFj0HpwFZSYTQI9GSIhpI4sLXM9QURPoN5vh2/XKRtGINS8cwUCyp8wBqN/7KC9XZ86LerF -cZSvg5PUWb/9RjdzzlqSrDs2sXHYH+DfEAPkWxWbTG2AokQRxRylQcJ7f2vMfthRiJlu46eNlC/Q -bjMG42hs4ZFo68jxm3qLj22LlAc45w3me9r5v6nNefOwdg6E5rJMNPisBVis0/J1KgjxDp8JLi05 -BJBKaTbTbEgjQTNvLrOf+Fl6Gw0NEGAAfmM5qOzvphTPwY+UuWpAliqBkCF76Sjk4ZU9FxIDQJiK -ohX5ARS7odLOz6baZgqnLyF0ZlZ7wbdtlNRD/L8gJGh+vswwj/CDNhbNRQEpzcKmhNct3AvnDxYj -1HjIBqg+r/3yAbSgI3cOOFwWz6ZbtnEcM9TJ80Mt882msmdw6MzwVBg1kqmrpaMzhcehGyulDcl6 -zKu15FOW3Y0bphuai/7WAUFJ7HMNFQ8c9ONqp9q/Qxdx+XMueDcNmO2y6xWq7iyCw2crXkZAdnzp -6OXiByDcc6XAP53fpj5hAC2lxNRW2Af0VzSC0azghfDJmy26Xvww93GHv8HA/O1eCPmVxsMrMNxi -26WY4a7tsk+4GANIMnqphNt4pVzNxaFH3KnO+4HLKuH5SU0123QCR8KJ0IRdzYea6W8Sgd15p+1m -tnZTLrFbDxNd0w49PBWgC+psAeiT0TqKLMnRCG2jxMe343fuOtPMc/u6E3QoPkdtyTh+Cffz1XOr -kECbX4FHsKu+STRTyWkD44uychWSke8m2Bfh5tIJ6iBN8jvLI/IbT+lv9h5N5CP6bAlqsNZXJRRW -Q0kejesz567vTCR3o8LNsU2/Z93Va+hvIuCmoXBJyv5s7V4gc/F862kLjoPCgpsiiXcx7VKCdi4r -7wU+ZesGdAWntx+hgCjQtbJXseISs7IRqsOK9FomQ1rG/mTC1/7irbFjzIU7AvScy4f7nvTljmMA -8dR8RxemRkrKKOsHjXrvB+FU9qQ8VoC5RcW6Y6btUsWTPQr4u+Dv2NhpwkW4XhwEvLLHLZIRhFWx -HY4lbNsvBq80YoI4az8zCGSs8V7BEy9/gSRnxYKxxvRLw07n6gPweQMxAH9HHc/4ByuMJOeMARhA -LHMBpXyitB03LDmLPQ9lzVD1NUon+KZugJhc4yl7hiIfRQaPxvx6073dtS2//f8E31DSPXi068bX -0udKrdrjanVk9lR2s3eNbQkmSpmBpU5o2UeLMb4qHT9IqrQd6REH6cWZI3+ioR86o9K3rcB/zOPD -axo4NqGd5Bv4g3yD5SijP1gk8L9vAeBU+6d8r8AnuOsWwe+IAdAflNCJq/Lt1DoAr2njgrq5fULE -SeKHv7pwLcRvk7V7BBvrtrn3nW6hDmJxfcYV6w2iol6cljRJDRyPI5QrEHWBS3VcV41E9L9soH62 -WjCJno9UtHk/fZOmja1M+h4SAXb6rpwZnBi5XXns8dajfKzfVqp7UBiMUpC0ThLKYVfvsstV1vJh -AdXiKuNqc0Vi4jkjwbkJweJtLVw+iWj+9OKmVMgLdvSHVFm3pG/i+z0wjp9ngijhPQ/GX/H9L3OG -83drZ4pESsduNkgiOJeeU/I8OAUN6ZBzgx6nA/pFaB9HnUMmL8qG/mbKgAi1fhYLVo/r7UaQex/Z -rO33qPAdiTUvjUq/7jjud7zA4QkvskzyR3ofEGlRK7DXIw6zaImKNFB/T9pL6nNeo1rnFO8ihw/n -NbbD4htWN+EjpW/qQsbyRnAqaaDMU791VMrkR8P4qvoz1iXkDQI0ADyFJKUYAKn1Nvvk3Mf9yulZ -DEBmYgO8aKVSZfMu5oY1sw68OGbLNZEHPhvs5bOqu7N47moE+FZsSaXCBQpdCKl5y5And6USc+KG -C+/tyJEc7hWsRSp9yVXdoLD4memVl9NUHT9OjT8GkrD1JSW7gosiLCzEjUrLrbPaP9c1J4pmacXg -phOUXwRXpcY3MOSVGojylk7k/O3Qzht+apmQiF3IltjKsQAwgI5xAxWrFL4Dn09DfDIakG9X2jQO -/F9H3Q3lGjAAPGt0DRREsx3zgZOCxH841KqgWj2WpDcu7H0KtTNDG+s5vwx+46KxR0qbdT4rj/ut -6yQH99Gjw8WsyDiTNCm5bLYJXxsGRGCACvCx11AQmxo4UYMz/641UCIzYVydKyXwRnFWZ9aIaUkO -A3jN/DpSuySb4/g7f0ZqwGLUKZ3DMSTpio6SYghHftCXCm71XLTGjrb7fSOjsoxWbWY0YzrnB85w -CTobLz8bu1O4fnVS2CXhOEi5TUTG1hsiYhIeFTaAXgNzYQDuPQVvLyF/Yg+B3QJXksCWCrUX6wbR -DstnEIllgWuj/kE+nIoQO50BAlekf1VC7fSwhNG0hJVam+MwVd9T6x8rJC/9c8I8LZEzEX+GZo5+ -2eF3hNBrKfnhUlKeJhFOcFc2CFgdL9PiCVPxohuZsQ09T+rVDKnCJVKNcupMSIo1N7AsW/UyaI/N -aqiFYk7paxA24Rydh8ZfYcZais34316Sq/SyclNGcq540w5Ks7jR+8RMPQheH6eMeON/WjeToCR/ -mdbNXJ9DpKvZKZL49sL4JKuanfNN3VYmi4xAGhVzkBv+FQE/+TYsMUejCvzpQcNUpKk0PKA6mkzD -MkGDkUOkVPB6usY6M0QpdNGBbY3JoxYnxlyorQrM5sy1w17nvUq8b+RF2I5rG6S8wsG9PByDXNVR -ImeXR9cd/Wl5cK7mhZq3qXpU6lAxH2xtBpKbxw5zAMT5ZsYfU9JKAMn6FumzoAIzNSy9a2yzOEoI -YSfZ0AV1Fyi2BtqT5TOBUmyCiTNCSkzh2jtoCalqYewo+L4s8q7t1Fc9rfkw7awgkDlKD+X5eYG3 -ljW9YZ9hzQVxU5ehGFnas1K4safPos2l7IB8U8+e+H/a++64prZ07UBoQVpIqCKEXoU0QkIPHaR3 -FJEWmihNpErvvUlXqkgTECyIqID0Ik0UVJQOoiBVioAfzpk545yZezhnZn7nm3vH54/snb3eVZJ3 -P2uv510rK4IcMVV8sBm1T1P5jHWZsoKQXnz5qsygjkQZS4JzVyjFQP+B59klRP98OQFKlfv06aed -aor0wWsGra6CQPv+/Uz26IuDwcfnOMxHFCdPN/dduEjCC8ycmZeVNmbuUiaQsfuAplrleUBmzZrS -hq8kRY1TqYLwOfpoosj7Nx4EeOeaS1n7bJpezxdU4+0YDZ2UexiuPMgxO06iyPw5/nqisaUE+Al/ -Yg63RunpjZGoRccxEWVKrxmEQXlnblryvtbihEWaxM5jut6O6FIEMQUe+WGp2dPYfSXpZjPCeCD3 -LeglciBRElizfD9T03JUke6RHPe4fe+xD+z3t/DuFFocj9aXC8gi7XMYqjyuECN2KitlwXb+QU9a -2qmWih/tPX8zoqJR3MW3XMyn4tbHD+MUEiXmgNxQqiKaDa1BWte/6k6mSaKFQEzdsETqKVltXBKV -i19CMoR6oP55scmULTVNs9ullyj2bq5XWy41QXj39Bja94TO3RZLjN79CphUMjl3+wYVhRUUsOw1 -dbc/ny54IT3MsnmL+nQGYdYkYM55WhXTGy9piUjzLP80cvpOOmEM6c0l5VucmR+pSj68p+8fZJ0Y -En1bfiEqXZNEYIirqcXUeYDd2F2MnpKtuy64zt05BOTA0rryNPkyUi3gJNmsvJrg+sHdqGL9dhEN -9bK0HGsHt/thLVShVJv0VTg59YlFYp+sTauRTJKgEB4lPJ+FUCH6FgWR5bHW29J3eZuaKTJF/MoX -7RXJ5QeDPuVdNuDxssnwUoIUrIy2SxHAUMt+9sCXJgj2vWPkzx6aVAbJc3K25kG06HnAERpbbcMd -uWcFzjELJaVtFJ6ehQvamn+wG3VWhbVaK1b0KlDjWwP7qTnnaoJRYml1aQimZJo+eeqYzrD5LQLg -pcWDnOaburLTvTfXjSVbGxP4/ccLLicl2FMUSftnmG6r4IPHKMzuuQKZOwCQKCMdD+WX4om+n7IL -3xse0xMTORvQbbMmpAAXu162S8cWE7I/dKU1JwiXI9SDGrci6YqKXHjXZzNrR05bzlmbQBSlnW2e -Psab09m/OleU00JMekIY3w0CT38YiVWwyHi5qf96ZtBTDGj5QceaxeBN2IqAlyb1wugZ5rxJNTtL -JtAtkD2oi2240Jc4Ze2er+5LXb08+rXkFYPqmGKrj3yaHqlPFeWYWbVPafmRI1WU92azgNwqqHEq -dTX6AO3CZJuFIsHAfmOTfJ2AuQpeLuKR3BiCvdru+bYIH/oDJzonkk8j1gKBd4PlgIvXBCvUQsjf -G+4Up2ZzTk9u2svGPNp+pSufm3s7EHgXktZL0nrizlZNN5aTRl02O8e9fGZIJyO7hEox3q+7BsWS -vN1Q/R6AJL6RkDFMh9fbFpw6pwSazEeQcIOT/LMHyhjoScn9rg0+LMjFfQELRfLaZwl80Rcd4ZO3 -wLOt35DSjQZ18S/LlgPreJOlEqHyBflR2w0Fpfx6yQcL2DU+6fbNvm6tpzjI9M25kun1WAr0OfO+ -6JlZSLvNpqv8FKF5xow5LRXCA3o184L4JSyMbULm7mGPTpR+C69CEr96Wp6UDCTVtdoWalgGTiCd -LLku4sUZkOiJCmbUeGGfXXzPlmIfhJHnIJNzuhPvM89eOyFF2tRA433gHFtKvUqqRTHffFuO6Z0L -RUaIeKG7za0gkOrVxLlo2mhL1kiRyOUi+xMfBbda/M+WXOkM+gqA5m8HNuv2jh8O48IFPjaHLdMq -WRjtk22oVa1wh9jcCzJsGtokG2zSnKDT2LkeyMiWNhWS24HfqxgHhQ4FBQorBDD0cMLMGqX2BjMt -7ydYt8sDMy77v0CuqyPuH4raGS6DDb2SE2E22iJCgDfqkRx5I9fIDOmLePir3dD5GgUw5uHHx+iK -dNVXZmFdNHS0H6e+FKEZhatp3iqnT/Dq63M/jxnCN35++7KETbUNtgI9EU+0M1c3qY3fx1afBEho -JxolCWLX1DaivtSrIV3PcyoW321ls2pNrDfw18nmm02KoqRp8a605WZUZFdaROalPxOORzXjBeEd -qh1bCnjmZyFPrcCDKcGrZLnkZ+IoS+U9TIKwpQC82HXFqcIDmMgmLbRmYHrymdQ52YpjoJnuxp6D -RxbH0u/weHd+nDO66UfpVsuxPqJfkZTCOTHCfe/azgJvL0V6zkBvZ7Mm89qmuSd3OI64fy77NJUG -iN0zMxEjYwjAVpqpT4m4s6biSAuPZ3awkKzlDxcCX7ypusC8j90t7WtwszIz9W3cfTA7G5jYdhW2 -t5wleQKj1UuR55BVC5rO9ZXJt5PRfRIWRAfrsqkQeg9+SvMqWa+Z/C2aLQ5Mwts4YkKkyh/h72FA -Q0RMTvnXCAMn4Ki4AbAFTP/XqAa94M8hh6MyfhfVoP8uqkH/XVQDov6Slamfjij6H/9Uh74U1sV7 -Y6A7u2cDFSKjT/m27lHbfdUsbQP917703RZLgPiSv0Q19FS7FdcVmW6aubP7vJMeVG/irNSA5PmN -22Zu234FGPLgM2cebwnAHzioUpKvCE48F5VDsBfNOGrY7szso7Zca1YCy4tBc+GwLPuGYDZoMJdj -dhOzCDDxsmW4eSDxOiOrU1e930XL65+yyR98ya8dZfa+nupRlQg0WF8dwuVaCmLor6yjn2GYQ7Ny -r0hEDHIBu7dWJa4UmZPPKhhKURz29yFKm66nNWdtTgMMg2OdlXxSboKoHk71JnOBR6yipiAmDRbR -cIQcrdaCF64z+sznzPHoG17hV8gsk6WbI0vr1grI10lDI0I07szGPD0+w6Gczf20sDjSc3VHsd4n -kb1yI27hBSnx47WgT5veEy5iTCC1CdcvNemDiAldT1MQpFrLz549cJZj1b57WP6xjRp/5iua4ef0 -Ps8G6JPHaRZCpE907ldFP0ekTp1y5tlorm52n3jQaTrSvMlixNMZhrrGsn6KIkluObD8TQ4gkO95 -Ce+zVEPsrWMJZ8Rtr22YKiFSH5grgbfMB7YhUJ3XhLgFNBOFmpLaddj529HppzsYeNhiYLv1zupx -JOGhhQVi3A1QSVnpq7Nm1+heySpiCnshUkWcIU9PnEwrrcGQZl7v1hXQgkgtrZ5VY8e7BcBuXi1N -OHHqU+BrPBcj+R61wae8hXyYmtRcEJ82eSwvkBWY8CAGhgtRNxcss9R+RpVrnZ8uLxFJquomnrZI -4K5DwK3drc82upWxbbWBsW4LxXi6dbSWbpVGs1bq7H6Ak2/sqe5R1ckbnIqwg0pPwMfFBkklMxH8 -thhvel1k9VwOAUxRFz+Aj+RXPD21JKh1pvnNAMPzh6v2s2U6hlHktAJP6hjCivdN7Ex3zieRPBAe -BFK4SQb5bTXeCjrWtdP2cupeHInJQuBd+Zq7L6VUAycUaab3TISSrMo+AE6MBsUGk0dfc3pM+omn -be8ki82mKdW6RChV+5ACDzhA4OR0eotakE++jWaqy9UTFwKYHbKvru2nCq7ONGqohMSmy+UCm3nR -vMEUYCSp9kSXmmZNAN2O6KYCNsyKiP+ppnR2Uq6/4v1POfwXyOWReRNbprbwuuVik1BaiBfnCVZb -8DV2v0IuzUoRWQNem2byCZEsJIewcaI8PAIsnGhm4XwtaFsu72pNEkUy6GopOdHLHQbwWq7QyKeO -kdh7mYUB2gelhfLFtAprHdExYTc4GEAgXye/28iarsVGZ9dzaMIpkANet7AJL8W5q2XF5xoI8BgB -xCdw+VxKKtTkiorRx696nbhMTOmubTQVnSpC59vL76JivWqTuRa27XOj3Pz2NplsYRYtjnbjDr0J -l1/CW/093Z7RjxwGzQuxzTrhgbwf9UV1mgywtDGcqHQFWI1bpmVzQpnPGv5zls26rkpac8FHtf0v -hXAl8R2KLwW1yRRw054RPJsd9e4+cdeordgHpSsvAylF8nI888byHgRU3k8QaF9N2l9KO20n80Kz -Qqw/tqs1Xq/uBUHkWmFrlin/5zGSelgFSJNtEeIBz21muxoEc9itdKCFuxg2UluH8DmXRGBh0eNY -ZZVM2kwqn/NTs6EpGpyDsCHu24s1Bc1RRKU67szbBXT06dIfeGS71nIgZMdBM8lvYe63eG7lM7DX -2vWyqMGZml+fDmLUPuw93MtZVi68MwJ2caGhYY9PyxIJ8KfcsMTPpBikQAXo3JO3CwkqwXshteaz -G8hqIjeBg4ISVaF+md72pWPYa5n7A7WoiLQoyvvxef0cl4QoguSpyKeEshrsP9a2+uxXLUVdoNO3 -ZuYY3FLpN1A7IPkKQEft5K8s3e5FEdM2nxnicY85iGOChYvduoWI7KEIbKhh8qj9bBphAycX262D -omCY0Bp6Qe+MonHWOd7x+mmhlzzV6Amj2ytQ2bPEWjaQe8Uc1EFpjMxkNM8fa4qE7xbYQXdq1gNP -paNFHMznv5g9nUS9zNYsJmUHCn7WmSuc8KwPHQAuLl0XIjk5LwQDsYhXqpUtxLSvoM5aNz2JKbZV -TauVHlxyTHP2Ve1Ts1+CsusQ0p3LqvNshhVOraYcOA7ZqeukiMerkvjCTJZ4zOV87V/U6/R0jcvz -KaV6PTwZZVNQdqyfs8Nzcj1drAm/48DFUCC3b6jLOW6zOE8ljdMcNEyIEGqhR1LYnzsvOSPXZjZV -G6naeIsazO9EsIWF7bAIP6aUUq3/Uobrmp169FYEe2dTr4RYmKSNz+Ruj3jJfAb+i2B2dwKP4o7D -IMUV8SD5znBpBO3oc+q5BlVtGk/291a5rprMfB/6p3rpNbU5no0t63bQb9q250VOPVX6uF383qvr -Hr2haAnI0oV4UFGtt5GonekeSSM0+isAcOUrgN4fHXwJx8MZnQNsfi1kHd9ERQvPczYBDIrEJR2U -g8yGEsdUPfWDRpUDjzV7fuTmpapuQLalPKVtw3NN2ympkc8Ehtq2LLrfUwGTYLgw7jzrEnfj+WA6 -KFyeZxJSX+99jKPfVwCBrlsEvG7hwCy5NxpfdDJqaeg5C74YVh6lSuw4T59qPS/83r1JKpg5NK9s -b2wQbIwzlenscJxUb9KxGdKaEZTv6Oryw2SMFeCTseCP+UgI/bm76SWVce3eNpcfEHsznyh6uzp1 -B3zqIcy1cBtcw9Be1HyNnKgJKydudgvq7DZcGDnlGLSB108V2i4Bgy+beM5Gh9nqE6np8n2Q7vU6 -xeLfPxIUtXLTpn/5S41AVLDIbU1OaVod1oMq32B+jtWJW+/4mlexe2bzIQGpzcoCHM5+2+0Tzd2+ -gZ91yuMw0QJyuzVVQ2tfAXQZL1/1XYQBH6v7++yd1SikoT/x1v6S1eLOsD5J0ZR2wGUqzQInG5n7 -bdiByop9IyWZXMj+IA4Yg/oKcDixAqAlHnzPwHlmu/OsRd6Nqjcyw0mz7SZhSnMFTy5Bb0CwwYM8 -tG6yokMhO86l4otJEmLCktA8UjIuB5/u9jA9ADDuVrpkOc4ilj+Hu82n4srSLKUWKzwKsVPiQN5Y -RmcmWKr9sZ53y5L+HcZ74POYLidbD8Sao8WUFM3fzG+vFSy/Nu4nfZUlmxE8gZURt3S2hAxeG5t2 -R6lPYff1c2wvSD+Z/NDmoMYVxQkOS8jqzAfOqmLko3lUOfYK57vl7tBN+T8HqQTxybeX0yeZSrwZ -YqUrZtFl7z9RUb1UzBNGt84svpLsDXk4Dg3sc2rn6GIL0MCzYILpv3hn14Ncm3JFwzyX7AdL8LNt -tOT0MgbMQ6ngpPlyZpkONhRkLS9GfiQJMUYRte3Ee9FHLNXCOU4neMdzt77kHu6dFuVZH4IcaWrG -k0sUyTHK3bI+JXFOvsW9UYu0Ds4exy3W9MXeQU+CpRXX6f2J1nUiyDQr+ZJG08IuqJ9v9xOYsacp -S5Ynkrt3OfxexEirUppcanZWE6a5lu5wuB/1FeCEBfHt3uoN4zRcI18sl/R5bq0KGvOQ82Pi5J99 -kOCycQztz/WsoiKZpAsaWywDKrWOUkpVcc1rgHpPRa+K90A1LGBPqC/eeHYtcfEBeeTeQDRLHjBm -HtfaqEXm7iZXcez+1F0jHbE2DccQ70K7tZc8n7/4mzeWJZmu4iHHS/VcTQtJUsfkR2Ic5N6NmDwE -aOSB6Uc0CEJobXew5FVC50Lralen2Ih7okph8KzjbIp3w5T5h+WMh027JXTG+HV5N7svBYsN8kwR -uBJgHl1gwxlQ1FQz8Sx/46upmkzc8Y7i57vVrGkLJqpjaH22rwBsDat9ggA5i+qjY5NF9mm4oNpM -omlLRxsafpKzPWLGomkbugsrwtvHqCytJl1Y++Kq4QKqVI+FE7d5Kj+48WuOzwkcp7Jy8N7EN1Fe -nSlKZ+eLo2ABh9Xu4AE7qZofGzijAXm6KVVMUZlvT3XIxfaLPWdQKvRzTLLuKSYK93tIoLvEMDOc -a7ImQN6yItw428YWpoUIiaBs3b6t12epQv6wS4sUVnSV7PQ9d3NyC8GbLhfCQ98YGlOT1ybGyHrE -zry/1Xn9wx6mNywy/INY6oEhtAPevGJ6SqhmPoAuDySjC0GT0rSASpBmveCOyXJiFvLOdeHIWqlq -PgfXSPJgKsX6G+cARHINziT8ikQvzO9x04SI1Bh4RVMcGF8Z51js6miRzHf1IVKTRTk54emwxNPa -CyJ0/MzjxauXNbijnHniVTNX1YgsrNf6MQ52eDjOUeWkKEiusA2mPVPnwn5tv7imKv/uFsdiD7t0 -7eMNaM5n+8XekOzQDZfFrMqvgDa02XE7xU1dP7+iPTVaHZFxv9gPH4t2K1napDhmQqywy+9zlM1I -pMEjKbLvpb8CtlSGWbzv2a4AqZueyB177HANnQ8+kWToqXtbw/hse9wN4guU1fVK7Gr1VOSPATxd -1+5GzTWd5AKD2pVZ1xyLGI1p8wPLDWLsVAMWEozvzEdFtPsoPG41MzzX1Te5Ixw279cY3DcUV401 -ouKezs5nIwpk/+SzbyB5EBLDIcJel8Oa8kklf9wwQ4y7WQPGGRXC7PAps9CZMwoY0tTRxervfXNo -Acc/DAo4Jem9jbtiOyIc1mjcuP4VQCJLfR7ECt8pNTNouDOuroqnJJaX2Rh24o9Q2dM3r2AIf7lR -z8en75nGHpcaZH0lcnmaUGiDF1ZiDzcf4wRDUgoecrldPRe6Ka7RSLJS0GaQu/dGYN+NlrycKiKh -w6nMX7QLQmmzpOFG/xwa+bzNsA4jnfUYulNEjtaRNqVPygie/gpwNpSIZ1inZQAryvoPNV59CjCa -SNmaqqfraDjLw5RGXteWNOBjXQWNWDXgFUlNxjtXh7ZlNFsjTtdwbckbV+jsBbDa3zCd3XVWt5SK -yg8cq16l9stcddVaNNaLNYSQjl7lZ1YFTOfNZTNrk8iwd3vyqGm+UTH4cnOFk+f68D0jF6cgTTb6 -8DQlelCWal+COxEfN7vmDSqaSykp9b2gp+uemk5XjOMKbTbqPdiX214FJ7qfk35cRaWdoR3wEVQ+ -s1NCkstvivriMNMnmX4/fYq/KSEGVyZqsAh+faM1wWZNZzamLOkxK5tdsLQh4GaamBj/yQ46mAgg -xvm8uhjD6Hycpqz0y6j7UYGF2WdwuQHku1UncyPnRs/cQinnRQpO9RMxfYyIQJy+um0XRXo9eEuR -+KJjAGsVobNW95kDsbfXpvhM0sQa9RpTsGIMsWka/LFqOS7INJM0wEnOPk7mnvpnpRGLrIz5MzCW -6DwBTtUXzCX00s+mZHPyXQnXE3uL4iP7PaeIMymDmgD01UFLZa+JkLv4smhIfXp16nzHxAMBALDs -eBLiVdmMZBP7qwQKkExFuvNnR95Wt+BP7xomVLhXvdSkW3tIXsBTQ239vHgTmW2TpPvdlqNF1GJI -k80zeWjvC0ntRDLPSPMfPgCtM90rGQFw5DTvTlajKRPRUz35PD2w+1dAbTMje1kxWbvYQ2EEsoT+ -adplrMiwjWxXmiyrnmI6w9ZBvG/7RCRqIDgEdAMXUAlrYqr5fnsN+m/baxwRNwC20EP+GtWA/Ly9 -Bv1RGb+LakC+i2pAvotqQOtVMNr9dERJ/ziqASmFTQJmHZexjVqL7SuemcQxqxbn38U/L1B6Ricj -k1SHeDPxl6hGafh8scvyLrcTYG4RClil6gnTCLbESZbSha1DLiUr0lTb84rR9NhPfsjBphoZXZWu -eHVfQvgT1P44SuV6QcFMMWIXQ5/rCAaWVt3u6jH77P/SPVrAZddY1pmxfVRaKy3+4tqpRPxO9f2v -gPAVGUcvUX2RsC3oqaHr5hl3qtjLh4iyaBaAO85wvTCma/z3becDzpOSDyrzvUkuo8UcjsAn1ei8 -ltMFiGUS8/brYKDxme2KlHckPfumqueCu/UpYBzlZCC6npFtf+lsL2b8/Yj6WcCU5PlcznTslo6H -WtfE+z1DcGtdsCJQPIu+bjGeaYB+fuzpxpbh1rq1HuwAauarDY7+/KQCGYgp1JshiPVAzOka+Cyv -Xxn7XJ9MbJmgGngZxYrWhnt2H3sgaRh8DWOeC2wzmzWUOzGK76ap0HxcTRR/04Kyc1UpcUamZ86b -htTjlfZXgFEQd75cbaCnqnzYE71G6b0+Ifkt2o+6BRl3dZ7K69w4eOv8yZbzK6DiUV84x1z2hxU+ -OlkDm5E011DREDIzafbtm2eaBk9w7tJvLxcaN4pvEdnA0Mmy4QfCiQp4RezJyDQFnmAAd2zfPZBb -6ORXwBLJOsUcodOvnBpgpDaN3eyQ0f9EVQTQpD/V74nHGkm00l7hUpJ+aTpwLkeMm87q4T1QGjI5 -IwSARXT0cXEkgumEEXGZos1NAsfbHuAqA6FiQicYloWA5C6xJFmFQeGR6h3reo3QTfLErryYezJ5 -sZc+1vLAbMWqD85Iom17pc1dP4/JXnyed9xyAarTwnxBooy2/8C4V4iqbqcaxj/Cw3kQyngrHH84 -/u+0zhBkeRRRXStGTJbzGbyJJwcCJmroNFdNoXdHON4wafX6mx50BysmVXJc6gApcm8zRXJyp3ZW -0oacF/PyJEk5zTsaLb9YF4NLpUpB2i/GXOZjzXMzUnj1wLiilcyvJqfDqB/SJ1/XZ1BnUvrgo1iX -aWsxgl6WA4pPu2wUkhrkZdPKwqizdZ5AJeG5Lddg9GbIzsuQT3AqOOp6Qim1YZYL5C5lYx/dlHGc -YIuuRwLHVLCHIxP85YLsMvAeG6/JG7Mg2VJPy67qFL6YTDcFE6O4pJIZ3jhe/vieIKWgT10f5x2S -mu1VscPe1UXlAEtkRHurbw3lAMGv4sliFqR3Xy9bzTp0JRGEby5kxK989N7PvJ/W6v9xDMbbmSkS -PIyCrKu9S7LlfzP4nlIwame+3XZIdDWVTj6iOpas9HNWomGnAuT96baJAivo1Z1yVpv4dAjH+Nll -mPAJwW2c8GQuV1Cm14xvIuS0FrYzLbrm1PD+oHz35Lp++daTNT7JIljGcok7Z+8LNvzTp+rNAf0P -dECpN7sMak58NEwMi/ggqnOJRo0TpEMf1867vqMUMaGzmxE2sr5zE/r20+TZUqWg0P0BdcFJqLW/ -VEv5xikOcUZu3qiMz4JBemHWX3KY33Qc362M9PQxpbVrAa7168mYMdCeR60vz9VRxz7P3DOF+AU+ -DJNygZl2Inxl/F/geTLzidGau68uknv0AXp9s4O8vhw4CdZc4jKtFqfUEAgjmYlxTqVg2N8fK6l3 -h6HYng8lUOMTLSyd3EPPA2/XhGT6iG/3x5TzhebLjO1kP8jF749kBUKYyE1Ud4XpbUmus78jDeYz -T97A5WSl60rMymGUTIJknu6VcVJFqezFHRw7GaYyvZTYxldEnDdIqBLucG+tohkk57PtJwTZxtJP -FIypP15IDs9U6ipTZt1IgYwNvxq4i66xcAUn60Cgp9AUenmkr+QZ1zifr+n0GRrjxWjeueEduQiy -ByJL8hNYyu0mVyPVgcSEZb1dIRFfp93Hn+COVhPe/ob9kGHfmW6zvnAgqU13G9GhK2fKfGStmxAQ -25hNRchY7dSz3FkFztEehkayPs0aNp6yS0Uc59YOztucYf0KAIuvYWKlp9UWXt2k32O0tg6oHAK2 -nWPQkXpHPSVABFwW6gmS5/HdHAci9Wkf5b5dNOMyWra5WE85La3a8H6Ys8Vv7XogLVUQUlrRij12 -qS01M9/OOoDR+/3WO086KgyAJZ49pFcPIAmhX5t0bTHSA9Ki3/BGZareXqwSrMtW3Dm25fs8Ti+M -hn717LChndYnwRmv4XMMJMSSsfy55RYPGXlU+K6wd2/Yn89MDpo5sTfko/kZYyQRIkyt2v2kkPMa -pOWybwmF/8S5C5NLN/WVk2EZgAMNfUV3sQVBq2fDrMNLEhO3CVPrgZ7e08MjszsK76jkaK251OKZ -GaxA23Or14nP7q3eilHspficevfcZc2780UWesdbx+3pZK+8uyvwFcC/bkn/nC9C26dAJ2mERwPg -b/pU8XVb2/ZA4YQ69vhrVDPtOfu5mK20JCnJqHitHFw2yTFoQgY+D5vO0xpOS8QeDZ4fIFrRDn++ -MsuahjuXFfm5wNXXIBXY8URWcIyHyNGQhUMdodcbLaqkJD+212NXpOYQCHfwS3uVhJsP3eDoO/us -SezBR9FuFUgjZKZGUvJAuoHzXJ9NlfOo0pgb4irU09DVfKp49QorEROariwMNEur+kAzzVRwvkIs -s5IxhlO1hSNLXy84CKZ74nHTTR+qO8fa1GQAVGsyIvosNJTcXSf6z++WX4FxCto3RS9MCCQv3dJ8 -NHYx97FgDMu5onJLl7Thy8tOZNs1lh+Ln/Uqh1RxtIQSk/c5w3bqpSWtrz7FpenwmGJPGfBjSpUF -z59zugaykzahmI1NcwKOx6YyKeZNvR4g7EwttfUzcuT0cpaz5a+n8TxfZ2T7YMKsEytTsN0jcVnN -nsBeEOHCdYOihd0/yqX3BY9S3COgig6GM73nDJPV+r6zH1YZur2xddDFnl4eKB7cvjYc6XOLstbN -lyx0bX6x4RGLb+CGIyWbcKrp9YVwGlMU+EPf8dQ0mzzCe9jN1qJNVe3jm7YKCd1cFdqEW/h3e2SQ -ccWDq5IBgvxsNTVZFPQaqT5zPcQc1Rlf6gSYwirfMFQV8d7Delie4AR+HmaUl6rs7CQDDc9szC62 -EPwSD8bm+xbAL9NBd+i632SWRqY2XFRgHXoA0Hz0pAGbbkKeGimi3Ew+xjHCw8FLpwx8Si2jjMUr -cDRUjU7ybeN4zltf91GUM9Ki6wRQSrvrNMi9pQIKUumbTucMLuGJq0XitsUGwlJp7J8wuzpD1GlD -oq6K8WzP4erm0vURw5GQPu1n8W85d4VCvPLig7Bwjdw+q8ov3TJ3Ej7uGaZlM7yZeWF+wYJPePDV -TppvbePg9UX7bCbzx9JizFXT9kwpdTxnA70CL/POxsVELmWbSYF5uAd71t4eEzGXFGm7XPnoPruL -vvPuql0V4uDqy7hGO5/HL6z6WOXJLi8DeTnHz0B8om/TAQcNU5WOjXysXGPnTx1JLxQ59a68FY0G -b4mr6W77PqK4YMuuIjI5PdXGV72Yf+pBGR0C/uJzcWBKYu32mdSNEQiV33J03ckzx13fzQUD0nu3 -/UcNDkc/B+BLV1+pZmazO2WOUkq9pkaoC8q1WYV5KlxR0y9xXWHStnFS0XMlE+8VzMBnBGvce4Ta -5pgT5KHLWE0MJTS2hL1QX+0d1XvUHDk+5UE40atYzacTIIjegbwmsLT4f3LZzQd1S/OXF+mPBqTR -tgbpS1o4Vd5uJn1IRHIZf/aUFKPN5rkeG2u5qa8AjT3drHU9OnjH+Eqs4nT57NLTqeLTBXrE3Bk2 -Sq/pQbS3Z+ZXNXgZWiuWM9zK62uG2yYmT6CyQwEDZqxTjHhv2+lNMyFGLenoRZG0KTeTbL5W9ife -wzR6TdwRd29zf/4K8JSPlN9/0ZXabuB/54ULCDqf0pVJz8WU8bp/nFmNuo0swTunoijUcQOyerqA -C38KF+dfvIpvXcPTIKd76a6Y5G43sOWWPhC4fC1wic1NxbVo8oD+7rMY0b6VsxX9ElolVBV10xy8 -QRyy78Vv4WJ4ekJ6LndsNM4/jLfh00gl23LlXusfyZPv5CBnmNVkbUev6rDLjJg2ArqNJnQFSni2 -CIivgLsdKdAADmjeZctVM6OVOt3BYkbLlFanfuMrFtZsu3K9BZlktKTyTLcvJ7DJXqwtuCYj43tL -XELCa7uBnH9jhMVX1slojJS6aNDEhhrc02qhg1Jg0rqWgum7LNjflufgmgMNyX+oKo4SGwkKvlpf -p+seIBQLJZEygF5HDtPchj3ZGu99cI3adcci8vFWqrpqbPCmexRsw/dLQUpB03vcfrr54KBd/MJV -YmZ+DTZmogN24RUOxnPhn+bb8HCPGsaRyHVt3Fzro3VDyEgvxP54X5A6Qt8bFK5LU6WBvu36NrDG -pQ9AqfJshZaYzs8vpyyjIQmKu2gSAC2jOD7O0/WI3SklS0KumhGv1kRM6CSJO/XomF1vUiRERqjW -K3fWaNOjh/c8yKdBsc/CXtwuIAellfD+ul0aCKu65hDWteqWf4kWWsU9q86rrpC/RsJ2UJ4k8IKD -EEqFE5QkRoZQ8cCu03mA36wr9yKpgLY0ensDr8kLEWzDN0m6qoN2tj5M9bdT7fh8qRE4qH5c3Dlq -4VP9FcCx9mXEunsvQ2WWjLBhJMPU43qMqE9zgHXUWmmn3ohcQhNlEMT8JLDPQ/rEV4Ax6WvnU9vZ -740hWzrmyoacQIpuycj3+hqswhUMZAEv7MRITUu6V8zl1hlbC0JNRtwBWN2xdMnbAU91u+ZPVQxH -jqw+iRWQqtHYCCiLimtYt/8KGDlXHs9Iphgsl7fYCnlq6P7WuG+XrCiCe8w2aK4i2VigP1h1lOMy -d9wwUtr79nMu6S07DIdnaFB/7DOBz33ItvqMHC46OQKvZs4n1dvQyVYELUjRgTDHrjz/WVY4l94v -4GPnTOe4vvsFCsox13Uldc3nile/SJn2UfmY1bRysZIDwqKk5trIRyYaSDcvfQiXdx+B06IpxCiJ -RVFXoXxWzFWs0xPlNOzGRELXRSA6F57yNxGe64bqNwSSEG+xGT+kk/8Stp9Q0VsshMtLAZBTTjnd -Fj6VQOIdxracWXsrhfUA+n5uD/oVAG2RfpJ9LKOsAJh+7l7fdPLekLUs/4LhaxLNQvawQAxDwYck -Eh2VTzkS6pREHOX9guyY8/wxD8+S8gy5QEUWx0iJZlDJcWB9RRqSbrD0SyFSdsPmff2n0ktrFaqe -Co7k51YKRI8xpJWGiRop9DxUK2C40TdBb/a+h/HwUarFH3NsdDgmmpyKu0TsId3TB2dosDH1e+Y8 -cx8Z69SUGPo4d9wkrDRCLVykNy2zFKOm7nM/duJL+ETtrg9hXRvmD9W8TmkIajS+O2YLStU6FwOL -cTv56r64aorCQzEjcK9+POPm3guV+W2oAMz+YdN1/cb1W6bO01MPMkvfp3OdzReJkB6Aw4p9a9Wu -FYKnyh6pDC30zSgulu2Qs1DNcqLOcguTi+0UwZDeFUq0UrMrV9xWDawzNTFFPNJtucEkV+52eG4t -Nr2lLgOyqM2Xq6Cm6lJPu9oGfh/VgBBxAo6KGwBbINC/RjWgP0c1IEdl/C6qAf0uqgH9LqrBEFR1 -fEMMSJTxjzcNhUaR8qMR1RUpz+/NXLLzeCG8foa2QgB6bFLKizrQ7MuF9RA9LdhPWVEEz1oDh/ab -gSpGF21OnYY4P0x/efak7Uz9iddl784mlizQL/J9AJbR663SXtTyG/XHV0AeBlxs/hJahOIba7Zs -OlNsxmMW4ZxdbVw7T+zZ/CTBbJMxHCpxPjZuTaNTMqbTifiqz/uzVajUKzbDJVtjCX6zj6QSJN/3 -vJ9+MBxPcbwz0QN8s95GTswpii9qd/NzWMEA863WXeuqAkyR3Er1NDtFQ8QJ6q3nwcde571yo2AI -5YoiymiM7aab/Kw88vLgnLl/bNxQmLfap03qenMuWxstw/Hc/sqXV07vvltuCfEBKF3U5thv8K6t -L+Xe3Fy0d5tlE02IUcfhRPoA8Avh5fPLX29agcm7Of0/PIisSPV3veX1Ca99usejVsZWK+bTTSgz -uwYFnacCnahsIN/5BzjaoizW/oiPvjZ6FXdqLmXkHkQe9X/GR/0z0FF77B71c6WjFv4ctZfLUSG2 -o27WI3fA/W5TGugha466L4EtUIa/sobh501poEdl/I41DN+xhuE71jC2nvjoHEJEdP0fs4bhNZF9 -qWXIMk1B45XRMaOH7NABHauR03PFdX4yxOlFZRbKGnV/NvXjIly85O5I8OCSPOPH5WDl4cAlyYWU -QKFRCCs7K2sc0hZtjSGgJdAYjATKFoO0tkOJW8MPU5BYBBpuTUCgrCUk4LYSduI4O2uMrR0KixRH -cIlw2bhcvHRYsqGPK+GwQMcLVvYEMSdXgv1h0gUX28NraCRchMvD0ffwVAKFhYv/6fq5S44Xvtkj -4QjcSTjqJAJpiEBJohCScLQw/PAVznXl7JXvHcFw6IijPiqwhYHxr45g/NkRDEdl/M4RjN85gvE7 -RzABfuA3wcPLyv2CmLWv70m4lRVCHAdH4uysECg7Oyvs4dEGY2dnhyFY2xDsrGwIOJwtxgotZuPg -efG8h5gWXltdRdnA8CT8T/iVOg5TMWg07NtRAiP+pyMc+dP7n4DBwBAoNBohcXiPiovDDhMl4GgA -7NfK/LfB0+OSlfthU5ysLrp4/IrdoZmd3a+k//RJYD8f/5egHm6owgUgImJ1JlwmONtaiyr4XCJ4 -OXoQFF0uuFq5W11ycScGAIlIACXJHRRkACJiIiAxydHF/sD/Evzz/NfUUTz12+o4kv+HfPlb/qPQ -EuI/+P9H4J/3v6KRvr6ytuFvqONI/yN/6X80XALxw/9/BH7xFKc8OscP/F/Cv9L/q/7GOo7iPwaD -/pn/SDj6T/0//Af//xDI/C1gWlbuMARSBPZN6cEEFJUNBWG/MKE8VH5oCUk0QlQCi8CKI2HOLvby -zgR7wkVbmErLfW3PCyqOzgSYQcv9b0eDQyUJ0265r3yoZn1gii33FaxsfzpX+NO5grOLzXnYKULL -/VMEH2V3dxd3mFLLfSV3F1dXwp8NNVvua34bnML0Wu4bENwOK4AZttw3PFSkys5Wrh4E2+9ahEOg -JJAwW2t5F1fCRdi3F8eL9t+nix8KZthlgruHo8tF+UOfXvrW5jNnvzUXrvDtaPPt7fc5cDgs+luJ -hzeI4+Fo+Js9EqZ6aP5XIywcgUFif67W1uUi4VsTcaISaLQ4DnHB40+m2EO1fHgFh0FIfDO1cXbx -IMC+vf6liT8ZiMPh4vC/GvylMDRSQhSNQbTc9fi39tH/BP+/fWuEkx6H3wVB1NZa7KcnuOjhXfA/ -1XHk8x8l8Qv+i2MQmB/8/yPgtipFy3yo//789tuRiNSVcEgQkouezs7/P5v2A38A/nX+H60Df4/+ -g0t8G/+Lw9E/nv9/CP51/x+tA3+//hNHo37E//4Q/K3+Q/3Qf/9l+Hf0/0fpwCP4j8CgUb8Y/6El -0Mgf/P8j8E/qP4ykOEoUdehPJO4/RP/91CIEShyD+4f678/p4uLiv1X//ZQDeTgigf/P+u/PRkgM -Cv0P9N83aYPDHOq/f0lmwxFo+H+WzIYjvhH598jowxy4XxPmcARWAg5zcvF0v2jlLO9OsHE5LN3n -W6mI762QSBz2763+fHJYIkz+e3OUuATq96l9LAKFRByh9r8ZYSX+ztsSOFHxbwERzN/IfXE4Cgf/ -dbmPwf0DuY/EYUSREuL/brn/d/jX+/9fjCD+QR1Hjv/EEb8Y/2GQ6B/jvz8EHo9EoEfN/xIDSX5M -+f4fxb9N/4laW53/H+r4/foPg5CA/+D/H4Ef83//3fiJ/xddbAkeP0XyEb8Wyf/ncBT/Ed/F///E -f4Q4HCnxg/9/BIavYxiYfhH/J//ziJmIXr/zHUwSQET8farQoZSwcpYsOPuMGO5i3bVHdCDX0wr6 -QHS+D9PPOd/2SqL9q20oMFvSg+D2c7E/8J+K7/n/21d0/j4c+fz/5fpPhDhaHPWD/38Efqz//O/G -9/z/7Ss6fx+O5P8v138i0D/0/x+E7/3/21d0/j78bv2HQGPQP/TfH4If+u+/G3/b///WFZ2/D0fx -H3N48W/m/xBohPiP9R9/CP6ViSksHI1AYP6TJqawCLQE/FemmbAIHAaO+j0zQlgkCidx1IwQFoXB -YP9+/ScSLopEYXEY9N/OCCEO2fCrM0IIBA739zNCCBRSFIX+ty8A/YEf+IH/Wvw/TzqIjQCQAQA=` diff --git a/cmd/swarm/upload.go b/cmd/swarm/upload.go deleted file mode 100644 index ab07908351..0000000000 --- a/cmd/swarm/upload.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command bzzup uploads files to the swarm HTTP API. -package main - -import ( - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/user" - "path" - "path/filepath" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/log" - swarm "github.com/ethereum/go-ethereum/swarm/api/client" - - "github.com/ethereum/go-ethereum/cmd/utils" - "gopkg.in/urfave/cli.v1" -) - -var upCommand = cli.Command{ - Action: upload, - CustomHelpTemplate: helpTemplate, - Name: "up", - Usage: "uploads a file or directory to swarm using the HTTP API", - ArgsUsage: "", - Flags: []cli.Flag{SwarmEncryptedFlag}, - Description: "uploads a file or directory to swarm using the HTTP API and prints the root hash", -} - -func upload(ctx *cli.Context) { - args := ctx.Args() - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - recursive = ctx.GlobalBool(SwarmRecursiveFlag.Name) - wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) - defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name) - fromStdin = ctx.GlobalBool(SwarmUpFromStdinFlag.Name) - mimeType = ctx.GlobalString(SwarmUploadMimeType.Name) - client = swarm.NewClient(bzzapi) - toEncrypt = ctx.Bool(SwarmEncryptedFlag.Name) - autoDefaultPath = false - file string - ) - if autoDefaultPathString := os.Getenv(SwarmAutoDefaultPath); autoDefaultPathString != "" { - b, err := strconv.ParseBool(autoDefaultPathString) - if err != nil { - utils.Fatalf("invalid environment variable %s: %v", SwarmAutoDefaultPath, err) - } - autoDefaultPath = b - } - if len(args) != 1 { - if fromStdin { - tmp, err := ioutil.TempFile("", "swarm-stdin") - if err != nil { - utils.Fatalf("error create tempfile: %s", err) - } - defer os.Remove(tmp.Name()) - n, err := io.Copy(tmp, os.Stdin) - if err != nil { - utils.Fatalf("error copying stdin to tempfile: %s", err) - } else if n == 0 { - utils.Fatalf("error reading from stdin: zero length") - } - file = tmp.Name() - } else { - utils.Fatalf("Need filename as the first and only argument") - } - } else { - file = expandPath(args[0]) - } - - if !wantManifest { - f, err := swarm.Open(file) - if err != nil { - utils.Fatalf("Error opening file: %s", err) - } - defer f.Close() - hash, err := client.UploadRaw(f, f.Size, toEncrypt) - if err != nil { - utils.Fatalf("Upload failed: %s", err) - } - fmt.Println(hash) - return - } - - stat, err := os.Stat(file) - if err != nil { - utils.Fatalf("Error opening file: %s", err) - } - - // define a function which either uploads a directory or single file - // based on the type of the file being uploaded - var doUpload func() (hash string, err error) - if stat.IsDir() { - doUpload = func() (string, error) { - if !recursive { - return "", errors.New("Argument is a directory and recursive upload is disabled") - } - if autoDefaultPath && defaultPath == "" { - defaultEntryCandidate := path.Join(file, "index.html") - log.Debug("trying to find default path", "path", defaultEntryCandidate) - defaultEntryStat, err := os.Stat(defaultEntryCandidate) - if err == nil && !defaultEntryStat.IsDir() { - log.Debug("setting auto detected default path", "path", defaultEntryCandidate) - defaultPath = defaultEntryCandidate - } - } - if defaultPath != "" { - // construct absolute default path - absDefaultPath, _ := filepath.Abs(defaultPath) - absFile, _ := filepath.Abs(file) - // make sure absolute directory ends with only one "/" - // to trim it from absolute default path and get relative default path - absFile = strings.TrimRight(absFile, "/") + "/" - if absDefaultPath != "" && absFile != "" && strings.HasPrefix(absDefaultPath, absFile) { - defaultPath = strings.TrimPrefix(absDefaultPath, absFile) - } - } - return client.UploadDirectory(file, defaultPath, "", toEncrypt) - } - } else { - doUpload = func() (string, error) { - f, err := swarm.Open(file) - if err != nil { - return "", fmt.Errorf("error opening file: %s", err) - } - defer f.Close() - if mimeType != "" { - f.ContentType = mimeType - } - return client.Upload(f, "", toEncrypt) - } - } - hash, err := doUpload() - if err != nil { - utils.Fatalf("Upload failed: %s", err) - } - fmt.Println(hash) -} - -// Expands a file path -// 1. replace tilde with users home dir -// 2. expands embedded environment variables -// 3. cleans the path, e.g. /a/b/../c -> /a/c -// Note, it has limitations, e.g. ~someuser/tmp will not be expanded -func expandPath(p string) string { - if i := strings.Index(p, ":"); i > 0 { - return p - } - if i := strings.Index(p, "@"); i > 0 { - return p - } - if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { - if home := homeDir(); home != "" { - p = home + p[1:] - } - } - return path.Clean(os.ExpandEnv(p)) -} - -func homeDir() string { - if home := os.Getenv("HOME"); home != "" { - return home - } - if usr, err := user.Current(); err == nil { - return usr.HomeDir - } - return "" -} diff --git a/cmd/swarm/upload_test.go b/cmd/swarm/upload_test.go deleted file mode 100644 index 356424c66f..0000000000 --- a/cmd/swarm/upload_test.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "runtime" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - swarmapi "github.com/ethereum/go-ethereum/swarm/api/client" - "github.com/ethereum/go-ethereum/swarm/testutil" - "github.com/mattn/go-colorable" -) - -func init() { - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) -} - -func TestSwarmUp(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - cluster := newTestCluster(t, clusterSize) - defer cluster.Shutdown() - - cases := []struct { - name string - f func(t *testing.T, cluster *testCluster) - }{ - {"NoEncryption", testNoEncryption}, - {"Encrypted", testEncrypted}, - {"RecursiveNoEncryption", testRecursiveNoEncryption}, - {"RecursiveEncrypted", testRecursiveEncrypted}, - {"DefaultPathAll", testDefaultPathAll}, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - tc.f(t, cluster) - }) - } -} - -// testNoEncryption tests that running 'swarm up' makes the resulting file -// available from all nodes via the HTTP API -func testNoEncryption(t *testing.T, cluster *testCluster) { - testDefault(t, cluster, false) -} - -// testEncrypted tests that running 'swarm up --encrypted' makes the resulting file -// available from all nodes via the HTTP API -func testEncrypted(t *testing.T, cluster *testCluster) { - testDefault(t, cluster, true) -} - -func testRecursiveNoEncryption(t *testing.T, cluster *testCluster) { - testRecursive(t, cluster, false) -} - -func testRecursiveEncrypted(t *testing.T, cluster *testCluster) { - testRecursive(t, cluster, true) -} - -func testDefault(t *testing.T, cluster *testCluster, toEncrypt bool) { - tmpFileName := testutil.TempFileWithContent(t, data) - defer os.Remove(tmpFileName) - - // write data to file - hashRegexp := `[a-f\d]{64}` - flags := []string{ - "--bzzapi", cluster.Nodes[0].URL, - "up", - tmpFileName} - if toEncrypt { - hashRegexp = `[a-f\d]{128}` - flags = []string{ - "--bzzapi", cluster.Nodes[0].URL, - "up", - "--encrypt", - tmpFileName} - } - // upload the file with 'swarm up' and expect a hash - log.Info(fmt.Sprintf("uploading file with 'swarm up'")) - up := runSwarm(t, flags...) - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - hash := matches[0] - log.Info("file uploaded", "hash", hash) - - // get the file from the HTTP API of each node - for _, node := range cluster.Nodes { - log.Info("getting file from node", "node", node.Name) - - res, err := http.Get(node.URL + "/bzz:/" + hash) - if err != nil { - t.Fatal(err) - } - defer res.Body.Close() - - reply, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatal(err) - } - if res.StatusCode != 200 { - t.Fatalf("expected HTTP status 200, got %s", res.Status) - } - if string(reply) != data { - t.Fatalf("expected HTTP body %q, got %q", data, reply) - } - log.Debug("verifying uploaded file using `swarm down`") - //try to get the content with `swarm down` - tmpDownload, err := ioutil.TempDir("", "swarm-test") - tmpDownload = path.Join(tmpDownload, "tmpfile.tmp") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDownload) - - bzzLocator := "bzz:/" + hash - flags = []string{ - "--bzzapi", cluster.Nodes[0].URL, - "down", - bzzLocator, - tmpDownload, - } - - down := runSwarm(t, flags...) - down.ExpectExit() - - fi, err := os.Stat(tmpDownload) - if err != nil { - t.Fatalf("could not stat path: %v", err) - } - - switch mode := fi.Mode(); { - case mode.IsRegular(): - downloadedBytes, err := ioutil.ReadFile(tmpDownload) - if err != nil { - t.Fatalf("had an error reading the downloaded file: %v", err) - } - if !bytes.Equal(downloadedBytes, bytes.NewBufferString(data).Bytes()) { - t.Fatalf("retrieved data and posted data not equal!") - } - - default: - t.Fatalf("expected to download regular file, got %s", fi.Mode()) - } - } - - timeout := time.Duration(2 * time.Second) - httpClient := http.Client{ - Timeout: timeout, - } - - // try to squeeze a timeout by getting an non-existent hash from each node - for _, node := range cluster.Nodes { - _, err := httpClient.Get(node.URL + "/bzz:/1023e8bae0f70be7d7b5f74343088ba408a218254391490c85ae16278e230340") - // we're speeding up the timeout here since netstore has a 60 seconds timeout on a request - if err != nil && !strings.Contains(err.Error(), "Client.Timeout exceeded while awaiting headers") { - t.Fatal(err) - } - // this is disabled since it takes 60s due to netstore timeout - // if res.StatusCode != 404 { - // t.Fatalf("expected HTTP status 404, got %s", res.Status) - // } - } -} - -func testRecursive(t *testing.T, cluster *testCluster, toEncrypt bool) { - tmpUploadDir, err := ioutil.TempDir("", "swarm-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpUploadDir) - // create tmp files - for _, path := range []string{"tmp1", "tmp2"} { - if err := ioutil.WriteFile(filepath.Join(tmpUploadDir, path), bytes.NewBufferString(data).Bytes(), 0644); err != nil { - t.Fatal(err) - } - } - - hashRegexp := `[a-f\d]{64}` - flags := []string{ - "--bzzapi", cluster.Nodes[0].URL, - "--recursive", - "up", - tmpUploadDir} - if toEncrypt { - hashRegexp = `[a-f\d]{128}` - flags = []string{ - "--bzzapi", cluster.Nodes[0].URL, - "--recursive", - "up", - "--encrypt", - tmpUploadDir} - } - // upload the file with 'swarm up' and expect a hash - log.Info(fmt.Sprintf("uploading file with 'swarm up'")) - up := runSwarm(t, flags...) - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - hash := matches[0] - log.Info("dir uploaded", "hash", hash) - - // get the file from the HTTP API of each node - for _, node := range cluster.Nodes { - log.Info("getting file from node", "node", node.Name) - //try to get the content with `swarm down` - tmpDownload, err := ioutil.TempDir("", "swarm-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDownload) - bzzLocator := "bzz:/" + hash - flagss := []string{ - "--bzzapi", cluster.Nodes[0].URL, - "down", - "--recursive", - bzzLocator, - tmpDownload, - } - - fmt.Println("downloading from swarm with recursive") - down := runSwarm(t, flagss...) - down.ExpectExit() - - files, err := ioutil.ReadDir(tmpDownload) - for _, v := range files { - fi, err := os.Stat(path.Join(tmpDownload, v.Name())) - if err != nil { - t.Fatalf("got an error: %v", err) - } - - switch mode := fi.Mode(); { - case mode.IsRegular(): - if file, err := swarmapi.Open(path.Join(tmpDownload, v.Name())); err != nil { - t.Fatalf("encountered an error opening the file returned from the CLI: %v", err) - } else { - ff := make([]byte, len(data)) - io.ReadFull(file, ff) - buf := bytes.NewBufferString(data) - - if !bytes.Equal(ff, buf.Bytes()) { - t.Fatalf("retrieved data and posted data not equal!") - } - } - default: - t.Fatalf("this shouldnt happen") - } - } - if err != nil { - t.Fatalf("could not list files at: %v", files) - } - } -} - -// testDefaultPathAll tests swarm recursive upload with relative and absolute -// default paths and with encryption. -func testDefaultPathAll(t *testing.T, cluster *testCluster) { - testDefaultPath(t, cluster, false, false) - testDefaultPath(t, cluster, false, true) - testDefaultPath(t, cluster, true, false) - testDefaultPath(t, cluster, true, true) -} - -func testDefaultPath(t *testing.T, cluster *testCluster, toEncrypt bool, absDefaultPath bool) { - tmp, err := ioutil.TempDir("", "swarm-defaultpath-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmp) - - err = ioutil.WriteFile(filepath.Join(tmp, "index.html"), []byte("

Test

"), 0666) - if err != nil { - t.Fatal(err) - } - err = ioutil.WriteFile(filepath.Join(tmp, "robots.txt"), []byte("Disallow: /"), 0666) - if err != nil { - t.Fatal(err) - } - - defaultPath := "index.html" - if absDefaultPath { - defaultPath = filepath.Join(tmp, defaultPath) - } - - args := []string{ - "--bzzapi", - cluster.Nodes[0].URL, - "--recursive", - "--defaultpath", - defaultPath, - "up", - tmp, - } - if toEncrypt { - args = append(args, "--encrypt") - } - - up := runSwarm(t, args...) - hashRegexp := `[a-f\d]{64,128}` - _, matches := up.ExpectRegexp(hashRegexp) - up.ExpectExit() - hash := matches[0] - - client := swarmapi.NewClient(cluster.Nodes[0].URL) - - m, isEncrypted, err := client.DownloadManifest(hash) - if err != nil { - t.Fatal(err) - } - - if toEncrypt != isEncrypted { - t.Error("downloaded manifest is not encrypted") - } - - var found bool - var entriesCount int - for _, e := range m.Entries { - entriesCount++ - if e.Path == "" { - found = true - } - } - - if !found { - t.Error("manifest default entry was not found") - } - - if entriesCount != 3 { - t.Errorf("manifest contains %v entries, expected %v", entriesCount, 3) - } -} diff --git a/contracts/chequebook/api.go b/contracts/chequebook/api.go deleted file mode 100644 index fb7080308b..0000000000 --- a/contracts/chequebook/api.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chequebook - -import ( - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -const Version = "1.0" - -var errNoChequebook = errors.New("no chequebook") - -type API struct { - chequebookf func() *Chequebook -} - -func NewAPI(ch func() *Chequebook) *API { - return &API{ch} -} - -func (a *API) Balance() (string, error) { - ch := a.chequebookf() - if ch == nil { - return "", errNoChequebook - } - return ch.Balance().String(), nil -} - -func (a *API) Issue(beneficiary common.Address, amount *big.Int) (cheque *Cheque, err error) { - ch := a.chequebookf() - if ch == nil { - return nil, errNoChequebook - } - return ch.Issue(beneficiary, amount) -} - -func (a *API) Cash(cheque *Cheque) (txhash string, err error) { - ch := a.chequebookf() - if ch == nil { - return "", errNoChequebook - } - return ch.Cash(cheque) -} - -func (a *API) Deposit(amount *big.Int) (txhash string, err error) { - ch := a.chequebookf() - if ch == nil { - return "", errNoChequebook - } - return ch.Deposit(amount) -} diff --git a/contracts/chequebook/cheque.go b/contracts/chequebook/cheque.go deleted file mode 100644 index 32e8406768..0000000000 --- a/contracts/chequebook/cheque.go +++ /dev/null @@ -1,642 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package chequebook package wraps the 'chequebook' Ethereum smart contract. -// -// The functions in this package allow using chequebook for -// issuing, receiving, verifying cheques in ether; (auto)cashing cheques in ether -// as well as (auto)depositing ether to the chequebook contract. -package chequebook - -//go:generate abigen --sol contract/chequebook.sol --exc contract/mortal.sol:mortal,contract/owned.sol:owned --pkg contract --out contract/chequebook.go -//go:generate go run ./gencode.go - -import ( - "bytes" - "context" - "crypto/ecdsa" - "encoding/json" - "fmt" - "io/ioutil" - "math/big" - "os" - "sync" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/contracts/chequebook/contract" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/services/swap/swap" -) - -// TODO(zelig): watch peer solvency and notify of bouncing cheques -// TODO(zelig): enable paying with cheque by signing off - -// Some functionality requires interacting with the blockchain: -// * setting current balance on peer's chequebook -// * sending the transaction to cash the cheque -// * depositing ether to the chequebook -// * watching incoming ether - -var ( - gasToCash = uint64(2000000) // gas cost of a cash transaction using chequebook - // gasToDeploy = uint64(3000000) -) - -// Backend wraps all methods required for chequebook operation. -type Backend interface { - bind.ContractBackend - TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - BalanceAt(ctx context.Context, address common.Address, blockNum *big.Int) (*big.Int, error) -} - -// Cheque represents a payment promise to a single beneficiary. -type Cheque struct { - Contract common.Address // address of chequebook, needed to avoid cross-contract submission - Beneficiary common.Address - Amount *big.Int // cumulative amount of all funds sent - Sig []byte // signature Sign(Keccak256(contract, beneficiary, amount), prvKey) -} - -func (ch *Cheque) String() string { - return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", ch.Contract.Hex(), ch.Beneficiary.Hex(), ch.Amount, ch.Sig) -} - -type Params struct { - ContractCode, ContractAbi string -} - -var ContractParams = &Params{contract.ChequebookBin, contract.ChequebookABI} - -// Chequebook can create and sign cheques from a single contract to multiple beneficiaries. -// It is the outgoing payment handler for peer to peer micropayments. -type Chequebook struct { - path string // path to chequebook file - prvKey *ecdsa.PrivateKey // private key to sign cheque with - lock sync.Mutex // - backend Backend // blockchain API - quit chan bool // when closed causes autodeposit to stop - owner common.Address // owner address (derived from pubkey) - contract *contract.Chequebook // abigen binding - session *contract.ChequebookSession // abigen binding with Tx Opts - - // persisted fields - balance *big.Int // not synced with blockchain - contractAddr common.Address // contract address - sent map[common.Address]*big.Int //tallies for beneficiaries - - txhash string // tx hash of last deposit tx - threshold *big.Int // threshold that triggers autodeposit if not nil - buffer *big.Int // buffer to keep on top of balance for fork protection - - log log.Logger // contextual logger with the contract address embedded -} - -func (cb *Chequebook) String() string { - return fmt.Sprintf("contract: %s, owner: %s, balance: %v, signer: %x", cb.contractAddr.Hex(), cb.owner.Hex(), cb.balance, cb.prvKey.PublicKey) -} - -// NewChequebook creates a new Chequebook. -func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (*Chequebook, error) { - balance := new(big.Int) - sent := make(map[common.Address]*big.Int) - - chbook, err := contract.NewChequebook(contractAddr, backend) - if err != nil { - return nil, err - } - transactOpts := bind.NewKeyedTransactor(prvKey) - session := &contract.ChequebookSession{ - Contract: chbook, - TransactOpts: *transactOpts, - } - - cb := &Chequebook{ - prvKey: prvKey, - balance: balance, - contractAddr: contractAddr, - sent: sent, - path: path, - backend: backend, - owner: transactOpts.From, - contract: chbook, - session: session, - log: log.New("contract", contractAddr), - } - if (contractAddr != common.Address{}) { - cb.setBalanceFromBlockChain() - cb.log.Trace("New chequebook initialised", "owner", cb.owner, "balance", cb.balance) - } - return cb, nil -} - -func (cb *Chequebook) setBalanceFromBlockChain() { - balance, err := cb.backend.BalanceAt(context.TODO(), cb.contractAddr, nil) - if err != nil { - log.Error("Failed to retrieve chequebook balance", "err", err) - } else { - cb.balance.Set(balance) - } -} - -// LoadChequebook loads a chequebook from disk (file path). -func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, checkBalance bool) (*Chequebook, error) { - data, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - cb, _ := NewChequebook(path, common.Address{}, prvKey, backend) - - if err = json.Unmarshal(data, cb); err != nil { - return nil, err - } - if checkBalance { - cb.setBalanceFromBlockChain() - } - log.Trace("Loaded chequebook from disk", "path", path) - - return cb, nil -} - -// chequebookFile is the JSON representation of a chequebook. -type chequebookFile struct { - Balance string - Contract string - Owner string - Sent map[string]string -} - -// UnmarshalJSON deserialises a chequebook. -func (cb *Chequebook) UnmarshalJSON(data []byte) error { - var file chequebookFile - err := json.Unmarshal(data, &file) - if err != nil { - return err - } - _, ok := cb.balance.SetString(file.Balance, 10) - if !ok { - return fmt.Errorf("cumulative amount sent: unable to convert string to big integer: %v", file.Balance) - } - cb.contractAddr = common.HexToAddress(file.Contract) - for addr, sent := range file.Sent { - cb.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10) - if !ok { - return fmt.Errorf("beneficiary %v cumulative amount sent: unable to convert string to big integer: %v", addr, sent) - } - } - return nil -} - -// MarshalJSON serialises a chequebook. -func (cb *Chequebook) MarshalJSON() ([]byte, error) { - var file = &chequebookFile{ - Balance: cb.balance.String(), - Contract: cb.contractAddr.Hex(), - Owner: cb.owner.Hex(), - Sent: make(map[string]string), - } - for addr, sent := range cb.sent { - file.Sent[addr.Hex()] = sent.String() - } - return json.Marshal(file) -} - -// Save persists the chequebook on disk, remembering balance, contract address and -// cumulative amount of funds sent for each beneficiary. -func (cb *Chequebook) Save() error { - data, err := json.MarshalIndent(cb, "", " ") - if err != nil { - return err - } - cb.log.Trace("Saving chequebook to disk", cb.path) - - return ioutil.WriteFile(cb.path, data, os.ModePerm) -} - -// Stop quits the autodeposit go routine to terminate -func (cb *Chequebook) Stop() { - defer cb.lock.Unlock() - cb.lock.Lock() - if cb.quit != nil { - close(cb.quit) - cb.quit = nil - } -} - -// Issue creates a cheque signed by the chequebook owner's private key. The -// signer commits to a contract (one that they own), a beneficiary and amount. -func (cb *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (*Cheque, error) { - defer cb.lock.Unlock() - cb.lock.Lock() - - if amount.Sign() <= 0 { - return nil, fmt.Errorf("amount must be greater than zero (%v)", amount) - } - var ( - ch *Cheque - err error - ) - if cb.balance.Cmp(amount) < 0 { - err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, cb.balance) - } else { - var sig []byte - sent, found := cb.sent[beneficiary] - if !found { - sent = new(big.Int) - cb.sent[beneficiary] = sent - } - sum := new(big.Int).Set(sent) - sum.Add(sum, amount) - - sig, err = crypto.Sign(sigHash(cb.contractAddr, beneficiary, sum), cb.prvKey) - if err == nil { - ch = &Cheque{ - Contract: cb.contractAddr, - Beneficiary: beneficiary, - Amount: sum, - Sig: sig, - } - sent.Set(sum) - cb.balance.Sub(cb.balance, amount) // subtract amount from balance - } - } - // auto deposit if threshold is set and balance is less then threshold - // note this is called even if issuing cheque fails - // so we reattempt depositing - if cb.threshold != nil { - if cb.balance.Cmp(cb.threshold) < 0 { - send := new(big.Int).Sub(cb.buffer, cb.balance) - cb.deposit(send) - } - } - return ch, err -} - -// Cash is a convenience method to cash any cheque. -func (cb *Chequebook) Cash(ch *Cheque) (string, error) { - return ch.Cash(cb.session) -} - -// data to sign: contract address, beneficiary, cumulative amount of funds ever sent -func sigHash(contract, beneficiary common.Address, sum *big.Int) []byte { - bigamount := sum.Bytes() - if len(bigamount) > 32 { - return nil - } - var amount32 [32]byte - copy(amount32[32-len(bigamount):32], bigamount) - input := append(contract.Bytes(), beneficiary.Bytes()...) - input = append(input, amount32[:]...) - return crypto.Keccak256(input) -} - -// Balance returns the current balance of the chequebook. -func (cb *Chequebook) Balance() *big.Int { - defer cb.lock.Unlock() - cb.lock.Lock() - return new(big.Int).Set(cb.balance) -} - -// Owner returns the owner account of the chequebook. -func (cb *Chequebook) Owner() common.Address { - return cb.owner -} - -// Address returns the on-chain contract address of the chequebook. -func (cb *Chequebook) Address() common.Address { - return cb.contractAddr -} - -// Deposit deposits money to the chequebook account. -func (cb *Chequebook) Deposit(amount *big.Int) (string, error) { - defer cb.lock.Unlock() - cb.lock.Lock() - return cb.deposit(amount) -} - -// deposit deposits amount to the chequebook account. -// The caller must hold lock. -func (cb *Chequebook) deposit(amount *big.Int) (string, error) { - // since the amount is variable here, we do not use sessions - depositTransactor := bind.NewKeyedTransactor(cb.prvKey) - depositTransactor.Value = amount - chbookRaw := &contract.ChequebookRaw{Contract: cb.contract} - tx, err := chbookRaw.Transfer(depositTransactor) - if err != nil { - cb.log.Warn("Failed to fund chequebook", "amount", amount, "balance", cb.balance, "target", cb.buffer, "err", err) - return "", err - } - // assume that transaction is actually successful, we add the amount to balance right away - cb.balance.Add(cb.balance, amount) - cb.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", cb.balance, "target", cb.buffer) - return tx.Hash().Hex(), nil -} - -// AutoDeposit (re)sets interval time and amount which triggers sending funds to the -// chequebook. Contract backend needs to be set if threshold is not less than buffer, then -// deposit will be triggered on every new cheque issued. -func (cb *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - defer cb.lock.Unlock() - cb.lock.Lock() - cb.threshold = threshold - cb.buffer = buffer - cb.autoDeposit(interval) -} - -// autoDeposit starts a goroutine that periodically sends funds to the chequebook -// contract caller holds the lock the go routine terminates if Chequebook.quit is closed. -func (cb *Chequebook) autoDeposit(interval time.Duration) { - if cb.quit != nil { - close(cb.quit) - cb.quit = nil - } - // if threshold >= balance autodeposit after every cheque issued - if interval == time.Duration(0) || cb.threshold != nil && cb.buffer != nil && cb.threshold.Cmp(cb.buffer) >= 0 { - return - } - - ticker := time.NewTicker(interval) - cb.quit = make(chan bool) - quit := cb.quit - - go func() { - for { - select { - case <-quit: - return - case <-ticker.C: - cb.lock.Lock() - if cb.balance.Cmp(cb.buffer) < 0 { - amount := new(big.Int).Sub(cb.buffer, cb.balance) - txhash, err := cb.deposit(amount) - if err == nil { - cb.txhash = txhash - } - } - cb.lock.Unlock() - } - } - }() -} - -// Outbox can issue cheques from a single contract to a single beneficiary. -type Outbox struct { - chequeBook *Chequebook - beneficiary common.Address -} - -// NewOutbox creates an outbox. -func NewOutbox(cb *Chequebook, beneficiary common.Address) *Outbox { - return &Outbox{cb, beneficiary} -} - -// Issue creates cheque. -func (o *Outbox) Issue(amount *big.Int) (swap.Promise, error) { - return o.chequeBook.Issue(o.beneficiary, amount) -} - -// AutoDeposit enables auto-deposits on the underlying chequebook. -func (o *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - o.chequeBook.AutoDeposit(interval, threshold, buffer) -} - -// Stop helps satisfy the swap.OutPayment interface. -func (o *Outbox) Stop() {} - -// String implements fmt.Stringer. -func (o *Outbox) String() string { - return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", o.chequeBook.Address().Hex(), o.beneficiary.Hex(), o.chequeBook.Balance()) -} - -// Inbox can deposit, verify and cash cheques from a single contract to a single -// beneficiary. It is the incoming payment handler for peer to peer micropayments. -type Inbox struct { - lock sync.Mutex - contract common.Address // peer's chequebook contract - beneficiary common.Address // local peer's receiving address - sender common.Address // local peer's address to send cashing tx from - signer *ecdsa.PublicKey // peer's public key - txhash string // tx hash of last cashing tx - session *contract.ChequebookSession // abi contract backend with tx opts - quit chan bool // when closed causes autocash to stop - maxUncashed *big.Int // threshold that triggers autocashing - cashed *big.Int // cumulative amount cashed - cheque *Cheque // last cheque, nil if none yet received - log log.Logger // contextual logger with the contract address embedded -} - -// NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated -// from blockchain when first cheque is received. -func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address, signer *ecdsa.PublicKey, abigen bind.ContractBackend) (*Inbox, error) { - if signer == nil { - return nil, fmt.Errorf("signer is null") - } - chbook, err := contract.NewChequebook(contractAddr, abigen) - if err != nil { - return nil, err - } - transactOpts := bind.NewKeyedTransactor(prvKey) - transactOpts.GasLimit = gasToCash - session := &contract.ChequebookSession{ - Contract: chbook, - TransactOpts: *transactOpts, - } - sender := transactOpts.From - - inbox := &Inbox{ - contract: contractAddr, - beneficiary: beneficiary, - sender: sender, - signer: signer, - session: session, - cashed: new(big.Int).Set(common.Big0), - log: log.New("contract", contractAddr), - } - inbox.log.Trace("New chequebook inbox initialized", "beneficiary", inbox.beneficiary, "signer", hexutil.Bytes(crypto.FromECDSAPub(signer))) - return inbox, nil -} - -func (i *Inbox) String() string { - return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", i.contract.Hex(), i.beneficiary.Hex(), i.cheque.Amount) -} - -// Stop quits the autocash goroutine. -func (i *Inbox) Stop() { - defer i.lock.Unlock() - i.lock.Lock() - if i.quit != nil { - close(i.quit) - i.quit = nil - } -} - -// Cash attempts to cash the current cheque. -func (i *Inbox) Cash() (string, error) { - if i.cheque == nil { - return "", nil - } - txhash, err := i.cheque.Cash(i.session) - i.log.Trace("Cashing in chequebook cheque", "amount", i.cheque.Amount, "beneficiary", i.beneficiary) - i.cashed = i.cheque.Amount - - return txhash, err -} - -// AutoCash (re)sets maximum time and amount which triggers cashing of the last uncashed -// cheque if maxUncashed is set to 0, then autocash on receipt. -func (i *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) { - defer i.lock.Unlock() - i.lock.Lock() - i.maxUncashed = maxUncashed - i.autoCash(cashInterval) -} - -// autoCash starts a loop that periodically clears the last cheque -// if the peer is trusted. Clearing period could be 24h or a week. -// The caller must hold lock. -func (i *Inbox) autoCash(cashInterval time.Duration) { - if i.quit != nil { - close(i.quit) - i.quit = nil - } - // if maxUncashed is set to 0, then autocash on receipt - if cashInterval == time.Duration(0) || i.maxUncashed != nil && i.maxUncashed.Sign() == 0 { - return - } - - ticker := time.NewTicker(cashInterval) - i.quit = make(chan bool) - quit := i.quit - - go func() { - for { - select { - case <-quit: - return - case <-ticker.C: - i.lock.Lock() - if i.cheque != nil && i.cheque.Amount.Cmp(i.cashed) != 0 { - txhash, err := i.Cash() - if err == nil { - i.txhash = txhash - } - } - i.lock.Unlock() - } - } - }() -} - -// Receive is called to deposit the latest cheque to the incoming Inbox. -// The given promise must be a *Cheque. -func (i *Inbox) Receive(promise swap.Promise) (*big.Int, error) { - ch := promise.(*Cheque) - - defer i.lock.Unlock() - i.lock.Lock() - - var sum *big.Int - if i.cheque == nil { - // the sum is checked against the blockchain once a cheque is received - tally, err := i.session.Sent(i.beneficiary) - if err != nil { - return nil, fmt.Errorf("inbox: error calling backend to set amount: %v", err) - } - sum = tally - } else { - sum = i.cheque.Amount - } - - amount, err := ch.Verify(i.signer, i.contract, i.beneficiary, sum) - var uncashed *big.Int - if err == nil { - i.cheque = ch - - if i.maxUncashed != nil { - uncashed = new(big.Int).Sub(ch.Amount, i.cashed) - if i.maxUncashed.Cmp(uncashed) < 0 { - i.Cash() - } - } - i.log.Trace("Received cheque in chequebook inbox", "amount", amount, "uncashed", uncashed) - } - - return amount, err -} - -// Verify verifies cheque for signer, contract, beneficiary, amount, valid signature. -func (ch *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) { - log.Trace("Verifying chequebook cheque", "cheque", ch, "sum", sum) - if sum == nil { - return nil, fmt.Errorf("invalid amount") - } - - if ch.Beneficiary != beneficiary { - return nil, fmt.Errorf("beneficiary mismatch: %v != %v", ch.Beneficiary.Hex(), beneficiary.Hex()) - } - if ch.Contract != contract { - return nil, fmt.Errorf("contract mismatch: %v != %v", ch.Contract.Hex(), contract.Hex()) - } - - amount := new(big.Int).Set(ch.Amount) - if sum != nil { - amount.Sub(amount, sum) - if amount.Sign() <= 0 { - return nil, fmt.Errorf("incorrect amount: %v <= 0", amount) - } - } - - pubKey, err := crypto.SigToPub(sigHash(ch.Contract, beneficiary, ch.Amount), ch.Sig) - if err != nil { - return nil, fmt.Errorf("invalid signature: %v", err) - } - if !bytes.Equal(crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey)) { - return nil, fmt.Errorf("signer mismatch: %x != %x", crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey)) - } - return amount, nil -} - -// v/r/s representation of signature -func sig2vrs(sig []byte) (v byte, r, s [32]byte) { - v = sig[64] + 27 - copy(r[:], sig[:32]) - copy(s[:], sig[32:64]) - return -} - -// Cash cashes the cheque by sending an Ethereum transaction. -func (ch *Cheque) Cash(session *contract.ChequebookSession) (string, error) { - v, r, s := sig2vrs(ch.Sig) - tx, err := session.Cash(ch.Beneficiary, ch.Amount, v, r, s) - if err != nil { - return "", err - } - return tx.Hash().Hex(), nil -} - -// ValidateCode checks that the on-chain code at address matches the expected chequebook -// contract code. This is used to detect suicided chequebooks. -func ValidateCode(ctx context.Context, b Backend, address common.Address) (bool, error) { - code, err := b.CodeAt(ctx, address, nil) - if err != nil { - return false, err - } - return bytes.Equal(code, common.FromHex(contract.ContractDeployedCode)), nil -} diff --git a/contracts/chequebook/cheque_test.go b/contracts/chequebook/cheque_test.go deleted file mode 100644 index 4bd2e176b1..0000000000 --- a/contracts/chequebook/cheque_test.go +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chequebook - -import ( - "crypto/ecdsa" - "math/big" - "os" - "path/filepath" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/chequebook/contract" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/crypto" -) - -var ( - key0, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - key1, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") - key2, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") - addr0 = crypto.PubkeyToAddress(key0.PublicKey) - addr1 = crypto.PubkeyToAddress(key1.PublicKey) - addr2 = crypto.PubkeyToAddress(key2.PublicKey) -) - -func newTestBackend() *backends.SimulatedBackend { - return backends.NewSimulatedBackend(core.GenesisAlloc{ - addr0: {Balance: big.NewInt(1000000000)}, - addr1: {Balance: big.NewInt(1000000000)}, - addr2: {Balance: big.NewInt(1000000000)}, - }, 10000000) -} - -func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) { - deployTransactor := bind.NewKeyedTransactor(prvKey) - deployTransactor.Value = amount - addr, _, _, err := contract.DeployChequebook(deployTransactor, backend) - if err != nil { - return common.Address{}, err - } - backend.Commit() - return addr, nil -} - -func TestIssueAndReceive(t *testing.T) { - path := filepath.Join(os.TempDir(), "chequebook-test.json") - backend := newTestBackend() - addr0, err := deploy(key0, big.NewInt(0), backend) - if err != nil { - t.Fatalf("deploy contract: expected no error, got %v", err) - } - chbook, err := NewChequebook(path, addr0, key0, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - chbook.sent[addr1] = new(big.Int).SetUint64(42) - amount := common.Big1 - - if _, err = chbook.Issue(addr1, amount); err == nil { - t.Fatalf("expected insufficient funds error, got none") - } - - chbook.balance = new(big.Int).Set(common.Big1) - if chbook.Balance().Cmp(common.Big1) != 0 { - t.Fatalf("expected: %v, got %v", "0", chbook.Balance()) - } - - ch, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if chbook.Balance().Sign() != 0 { - t.Errorf("expected: %v, got %v", "0", chbook.Balance()) - } - - chbox, err := NewInbox(key1, addr0, addr1, &key0.PublicKey, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - received, err := chbox.Receive(ch) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if received.Cmp(big.NewInt(43)) != 0 { - t.Errorf("expected: %v, got %v", "43", received) - } - -} - -func TestCheckbookFile(t *testing.T) { - path := filepath.Join(os.TempDir(), "chequebook-test.json") - backend := newTestBackend() - chbook, err := NewChequebook(path, addr0, key0, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - chbook.sent[addr1] = new(big.Int).SetUint64(42) - chbook.balance = new(big.Int).Set(common.Big1) - - chbook.Save() - - chbook, err = LoadChequebook(path, key0, backend, false) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if chbook.Balance().Cmp(common.Big1) != 0 { - t.Errorf("expected: %v, got %v", "0", chbook.Balance()) - } - - var ch *Cheque - if ch, err = chbook.Issue(addr1, common.Big1); err != nil { - t.Fatalf("expected no error, got %v", err) - } - if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 { - t.Errorf("expected: %v, got %v", "0", ch.Amount) - } - - err = chbook.Save() - if err != nil { - t.Fatalf("expected no error, got %v", err) - } -} - -func TestVerifyErrors(t *testing.T) { - path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json") - backend := newTestBackend() - contr0, err := deploy(key0, common.Big2, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - chbook0, err := NewChequebook(path0, contr0, key0, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json") - contr1, _ := deploy(key1, common.Big2, backend) - chbook1, err := NewChequebook(path1, contr1, key1, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - chbook0.sent[addr1] = new(big.Int).SetUint64(42) - chbook0.balance = new(big.Int).Set(common.Big2) - chbook1.balance = new(big.Int).Set(common.Big1) - amount := common.Big1 - ch0, err := chbook0.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - received, err := chbox.Receive(ch0) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if received.Cmp(big.NewInt(43)) != 0 { - t.Errorf("expected: %v, got %v", "43", received) - } - - ch1, err := chbook0.Issue(addr2, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - received, err = chbox.Receive(ch1) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected receiver error, got none and value %v", received) - } - - ch2, err := chbook1.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - received, err = chbox.Receive(ch2) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected sender error, got none and value %v", received) - } - - _, err = chbook1.Issue(addr1, new(big.Int).SetInt64(-1)) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected incorrect amount error, got none") - } - - received, err = chbox.Receive(ch0) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected incorrect amount error, got none and value %v", received) - } - -} - -func TestDeposit(t *testing.T) { - path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json") - backend := newTestBackend() - contr0, _ := deploy(key0, new(big.Int), backend) - - chbook, err := NewChequebook(path0, contr0, key0, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - balance := new(big.Int).SetUint64(42) - chbook.Deposit(balance) - backend.Commit() - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - amount := common.Big1 - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - exp := new(big.Int).SetUint64(41) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - // autodeposit on each issue - chbook.AutoDeposit(0, balance, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - // autodeposit off - chbook.AutoDeposit(0, common.Big0, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - exp = new(big.Int).SetUint64(40) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - // autodeposit every 200ms if new cheque issued - interval := 200 * time.Millisecond - chbook.AutoDeposit(interval, common.Big1, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - exp = new(big.Int).SetUint64(38) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - time.Sleep(3 * interval) - backend.Commit() - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - exp = new(big.Int).SetUint64(40) - chbook.AutoDeposit(4*interval, exp, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - time.Sleep(3 * interval) - backend.Commit() - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - time.Sleep(1 * interval) - backend.Commit() - - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - chbook.AutoDeposit(1*interval, common.Big0, balance) - chbook.Stop() - - _, err = chbook.Issue(addr1, common.Big1) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - _, err = chbook.Issue(addr1, common.Big2) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - time.Sleep(1 * interval) - backend.Commit() - - exp = new(big.Int).SetUint64(39) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - -} - -func TestCash(t *testing.T) { - path := filepath.Join(os.TempDir(), "chequebook-test.json") - backend := newTestBackend() - contr0, _ := deploy(key0, common.Big2, backend) - - chbook, err := NewChequebook(path, contr0, key0, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - chbook.sent[addr1] = new(big.Int).SetUint64(42) - amount := common.Big1 - chbook.balance = new(big.Int).Set(common.Big1) - ch, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - // cashing latest cheque - if _, err = chbox.Receive(ch); err != nil { - t.Fatalf("expected no error, got %v", err) - } - if _, err = ch.Cash(chbook.session); err != nil { - t.Fatal("Cash failed:", err) - } - backend.Commit() - - chbook.balance = new(big.Int).Set(common.Big3) - ch0, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - ch1, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - interval := 10 * time.Millisecond - // setting autocash with interval of 10ms - chbox.AutoCash(interval, nil) - _, err = chbox.Receive(ch0) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - _, err = chbox.Receive(ch1) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - // after 3x interval time and 2 cheques received, exactly one cashing tx is sent - time.Sleep(4 * interval) - backend.Commit() - - // after stopping autocash no more tx are sent - ch2, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - chbox.Stop() - _, err = chbox.Receive(ch2) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - time.Sleep(2 * interval) - backend.Commit() - - // autocash below 1 - chbook.balance = big.NewInt(2) - chbox.AutoCash(0, common.Big1) - - ch3, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - ch4, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - _, err = chbox.Receive(ch3) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbox.Receive(ch4) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - // autochash on receipt when maxUncashed is 0 - chbook.balance = new(big.Int).Set(common.Big2) - chbox.AutoCash(0, common.Big0) - - ch5, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - ch6, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - _, err = chbox.Receive(ch5) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - _, err = chbox.Receive(ch6) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - -} diff --git a/contracts/chequebook/contract/chequebook.go b/contracts/chequebook/contract/chequebook.go deleted file mode 100644 index 3129b811c6..0000000000 --- a/contracts/chequebook/contract/chequebook.go +++ /dev/null @@ -1,367 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contract - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// ChequebookABI is the input ABI used to generate the binding from. -const ChequebookABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"kill\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"sent\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"beneficiary\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"sig_v\",\"type\":\"uint8\"},{\"name\":\"sig_r\",\"type\":\"bytes32\"},{\"name\":\"sig_s\",\"type\":\"bytes32\"}],\"name\":\"cash\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"deadbeat\",\"type\":\"address\"}],\"name\":\"Overdraft\",\"type\":\"event\"}]" - -// ChequebookBin is the compiled bytecode used for deploying new contracts. -const ChequebookBin = `0x606060405260008054600160a060020a033316600160a060020a03199091161790556102ec806100306000396000f3006060604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166341c0e1b581146100585780637bf786f81461006b578063fbf788d61461009c575b005b341561006357600080fd5b6100566100ca565b341561007657600080fd5b61008a600160a060020a03600435166100f1565b60405190815260200160405180910390f35b34156100a757600080fd5b610056600160a060020a036004351660243560ff60443516606435608435610103565b60005433600160a060020a03908116911614156100ef57600054600160a060020a0316ff5b565b60016020526000908152604090205481565b600160a060020a0385166000908152600160205260408120548190861161012957600080fd5b3087876040516c01000000000000000000000000600160a060020a03948516810282529290931690910260148301526028820152604801604051809103902091506001828686866040516000815260200160405260006040516020015260405193845260ff90921660208085019190915260408085019290925260608401929092526080909201915160208103908084039060008661646e5a03f115156101cf57600080fd5b505060206040510351600054600160a060020a039081169116146101f257600080fd5b50600160a060020a03808716600090815260016020526040902054860390301631811161026257600160a060020a0387166000818152600160205260409081902088905582156108fc0290839051600060405180830381858888f19350505050151561025d57600080fd5b6102b7565b6000547f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f97890600160a060020a0316604051600160a060020a03909116815260200160405180910390a186600160a060020a0316ff5b505050505050505600a165627a7a72305820533e856fc37e3d64d1706bcc7dfb6b1d490c8d566ea498d9d01ec08965a896ca0029` - -// DeployChequebook deploys a new Ethereum contract, binding an instance of Chequebook to it. -func DeployChequebook(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Chequebook, error) { - parsed, err := abi.JSON(strings.NewReader(ChequebookABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ChequebookBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &Chequebook{ChequebookCaller: ChequebookCaller{contract: contract}, ChequebookTransactor: ChequebookTransactor{contract: contract}, ChequebookFilterer: ChequebookFilterer{contract: contract}}, nil -} - -// Chequebook is an auto generated Go binding around an Ethereum contract. -type Chequebook struct { - ChequebookCaller // Read-only binding to the contract - ChequebookTransactor // Write-only binding to the contract - ChequebookFilterer // Log filterer for contract events -} - -// ChequebookCaller is an auto generated read-only Go binding around an Ethereum contract. -type ChequebookCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ChequebookTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ChequebookTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ChequebookFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ChequebookFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ChequebookSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ChequebookSession struct { - Contract *Chequebook // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ChequebookCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ChequebookCallerSession struct { - Contract *ChequebookCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ChequebookTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ChequebookTransactorSession struct { - Contract *ChequebookTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ChequebookRaw is an auto generated low-level Go binding around an Ethereum contract. -type ChequebookRaw struct { - Contract *Chequebook // Generic contract binding to access the raw methods on -} - -// ChequebookCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ChequebookCallerRaw struct { - Contract *ChequebookCaller // Generic read-only contract binding to access the raw methods on -} - -// ChequebookTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ChequebookTransactorRaw struct { - Contract *ChequebookTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewChequebook creates a new instance of Chequebook, bound to a specific deployed contract. -func NewChequebook(address common.Address, backend bind.ContractBackend) (*Chequebook, error) { - contract, err := bindChequebook(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Chequebook{ChequebookCaller: ChequebookCaller{contract: contract}, ChequebookTransactor: ChequebookTransactor{contract: contract}, ChequebookFilterer: ChequebookFilterer{contract: contract}}, nil -} - -// NewChequebookCaller creates a new read-only instance of Chequebook, bound to a specific deployed contract. -func NewChequebookCaller(address common.Address, caller bind.ContractCaller) (*ChequebookCaller, error) { - contract, err := bindChequebook(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ChequebookCaller{contract: contract}, nil -} - -// NewChequebookTransactor creates a new write-only instance of Chequebook, bound to a specific deployed contract. -func NewChequebookTransactor(address common.Address, transactor bind.ContractTransactor) (*ChequebookTransactor, error) { - contract, err := bindChequebook(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ChequebookTransactor{contract: contract}, nil -} - -// NewChequebookFilterer creates a new log filterer instance of Chequebook, bound to a specific deployed contract. -func NewChequebookFilterer(address common.Address, filterer bind.ContractFilterer) (*ChequebookFilterer, error) { - contract, err := bindChequebook(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ChequebookFilterer{contract: contract}, nil -} - -// bindChequebook binds a generic wrapper to an already deployed contract. -func bindChequebook(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(ChequebookABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Chequebook *ChequebookRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Chequebook.Contract.ChequebookCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Chequebook *ChequebookRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Chequebook.Contract.ChequebookTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Chequebook *ChequebookRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Chequebook.Contract.ChequebookTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Chequebook *ChequebookCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Chequebook.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Chequebook *ChequebookTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Chequebook.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Chequebook *ChequebookTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Chequebook.Contract.contract.Transact(opts, method, params...) -} - -// Sent is a free data retrieval call binding the contract method 0x7bf786f8. -// -// Solidity: function sent( address) constant returns(uint256) -func (_Chequebook *ChequebookCaller) Sent(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _Chequebook.contract.Call(opts, out, "sent", arg0) - return *ret0, err -} - -// Sent is a free data retrieval call binding the contract method 0x7bf786f8. -// -// Solidity: function sent( address) constant returns(uint256) -func (_Chequebook *ChequebookSession) Sent(arg0 common.Address) (*big.Int, error) { - return _Chequebook.Contract.Sent(&_Chequebook.CallOpts, arg0) -} - -// Sent is a free data retrieval call binding the contract method 0x7bf786f8. -// -// Solidity: function sent( address) constant returns(uint256) -func (_Chequebook *ChequebookCallerSession) Sent(arg0 common.Address) (*big.Int, error) { - return _Chequebook.Contract.Sent(&_Chequebook.CallOpts, arg0) -} - -// Cash is a paid mutator transaction binding the contract method 0xfbf788d6. -// -// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookTransactor) Cash(opts *bind.TransactOpts, beneficiary common.Address, amount *big.Int, sigV uint8, sigR [32]byte, sigS [32]byte) (*types.Transaction, error) { - return _Chequebook.contract.Transact(opts, "cash", beneficiary, amount, sigV, sigR, sigS) -} - -// Cash is a paid mutator transaction binding the contract method 0xfbf788d6. -// -// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookSession) Cash(beneficiary common.Address, amount *big.Int, sigV uint8, sigR [32]byte, sigS [32]byte) (*types.Transaction, error) { - return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sigV, sigR, sigS) -} - -// Cash is a paid mutator transaction binding the contract method 0xfbf788d6. -// -// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookTransactorSession) Cash(beneficiary common.Address, amount *big.Int, sigV uint8, sigR [32]byte, sigS [32]byte) (*types.Transaction, error) { - return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sigV, sigR, sigS) -} - -// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. -// -// Solidity: function kill() returns() -func (_Chequebook *ChequebookTransactor) Kill(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Chequebook.contract.Transact(opts, "kill") -} - -// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. -// -// Solidity: function kill() returns() -func (_Chequebook *ChequebookSession) Kill() (*types.Transaction, error) { - return _Chequebook.Contract.Kill(&_Chequebook.TransactOpts) -} - -// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. -// -// Solidity: function kill() returns() -func (_Chequebook *ChequebookTransactorSession) Kill() (*types.Transaction, error) { - return _Chequebook.Contract.Kill(&_Chequebook.TransactOpts) -} - -// ChequebookOverdraftIterator is returned from FilterOverdraft and is used to iterate over the raw logs and unpacked data for Overdraft events raised by the Chequebook contract. -type ChequebookOverdraftIterator struct { - Event *ChequebookOverdraft // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ChequebookOverdraftIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ChequebookOverdraft) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ChequebookOverdraft) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *ChequebookOverdraftIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ChequebookOverdraftIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ChequebookOverdraft represents a Overdraft event raised by the Chequebook contract. -type ChequebookOverdraft struct { - Deadbeat common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOverdraft is a free log retrieval operation binding the contract event 0x2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f978. -// -// Solidity: event Overdraft(deadbeat address) -func (_Chequebook *ChequebookFilterer) FilterOverdraft(opts *bind.FilterOpts) (*ChequebookOverdraftIterator, error) { - - logs, sub, err := _Chequebook.contract.FilterLogs(opts, "Overdraft") - if err != nil { - return nil, err - } - return &ChequebookOverdraftIterator{contract: _Chequebook.contract, event: "Overdraft", logs: logs, sub: sub}, nil -} - -// WatchOverdraft is a free log subscription operation binding the contract event 0x2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f978. -// -// Solidity: event Overdraft(deadbeat address) -func (_Chequebook *ChequebookFilterer) WatchOverdraft(opts *bind.WatchOpts, sink chan<- *ChequebookOverdraft) (event.Subscription, error) { - - logs, sub, err := _Chequebook.contract.WatchLogs(opts, "Overdraft") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ChequebookOverdraft) - if err := _Chequebook.contract.UnpackLog(event, "Overdraft", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/contracts/chequebook/contract/chequebook.sol b/contracts/chequebook/contract/chequebook.sol deleted file mode 100644 index c386cceed8..0000000000 --- a/contracts/chequebook/contract/chequebook.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity ^0.4.18; - -import "./mortal.sol"; - -/// @title Chequebook for Ethereum micropayments -/// @author Daniel A. Nagy -contract chequebook is mortal { - // Cumulative paid amount in wei to each beneficiary - mapping (address => uint256) public sent; - - /// @notice Overdraft event - event Overdraft(address deadbeat); - - // Allow sending ether to the chequebook. - function() public payable { } - - /// @notice Cash cheque - /// - /// @param beneficiary beneficiary address - /// @param amount cumulative amount in wei - /// @param sig_v signature parameter v - /// @param sig_r signature parameter r - /// @param sig_s signature parameter s - /// The digital signature is calculated on the concatenated triplet of contract address, beneficiary address and cumulative amount - function cash(address beneficiary, uint256 amount, uint8 sig_v, bytes32 sig_r, bytes32 sig_s) public { - // Check if the cheque is old. - // Only cheques that are more recent than the last cashed one are considered. - require(amount > sent[beneficiary]); - // Check the digital signature of the cheque. - bytes32 hash = keccak256(address(this), beneficiary, amount); - require(owner == ecrecover(hash, sig_v, sig_r, sig_s)); - // Attempt sending the difference between the cumulative amount on the cheque - // and the cumulative amount on the last cashed cheque to beneficiary. - uint256 diff = amount - sent[beneficiary]; - if (diff <= this.balance) { - // update the cumulative amount before sending - sent[beneficiary] = amount; - beneficiary.transfer(diff); - } else { - // Upon failure, punish owner for writing a bounced cheque. - // owner.sendToDebtorsPrison(); - Overdraft(owner); - // Compensate beneficiary. - selfdestruct(beneficiary); - } - } -} diff --git a/contracts/chequebook/contract/code.go b/contracts/chequebook/contract/code.go deleted file mode 100644 index d837a9d601..0000000000 --- a/contracts/chequebook/contract/code.go +++ /dev/null @@ -1,5 +0,0 @@ -package contract - -// ContractDeployedCode is used to detect suicides. This constant needs to be -// updated when the contract code is changed. -const ContractDeployedCode = "0x6060604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166341c0e1b581146100585780637bf786f81461006b578063fbf788d61461009c575b005b341561006357600080fd5b6100566100ca565b341561007657600080fd5b61008a600160a060020a03600435166100f1565b60405190815260200160405180910390f35b34156100a757600080fd5b610056600160a060020a036004351660243560ff60443516606435608435610103565b60005433600160a060020a03908116911614156100ef57600054600160a060020a0316ff5b565b60016020526000908152604090205481565b600160a060020a0385166000908152600160205260408120548190861161012957600080fd5b3087876040516c01000000000000000000000000600160a060020a03948516810282529290931690910260148301526028820152604801604051809103902091506001828686866040516000815260200160405260006040516020015260405193845260ff90921660208085019190915260408085019290925260608401929092526080909201915160208103908084039060008661646e5a03f115156101cf57600080fd5b505060206040510351600054600160a060020a039081169116146101f257600080fd5b50600160a060020a03808716600090815260016020526040902054860390301631811161026257600160a060020a0387166000818152600160205260409081902088905582156108fc0290839051600060405180830381858888f19350505050151561025d57600080fd5b6102b7565b6000547f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f97890600160a060020a0316604051600160a060020a03909116815260200160405180910390a186600160a060020a0316ff5b505050505050505600a165627a7a72305820533e856fc37e3d64d1706bcc7dfb6b1d490c8d566ea498d9d01ec08965a896ca0029" diff --git a/contracts/chequebook/contract/mortal.sol b/contracts/chequebook/contract/mortal.sol deleted file mode 100644 index c43f1e4f79..0000000000 --- a/contracts/chequebook/contract/mortal.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity ^0.4.0; - -import "./owned.sol"; - -contract mortal is owned { - function kill() public { - if (msg.sender == owner) - selfdestruct(owner); - } -} diff --git a/contracts/chequebook/contract/owned.sol b/contracts/chequebook/contract/owned.sol deleted file mode 100644 index ee9860d343..0000000000 --- a/contracts/chequebook/contract/owned.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.4.0; - -contract owned { - address owner; - - modifier onlyowner() { - if (msg.sender == owner) { - _; - } - } - - function owned() public { - owner = msg.sender; - } -} diff --git a/contracts/chequebook/gencode.go b/contracts/chequebook/gencode.go deleted file mode 100644 index ddfe8d1512..0000000000 --- a/contracts/chequebook/gencode.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build none - -// This program generates contract/code.go, which contains the chequebook code -// after deployment. -package main - -import ( - "fmt" - "io/ioutil" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/contracts/chequebook/contract" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/crypto" -) - -var ( - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAlloc = core.GenesisAlloc{ - crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(500000000000)}, - } -) - -func main() { - backend := backends.NewSimulatedBackend(testAlloc, uint64(100000000)) - auth := bind.NewKeyedTransactor(testKey) - - // Deploy the contract, get the code. - addr, _, _, err := contract.DeployChequebook(auth, backend) - if err != nil { - panic(err) - } - backend.Commit() - code, err := backend.CodeAt(nil, addr, nil) - if err != nil { - panic(err) - } - if len(code) == 0 { - panic("empty code") - } - - // Write the output file. - content := fmt.Sprintf(`package contract - -// ContractDeployedCode is used to detect suicides. This constant needs to be -// updated when the contract code is changed. -const ContractDeployedCode = "%#x" -`, code) - if err := ioutil.WriteFile("contract/code.go", []byte(content), 0644); err != nil { - panic(err) - } -} diff --git a/contracts/ens/README.md b/contracts/ens/README.md deleted file mode 100644 index f2ea1330c5..0000000000 --- a/contracts/ens/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Swarm ENS interface - -## Usage - -Full documentation for the Ethereum Name Service [can be found as EIP 137](https://github.com/ethereum/EIPs/issues/137). -This package offers a simple binding that streamlines the registration of arbitrary UTF8 domain names to swarm content hashes. - -## Development - -The SOL file in contract subdirectory implements the ENS root registry, a simple -first-in, first-served registrar for the root namespace, and a simple resolver contract; -they're used in tests, and can be used to deploy these contracts for your own purposes. - -The solidity source code can be found at [github.com/arachnid/ens/](https://github.com/arachnid/ens/). - -The go bindings for ENS contracts are generated using `abigen` via the go generator: - -```shell -go generate ./contracts/ens -``` - -## Fallback contract support - -In order to better support content resolution on different service providers (such as Swarm and IPFS), [EIP-1577](https://eips.ethereum.org/EIPS/eip-1577) -was introduced and with it changes that allow applications to know _where_ content hashes are stored (i.e. if the -requested hash resides on Swarm or IPFS). - -The code under `contracts/ens/contract` reflects the new Public Resolver changes and the code under `fallback_contract` allows -us to support the old contract resolution in cases where the ENS name owner did not update her Resolver contract, until the migration -period ends (date arbitrarily set to June 1st, 2019). diff --git a/contracts/ens/cid.go b/contracts/ens/cid.go deleted file mode 100644 index 673e8203e4..0000000000 --- a/contracts/ens/cid.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ens - -import ( - "encoding/binary" - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" -) - -const ( - cidv1 = 0x1 - - nsIpfs = 0xe3 - nsSwarm = 0xe4 - - swarmTypecode = 0xfa // swarm manifest, see https://github.com/multiformats/multicodec/blob/master/table.csv - swarmHashtype = 0x1b // keccak256, see https://github.com/multiformats/multicodec/blob/master/table.csv - - hashLength = 32 -) - -// deocodeEIP1577ContentHash decodes a chain-stored content hash from an ENS record according to EIP-1577 -// a successful decode will result the different parts of the content hash in accordance to the CID spec -// Note: only CIDv1 is supported -func decodeEIP1577ContentHash(buf []byte) (storageNs, contentType, hashType, hashLength uint64, hash []byte, err error) { - if len(buf) < 10 { - return 0, 0, 0, 0, nil, errors.New("buffer too short") - } - - storageNs, n := binary.Uvarint(buf) - - buf = buf[n:] - vers, n := binary.Uvarint(buf) - - if vers != 1 { - return 0, 0, 0, 0, nil, fmt.Errorf("expected cid v1, got: %d", vers) - } - buf = buf[n:] - contentType, n = binary.Uvarint(buf) - - buf = buf[n:] - hashType, n = binary.Uvarint(buf) - - buf = buf[n:] - hashLength, n = binary.Uvarint(buf) - - hash = buf[n:] - - if len(hash) != int(hashLength) { - return 0, 0, 0, 0, nil, errors.New("hash length mismatch") - } - return storageNs, contentType, hashType, hashLength, hash, nil -} - -func extractContentHash(buf []byte) (common.Hash, error) { - storageNs, _ /*contentType*/, _ /* hashType*/, decodedHashLength, hashBytes, err := decodeEIP1577ContentHash(buf) - - if err != nil { - return common.Hash{}, err - } - - if storageNs != nsSwarm { - return common.Hash{}, errors.New("unknown storage system") - } - - //todo: for the time being we implement loose enforcement for the EIP rules until ENS manager is updated - /*if contentType != swarmTypecode { - return common.Hash{}, errors.New("unknown content type") - } - - if hashType != swarmHashtype { - return common.Hash{}, errors.New("unknown multihash type") - }*/ - - if decodedHashLength != hashLength { - return common.Hash{}, errors.New("odd hash length, swarm expects 32 bytes") - } - - if len(hashBytes) != int(hashLength) { - return common.Hash{}, errors.New("hash length mismatch") - } - - return common.BytesToHash(buf), nil -} - -func EncodeSwarmHash(hash common.Hash) ([]byte, error) { - var cidBytes []byte - var headerBytes = []byte{ - nsSwarm, //swarm namespace - cidv1, // CIDv1 - swarmTypecode, // swarm hash - swarmHashtype, // keccak256 hash - hashLength, //hash length. 32 bytes - } - - varintbuf := make([]byte, binary.MaxVarintLen64) - for _, v := range headerBytes { - n := binary.PutUvarint(varintbuf, uint64(v)) - cidBytes = append(cidBytes, varintbuf[:n]...) - } - - cidBytes = append(cidBytes, hash[:]...) - return cidBytes, nil -} diff --git a/contracts/ens/cid_test.go b/contracts/ens/cid_test.go deleted file mode 100644 index 7d0e67851a..0000000000 --- a/contracts/ens/cid_test.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ens - -import ( - "bytes" - "encoding/binary" - "encoding/hex" - "fmt" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -// Tests for the decoding of the example ENS -func TestEIPSpecCidDecode(t *testing.T) { - const ( - eipSpecHash = "e3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" - eipHash = "29f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" - dagPb = 0x70 - sha2256 = 0x12 - ) - b, err := hex.DecodeString(eipSpecHash) - if err != nil { - t.Fatal(err) - } - hashBytes, err := hex.DecodeString(eipHash) - - if err != nil { - t.Fatal(err) - } - - storageNs, contentType, hashType, hashLength, decodedHashBytes, err := decodeEIP1577ContentHash(b) - - if err != nil { - t.Fatal(err) - } - if storageNs != nsIpfs { - t.Fatal("wrong ns") - } - if contentType != dagPb { - t.Fatal("should be ipfs typecode") - } - if hashType != sha2256 { - t.Fatal("should be sha2-256") - } - if hashLength != 32 { - t.Fatal("should be 32") - } - if !bytes.Equal(hashBytes, decodedHashBytes) { - t.Fatal("should be equal") - } - -} -func TestManualCidDecode(t *testing.T) { - // call cid encode method with hash. expect byte slice returned, compare according to spec - - for _, v := range []struct { - name string - headerBytes []byte - wantErr bool - }{ - { - name: "values correct, should not fail", - headerBytes: []byte{0xe4, 0x01, 0xfa, 0x1b, 0x20}, - wantErr: false, - }, - { - name: "cid version wrong, should fail", - headerBytes: []byte{0xe4, 0x00, 0xfa, 0x1b, 0x20}, - wantErr: true, - }, - { - name: "hash length wrong, should fail", - headerBytes: []byte{0xe4, 0x01, 0xfa, 0x1b, 0x1f}, - wantErr: true, - }, - { - name: "values correct for ipfs, should fail", - headerBytes: []byte{0xe3, 0x01, 0x70, 0x12, 0x20}, - wantErr: true, - }, - { - name: "loose values for swarm, todo remove, should not fail", - headerBytes: []byte{0xe4, 0x01, 0x70, 0x12, 0x20}, - wantErr: false, - }, - { - name: "loose values for swarm, todo remove, should not fail", - headerBytes: []byte{0xe4, 0x01, 0x99, 0x99, 0x20}, - wantErr: false, - }, - } { - t.Run(v.name, func(t *testing.T) { - const eipHash = "29f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" - - var bb []byte - buf := make([]byte, binary.MaxVarintLen64) - for _, vv := range v.headerBytes { - n := binary.PutUvarint(buf, uint64(vv)) - bb = append(bb, buf[:n]...) - } - - h := common.HexToHash(eipHash) - bb = append(bb, h[:]...) - str := hex.EncodeToString(bb) - fmt.Println(str) - decodedHash, e := extractContentHash(bb) - switch v.wantErr { - case true: - if e == nil { - t.Fatal("the decode should fail") - } - case false: - if e != nil { - t.Fatalf("the deccode shouldnt fail: %v", e) - } - if !bytes.Equal(decodedHash[:], h[:]) { - t.Fatal("hashes not equal") - } - } - }) - } -} - -func TestManuelCidEncode(t *testing.T) { - // call cid encode method with hash. expect byte slice returned, compare according to spec - const eipHash = "29f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f" - cidBytes, err := EncodeSwarmHash(common.HexToHash(eipHash)) - if err != nil { - t.Fatal(err) - } - - // logic in extractContentHash is unit tested thoroughly - // hence we just check that the returned hash is equal - h, err := extractContentHash(cidBytes) - if err != nil { - t.Fatal(err) - } - - if bytes.Equal(h[:], cidBytes) { - t.Fatal("should be equal") - } -} diff --git a/contracts/ens/contract/ENS.sol b/contracts/ens/contract/ENS.sol deleted file mode 100644 index 5ab8c92b41..0000000000 --- a/contracts/ens/contract/ENS.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity >=0.4.24; - -interface ENS { - - // Logged when the owner of a node assigns a new owner to a subnode. - event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); - - // Logged when the owner of a node transfers ownership to a new account. - event Transfer(bytes32 indexed node, address owner); - - // Logged when the resolver for a node changes. - event NewResolver(bytes32 indexed node, address resolver); - - // Logged when the TTL of a node changes - event NewTTL(bytes32 indexed node, uint64 ttl); - - - function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external; - function setResolver(bytes32 node, address resolver) external; - function setOwner(bytes32 node, address owner) external; - function setTTL(bytes32 node, uint64 ttl) external; - function owner(bytes32 node) external view returns (address); - function resolver(bytes32 node) external view returns (address); - function ttl(bytes32 node) external view returns (uint64); - -} \ No newline at end of file diff --git a/contracts/ens/contract/ENSRegistry.sol b/contracts/ens/contract/ENSRegistry.sol deleted file mode 100644 index fa19131de0..0000000000 --- a/contracts/ens/contract/ENSRegistry.sol +++ /dev/null @@ -1,99 +0,0 @@ -pragma solidity ^0.5.0; - -import "./ENS.sol"; - -/** - * The ENS registry contract. - */ -contract ENSRegistry is ENS { - struct Record { - address owner; - address resolver; - uint64 ttl; - } - - mapping (bytes32 => Record) records; - - // Permits modifications only by the owner of the specified node. - modifier only_owner(bytes32 node) { - require(records[node].owner == msg.sender); - _; - } - - /** - * @dev Constructs a new ENS registrar. - */ - constructor() public { - records[0x0].owner = msg.sender; - } - - /** - * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node. - * @param node The node to transfer ownership of. - * @param owner The address of the new owner. - */ - function setOwner(bytes32 node, address owner) external only_owner(node) { - emit Transfer(node, owner); - records[node].owner = owner; - } - - /** - * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node. - * @param node The parent node. - * @param label The hash of the label specifying the subnode. - * @param owner The address of the new owner. - */ - function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external only_owner(node) { - bytes32 subnode = keccak256(abi.encodePacked(node, label)); - emit NewOwner(node, label, owner); - records[subnode].owner = owner; - } - - /** - * @dev Sets the resolver address for the specified node. - * @param node The node to update. - * @param resolver The address of the resolver. - */ - function setResolver(bytes32 node, address resolver) external only_owner(node) { - emit NewResolver(node, resolver); - records[node].resolver = resolver; - } - - /** - * @dev Sets the TTL for the specified node. - * @param node The node to update. - * @param ttl The TTL in seconds. - */ - function setTTL(bytes32 node, uint64 ttl) external only_owner(node) { - emit NewTTL(node, ttl); - records[node].ttl = ttl; - } - - /** - * @dev Returns the address that owns the specified node. - * @param node The specified node. - * @return address of the owner. - */ - function owner(bytes32 node) external view returns (address) { - return records[node].owner; - } - - /** - * @dev Returns the address of the resolver for the specified node. - * @param node The specified node. - * @return address of the resolver. - */ - function resolver(bytes32 node) external view returns (address) { - return records[node].resolver; - } - - /** - * @dev Returns the TTL of a node, and any records associated with it. - * @param node The specified node. - * @return ttl of the node. - */ - function ttl(bytes32 node) external view returns (uint64) { - return records[node].ttl; - } - -} \ No newline at end of file diff --git a/contracts/ens/contract/FIFSRegistrar.sol b/contracts/ens/contract/FIFSRegistrar.sol deleted file mode 100644 index 19287408f6..0000000000 --- a/contracts/ens/contract/FIFSRegistrar.sol +++ /dev/null @@ -1,36 +0,0 @@ -pragma solidity ^0.5.0; - -import "./ENS.sol"; - -/** - * A registrar that allocates subdomains to the first person to claim them. - */ -contract FIFSRegistrar { - ENS ens; - bytes32 rootNode; - - modifier only_owner(bytes32 label) { - address currentOwner = ens.owner(keccak256(abi.encodePacked(rootNode, label))); - require(currentOwner == address(0x0) || currentOwner == msg.sender); - _; - } - - /** - * Constructor. - * @param ensAddr The address of the ENS registry. - * @param node The node that this registrar administers. - */ - constructor(ENS ensAddr, bytes32 node) public { - ens = ensAddr; - rootNode = node; - } - - /** - * Register a name, or change the owner of an existing registration. - * @param label The hash of the label to register. - * @param owner The address of the new owner. - */ - function register(bytes32 label, address owner) public only_owner(label) { - ens.setSubnodeOwner(rootNode, label, owner); - } -} \ No newline at end of file diff --git a/contracts/ens/contract/PublicResolver.sol b/contracts/ens/contract/PublicResolver.sol deleted file mode 100644 index cfcd5dd6b3..0000000000 --- a/contracts/ens/contract/PublicResolver.sol +++ /dev/null @@ -1,212 +0,0 @@ -pragma solidity >=0.4.25; - -import "./ENS.sol"; - -/** - * A simple resolver anyone can use; only allows the owner of a node to set its - * address. - */ -contract PublicResolver { - - bytes4 constant INTERFACE_META_ID = 0x01ffc9a7; - bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de; - bytes4 constant NAME_INTERFACE_ID = 0x691f3431; - bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; - bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; - bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; - bytes4 constant CONTENTHASH_INTERFACE_ID = 0xbc1c58d1; - - event AddrChanged(bytes32 indexed node, address a); - event NameChanged(bytes32 indexed node, string name); - event ABIChanged(bytes32 indexed node, uint256 indexed contentType); - event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); - event TextChanged(bytes32 indexed node, string indexedKey, string key); - event ContenthashChanged(bytes32 indexed node, bytes hash); - - struct PublicKey { - bytes32 x; - bytes32 y; - } - - struct Record { - address addr; - string name; - PublicKey pubkey; - mapping(string=>string) text; - mapping(uint256=>bytes) abis; - bytes contenthash; - } - - ENS ens; - - mapping (bytes32 => Record) records; - - modifier onlyOwner(bytes32 node) { - require(ens.owner(node) == msg.sender); - _; - } - - /** - * Constructor. - * @param ensAddr The ENS registrar contract. - */ - constructor(ENS ensAddr) public { - ens = ensAddr; - } - - /** - * Sets the address associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param addr The address to set. - */ - function setAddr(bytes32 node, address addr) external onlyOwner(node) { - records[node].addr = addr; - emit AddrChanged(node, addr); - } - - /** - * Sets the contenthash associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param hash The contenthash to set - */ - function setContenthash(bytes32 node, bytes calldata hash) external onlyOwner(node) { - records[node].contenthash = hash; - emit ContenthashChanged(node, hash); - } - - /** - * Sets the name associated with an ENS node, for reverse records. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param name The name to set. - */ - function setName(bytes32 node, string calldata name) external onlyOwner(node) { - records[node].name = name; - emit NameChanged(node, name); - } - - /** - * Sets the ABI associated with an ENS node. - * Nodes may have one ABI of each content type. To remove an ABI, set it to - * the empty string. - * @param node The node to update. - * @param contentType The content type of the ABI - * @param data The ABI data. - */ - function setABI(bytes32 node, uint256 contentType, bytes calldata data) external onlyOwner(node) { - // Content types must be powers of 2 - require(((contentType - 1) & contentType) == 0); - - records[node].abis[contentType] = data; - emit ABIChanged(node, contentType); - } - - /** - * Sets the SECP256k1 public key associated with an ENS node. - * @param node The ENS node to query - * @param x the X coordinate of the curve point for the public key. - * @param y the Y coordinate of the curve point for the public key. - */ - function setPubkey(bytes32 node, bytes32 x, bytes32 y) external onlyOwner(node) { - records[node].pubkey = PublicKey(x, y); - emit PubkeyChanged(node, x, y); - } - - /** - * Sets the text data associated with an ENS node and key. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param key The key to set. - * @param value The text data value to set. - */ - function setText(bytes32 node, string calldata key, string calldata value) external onlyOwner(node) { - records[node].text[key] = value; - emit TextChanged(node, key, key); - } - - /** - * Returns the text data associated with an ENS node and key. - * @param node The ENS node to query. - * @param key The text data key to query. - * @return The associated text data. - */ - function text(bytes32 node, string calldata key) external view returns (string memory) { - return records[node].text[key]; - } - - /** - * Returns the SECP256k1 public key associated with an ENS node. - * Defined in EIP 619. - * @param node The ENS node to query - * @return x, y the X and Y coordinates of the curve point for the public key. - */ - function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) { - return (records[node].pubkey.x, records[node].pubkey.y); - } - - /** - * Returns the ABI associated with an ENS node. - * Defined in EIP205. - * @param node The ENS node to query - * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. - * @return contentType The content type of the return value - * @return data The ABI data - */ - function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) { - Record storage record = records[node]; - - for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) { - if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { - return (contentType, record.abis[contentType]); - } - } - - bytes memory empty; - return (0, empty); - } - - /** - * Returns the name associated with an ENS node, for reverse records. - * Defined in EIP181. - * @param node The ENS node to query. - * @return The associated name. - */ - function name(bytes32 node) external view returns (string memory) { - return records[node].name; - } - - /** - * Returns the address associated with an ENS node. - * @param node The ENS node to query. - * @return The associated address. - */ - function addr(bytes32 node) external view returns (address) { - return records[node].addr; - } - - /** - * Returns the contenthash associated with an ENS node. - * @param node The ENS node to query. - * @return The associated contenthash. - */ - function contenthash(bytes32 node) external view returns (bytes memory) { - return records[node].contenthash; - } - - /** - * Returns true if the resolver implements the interface specified by the provided hash. - * @param interfaceID The ID of the interface to check for. - * @return True if the contract implements the requested interface. - */ - function supportsInterface(bytes4 interfaceID) external pure returns (bool) { - return interfaceID == ADDR_INTERFACE_ID || - interfaceID == NAME_INTERFACE_ID || - interfaceID == ABI_INTERFACE_ID || - interfaceID == PUBKEY_INTERFACE_ID || - interfaceID == TEXT_INTERFACE_ID || - interfaceID == CONTENTHASH_INTERFACE_ID || - interfaceID == INTERFACE_META_ID; - } -} diff --git a/contracts/ens/contract/ens.go b/contracts/ens/contract/ens.go deleted file mode 100644 index 7c0aed342e..0000000000 --- a/contracts/ens/contract/ens.go +++ /dev/null @@ -1,892 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contract - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = abi.U256 - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// ENSABI is the input ABI used to generate the binding from. -const ENSABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"resolver\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"label\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setSubnodeOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"setTTL\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"ttl\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"setResolver\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"label\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"NewOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"NewResolver\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"NewTTL\",\"type\":\"event\"}]" - -// ENSBin is the compiled bytecode used for deploying new contracts. -const ENSBin = `0x` - -// DeployENS deploys a new Ethereum contract, binding an instance of ENS to it. -func DeployENS(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ENS, error) { - parsed, err := abi.JSON(strings.NewReader(ENSABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ENSBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &ENS{ENSCaller: ENSCaller{contract: contract}, ENSTransactor: ENSTransactor{contract: contract}, ENSFilterer: ENSFilterer{contract: contract}}, nil -} - -// ENS is an auto generated Go binding around an Ethereum contract. -type ENS struct { - ENSCaller // Read-only binding to the contract - ENSTransactor // Write-only binding to the contract - ENSFilterer // Log filterer for contract events -} - -// ENSCaller is an auto generated read-only Go binding around an Ethereum contract. -type ENSCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ENSTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ENSTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ENSFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ENSFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ENSSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ENSSession struct { - Contract *ENS // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ENSCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ENSCallerSession struct { - Contract *ENSCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ENSTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ENSTransactorSession struct { - Contract *ENSTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ENSRaw is an auto generated low-level Go binding around an Ethereum contract. -type ENSRaw struct { - Contract *ENS // Generic contract binding to access the raw methods on -} - -// ENSCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ENSCallerRaw struct { - Contract *ENSCaller // Generic read-only contract binding to access the raw methods on -} - -// ENSTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ENSTransactorRaw struct { - Contract *ENSTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewENS creates a new instance of ENS, bound to a specific deployed contract. -func NewENS(address common.Address, backend bind.ContractBackend) (*ENS, error) { - contract, err := bindENS(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &ENS{ENSCaller: ENSCaller{contract: contract}, ENSTransactor: ENSTransactor{contract: contract}, ENSFilterer: ENSFilterer{contract: contract}}, nil -} - -// NewENSCaller creates a new read-only instance of ENS, bound to a specific deployed contract. -func NewENSCaller(address common.Address, caller bind.ContractCaller) (*ENSCaller, error) { - contract, err := bindENS(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ENSCaller{contract: contract}, nil -} - -// NewENSTransactor creates a new write-only instance of ENS, bound to a specific deployed contract. -func NewENSTransactor(address common.Address, transactor bind.ContractTransactor) (*ENSTransactor, error) { - contract, err := bindENS(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ENSTransactor{contract: contract}, nil -} - -// NewENSFilterer creates a new log filterer instance of ENS, bound to a specific deployed contract. -func NewENSFilterer(address common.Address, filterer bind.ContractFilterer) (*ENSFilterer, error) { - contract, err := bindENS(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ENSFilterer{contract: contract}, nil -} - -// bindENS binds a generic wrapper to an already deployed contract. -func bindENS(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(ENSABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ENS *ENSRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _ENS.Contract.ENSCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ENS *ENSRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ENS.Contract.ENSTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ENS *ENSRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ENS.Contract.ENSTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ENS *ENSCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _ENS.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ENS *ENSTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ENS.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ENS *ENSTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ENS.Contract.contract.Transact(opts, method, params...) -} - -// Owner is a free data retrieval call binding the contract method 0x02571be3. -// -// Solidity: function owner(bytes32 node) constant returns(address) -func (_ENS *ENSCaller) Owner(opts *bind.CallOpts, node [32]byte) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _ENS.contract.Call(opts, out, "owner", node) - return *ret0, err -} - -// Owner is a free data retrieval call binding the contract method 0x02571be3. -// -// Solidity: function owner(bytes32 node) constant returns(address) -func (_ENS *ENSSession) Owner(node [32]byte) (common.Address, error) { - return _ENS.Contract.Owner(&_ENS.CallOpts, node) -} - -// Owner is a free data retrieval call binding the contract method 0x02571be3. -// -// Solidity: function owner(bytes32 node) constant returns(address) -func (_ENS *ENSCallerSession) Owner(node [32]byte) (common.Address, error) { - return _ENS.Contract.Owner(&_ENS.CallOpts, node) -} - -// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. -// -// Solidity: function resolver(bytes32 node) constant returns(address) -func (_ENS *ENSCaller) Resolver(opts *bind.CallOpts, node [32]byte) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _ENS.contract.Call(opts, out, "resolver", node) - return *ret0, err -} - -// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. -// -// Solidity: function resolver(bytes32 node) constant returns(address) -func (_ENS *ENSSession) Resolver(node [32]byte) (common.Address, error) { - return _ENS.Contract.Resolver(&_ENS.CallOpts, node) -} - -// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. -// -// Solidity: function resolver(bytes32 node) constant returns(address) -func (_ENS *ENSCallerSession) Resolver(node [32]byte) (common.Address, error) { - return _ENS.Contract.Resolver(&_ENS.CallOpts, node) -} - -// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. -// -// Solidity: function ttl(bytes32 node) constant returns(uint64) -func (_ENS *ENSCaller) Ttl(opts *bind.CallOpts, node [32]byte) (uint64, error) { - var ( - ret0 = new(uint64) - ) - out := ret0 - err := _ENS.contract.Call(opts, out, "ttl", node) - return *ret0, err -} - -// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. -// -// Solidity: function ttl(bytes32 node) constant returns(uint64) -func (_ENS *ENSSession) Ttl(node [32]byte) (uint64, error) { - return _ENS.Contract.Ttl(&_ENS.CallOpts, node) -} - -// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. -// -// Solidity: function ttl(bytes32 node) constant returns(uint64) -func (_ENS *ENSCallerSession) Ttl(node [32]byte) (uint64, error) { - return _ENS.Contract.Ttl(&_ENS.CallOpts, node) -} - -// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. -// -// Solidity: function setOwner(bytes32 node, address owner) returns() -func (_ENS *ENSTransactor) SetOwner(opts *bind.TransactOpts, node [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENS.contract.Transact(opts, "setOwner", node, owner) -} - -// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. -// -// Solidity: function setOwner(bytes32 node, address owner) returns() -func (_ENS *ENSSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENS.Contract.SetOwner(&_ENS.TransactOpts, node, owner) -} - -// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. -// -// Solidity: function setOwner(bytes32 node, address owner) returns() -func (_ENS *ENSTransactorSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENS.Contract.SetOwner(&_ENS.TransactOpts, node, owner) -} - -// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. -// -// Solidity: function setResolver(bytes32 node, address resolver) returns() -func (_ENS *ENSTransactor) SetResolver(opts *bind.TransactOpts, node [32]byte, resolver common.Address) (*types.Transaction, error) { - return _ENS.contract.Transact(opts, "setResolver", node, resolver) -} - -// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. -// -// Solidity: function setResolver(bytes32 node, address resolver) returns() -func (_ENS *ENSSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { - return _ENS.Contract.SetResolver(&_ENS.TransactOpts, node, resolver) -} - -// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. -// -// Solidity: function setResolver(bytes32 node, address resolver) returns() -func (_ENS *ENSTransactorSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { - return _ENS.Contract.SetResolver(&_ENS.TransactOpts, node, resolver) -} - -// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. -// -// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() -func (_ENS *ENSTransactor) SetSubnodeOwner(opts *bind.TransactOpts, node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENS.contract.Transact(opts, "setSubnodeOwner", node, label, owner) -} - -// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. -// -// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() -func (_ENS *ENSSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENS.Contract.SetSubnodeOwner(&_ENS.TransactOpts, node, label, owner) -} - -// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. -// -// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() -func (_ENS *ENSTransactorSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENS.Contract.SetSubnodeOwner(&_ENS.TransactOpts, node, label, owner) -} - -// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. -// -// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() -func (_ENS *ENSTransactor) SetTTL(opts *bind.TransactOpts, node [32]byte, ttl uint64) (*types.Transaction, error) { - return _ENS.contract.Transact(opts, "setTTL", node, ttl) -} - -// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. -// -// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() -func (_ENS *ENSSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { - return _ENS.Contract.SetTTL(&_ENS.TransactOpts, node, ttl) -} - -// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. -// -// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() -func (_ENS *ENSTransactorSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { - return _ENS.Contract.SetTTL(&_ENS.TransactOpts, node, ttl) -} - -// ENSNewOwnerIterator is returned from FilterNewOwner and is used to iterate over the raw logs and unpacked data for NewOwner events raised by the ENS contract. -type ENSNewOwnerIterator struct { - Event *ENSNewOwner // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSNewOwnerIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSNewOwner) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSNewOwner) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSNewOwnerIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSNewOwnerIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSNewOwner represents a NewOwner event raised by the ENS contract. -type ENSNewOwner struct { - Node [32]byte - Label [32]byte - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNewOwner is a free log retrieval operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. -// -// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) -func (_ENS *ENSFilterer) FilterNewOwner(opts *bind.FilterOpts, node [][32]byte, label [][32]byte) (*ENSNewOwnerIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var labelRule []interface{} - for _, labelItem := range label { - labelRule = append(labelRule, labelItem) - } - - logs, sub, err := _ENS.contract.FilterLogs(opts, "NewOwner", nodeRule, labelRule) - if err != nil { - return nil, err - } - return &ENSNewOwnerIterator{contract: _ENS.contract, event: "NewOwner", logs: logs, sub: sub}, nil -} - -// WatchNewOwner is a free log subscription operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. -// -// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) -func (_ENS *ENSFilterer) WatchNewOwner(opts *bind.WatchOpts, sink chan<- *ENSNewOwner, node [][32]byte, label [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var labelRule []interface{} - for _, labelItem := range label { - labelRule = append(labelRule, labelItem) - } - - logs, sub, err := _ENS.contract.WatchLogs(opts, "NewOwner", nodeRule, labelRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSNewOwner) - if err := _ENS.contract.UnpackLog(event, "NewOwner", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ENSNewResolverIterator is returned from FilterNewResolver and is used to iterate over the raw logs and unpacked data for NewResolver events raised by the ENS contract. -type ENSNewResolverIterator struct { - Event *ENSNewResolver // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSNewResolverIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSNewResolver) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSNewResolver) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSNewResolverIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSNewResolverIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSNewResolver represents a NewResolver event raised by the ENS contract. -type ENSNewResolver struct { - Node [32]byte - Resolver common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNewResolver is a free log retrieval operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. -// -// Solidity: event NewResolver(bytes32 indexed node, address resolver) -func (_ENS *ENSFilterer) FilterNewResolver(opts *bind.FilterOpts, node [][32]byte) (*ENSNewResolverIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENS.contract.FilterLogs(opts, "NewResolver", nodeRule) - if err != nil { - return nil, err - } - return &ENSNewResolverIterator{contract: _ENS.contract, event: "NewResolver", logs: logs, sub: sub}, nil -} - -// WatchNewResolver is a free log subscription operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. -// -// Solidity: event NewResolver(bytes32 indexed node, address resolver) -func (_ENS *ENSFilterer) WatchNewResolver(opts *bind.WatchOpts, sink chan<- *ENSNewResolver, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENS.contract.WatchLogs(opts, "NewResolver", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSNewResolver) - if err := _ENS.contract.UnpackLog(event, "NewResolver", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ENSNewTTLIterator is returned from FilterNewTTL and is used to iterate over the raw logs and unpacked data for NewTTL events raised by the ENS contract. -type ENSNewTTLIterator struct { - Event *ENSNewTTL // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSNewTTLIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSNewTTL) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSNewTTL) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSNewTTLIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSNewTTLIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSNewTTL represents a NewTTL event raised by the ENS contract. -type ENSNewTTL struct { - Node [32]byte - Ttl uint64 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNewTTL is a free log retrieval operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. -// -// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) -func (_ENS *ENSFilterer) FilterNewTTL(opts *bind.FilterOpts, node [][32]byte) (*ENSNewTTLIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENS.contract.FilterLogs(opts, "NewTTL", nodeRule) - if err != nil { - return nil, err - } - return &ENSNewTTLIterator{contract: _ENS.contract, event: "NewTTL", logs: logs, sub: sub}, nil -} - -// WatchNewTTL is a free log subscription operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. -// -// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) -func (_ENS *ENSFilterer) WatchNewTTL(opts *bind.WatchOpts, sink chan<- *ENSNewTTL, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENS.contract.WatchLogs(opts, "NewTTL", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSNewTTL) - if err := _ENS.contract.UnpackLog(event, "NewTTL", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ENSTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the ENS contract. -type ENSTransferIterator struct { - Event *ENSTransfer // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSTransferIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSTransferIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSTransferIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSTransfer represents a Transfer event raised by the ENS contract. -type ENSTransfer struct { - Node [32]byte - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTransfer is a free log retrieval operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. -// -// Solidity: event Transfer(bytes32 indexed node, address owner) -func (_ENS *ENSFilterer) FilterTransfer(opts *bind.FilterOpts, node [][32]byte) (*ENSTransferIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENS.contract.FilterLogs(opts, "Transfer", nodeRule) - if err != nil { - return nil, err - } - return &ENSTransferIterator{contract: _ENS.contract, event: "Transfer", logs: logs, sub: sub}, nil -} - -// WatchTransfer is a free log subscription operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. -// -// Solidity: event Transfer(bytes32 indexed node, address owner) -func (_ENS *ENSFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *ENSTransfer, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENS.contract.WatchLogs(opts, "Transfer", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSTransfer) - if err := _ENS.contract.UnpackLog(event, "Transfer", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/contracts/ens/contract/ensregistry.go b/contracts/ens/contract/ensregistry.go deleted file mode 100644 index ca89a87bc2..0000000000 --- a/contracts/ens/contract/ensregistry.go +++ /dev/null @@ -1,892 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contract - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = abi.U256 - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// ENSRegistryABI is the input ABI used to generate the binding from. -const ENSRegistryABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"resolver\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"label\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setSubnodeOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"setTTL\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"ttl\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"setResolver\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"label\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"NewOwner\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"resolver\",\"type\":\"address\"}],\"name\":\"NewResolver\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"NewTTL\",\"type\":\"event\"}]" - -// ENSRegistryBin is the compiled bytecode used for deploying new contracts. -const ENSRegistryBin = `0x608060405234801561001057600080fd5b5060008080526020527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58054600160a060020a0319163317905561059d806100596000396000f3fe6080604052600436106100825763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630178b8bf811461008757806302571be3146100cd57806306ab5923146100f757806314ab90381461013857806316a25cbd146101725780631896f70a146101b95780635b0fc9c3146101f2575b600080fd5b34801561009357600080fd5b506100b1600480360360208110156100aa57600080fd5b503561022b565b60408051600160a060020a039092168252519081900360200190f35b3480156100d957600080fd5b506100b1600480360360208110156100f057600080fd5b5035610249565b34801561010357600080fd5b506101366004803603606081101561011a57600080fd5b5080359060208101359060400135600160a060020a0316610264565b005b34801561014457600080fd5b506101366004803603604081101561015b57600080fd5b508035906020013567ffffffffffffffff1661032e565b34801561017e57600080fd5b5061019c6004803603602081101561019557600080fd5b50356103f7565b6040805167ffffffffffffffff9092168252519081900360200190f35b3480156101c557600080fd5b50610136600480360360408110156101dc57600080fd5b5080359060200135600160a060020a031661042e565b3480156101fe57600080fd5b506101366004803603604081101561021557600080fd5b5080359060200135600160a060020a03166104d1565b600090815260208190526040902060010154600160a060020a031690565b600090815260208190526040902054600160a060020a031690565b6000838152602081905260409020548390600160a060020a0316331461028957600080fd5b6040805160208082018790528183018690528251808303840181526060830180855281519190920120600160a060020a0386169091529151859187917fce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e829181900360800190a36000908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039390931692909217909155505050565b6000828152602081905260409020548290600160a060020a0316331461035357600080fd5b6040805167ffffffffffffffff84168152905184917f1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68919081900360200190a250600091825260208290526040909120600101805467ffffffffffffffff90921674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60009081526020819052604090206001015474010000000000000000000000000000000000000000900467ffffffffffffffff1690565b6000828152602081905260409020548290600160a060020a0316331461045357600080fd5b60408051600160a060020a0384168152905184917f335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0919081900360200190a250600091825260208290526040909120600101805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03909216919091179055565b6000828152602081905260409020548290600160a060020a031633146104f657600080fd5b60408051600160a060020a0384168152905184917fd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266919081900360200190a250600091825260208290526040909120805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0390921691909117905556fea165627a7a723058208be97eda88107945616fbd44aa4f2f1ce188b1a930a4bc5f8e1fb7924395d1650029` - -// DeployENSRegistry deploys a new Ethereum contract, binding an instance of ENSRegistry to it. -func DeployENSRegistry(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ENSRegistry, error) { - parsed, err := abi.JSON(strings.NewReader(ENSRegistryABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ENSRegistryBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &ENSRegistry{ENSRegistryCaller: ENSRegistryCaller{contract: contract}, ENSRegistryTransactor: ENSRegistryTransactor{contract: contract}, ENSRegistryFilterer: ENSRegistryFilterer{contract: contract}}, nil -} - -// ENSRegistry is an auto generated Go binding around an Ethereum contract. -type ENSRegistry struct { - ENSRegistryCaller // Read-only binding to the contract - ENSRegistryTransactor // Write-only binding to the contract - ENSRegistryFilterer // Log filterer for contract events -} - -// ENSRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. -type ENSRegistryCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ENSRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ENSRegistryTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ENSRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ENSRegistryFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ENSRegistrySession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ENSRegistrySession struct { - Contract *ENSRegistry // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ENSRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ENSRegistryCallerSession struct { - Contract *ENSRegistryCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ENSRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ENSRegistryTransactorSession struct { - Contract *ENSRegistryTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ENSRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. -type ENSRegistryRaw struct { - Contract *ENSRegistry // Generic contract binding to access the raw methods on -} - -// ENSRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ENSRegistryCallerRaw struct { - Contract *ENSRegistryCaller // Generic read-only contract binding to access the raw methods on -} - -// ENSRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ENSRegistryTransactorRaw struct { - Contract *ENSRegistryTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewENSRegistry creates a new instance of ENSRegistry, bound to a specific deployed contract. -func NewENSRegistry(address common.Address, backend bind.ContractBackend) (*ENSRegistry, error) { - contract, err := bindENSRegistry(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &ENSRegistry{ENSRegistryCaller: ENSRegistryCaller{contract: contract}, ENSRegistryTransactor: ENSRegistryTransactor{contract: contract}, ENSRegistryFilterer: ENSRegistryFilterer{contract: contract}}, nil -} - -// NewENSRegistryCaller creates a new read-only instance of ENSRegistry, bound to a specific deployed contract. -func NewENSRegistryCaller(address common.Address, caller bind.ContractCaller) (*ENSRegistryCaller, error) { - contract, err := bindENSRegistry(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ENSRegistryCaller{contract: contract}, nil -} - -// NewENSRegistryTransactor creates a new write-only instance of ENSRegistry, bound to a specific deployed contract. -func NewENSRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*ENSRegistryTransactor, error) { - contract, err := bindENSRegistry(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ENSRegistryTransactor{contract: contract}, nil -} - -// NewENSRegistryFilterer creates a new log filterer instance of ENSRegistry, bound to a specific deployed contract. -func NewENSRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*ENSRegistryFilterer, error) { - contract, err := bindENSRegistry(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ENSRegistryFilterer{contract: contract}, nil -} - -// bindENSRegistry binds a generic wrapper to an already deployed contract. -func bindENSRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(ENSRegistryABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ENSRegistry *ENSRegistryRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _ENSRegistry.Contract.ENSRegistryCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ENSRegistry *ENSRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ENSRegistry.Contract.ENSRegistryTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ENSRegistry *ENSRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ENSRegistry.Contract.ENSRegistryTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ENSRegistry *ENSRegistryCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _ENSRegistry.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ENSRegistry *ENSRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ENSRegistry.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ENSRegistry *ENSRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ENSRegistry.Contract.contract.Transact(opts, method, params...) -} - -// Owner is a free data retrieval call binding the contract method 0x02571be3. -// -// Solidity: function owner(bytes32 node) constant returns(address) -func (_ENSRegistry *ENSRegistryCaller) Owner(opts *bind.CallOpts, node [32]byte) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _ENSRegistry.contract.Call(opts, out, "owner", node) - return *ret0, err -} - -// Owner is a free data retrieval call binding the contract method 0x02571be3. -// -// Solidity: function owner(bytes32 node) constant returns(address) -func (_ENSRegistry *ENSRegistrySession) Owner(node [32]byte) (common.Address, error) { - return _ENSRegistry.Contract.Owner(&_ENSRegistry.CallOpts, node) -} - -// Owner is a free data retrieval call binding the contract method 0x02571be3. -// -// Solidity: function owner(bytes32 node) constant returns(address) -func (_ENSRegistry *ENSRegistryCallerSession) Owner(node [32]byte) (common.Address, error) { - return _ENSRegistry.Contract.Owner(&_ENSRegistry.CallOpts, node) -} - -// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. -// -// Solidity: function resolver(bytes32 node) constant returns(address) -func (_ENSRegistry *ENSRegistryCaller) Resolver(opts *bind.CallOpts, node [32]byte) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _ENSRegistry.contract.Call(opts, out, "resolver", node) - return *ret0, err -} - -// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. -// -// Solidity: function resolver(bytes32 node) constant returns(address) -func (_ENSRegistry *ENSRegistrySession) Resolver(node [32]byte) (common.Address, error) { - return _ENSRegistry.Contract.Resolver(&_ENSRegistry.CallOpts, node) -} - -// Resolver is a free data retrieval call binding the contract method 0x0178b8bf. -// -// Solidity: function resolver(bytes32 node) constant returns(address) -func (_ENSRegistry *ENSRegistryCallerSession) Resolver(node [32]byte) (common.Address, error) { - return _ENSRegistry.Contract.Resolver(&_ENSRegistry.CallOpts, node) -} - -// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. -// -// Solidity: function ttl(bytes32 node) constant returns(uint64) -func (_ENSRegistry *ENSRegistryCaller) Ttl(opts *bind.CallOpts, node [32]byte) (uint64, error) { - var ( - ret0 = new(uint64) - ) - out := ret0 - err := _ENSRegistry.contract.Call(opts, out, "ttl", node) - return *ret0, err -} - -// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. -// -// Solidity: function ttl(bytes32 node) constant returns(uint64) -func (_ENSRegistry *ENSRegistrySession) Ttl(node [32]byte) (uint64, error) { - return _ENSRegistry.Contract.Ttl(&_ENSRegistry.CallOpts, node) -} - -// Ttl is a free data retrieval call binding the contract method 0x16a25cbd. -// -// Solidity: function ttl(bytes32 node) constant returns(uint64) -func (_ENSRegistry *ENSRegistryCallerSession) Ttl(node [32]byte) (uint64, error) { - return _ENSRegistry.Contract.Ttl(&_ENSRegistry.CallOpts, node) -} - -// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. -// -// Solidity: function setOwner(bytes32 node, address owner) returns() -func (_ENSRegistry *ENSRegistryTransactor) SetOwner(opts *bind.TransactOpts, node [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENSRegistry.contract.Transact(opts, "setOwner", node, owner) -} - -// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. -// -// Solidity: function setOwner(bytes32 node, address owner) returns() -func (_ENSRegistry *ENSRegistrySession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetOwner(&_ENSRegistry.TransactOpts, node, owner) -} - -// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3. -// -// Solidity: function setOwner(bytes32 node, address owner) returns() -func (_ENSRegistry *ENSRegistryTransactorSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetOwner(&_ENSRegistry.TransactOpts, node, owner) -} - -// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. -// -// Solidity: function setResolver(bytes32 node, address resolver) returns() -func (_ENSRegistry *ENSRegistryTransactor) SetResolver(opts *bind.TransactOpts, node [32]byte, resolver common.Address) (*types.Transaction, error) { - return _ENSRegistry.contract.Transact(opts, "setResolver", node, resolver) -} - -// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. -// -// Solidity: function setResolver(bytes32 node, address resolver) returns() -func (_ENSRegistry *ENSRegistrySession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetResolver(&_ENSRegistry.TransactOpts, node, resolver) -} - -// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a. -// -// Solidity: function setResolver(bytes32 node, address resolver) returns() -func (_ENSRegistry *ENSRegistryTransactorSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetResolver(&_ENSRegistry.TransactOpts, node, resolver) -} - -// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. -// -// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() -func (_ENSRegistry *ENSRegistryTransactor) SetSubnodeOwner(opts *bind.TransactOpts, node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENSRegistry.contract.Transact(opts, "setSubnodeOwner", node, label, owner) -} - -// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. -// -// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() -func (_ENSRegistry *ENSRegistrySession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetSubnodeOwner(&_ENSRegistry.TransactOpts, node, label, owner) -} - -// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923. -// -// Solidity: function setSubnodeOwner(bytes32 node, bytes32 label, address owner) returns() -func (_ENSRegistry *ENSRegistryTransactorSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetSubnodeOwner(&_ENSRegistry.TransactOpts, node, label, owner) -} - -// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. -// -// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() -func (_ENSRegistry *ENSRegistryTransactor) SetTTL(opts *bind.TransactOpts, node [32]byte, ttl uint64) (*types.Transaction, error) { - return _ENSRegistry.contract.Transact(opts, "setTTL", node, ttl) -} - -// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. -// -// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() -func (_ENSRegistry *ENSRegistrySession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetTTL(&_ENSRegistry.TransactOpts, node, ttl) -} - -// SetTTL is a paid mutator transaction binding the contract method 0x14ab9038. -// -// Solidity: function setTTL(bytes32 node, uint64 ttl) returns() -func (_ENSRegistry *ENSRegistryTransactorSession) SetTTL(node [32]byte, ttl uint64) (*types.Transaction, error) { - return _ENSRegistry.Contract.SetTTL(&_ENSRegistry.TransactOpts, node, ttl) -} - -// ENSRegistryNewOwnerIterator is returned from FilterNewOwner and is used to iterate over the raw logs and unpacked data for NewOwner events raised by the ENSRegistry contract. -type ENSRegistryNewOwnerIterator struct { - Event *ENSRegistryNewOwner // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSRegistryNewOwnerIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSRegistryNewOwner) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSRegistryNewOwner) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSRegistryNewOwnerIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSRegistryNewOwnerIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSRegistryNewOwner represents a NewOwner event raised by the ENSRegistry contract. -type ENSRegistryNewOwner struct { - Node [32]byte - Label [32]byte - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNewOwner is a free log retrieval operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. -// -// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) -func (_ENSRegistry *ENSRegistryFilterer) FilterNewOwner(opts *bind.FilterOpts, node [][32]byte, label [][32]byte) (*ENSRegistryNewOwnerIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var labelRule []interface{} - for _, labelItem := range label { - labelRule = append(labelRule, labelItem) - } - - logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "NewOwner", nodeRule, labelRule) - if err != nil { - return nil, err - } - return &ENSRegistryNewOwnerIterator{contract: _ENSRegistry.contract, event: "NewOwner", logs: logs, sub: sub}, nil -} - -// WatchNewOwner is a free log subscription operation binding the contract event 0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82. -// -// Solidity: event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) -func (_ENSRegistry *ENSRegistryFilterer) WatchNewOwner(opts *bind.WatchOpts, sink chan<- *ENSRegistryNewOwner, node [][32]byte, label [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var labelRule []interface{} - for _, labelItem := range label { - labelRule = append(labelRule, labelItem) - } - - logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "NewOwner", nodeRule, labelRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSRegistryNewOwner) - if err := _ENSRegistry.contract.UnpackLog(event, "NewOwner", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ENSRegistryNewResolverIterator is returned from FilterNewResolver and is used to iterate over the raw logs and unpacked data for NewResolver events raised by the ENSRegistry contract. -type ENSRegistryNewResolverIterator struct { - Event *ENSRegistryNewResolver // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSRegistryNewResolverIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSRegistryNewResolver) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSRegistryNewResolver) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSRegistryNewResolverIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSRegistryNewResolverIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSRegistryNewResolver represents a NewResolver event raised by the ENSRegistry contract. -type ENSRegistryNewResolver struct { - Node [32]byte - Resolver common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNewResolver is a free log retrieval operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. -// -// Solidity: event NewResolver(bytes32 indexed node, address resolver) -func (_ENSRegistry *ENSRegistryFilterer) FilterNewResolver(opts *bind.FilterOpts, node [][32]byte) (*ENSRegistryNewResolverIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "NewResolver", nodeRule) - if err != nil { - return nil, err - } - return &ENSRegistryNewResolverIterator{contract: _ENSRegistry.contract, event: "NewResolver", logs: logs, sub: sub}, nil -} - -// WatchNewResolver is a free log subscription operation binding the contract event 0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0. -// -// Solidity: event NewResolver(bytes32 indexed node, address resolver) -func (_ENSRegistry *ENSRegistryFilterer) WatchNewResolver(opts *bind.WatchOpts, sink chan<- *ENSRegistryNewResolver, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "NewResolver", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSRegistryNewResolver) - if err := _ENSRegistry.contract.UnpackLog(event, "NewResolver", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ENSRegistryNewTTLIterator is returned from FilterNewTTL and is used to iterate over the raw logs and unpacked data for NewTTL events raised by the ENSRegistry contract. -type ENSRegistryNewTTLIterator struct { - Event *ENSRegistryNewTTL // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSRegistryNewTTLIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSRegistryNewTTL) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSRegistryNewTTL) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSRegistryNewTTLIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSRegistryNewTTLIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSRegistryNewTTL represents a NewTTL event raised by the ENSRegistry contract. -type ENSRegistryNewTTL struct { - Node [32]byte - Ttl uint64 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNewTTL is a free log retrieval operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. -// -// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) -func (_ENSRegistry *ENSRegistryFilterer) FilterNewTTL(opts *bind.FilterOpts, node [][32]byte) (*ENSRegistryNewTTLIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "NewTTL", nodeRule) - if err != nil { - return nil, err - } - return &ENSRegistryNewTTLIterator{contract: _ENSRegistry.contract, event: "NewTTL", logs: logs, sub: sub}, nil -} - -// WatchNewTTL is a free log subscription operation binding the contract event 0x1d4f9bbfc9cab89d66e1a1562f2233ccbf1308cb4f63de2ead5787adddb8fa68. -// -// Solidity: event NewTTL(bytes32 indexed node, uint64 ttl) -func (_ENSRegistry *ENSRegistryFilterer) WatchNewTTL(opts *bind.WatchOpts, sink chan<- *ENSRegistryNewTTL, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "NewTTL", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSRegistryNewTTL) - if err := _ENSRegistry.contract.UnpackLog(event, "NewTTL", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ENSRegistryTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the ENSRegistry contract. -type ENSRegistryTransferIterator struct { - Event *ENSRegistryTransfer // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ENSRegistryTransferIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ENSRegistryTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ENSRegistryTransfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ENSRegistryTransferIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ENSRegistryTransferIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ENSRegistryTransfer represents a Transfer event raised by the ENSRegistry contract. -type ENSRegistryTransfer struct { - Node [32]byte - Owner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTransfer is a free log retrieval operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. -// -// Solidity: event Transfer(bytes32 indexed node, address owner) -func (_ENSRegistry *ENSRegistryFilterer) FilterTransfer(opts *bind.FilterOpts, node [][32]byte) (*ENSRegistryTransferIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENSRegistry.contract.FilterLogs(opts, "Transfer", nodeRule) - if err != nil { - return nil, err - } - return &ENSRegistryTransferIterator{contract: _ENSRegistry.contract, event: "Transfer", logs: logs, sub: sub}, nil -} - -// WatchTransfer is a free log subscription operation binding the contract event 0xd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266. -// -// Solidity: event Transfer(bytes32 indexed node, address owner) -func (_ENSRegistry *ENSRegistryFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *ENSRegistryTransfer, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _ENSRegistry.contract.WatchLogs(opts, "Transfer", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ENSRegistryTransfer) - if err := _ENSRegistry.contract.UnpackLog(event, "Transfer", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/contracts/ens/contract/fifsregistrar.go b/contracts/ens/contract/fifsregistrar.go deleted file mode 100644 index 97263cbefa..0000000000 --- a/contracts/ens/contract/fifsregistrar.go +++ /dev/null @@ -1,210 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contract - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = abi.U256 - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// FIFSRegistrarABI is the input ABI used to generate the binding from. -const FIFSRegistrarABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"label\",\"type\":\"bytes32\"},{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"},{\"name\":\"node\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]" - -// FIFSRegistrarBin is the compiled bytecode used for deploying new contracts. -const FIFSRegistrarBin = `0x608060405234801561001057600080fd5b506040516040806102cc8339810180604052604081101561003057600080fd5b50805160209091015160008054600160a060020a031916600160a060020a0390931692909217825560015561026190819061006b90396000f3fe6080604052600436106100405763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663d22057a98114610045575b600080fd5b34801561005157600080fd5b5061008b6004803603604081101561006857600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff1661008d565b005b6000805460015460408051602080820193909352808201879052815180820383018152606082018084528151918501919091207f02571be3000000000000000000000000000000000000000000000000000000009091526064820152905186949373ffffffffffffffffffffffffffffffffffffffff16926302571be39260848082019391829003018186803b15801561012657600080fd5b505afa15801561013a573d6000803e3d6000fd5b505050506040513d602081101561015057600080fd5b5051905073ffffffffffffffffffffffffffffffffffffffff8116158061018c575073ffffffffffffffffffffffffffffffffffffffff811633145b151561019757600080fd5b60008054600154604080517f06ab592300000000000000000000000000000000000000000000000000000000815260048101929092526024820188905273ffffffffffffffffffffffffffffffffffffffff878116604484015290519216926306ab59239260648084019382900301818387803b15801561021757600080fd5b505af115801561022b573d6000803e3d6000fd5b505050505050505056fea165627a7a723058200f21424d48c6fc6f2bc79f5b36b3a0e3067a97d4ce084ab0e0f9106303a3ee520029` - -// DeployFIFSRegistrar deploys a new Ethereum contract, binding an instance of FIFSRegistrar to it. -func DeployFIFSRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address, node [32]byte) (common.Address, *types.Transaction, *FIFSRegistrar, error) { - parsed, err := abi.JSON(strings.NewReader(FIFSRegistrarABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(FIFSRegistrarBin), backend, ensAddr, node) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &FIFSRegistrar{FIFSRegistrarCaller: FIFSRegistrarCaller{contract: contract}, FIFSRegistrarTransactor: FIFSRegistrarTransactor{contract: contract}, FIFSRegistrarFilterer: FIFSRegistrarFilterer{contract: contract}}, nil -} - -// FIFSRegistrar is an auto generated Go binding around an Ethereum contract. -type FIFSRegistrar struct { - FIFSRegistrarCaller // Read-only binding to the contract - FIFSRegistrarTransactor // Write-only binding to the contract - FIFSRegistrarFilterer // Log filterer for contract events -} - -// FIFSRegistrarCaller is an auto generated read-only Go binding around an Ethereum contract. -type FIFSRegistrarCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// FIFSRegistrarTransactor is an auto generated write-only Go binding around an Ethereum contract. -type FIFSRegistrarTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// FIFSRegistrarFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type FIFSRegistrarFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// FIFSRegistrarSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type FIFSRegistrarSession struct { - Contract *FIFSRegistrar // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// FIFSRegistrarCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type FIFSRegistrarCallerSession struct { - Contract *FIFSRegistrarCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// FIFSRegistrarTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type FIFSRegistrarTransactorSession struct { - Contract *FIFSRegistrarTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// FIFSRegistrarRaw is an auto generated low-level Go binding around an Ethereum contract. -type FIFSRegistrarRaw struct { - Contract *FIFSRegistrar // Generic contract binding to access the raw methods on -} - -// FIFSRegistrarCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type FIFSRegistrarCallerRaw struct { - Contract *FIFSRegistrarCaller // Generic read-only contract binding to access the raw methods on -} - -// FIFSRegistrarTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type FIFSRegistrarTransactorRaw struct { - Contract *FIFSRegistrarTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewFIFSRegistrar creates a new instance of FIFSRegistrar, bound to a specific deployed contract. -func NewFIFSRegistrar(address common.Address, backend bind.ContractBackend) (*FIFSRegistrar, error) { - contract, err := bindFIFSRegistrar(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &FIFSRegistrar{FIFSRegistrarCaller: FIFSRegistrarCaller{contract: contract}, FIFSRegistrarTransactor: FIFSRegistrarTransactor{contract: contract}, FIFSRegistrarFilterer: FIFSRegistrarFilterer{contract: contract}}, nil -} - -// NewFIFSRegistrarCaller creates a new read-only instance of FIFSRegistrar, bound to a specific deployed contract. -func NewFIFSRegistrarCaller(address common.Address, caller bind.ContractCaller) (*FIFSRegistrarCaller, error) { - contract, err := bindFIFSRegistrar(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &FIFSRegistrarCaller{contract: contract}, nil -} - -// NewFIFSRegistrarTransactor creates a new write-only instance of FIFSRegistrar, bound to a specific deployed contract. -func NewFIFSRegistrarTransactor(address common.Address, transactor bind.ContractTransactor) (*FIFSRegistrarTransactor, error) { - contract, err := bindFIFSRegistrar(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &FIFSRegistrarTransactor{contract: contract}, nil -} - -// NewFIFSRegistrarFilterer creates a new log filterer instance of FIFSRegistrar, bound to a specific deployed contract. -func NewFIFSRegistrarFilterer(address common.Address, filterer bind.ContractFilterer) (*FIFSRegistrarFilterer, error) { - contract, err := bindFIFSRegistrar(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &FIFSRegistrarFilterer{contract: contract}, nil -} - -// bindFIFSRegistrar binds a generic wrapper to an already deployed contract. -func bindFIFSRegistrar(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(FIFSRegistrarABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_FIFSRegistrar *FIFSRegistrarRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _FIFSRegistrar.Contract.FIFSRegistrarCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_FIFSRegistrar *FIFSRegistrarRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.FIFSRegistrarTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_FIFSRegistrar *FIFSRegistrarRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.FIFSRegistrarTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_FIFSRegistrar *FIFSRegistrarCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _FIFSRegistrar.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_FIFSRegistrar *FIFSRegistrarTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_FIFSRegistrar *FIFSRegistrarTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.contract.Transact(opts, method, params...) -} - -// Register is a paid mutator transaction binding the contract method 0xd22057a9. -// -// Solidity: function register(bytes32 label, address owner) returns() -func (_FIFSRegistrar *FIFSRegistrarTransactor) Register(opts *bind.TransactOpts, label [32]byte, owner common.Address) (*types.Transaction, error) { - return _FIFSRegistrar.contract.Transact(opts, "register", label, owner) -} - -// Register is a paid mutator transaction binding the contract method 0xd22057a9. -// -// Solidity: function register(bytes32 label, address owner) returns() -func (_FIFSRegistrar *FIFSRegistrarSession) Register(label [32]byte, owner common.Address) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, label, owner) -} - -// Register is a paid mutator transaction binding the contract method 0xd22057a9. -// -// Solidity: function register(bytes32 label, address owner) returns() -func (_FIFSRegistrar *FIFSRegistrarTransactorSession) Register(label [32]byte, owner common.Address) (*types.Transaction, error) { - return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, label, owner) -} diff --git a/contracts/ens/contract/publicresolver.go b/contracts/ens/contract/publicresolver.go deleted file mode 100644 index 01bfce5e15..0000000000 --- a/contracts/ens/contract/publicresolver.go +++ /dev/null @@ -1,1319 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contract - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = abi.U256 - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// PublicResolverABI is the input ABI used to generate the binding from. -const PublicResolverABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceID\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setText\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentTypes\",\"type\":\"uint256\"}],\"name\":\"ABI\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"setPubkey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"hash\",\"type\":\"bytes\"}],\"name\":\"setContenthash\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"}],\"name\":\"text\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"setABI\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setName\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"contenthash\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"pubkey\",\"outputs\":[{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAddr\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address\"}],\"name\":\"AddrChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NameChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"contentType\",\"type\":\"uint256\"}],\"name\":\"ABIChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"x\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"PubkeyChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"indexedKey\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"key\",\"type\":\"string\"}],\"name\":\"TextChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"hash\",\"type\":\"bytes\"}],\"name\":\"ContenthashChanged\",\"type\":\"event\"}]" - -// PublicResolverBin is the compiled bytecode used for deploying new contracts. -const PublicResolverBin = `0x608060405234801561001057600080fd5b506040516020806112ce8339810180604052602081101561003057600080fd5b505160008054600160a060020a03909216600160a060020a031990921691909117905561126c806100626000396000f3fe6080604052600436106100c45763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301ffc9a781146100c957806310f13a8c146101115780632203ab56146101e957806329cd62ea14610298578063304e6ade146102ce5780633b3b57de1461035257806359d1d43c14610398578063623195b014610491578063691f34311461051a5780637737221314610544578063bc1c58d1146105c8578063c8690233146105f2578063d5fa2b0014610635575b600080fd5b3480156100d557600080fd5b506100fd600480360360208110156100ec57600080fd5b5035600160e060020a03191661066e565b604080519115158252519081900360200190f35b34801561011d57600080fd5b506101e76004803603606081101561013457600080fd5b8135919081019060408101602082013564010000000081111561015657600080fd5b82018360208201111561016857600080fd5b8035906020019184600183028401116401000000008311171561018a57600080fd5b9193909290916020810190356401000000008111156101a857600080fd5b8201836020820111156101ba57600080fd5b803590602001918460018302840111640100000000831117156101dc57600080fd5b5090925090506107db565b005b3480156101f557600080fd5b506102196004803603604081101561020c57600080fd5b508035906020013561094d565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561025c578181015183820152602001610244565b50505050905090810190601f1680156102895780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156102a457600080fd5b506101e7600480360360608110156102bb57600080fd5b5080359060208101359060400135610a65565b3480156102da57600080fd5b506101e7600480360360408110156102f157600080fd5b8135919081019060408101602082013564010000000081111561031357600080fd5b82018360208201111561032557600080fd5b8035906020019184600183028401116401000000008311171561034757600080fd5b509092509050610b65565b34801561035e57600080fd5b5061037c6004803603602081101561037557600080fd5b5035610c7b565b60408051600160a060020a039092168252519081900360200190f35b3480156103a457600080fd5b5061041c600480360360408110156103bb57600080fd5b813591908101906040810160208201356401000000008111156103dd57600080fd5b8201836020820111156103ef57600080fd5b8035906020019184600183028401116401000000008311171561041157600080fd5b509092509050610c96565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561045657818101518382015260200161043e565b50505050905090810190601f1680156104835780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561049d57600080fd5b506101e7600480360360608110156104b457600080fd5b8135916020810135918101906060810160408201356401000000008111156104db57600080fd5b8201836020820111156104ed57600080fd5b8035906020019184600183028401116401000000008311171561050f57600080fd5b509092509050610d60565b34801561052657600080fd5b5061041c6004803603602081101561053d57600080fd5b5035610e5f565b34801561055057600080fd5b506101e76004803603604081101561056757600080fd5b8135919081019060408101602082013564010000000081111561058957600080fd5b82018360208201111561059b57600080fd5b803590602001918460018302840111640100000000831117156105bd57600080fd5b509092509050610f01565b3480156105d457600080fd5b5061041c600480360360208110156105eb57600080fd5b5035611018565b3480156105fe57600080fd5b5061061c6004803603602081101561061557600080fd5b5035611084565b6040805192835260208301919091528051918290030190f35b34801561064157600080fd5b506101e76004803603604081101561065857600080fd5b5080359060200135600160a060020a03166110a1565b6000600160e060020a031982167f3b3b57de0000000000000000000000000000000000000000000000000000000014806106d15750600160e060020a031982167f691f343100000000000000000000000000000000000000000000000000000000145b806107055750600160e060020a031982167f2203ab5600000000000000000000000000000000000000000000000000000000145b806107395750600160e060020a031982167fc869023300000000000000000000000000000000000000000000000000000000145b8061076d5750600160e060020a031982167f59d1d43c00000000000000000000000000000000000000000000000000000000145b806107a15750600160e060020a031982167fbc1c58d100000000000000000000000000000000000000000000000000000000145b806107d55750600160e060020a031982167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6000546040805160e060020a6302571be302815260048101889052905187923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b15801561082e57600080fd5b505afa158015610842573d6000803e3d6000fd5b505050506040513d602081101561085857600080fd5b5051600160a060020a03161461086d57600080fd5b8282600160008981526020019081526020016000206004018787604051808383808284378083019250505092505050908152602001604051809103902091906108b79291906111a5565b50857fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550868688886040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a2505050505050565b600082815260016020819052604082206060915b848111610a53578085161580159061099a5750600081815260058301602052604081205460026000196101006001841615020190911604115b15610a4b57600081815260058301602090815260409182902080548351601f6002600019610100600186161502019093169290920491820184900484028101840190945280845284939192839190830182828015610a395780601f10610a0e57610100808354040283529160200191610a39565b820191906000526020600020905b815481529060010190602001808311610a1c57829003601f168201915b50505050509050935093505050610a5e565b600202610961565b506000925060609150505b9250929050565b6000546040805160e060020a6302571be302815260048101869052905185923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610ab857600080fd5b505afa158015610acc573d6000803e3d6000fd5b505050506040513d6020811015610ae257600080fd5b5051600160a060020a031614610af757600080fd5b604080518082018252848152602080820185815260008881526001835284902092516002840155516003909201919091558151858152908101849052815186927f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46928290030190a250505050565b6000546040805160e060020a6302571be302815260048101869052905185923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610bb857600080fd5b505afa158015610bcc573d6000803e3d6000fd5b505050506040513d6020811015610be257600080fd5b5051600160a060020a031614610bf757600080fd5b6000848152600160205260409020610c139060060184846111a5565b50837fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d7578848460405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a250505050565b600090815260016020526040902054600160a060020a031690565b6060600160008581526020019081526020016000206004018383604051808383808284379190910194855250506040805160209481900385018120805460026001821615610100026000190190911604601f81018790048702830187019093528282529094909350909150830182828015610d525780601f10610d2757610100808354040283529160200191610d52565b820191906000526020600020905b815481529060010190602001808311610d3557829003601f168201915b505050505090509392505050565b6000546040805160e060020a6302571be302815260048101879052905186923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610db357600080fd5b505afa158015610dc7573d6000803e3d6000fd5b505050506040513d6020811015610ddd57600080fd5b5051600160a060020a031614610df257600080fd5b6000198401841615610e0357600080fd5b60008581526001602090815260408083208784526005019091529020610e2a9084846111a5565b50604051849086907faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe390600090a35050505050565b600081815260016020818152604092839020820180548451600294821615610100026000190190911693909304601f81018390048302840183019094528383526060939091830182828015610ef55780601f10610eca57610100808354040283529160200191610ef5565b820191906000526020600020905b815481529060010190602001808311610ed857829003601f168201915b50505050509050919050565b6000546040805160e060020a6302571be302815260048101869052905185923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b158015610f5457600080fd5b505afa158015610f68573d6000803e3d6000fd5b505050506040513d6020811015610f7e57600080fd5b5051600160a060020a031614610f9357600080fd5b6000848152600160208190526040909120610fb0910184846111a5565b50837fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7848460405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a250505050565b60008181526001602081815260409283902060060180548451600294821615610100026000190190911693909304601f81018390048302840183019094528383526060939091830182828015610ef55780601f10610eca57610100808354040283529160200191610ef5565b600090815260016020526040902060028101546003909101549091565b6000546040805160e060020a6302571be302815260048101859052905184923392600160a060020a03909116916302571be391602480820192602092909190829003018186803b1580156110f457600080fd5b505afa158015611108573d6000803e3d6000fd5b505050506040513d602081101561111e57600080fd5b5051600160a060020a03161461113357600080fd5b600083815260016020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0386169081179091558251908152915185927f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd292908290030190a2505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106111e65782800160ff19823516178555611213565b82800160010185558215611213579182015b828111156112135782358255916020019190600101906111f8565b5061121f929150611223565b5090565b61123d91905b8082111561121f5760008155600101611229565b9056fea165627a7a7230582047f310fc746ab2e282cf63ba794d20abb361f9284c6c5f2a2e26151e5b7fab600029` - -// DeployPublicResolver deploys a new Ethereum contract, binding an instance of PublicResolver to it. -func DeployPublicResolver(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address) (common.Address, *types.Transaction, *PublicResolver, error) { - parsed, err := abi.JSON(strings.NewReader(PublicResolverABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(PublicResolverBin), backend, ensAddr) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}, PublicResolverFilterer: PublicResolverFilterer{contract: contract}}, nil -} - -// PublicResolver is an auto generated Go binding around an Ethereum contract. -type PublicResolver struct { - PublicResolverCaller // Read-only binding to the contract - PublicResolverTransactor // Write-only binding to the contract - PublicResolverFilterer // Log filterer for contract events -} - -// PublicResolverCaller is an auto generated read-only Go binding around an Ethereum contract. -type PublicResolverCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PublicResolverTransactor is an auto generated write-only Go binding around an Ethereum contract. -type PublicResolverTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PublicResolverFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type PublicResolverFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PublicResolverSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type PublicResolverSession struct { - Contract *PublicResolver // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// PublicResolverCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type PublicResolverCallerSession struct { - Contract *PublicResolverCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// PublicResolverTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type PublicResolverTransactorSession struct { - Contract *PublicResolverTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// PublicResolverRaw is an auto generated low-level Go binding around an Ethereum contract. -type PublicResolverRaw struct { - Contract *PublicResolver // Generic contract binding to access the raw methods on -} - -// PublicResolverCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type PublicResolverCallerRaw struct { - Contract *PublicResolverCaller // Generic read-only contract binding to access the raw methods on -} - -// PublicResolverTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type PublicResolverTransactorRaw struct { - Contract *PublicResolverTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewPublicResolver creates a new instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolver(address common.Address, backend bind.ContractBackend) (*PublicResolver, error) { - contract, err := bindPublicResolver(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}, PublicResolverFilterer: PublicResolverFilterer{contract: contract}}, nil -} - -// NewPublicResolverCaller creates a new read-only instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolverCaller(address common.Address, caller bind.ContractCaller) (*PublicResolverCaller, error) { - contract, err := bindPublicResolver(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &PublicResolverCaller{contract: contract}, nil -} - -// NewPublicResolverTransactor creates a new write-only instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolverTransactor(address common.Address, transactor bind.ContractTransactor) (*PublicResolverTransactor, error) { - contract, err := bindPublicResolver(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &PublicResolverTransactor{contract: contract}, nil -} - -// NewPublicResolverFilterer creates a new log filterer instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolverFilterer(address common.Address, filterer bind.ContractFilterer) (*PublicResolverFilterer, error) { - contract, err := bindPublicResolver(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &PublicResolverFilterer{contract: contract}, nil -} - -// bindPublicResolver binds a generic wrapper to an already deployed contract. -func bindPublicResolver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(PublicResolverABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_PublicResolver *PublicResolverRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _PublicResolver.Contract.PublicResolverCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_PublicResolver *PublicResolverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _PublicResolver.Contract.PublicResolverTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_PublicResolver *PublicResolverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _PublicResolver.Contract.PublicResolverTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_PublicResolver *PublicResolverCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _PublicResolver.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_PublicResolver *PublicResolverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _PublicResolver.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_PublicResolver *PublicResolverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _PublicResolver.Contract.contract.Transact(opts, method, params...) -} - -// ABI is a free data retrieval call binding the contract method 0x2203ab56. -// -// Solidity: function ABI(bytes32 node, uint256 contentTypes) constant returns(uint256, bytes) -func (_PublicResolver *PublicResolverCaller) ABI(opts *bind.CallOpts, node [32]byte, contentTypes *big.Int) (*big.Int, []byte, error) { - var ( - ret0 = new(*big.Int) - ret1 = new([]byte) - ) - out := &[]interface{}{ - ret0, - ret1, - } - err := _PublicResolver.contract.Call(opts, out, "ABI", node, contentTypes) - return *ret0, *ret1, err -} - -// ABI is a free data retrieval call binding the contract method 0x2203ab56. -// -// Solidity: function ABI(bytes32 node, uint256 contentTypes) constant returns(uint256, bytes) -func (_PublicResolver *PublicResolverSession) ABI(node [32]byte, contentTypes *big.Int) (*big.Int, []byte, error) { - return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) -} - -// ABI is a free data retrieval call binding the contract method 0x2203ab56. -// -// Solidity: function ABI(bytes32 node, uint256 contentTypes) constant returns(uint256, bytes) -func (_PublicResolver *PublicResolverCallerSession) ABI(node [32]byte, contentTypes *big.Int) (*big.Int, []byte, error) { - return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) -} - -// Addr is a free data retrieval call binding the contract method 0x3b3b57de. -// -// Solidity: function addr(bytes32 node) constant returns(address) -func (_PublicResolver *PublicResolverCaller) Addr(opts *bind.CallOpts, node [32]byte) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "addr", node) - return *ret0, err -} - -// Addr is a free data retrieval call binding the contract method 0x3b3b57de. -// -// Solidity: function addr(bytes32 node) constant returns(address) -func (_PublicResolver *PublicResolverSession) Addr(node [32]byte) (common.Address, error) { - return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) -} - -// Addr is a free data retrieval call binding the contract method 0x3b3b57de. -// -// Solidity: function addr(bytes32 node) constant returns(address) -func (_PublicResolver *PublicResolverCallerSession) Addr(node [32]byte) (common.Address, error) { - return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) -} - -// Contenthash is a free data retrieval call binding the contract method 0xbc1c58d1. -// -// Solidity: function contenthash(bytes32 node) constant returns(bytes) -func (_PublicResolver *PublicResolverCaller) Contenthash(opts *bind.CallOpts, node [32]byte) ([]byte, error) { - var ( - ret0 = new([]byte) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "contenthash", node) - return *ret0, err -} - -// Contenthash is a free data retrieval call binding the contract method 0xbc1c58d1. -// -// Solidity: function contenthash(bytes32 node) constant returns(bytes) -func (_PublicResolver *PublicResolverSession) Contenthash(node [32]byte) ([]byte, error) { - return _PublicResolver.Contract.Contenthash(&_PublicResolver.CallOpts, node) -} - -// Contenthash is a free data retrieval call binding the contract method 0xbc1c58d1. -// -// Solidity: function contenthash(bytes32 node) constant returns(bytes) -func (_PublicResolver *PublicResolverCallerSession) Contenthash(node [32]byte) ([]byte, error) { - return _PublicResolver.Contract.Contenthash(&_PublicResolver.CallOpts, node) -} - -// Name is a free data retrieval call binding the contract method 0x691f3431. -// -// Solidity: function name(bytes32 node) constant returns(string) -func (_PublicResolver *PublicResolverCaller) Name(opts *bind.CallOpts, node [32]byte) (string, error) { - var ( - ret0 = new(string) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "name", node) - return *ret0, err -} - -// Name is a free data retrieval call binding the contract method 0x691f3431. -// -// Solidity: function name(bytes32 node) constant returns(string) -func (_PublicResolver *PublicResolverSession) Name(node [32]byte) (string, error) { - return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) -} - -// Name is a free data retrieval call binding the contract method 0x691f3431. -// -// Solidity: function name(bytes32 node) constant returns(string) -func (_PublicResolver *PublicResolverCallerSession) Name(node [32]byte) (string, error) { - return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) -} - -// Pubkey is a free data retrieval call binding the contract method 0xc8690233. -// -// Solidity: function pubkey(bytes32 node) constant returns(bytes32 x, bytes32 y) -func (_PublicResolver *PublicResolverCaller) Pubkey(opts *bind.CallOpts, node [32]byte) (struct { - X [32]byte - Y [32]byte -}, error) { - ret := new(struct { - X [32]byte - Y [32]byte - }) - out := ret - err := _PublicResolver.contract.Call(opts, out, "pubkey", node) - return *ret, err -} - -// Pubkey is a free data retrieval call binding the contract method 0xc8690233. -// -// Solidity: function pubkey(bytes32 node) constant returns(bytes32 x, bytes32 y) -func (_PublicResolver *PublicResolverSession) Pubkey(node [32]byte) (struct { - X [32]byte - Y [32]byte -}, error) { - return _PublicResolver.Contract.Pubkey(&_PublicResolver.CallOpts, node) -} - -// Pubkey is a free data retrieval call binding the contract method 0xc8690233. -// -// Solidity: function pubkey(bytes32 node) constant returns(bytes32 x, bytes32 y) -func (_PublicResolver *PublicResolverCallerSession) Pubkey(node [32]byte) (struct { - X [32]byte - Y [32]byte -}, error) { - return _PublicResolver.Contract.Pubkey(&_PublicResolver.CallOpts, node) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceID) constant returns(bool) -func (_PublicResolver *PublicResolverCaller) SupportsInterface(opts *bind.CallOpts, interfaceID [4]byte) (bool, error) { - var ( - ret0 = new(bool) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "supportsInterface", interfaceID) - return *ret0, err -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceID) constant returns(bool) -func (_PublicResolver *PublicResolverSession) SupportsInterface(interfaceID [4]byte) (bool, error) { - return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(bytes4 interfaceID) constant returns(bool) -func (_PublicResolver *PublicResolverCallerSession) SupportsInterface(interfaceID [4]byte) (bool, error) { - return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) -} - -// Text is a free data retrieval call binding the contract method 0x59d1d43c. -// -// Solidity: function text(bytes32 node, string key) constant returns(string) -func (_PublicResolver *PublicResolverCaller) Text(opts *bind.CallOpts, node [32]byte, key string) (string, error) { - var ( - ret0 = new(string) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "text", node, key) - return *ret0, err -} - -// Text is a free data retrieval call binding the contract method 0x59d1d43c. -// -// Solidity: function text(bytes32 node, string key) constant returns(string) -func (_PublicResolver *PublicResolverSession) Text(node [32]byte, key string) (string, error) { - return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) -} - -// Text is a free data retrieval call binding the contract method 0x59d1d43c. -// -// Solidity: function text(bytes32 node, string key) constant returns(string) -func (_PublicResolver *PublicResolverCallerSession) Text(node [32]byte, key string) (string, error) { - return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) -} - -// SetABI is a paid mutator transaction binding the contract method 0x623195b0. -// -// Solidity: function setABI(bytes32 node, uint256 contentType, bytes data) returns() -func (_PublicResolver *PublicResolverTransactor) SetABI(opts *bind.TransactOpts, node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setABI", node, contentType, data) -} - -// SetABI is a paid mutator transaction binding the contract method 0x623195b0. -// -// Solidity: function setABI(bytes32 node, uint256 contentType, bytes data) returns() -func (_PublicResolver *PublicResolverSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) -} - -// SetABI is a paid mutator transaction binding the contract method 0x623195b0. -// -// Solidity: function setABI(bytes32 node, uint256 contentType, bytes data) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) -} - -// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. -// -// Solidity: function setAddr(bytes32 node, address addr) returns() -func (_PublicResolver *PublicResolverTransactor) SetAddr(opts *bind.TransactOpts, node [32]byte, addr common.Address) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setAddr", node, addr) -} - -// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. -// -// Solidity: function setAddr(bytes32 node, address addr) returns() -func (_PublicResolver *PublicResolverSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { - return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) -} - -// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. -// -// Solidity: function setAddr(bytes32 node, address addr) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { - return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) -} - -// SetContenthash is a paid mutator transaction binding the contract method 0x304e6ade. -// -// Solidity: function setContenthash(bytes32 node, bytes hash) returns() -func (_PublicResolver *PublicResolverTransactor) SetContenthash(opts *bind.TransactOpts, node [32]byte, hash []byte) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setContenthash", node, hash) -} - -// SetContenthash is a paid mutator transaction binding the contract method 0x304e6ade. -// -// Solidity: function setContenthash(bytes32 node, bytes hash) returns() -func (_PublicResolver *PublicResolverSession) SetContenthash(node [32]byte, hash []byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetContenthash(&_PublicResolver.TransactOpts, node, hash) -} - -// SetContenthash is a paid mutator transaction binding the contract method 0x304e6ade. -// -// Solidity: function setContenthash(bytes32 node, bytes hash) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetContenthash(node [32]byte, hash []byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetContenthash(&_PublicResolver.TransactOpts, node, hash) -} - -// SetName is a paid mutator transaction binding the contract method 0x77372213. -// -// Solidity: function setName(bytes32 node, string name) returns() -func (_PublicResolver *PublicResolverTransactor) SetName(opts *bind.TransactOpts, node [32]byte, name string) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setName", node, name) -} - -// SetName is a paid mutator transaction binding the contract method 0x77372213. -// -// Solidity: function setName(bytes32 node, string name) returns() -func (_PublicResolver *PublicResolverSession) SetName(node [32]byte, name string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) -} - -// SetName is a paid mutator transaction binding the contract method 0x77372213. -// -// Solidity: function setName(bytes32 node, string name) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetName(node [32]byte, name string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) -} - -// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. -// -// Solidity: function setPubkey(bytes32 node, bytes32 x, bytes32 y) returns() -func (_PublicResolver *PublicResolverTransactor) SetPubkey(opts *bind.TransactOpts, node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setPubkey", node, x, y) -} - -// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. -// -// Solidity: function setPubkey(bytes32 node, bytes32 x, bytes32 y) returns() -func (_PublicResolver *PublicResolverSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) -} - -// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. -// -// Solidity: function setPubkey(bytes32 node, bytes32 x, bytes32 y) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) -} - -// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. -// -// Solidity: function setText(bytes32 node, string key, string value) returns() -func (_PublicResolver *PublicResolverTransactor) SetText(opts *bind.TransactOpts, node [32]byte, key string, value string) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setText", node, key, value) -} - -// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. -// -// Solidity: function setText(bytes32 node, string key, string value) returns() -func (_PublicResolver *PublicResolverSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) -} - -// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. -// -// Solidity: function setText(bytes32 node, string key, string value) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) -} - -// PublicResolverABIChangedIterator is returned from FilterABIChanged and is used to iterate over the raw logs and unpacked data for ABIChanged events raised by the PublicResolver contract. -type PublicResolverABIChangedIterator struct { - Event *PublicResolverABIChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverABIChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverABIChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverABIChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *PublicResolverABIChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverABIChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverABIChanged represents a ABIChanged event raised by the PublicResolver contract. -type PublicResolverABIChanged struct { - Node [32]byte - ContentType *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterABIChanged is a free log retrieval operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. -// -// Solidity: event ABIChanged(bytes32 indexed node, uint256 indexed contentType) -func (_PublicResolver *PublicResolverFilterer) FilterABIChanged(opts *bind.FilterOpts, node [][32]byte, contentType []*big.Int) (*PublicResolverABIChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var contentTypeRule []interface{} - for _, contentTypeItem := range contentType { - contentTypeRule = append(contentTypeRule, contentTypeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ABIChanged", nodeRule, contentTypeRule) - if err != nil { - return nil, err - } - return &PublicResolverABIChangedIterator{contract: _PublicResolver.contract, event: "ABIChanged", logs: logs, sub: sub}, nil -} - -// WatchABIChanged is a free log subscription operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. -// -// Solidity: event ABIChanged(bytes32 indexed node, uint256 indexed contentType) -func (_PublicResolver *PublicResolverFilterer) WatchABIChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverABIChanged, node [][32]byte, contentType []*big.Int) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var contentTypeRule []interface{} - for _, contentTypeItem := range contentType { - contentTypeRule = append(contentTypeRule, contentTypeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ABIChanged", nodeRule, contentTypeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverABIChanged) - if err := _PublicResolver.contract.UnpackLog(event, "ABIChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverAddrChangedIterator is returned from FilterAddrChanged and is used to iterate over the raw logs and unpacked data for AddrChanged events raised by the PublicResolver contract. -type PublicResolverAddrChangedIterator struct { - Event *PublicResolverAddrChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverAddrChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverAddrChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverAddrChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *PublicResolverAddrChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverAddrChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverAddrChanged represents a AddrChanged event raised by the PublicResolver contract. -type PublicResolverAddrChanged struct { - Node [32]byte - A common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAddrChanged is a free log retrieval operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. -// -// Solidity: event AddrChanged(bytes32 indexed node, address a) -func (_PublicResolver *PublicResolverFilterer) FilterAddrChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverAddrChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "AddrChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverAddrChangedIterator{contract: _PublicResolver.contract, event: "AddrChanged", logs: logs, sub: sub}, nil -} - -// WatchAddrChanged is a free log subscription operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. -// -// Solidity: event AddrChanged(bytes32 indexed node, address a) -func (_PublicResolver *PublicResolverFilterer) WatchAddrChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverAddrChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "AddrChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverAddrChanged) - if err := _PublicResolver.contract.UnpackLog(event, "AddrChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverContenthashChangedIterator is returned from FilterContenthashChanged and is used to iterate over the raw logs and unpacked data for ContenthashChanged events raised by the PublicResolver contract. -type PublicResolverContenthashChangedIterator struct { - Event *PublicResolverContenthashChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverContenthashChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverContenthashChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverContenthashChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *PublicResolverContenthashChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverContenthashChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverContenthashChanged represents a ContenthashChanged event raised by the PublicResolver contract. -type PublicResolverContenthashChanged struct { - Node [32]byte - Hash []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterContenthashChanged is a free log retrieval operation binding the contract event 0xe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d7578. -// -// Solidity: event ContenthashChanged(bytes32 indexed node, bytes hash) -func (_PublicResolver *PublicResolverFilterer) FilterContenthashChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverContenthashChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ContenthashChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverContenthashChangedIterator{contract: _PublicResolver.contract, event: "ContenthashChanged", logs: logs, sub: sub}, nil -} - -// WatchContenthashChanged is a free log subscription operation binding the contract event 0xe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d7578. -// -// Solidity: event ContenthashChanged(bytes32 indexed node, bytes hash) -func (_PublicResolver *PublicResolverFilterer) WatchContenthashChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverContenthashChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ContenthashChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverContenthashChanged) - if err := _PublicResolver.contract.UnpackLog(event, "ContenthashChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverNameChangedIterator is returned from FilterNameChanged and is used to iterate over the raw logs and unpacked data for NameChanged events raised by the PublicResolver contract. -type PublicResolverNameChangedIterator struct { - Event *PublicResolverNameChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverNameChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverNameChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverNameChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *PublicResolverNameChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverNameChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverNameChanged represents a NameChanged event raised by the PublicResolver contract. -type PublicResolverNameChanged struct { - Node [32]byte - Name string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNameChanged is a free log retrieval operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. -// -// Solidity: event NameChanged(bytes32 indexed node, string name) -func (_PublicResolver *PublicResolverFilterer) FilterNameChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverNameChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "NameChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverNameChangedIterator{contract: _PublicResolver.contract, event: "NameChanged", logs: logs, sub: sub}, nil -} - -// WatchNameChanged is a free log subscription operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. -// -// Solidity: event NameChanged(bytes32 indexed node, string name) -func (_PublicResolver *PublicResolverFilterer) WatchNameChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverNameChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "NameChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverNameChanged) - if err := _PublicResolver.contract.UnpackLog(event, "NameChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverPubkeyChangedIterator is returned from FilterPubkeyChanged and is used to iterate over the raw logs and unpacked data for PubkeyChanged events raised by the PublicResolver contract. -type PublicResolverPubkeyChangedIterator struct { - Event *PublicResolverPubkeyChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverPubkeyChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverPubkeyChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverPubkeyChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *PublicResolverPubkeyChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverPubkeyChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverPubkeyChanged represents a PubkeyChanged event raised by the PublicResolver contract. -type PublicResolverPubkeyChanged struct { - Node [32]byte - X [32]byte - Y [32]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterPubkeyChanged is a free log retrieval operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. -// -// Solidity: event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y) -func (_PublicResolver *PublicResolverFilterer) FilterPubkeyChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverPubkeyChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "PubkeyChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverPubkeyChangedIterator{contract: _PublicResolver.contract, event: "PubkeyChanged", logs: logs, sub: sub}, nil -} - -// WatchPubkeyChanged is a free log subscription operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. -// -// Solidity: event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y) -func (_PublicResolver *PublicResolverFilterer) WatchPubkeyChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverPubkeyChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "PubkeyChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverPubkeyChanged) - if err := _PublicResolver.contract.UnpackLog(event, "PubkeyChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverTextChangedIterator is returned from FilterTextChanged and is used to iterate over the raw logs and unpacked data for TextChanged events raised by the PublicResolver contract. -type PublicResolverTextChangedIterator struct { - Event *PublicResolverTextChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverTextChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverTextChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverTextChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *PublicResolverTextChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverTextChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverTextChanged represents a TextChanged event raised by the PublicResolver contract. -type PublicResolverTextChanged struct { - Node [32]byte - IndexedKey string - Key string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTextChanged is a free log retrieval operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. -// -// Solidity: event TextChanged(bytes32 indexed node, string indexedKey, string key) -func (_PublicResolver *PublicResolverFilterer) FilterTextChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverTextChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "TextChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverTextChangedIterator{contract: _PublicResolver.contract, event: "TextChanged", logs: logs, sub: sub}, nil -} - -// WatchTextChanged is a free log subscription operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. -// -// Solidity: event TextChanged(bytes32 indexed node, string indexedKey, string key) -func (_PublicResolver *PublicResolverFilterer) WatchTextChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverTextChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "TextChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverTextChanged) - if err := _PublicResolver.contract.UnpackLog(event, "TextChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/contracts/ens/ens.go b/contracts/ens/ens.go deleted file mode 100644 index 6fed172dcd..0000000000 --- a/contracts/ens/ens.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ens - -//go:generate abigen --sol contract/ENS.sol --pkg contract --out contract/ens.go -//go:generate abigen --sol contract/ENSRegistry.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/ensregistry.go -//go:generate abigen --sol contract/FIFSRegistrar.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/fifsregistrar.go -//go:generate abigen --sol contract/PublicResolver.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/publicresolver.go - -import ( - "encoding/binary" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/ens/contract" - "github.com/ethereum/go-ethereum/contracts/ens/fallback_contract" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" -) - -var ( - MainNetAddress = common.HexToAddress("0x314159265dD8dbb310642f98f50C066173C1259b") - TestNetAddress = common.HexToAddress("0x112234455c3a32fd11230c42e7bccd4a84e02010") - contentHash_Interface_Id [4]byte -) - -const contentHash_Interface_Id_Spec = 0xbc1c58d1 - -func init() { - binary.BigEndian.PutUint32(contentHash_Interface_Id[:], contentHash_Interface_Id_Spec) -} - -// ENS is the swarm domain name registry and resolver -type ENS struct { - *contract.ENSSession - contractBackend bind.ContractBackend -} - -// NewENS creates a struct exposing convenient high-level operations for interacting with -// the Ethereum Name Service. -func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*ENS, error) { - ens, err := contract.NewENS(contractAddr, contractBackend) - if err != nil { - return nil, err - } - return &ENS{ - &contract.ENSSession{ - Contract: ens, - TransactOpts: *transactOpts, - }, - contractBackend, - }, nil -} - -// DeployENS deploys an instance of the ENS nameservice, with a 'first-in, first-served' root registrar. -func DeployENS(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (common.Address, *ENS, error) { - // Deploy the ENS registry - ensAddr, _, _, err := contract.DeployENSRegistry(transactOpts, contractBackend) - if err != nil { - return ensAddr, nil, err - } - ens, err := NewENS(transactOpts, ensAddr, contractBackend) - if err != nil { - return ensAddr, nil, err - } - // Deploy the registrar - regAddr, _, _, err := contract.DeployFIFSRegistrar(transactOpts, contractBackend, ensAddr, [32]byte{}) - if err != nil { - return ensAddr, nil, err - } - // Set the registrar as owner of the ENS root - if _, err = ens.SetOwner([32]byte{}, regAddr); err != nil { - return ensAddr, nil, err - } - return ensAddr, ens, nil -} - -func ensParentNode(name string) (common.Hash, common.Hash) { - parts := strings.SplitN(name, ".", 2) - label := crypto.Keccak256Hash([]byte(parts[0])) - if len(parts) == 1 { - return [32]byte{}, label - } - parentNode, parentLabel := ensParentNode(parts[1]) - return crypto.Keccak256Hash(parentNode[:], parentLabel[:]), label -} - -func EnsNode(name string) common.Hash { - parentNode, parentLabel := ensParentNode(name) - return crypto.Keccak256Hash(parentNode[:], parentLabel[:]) -} - -func (ens *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) { - resolverAddr, err := ens.Resolver(node) - if err != nil { - return nil, err - } - resolver, err := contract.NewPublicResolver(resolverAddr, ens.contractBackend) - if err != nil { - return nil, err - } - return &contract.PublicResolverSession{ - Contract: resolver, - TransactOpts: ens.TransactOpts, - }, nil -} - -func (ens *ENS) getFallbackResolver(node [32]byte) (*fallback_contract.PublicResolverSession, error) { - resolverAddr, err := ens.Resolver(node) - if err != nil { - return nil, err - } - resolver, err := fallback_contract.NewPublicResolver(resolverAddr, ens.contractBackend) - if err != nil { - return nil, err - } - return &fallback_contract.PublicResolverSession{ - Contract: resolver, - TransactOpts: ens.TransactOpts, - }, nil -} - -func (ens *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) { - registrarAddr, err := ens.Owner(node) - if err != nil { - return nil, err - } - registrar, err := contract.NewFIFSRegistrar(registrarAddr, ens.contractBackend) - if err != nil { - return nil, err - } - return &contract.FIFSRegistrarSession{ - Contract: registrar, - TransactOpts: ens.TransactOpts, - }, nil -} - -// Resolve is a non-transactional call that returns the content hash associated with a name. -func (ens *ENS) Resolve(name string) (common.Hash, error) { - node := EnsNode(name) - - resolver, err := ens.getResolver(node) - if err != nil { - return common.Hash{}, err - } - - // IMPORTANT: The old contract is deprecated. This code should be removed latest on June 1st 2019 - supported, err := resolver.SupportsInterface(contentHash_Interface_Id) - if err != nil { - return common.Hash{}, err - } - - if !supported { - resolver, err := ens.getFallbackResolver(node) - if err != nil { - return common.Hash{}, err - } - ret, err := resolver.Content(node) - if err != nil { - return common.Hash{}, err - } - return common.BytesToHash(ret[:]), nil - } - - // END DEPRECATED CODE - - contentHash, err := resolver.Contenthash(node) - if err != nil { - return common.Hash{}, err - } - - return extractContentHash(contentHash) -} - -// Addr is a non-transactional call that returns the address associated with a name. -func (ens *ENS) Addr(name string) (common.Address, error) { - node := EnsNode(name) - - resolver, err := ens.getResolver(node) - if err != nil { - return common.Address{}, err - } - ret, err := resolver.Addr(node) - if err != nil { - return common.Address{}, err - } - return common.BytesToAddress(ret[:]), nil -} - -// SetAddress sets the address associated with a name. Only works if the caller -// owns the name, and the associated resolver implements a `setAddress` function. -func (ens *ENS) SetAddr(name string, addr common.Address) (*types.Transaction, error) { - node := EnsNode(name) - - resolver, err := ens.getResolver(node) - if err != nil { - return nil, err - } - opts := ens.TransactOpts - opts.GasLimit = 200000 - return resolver.Contract.SetAddr(&opts, node, addr) -} - -// Register registers a new domain name for the caller, making them the owner of the new name. -// Only works if the registrar for the parent domain implements the FIFS registrar protocol. -func (ens *ENS) Register(name string) (*types.Transaction, error) { - parentNode, label := ensParentNode(name) - registrar, err := ens.getRegistrar(parentNode) - if err != nil { - return nil, err - } - return registrar.Contract.Register(&ens.TransactOpts, label, ens.TransactOpts.From) -} - -// SetContentHash sets the content hash associated with a name. Only works if the caller -// owns the name, and the associated resolver implements a `setContenthash` function. -func (ens *ENS) SetContentHash(name string, hash []byte) (*types.Transaction, error) { - node := EnsNode(name) - - resolver, err := ens.getResolver(node) - if err != nil { - return nil, err - } - - opts := ens.TransactOpts - opts.GasLimit = 200000 - - // IMPORTANT: The old contract is deprecated. This code should be removed latest on June 1st 2019 - supported, err := resolver.SupportsInterface(contentHash_Interface_Id) - if err != nil { - return nil, err - } - - if !supported { - resolver, err := ens.getFallbackResolver(node) - if err != nil { - return nil, err - } - opts := ens.TransactOpts - opts.GasLimit = 200000 - var b [32]byte - copy(b[:], hash) - return resolver.Contract.SetContent(&opts, node, b) - } - - // END DEPRECATED CODE - return resolver.Contract.SetContenthash(&opts, node, hash) -} diff --git a/contracts/ens/ens_test.go b/contracts/ens/ens_test.go deleted file mode 100644 index c65df836ad..0000000000 --- a/contracts/ens/ens_test.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package ens - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/ens/contract" - "github.com/ethereum/go-ethereum/contracts/ens/fallback_contract" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/crypto" -) - -var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - name = "my name on ENS" - hash = crypto.Keccak256Hash([]byte("my content")) - fallbackHash = crypto.Keccak256Hash([]byte("my content hash")) - addr = crypto.PubkeyToAddress(key.PublicKey) - testAddr = common.HexToAddress("0x1234123412341234123412341234123412341234") -) - -func TestENS(t *testing.T) { - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) - transactOpts := bind.NewKeyedTransactor(key) - - ensAddr, ens, err := DeployENS(transactOpts, contractBackend) - if err != nil { - t.Fatalf("can't deploy root registry: %v", err) - } - contractBackend.Commit() - - // Set ourself as the owner of the name. - if _, err := ens.Register(name); err != nil { - t.Fatalf("can't register: %v", err) - } - contractBackend.Commit() - - // Deploy a resolver and make it responsible for the name. - resolverAddr, _, _, err := contract.DeployPublicResolver(transactOpts, contractBackend, ensAddr) - if err != nil { - t.Fatalf("can't deploy resolver: %v", err) - } - - if _, err := ens.SetResolver(EnsNode(name), resolverAddr); err != nil { - t.Fatalf("can't set resolver: %v", err) - } - contractBackend.Commit() - - // Set the content hash for the name. - cid, err := EncodeSwarmHash(hash) - if err != nil { - t.Fatal(err) - } - if _, err = ens.SetContentHash(name, cid); err != nil { - t.Fatalf("can't set content hash: %v", err) - } - contractBackend.Commit() - - // Try to resolve the name. - resolvedHash, err := ens.Resolve(name) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if resolvedHash.Hex() != hash.Hex() { - t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), resolvedHash.Hex()) - } - - // set the address for the name - if _, err = ens.SetAddr(name, testAddr); err != nil { - t.Fatalf("can't set address: %v", err) - } - contractBackend.Commit() - - // Try to resolve the name to an address - recoveredAddr, err := ens.Addr(name) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if testAddr.Hex() != recoveredAddr.Hex() { - t.Fatalf("resolve error, expected %v, got %v", testAddr.Hex(), recoveredAddr.Hex()) - } - - // deploy the fallback contract and see that the fallback mechanism works - fallbackResolverAddr, _, _, err := fallback_contract.DeployPublicResolver(transactOpts, contractBackend, ensAddr) - if err != nil { - t.Fatalf("can't deploy resolver: %v", err) - } - if _, err := ens.SetResolver(EnsNode(name), fallbackResolverAddr); err != nil { - t.Fatalf("can't set resolver: %v", err) - } - contractBackend.Commit() - - // Set the content hash for the name. - if _, err = ens.SetContentHash(name, fallbackHash.Bytes()); err != nil { - t.Fatalf("can't set content hash: %v", err) - } - contractBackend.Commit() - - // Try to resolve the name. - fallbackResolvedHash, err := ens.Resolve(name) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if fallbackResolvedHash.Hex() != fallbackHash.Hex() { - t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), resolvedHash.Hex()) - } -} diff --git a/contracts/ens/fallback_contract/PublicResolver.sol b/contracts/ens/fallback_contract/PublicResolver.sol deleted file mode 100644 index 9dcc95689e..0000000000 --- a/contracts/ens/fallback_contract/PublicResolver.sol +++ /dev/null @@ -1,212 +0,0 @@ -pragma solidity ^0.4.0; - -import './AbstractENS.sol'; - -/** - * A simple resolver anyone can use; only allows the owner of a node to set its - * address. - */ -contract PublicResolver { - bytes4 constant INTERFACE_META_ID = 0x01ffc9a7; - bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de; - bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5; - bytes4 constant NAME_INTERFACE_ID = 0x691f3431; - bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; - bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; - bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; - - event AddrChanged(bytes32 indexed node, address a); - event ContentChanged(bytes32 indexed node, bytes32 hash); - event NameChanged(bytes32 indexed node, string name); - event ABIChanged(bytes32 indexed node, uint256 indexed contentType); - event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); - event TextChanged(bytes32 indexed node, string indexed indexedKey, string key); - - struct PublicKey { - bytes32 x; - bytes32 y; - } - - struct Record { - address addr; - bytes32 content; - string name; - PublicKey pubkey; - mapping(string=>string) text; - mapping(uint256=>bytes) abis; - } - - AbstractENS ens; - mapping(bytes32=>Record) records; - - modifier only_owner(bytes32 node) { - if (ens.owner(node) != msg.sender) throw; - _; - } - - /** - * Constructor. - * @param ensAddr The ENS registrar contract. - */ - function PublicResolver(AbstractENS ensAddr) { - ens = ensAddr; - } - - /** - * Returns true if the resolver implements the interface specified by the provided hash. - * @param interfaceID The ID of the interface to check for. - * @return True if the contract implements the requested interface. - */ - function supportsInterface(bytes4 interfaceID) constant returns (bool) { - return interfaceID == ADDR_INTERFACE_ID || - interfaceID == CONTENT_INTERFACE_ID || - interfaceID == NAME_INTERFACE_ID || - interfaceID == ABI_INTERFACE_ID || - interfaceID == PUBKEY_INTERFACE_ID || - interfaceID == TEXT_INTERFACE_ID || - interfaceID == INTERFACE_META_ID; - } - - /** - * Returns the address associated with an ENS node. - * @param node The ENS node to query. - * @return The associated address. - */ - function addr(bytes32 node) constant returns (address ret) { - ret = records[node].addr; - } - - /** - * Sets the address associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param addr The address to set. - */ - function setAddr(bytes32 node, address addr) only_owner(node) { - records[node].addr = addr; - AddrChanged(node, addr); - } - - /** - * Returns the content hash associated with an ENS node. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. - * @param node The ENS node to query. - * @return The associated content hash. - */ - function content(bytes32 node) constant returns (bytes32 ret) { - ret = records[node].content; - } - - /** - * Sets the content hash associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. - * @param node The node to update. - * @param hash The content hash to set - */ - function setContent(bytes32 node, bytes32 hash) only_owner(node) { - records[node].content = hash; - ContentChanged(node, hash); - } - - /** - * Returns the name associated with an ENS node, for reverse records. - * Defined in EIP181. - * @param node The ENS node to query. - * @return The associated name. - */ - function name(bytes32 node) constant returns (string ret) { - ret = records[node].name; - } - - /** - * Sets the name associated with an ENS node, for reverse records. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param name The name to set. - */ - function setName(bytes32 node, string name) only_owner(node) { - records[node].name = name; - NameChanged(node, name); - } - - /** - * Returns the ABI associated with an ENS node. - * Defined in EIP205. - * @param node The ENS node to query - * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. - * @return contentType The content type of the return value - * @return data The ABI data - */ - function ABI(bytes32 node, uint256 contentTypes) constant returns (uint256 contentType, bytes data) { - var record = records[node]; - for(contentType = 1; contentType <= contentTypes; contentType <<= 1) { - if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { - data = record.abis[contentType]; - return; - } - } - contentType = 0; - } - - /** - * Sets the ABI associated with an ENS node. - * Nodes may have one ABI of each content type. To remove an ABI, set it to - * the empty string. - * @param node The node to update. - * @param contentType The content type of the ABI - * @param data The ABI data. - */ - function setABI(bytes32 node, uint256 contentType, bytes data) only_owner(node) { - // Content types must be powers of 2 - if (((contentType - 1) & contentType) != 0) throw; - - records[node].abis[contentType] = data; - ABIChanged(node, contentType); - } - - /** - * Returns the SECP256k1 public key associated with an ENS node. - * Defined in EIP 619. - * @param node The ENS node to query - * @return x, y the X and Y coordinates of the curve point for the public key. - */ - function pubkey(bytes32 node) constant returns (bytes32 x, bytes32 y) { - return (records[node].pubkey.x, records[node].pubkey.y); - } - - /** - * Sets the SECP256k1 public key associated with an ENS node. - * @param node The ENS node to query - * @param x the X coordinate of the curve point for the public key. - * @param y the Y coordinate of the curve point for the public key. - */ - function setPubkey(bytes32 node, bytes32 x, bytes32 y) only_owner(node) { - records[node].pubkey = PublicKey(x, y); - PubkeyChanged(node, x, y); - } - - /** - * Returns the text data associated with an ENS node and key. - * @param node The ENS node to query. - * @param key The text data key to query. - * @return The associated text data. - */ - function text(bytes32 node, string key) constant returns (string ret) { - ret = records[node].text[key]; - } - - /** - * Sets the text data associated with an ENS node and key. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param key The key to set. - * @param value The text data value to set. - */ - function setText(bytes32 node, string key, string value) only_owner(node) { - records[node].text[key] = value; - TextChanged(node, key, key); - } -} diff --git a/contracts/ens/fallback_contract/publicresolver.go b/contracts/ens/fallback_contract/publicresolver.go deleted file mode 100644 index a2a4be1c16..0000000000 --- a/contracts/ens/fallback_contract/publicresolver.go +++ /dev/null @@ -1,1321 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package fallback_contract - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// PublicResolverABI is the input ABI used to generate the binding from. -const PublicResolverABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceID\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setText\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentTypes\",\"type\":\"uint256\"}],\"name\":\"ABI\",\"outputs\":[{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"setPubkey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"content\",\"outputs\":[{\"name\":\"ret\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"addr\",\"outputs\":[{\"name\":\"ret\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"key\",\"type\":\"string\"}],\"name\":\"text\",\"outputs\":[{\"name\":\"ret\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"contentType\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"setABI\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"name\",\"outputs\":[{\"name\":\"ret\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setName\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"setContent\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"}],\"name\":\"pubkey\",\"outputs\":[{\"name\":\"x\",\"type\":\"bytes32\"},{\"name\":\"y\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"node\",\"type\":\"bytes32\"},{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAddr\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"ensAddr\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"a\",\"type\":\"address\"}],\"name\":\"AddrChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"ContentChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NameChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"contentType\",\"type\":\"uint256\"}],\"name\":\"ABIChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"x\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"y\",\"type\":\"bytes32\"}],\"name\":\"PubkeyChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"node\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"indexedKey\",\"type\":\"string\"},{\"indexed\":false,\"name\":\"key\",\"type\":\"string\"}],\"name\":\"TextChanged\",\"type\":\"event\"}]" - -// PublicResolverBin is the compiled bytecode used for deploying new contracts. -const PublicResolverBin = `0x6060604052341561000f57600080fd5b6040516020806111b28339810160405280805160008054600160a060020a03909216600160a060020a0319909216919091179055505061115e806100546000396000f3006060604052600436106100ab5763ffffffff60e060020a60003504166301ffc9a781146100b057806310f13a8c146100e45780632203ab561461017e57806329cd62ea146102155780632dff6941146102315780633b3b57de1461025957806359d1d43c1461028b578063623195b014610358578063691f3431146103b457806377372213146103ca578063c3d014d614610420578063c869023314610439578063d5fa2b0014610467575b600080fd5b34156100bb57600080fd5b6100d0600160e060020a031960043516610489565b604051901515815260200160405180910390f35b34156100ef57600080fd5b61017c600480359060446024803590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080601f0160208091040260200160405190810160405281815292919060208401838380828437509496506105f695505050505050565b005b341561018957600080fd5b610197600435602435610807565b60405182815260406020820181815290820183818151815260200191508051906020019080838360005b838110156101d95780820151838201526020016101c1565b50505050905090810190601f1680156102065780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561022057600080fd5b61017c600435602435604435610931565b341561023c57600080fd5b610247600435610a30565b60405190815260200160405180910390f35b341561026457600080fd5b61026f600435610a46565b604051600160a060020a03909116815260200160405180910390f35b341561029657600080fd5b6102e1600480359060446024803590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610a6195505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561031d578082015183820152602001610305565b50505050905090810190601f16801561034a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561036357600080fd5b61017c600480359060248035919060649060443590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610b8095505050505050565b34156103bf57600080fd5b6102e1600435610c7c565b34156103d557600080fd5b61017c600480359060446024803590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610d4295505050505050565b341561042b57600080fd5b61017c600435602435610e8c565b341561044457600080fd5b61044f600435610f65565b60405191825260208201526040908101905180910390f35b341561047257600080fd5b61017c600435600160a060020a0360243516610f82565b6000600160e060020a031982167f3b3b57de0000000000000000000000000000000000000000000000000000000014806104ec5750600160e060020a031982167fd8389dc500000000000000000000000000000000000000000000000000000000145b806105205750600160e060020a031982167f691f343100000000000000000000000000000000000000000000000000000000145b806105545750600160e060020a031982167f2203ab5600000000000000000000000000000000000000000000000000000000145b806105885750600160e060020a031982167fc869023300000000000000000000000000000000000000000000000000000000145b806105bc5750600160e060020a031982167f59d1d43c00000000000000000000000000000000000000000000000000000000145b806105f05750600160e060020a031982167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561064f57600080fd5b6102c65a03f1151561066057600080fd5b50505060405180519050600160a060020a031614151561067f57600080fd5b6000848152600160205260409081902083916005909101908590518082805190602001908083835b602083106106c65780518252601f1990920191602091820191016106a7565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902090805161070a929160200190611085565b50826040518082805190602001908083835b6020831061073b5780518252601f19909201916020918201910161071c565b6001836020036101000a0380198251168184511617909252505050919091019250604091505051908190039020847fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a75508560405160208082528190810183818151815260200191508051906020019080838360005b838110156107c75780820151838201526020016107af565b50505050905090810190601f1680156107f45780820380516001836020036101000a031916815260200191505b509250505060405180910390a350505050565b6000610811611103565b60008481526001602081905260409091209092505b838311610924578284161580159061085f5750600083815260068201602052604081205460026000196101006001841615020190911604115b15610919578060060160008481526020019081526020016000208054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561090d5780601f106108e25761010080835404028352916020019161090d565b820191906000526020600020905b8154815290600101906020018083116108f057829003601f168201915b50505050509150610929565b600290920291610826565b600092505b509250929050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b151561098a57600080fd5b6102c65a03f1151561099b57600080fd5b50505060405180519050600160a060020a03161415156109ba57600080fd5b6040805190810160409081528482526020808301859052600087815260019091522060030181518155602082015160019091015550837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46848460405191825260208201526040908101905180910390a250505050565b6000908152600160208190526040909120015490565b600090815260016020526040902054600160a060020a031690565b610a69611103565b60008381526001602052604090819020600501908390518082805190602001908083835b60208310610aac5780518252601f199092019160209182019101610a8d565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b735780601f10610b4857610100808354040283529160200191610b73565b820191906000526020600020905b815481529060010190602001808311610b5657829003601f168201915b5050505050905092915050565b600080548491600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610bd957600080fd5b6102c65a03f11515610bea57600080fd5b50505060405180519050600160a060020a0316141515610c0957600080fd5b6000198301831615610c1a57600080fd5b60008481526001602090815260408083208684526006019091529020828051610c47929160200190611085565b5082847faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a350505050565b610c84611103565b6001600083600019166000191681526020019081526020016000206002018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610d365780601f10610d0b57610100808354040283529160200191610d36565b820191906000526020600020905b815481529060010190602001808311610d1957829003601f168201915b50505050509050919050565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610d9b57600080fd5b6102c65a03f11515610dac57600080fd5b50505060405180519050600160a060020a0316141515610dcb57600080fd5b6000838152600160205260409020600201828051610ded929160200190611085565b50827fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f78360405160208082528190810183818151815260200191508051906020019080838360005b83811015610e4d578082015183820152602001610e35565b50505050905090810190601f168015610e7a5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505050565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610ee557600080fd5b6102c65a03f11515610ef657600080fd5b50505060405180519050600160a060020a0316141515610f1557600080fd5b6000838152600160208190526040918290200183905583907f0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc9084905190815260200160405180910390a2505050565b600090815260016020526040902060038101546004909101549091565b600080548391600160a060020a033381169216906302571be39084906040516020015260405160e060020a63ffffffff84160281526004810191909152602401602060405180830381600087803b1515610fdb57600080fd5b6102c65a03f11515610fec57600080fd5b50505060405180519050600160a060020a031614151561100b57600080fd5b60008381526001602052604090819020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03851617905583907f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd290849051600160a060020a03909116815260200160405180910390a2505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106110c657805160ff19168380011785556110f3565b828001600101855582156110f3579182015b828111156110f35782518255916020019190600101906110d8565b506110ff929150611115565b5090565b60206040519081016040526000815290565b61112f91905b808211156110ff576000815560010161111b565b905600a165627a7a723058201ecacbc445b9fbcd91b0ab164389f69d7283b856883bc7437eeed1008345a4920029` - -// DeployPublicResolver deploys a new Ethereum contract, binding an instance of PublicResolver to it. -func DeployPublicResolver(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address) (common.Address, *types.Transaction, *PublicResolver, error) { - parsed, err := abi.JSON(strings.NewReader(PublicResolverABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(PublicResolverBin), backend, ensAddr) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}, PublicResolverFilterer: PublicResolverFilterer{contract: contract}}, nil -} - -// PublicResolver is an auto generated Go binding around an Ethereum contract. -type PublicResolver struct { - PublicResolverCaller // Read-only binding to the contract - PublicResolverTransactor // Write-only binding to the contract - PublicResolverFilterer // Log filterer for contract events -} - -// PublicResolverCaller is an auto generated read-only Go binding around an Ethereum contract. -type PublicResolverCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PublicResolverTransactor is an auto generated write-only Go binding around an Ethereum contract. -type PublicResolverTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PublicResolverFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type PublicResolverFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PublicResolverSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type PublicResolverSession struct { - Contract *PublicResolver // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// PublicResolverCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type PublicResolverCallerSession struct { - Contract *PublicResolverCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// PublicResolverTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type PublicResolverTransactorSession struct { - Contract *PublicResolverTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// PublicResolverRaw is an auto generated low-level Go binding around an Ethereum contract. -type PublicResolverRaw struct { - Contract *PublicResolver // Generic contract binding to access the raw methods on -} - -// PublicResolverCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type PublicResolverCallerRaw struct { - Contract *PublicResolverCaller // Generic read-only contract binding to access the raw methods on -} - -// PublicResolverTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type PublicResolverTransactorRaw struct { - Contract *PublicResolverTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewPublicResolver creates a new instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolver(address common.Address, backend bind.ContractBackend) (*PublicResolver, error) { - contract, err := bindPublicResolver(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}, PublicResolverFilterer: PublicResolverFilterer{contract: contract}}, nil -} - -// NewPublicResolverCaller creates a new read-only instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolverCaller(address common.Address, caller bind.ContractCaller) (*PublicResolverCaller, error) { - contract, err := bindPublicResolver(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &PublicResolverCaller{contract: contract}, nil -} - -// NewPublicResolverTransactor creates a new write-only instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolverTransactor(address common.Address, transactor bind.ContractTransactor) (*PublicResolverTransactor, error) { - contract, err := bindPublicResolver(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &PublicResolverTransactor{contract: contract}, nil -} - -// NewPublicResolverFilterer creates a new log filterer instance of PublicResolver, bound to a specific deployed contract. -func NewPublicResolverFilterer(address common.Address, filterer bind.ContractFilterer) (*PublicResolverFilterer, error) { - contract, err := bindPublicResolver(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &PublicResolverFilterer{contract: contract}, nil -} - -// bindPublicResolver binds a generic wrapper to an already deployed contract. -func bindPublicResolver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(PublicResolverABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_PublicResolver *PublicResolverRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _PublicResolver.Contract.PublicResolverCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_PublicResolver *PublicResolverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _PublicResolver.Contract.PublicResolverTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_PublicResolver *PublicResolverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _PublicResolver.Contract.PublicResolverTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_PublicResolver *PublicResolverCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _PublicResolver.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_PublicResolver *PublicResolverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _PublicResolver.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_PublicResolver *PublicResolverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _PublicResolver.Contract.contract.Transact(opts, method, params...) -} - -// ABI is a free data retrieval call binding the contract method 0x2203ab56. -// -// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) -func (_PublicResolver *PublicResolverCaller) ABI(opts *bind.CallOpts, node [32]byte, contentTypes *big.Int) (struct { - ContentType *big.Int - Data []byte -}, error) { - ret := new(struct { - ContentType *big.Int - Data []byte - }) - out := ret - err := _PublicResolver.contract.Call(opts, out, "ABI", node, contentTypes) - return *ret, err -} - -// ABI is a free data retrieval call binding the contract method 0x2203ab56. -// -// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) -func (_PublicResolver *PublicResolverSession) ABI(node [32]byte, contentTypes *big.Int) (struct { - ContentType *big.Int - Data []byte -}, error) { - return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) -} - -// ABI is a free data retrieval call binding the contract method 0x2203ab56. -// -// Solidity: function ABI(node bytes32, contentTypes uint256) constant returns(contentType uint256, data bytes) -func (_PublicResolver *PublicResolverCallerSession) ABI(node [32]byte, contentTypes *big.Int) (struct { - ContentType *big.Int - Data []byte -}, error) { - return _PublicResolver.Contract.ABI(&_PublicResolver.CallOpts, node, contentTypes) -} - -// Addr is a free data retrieval call binding the contract method 0x3b3b57de. -// -// Solidity: function addr(node bytes32) constant returns(ret address) -func (_PublicResolver *PublicResolverCaller) Addr(opts *bind.CallOpts, node [32]byte) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "addr", node) - return *ret0, err -} - -// Addr is a free data retrieval call binding the contract method 0x3b3b57de. -// -// Solidity: function addr(node bytes32) constant returns(ret address) -func (_PublicResolver *PublicResolverSession) Addr(node [32]byte) (common.Address, error) { - return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) -} - -// Addr is a free data retrieval call binding the contract method 0x3b3b57de. -// -// Solidity: function addr(node bytes32) constant returns(ret address) -func (_PublicResolver *PublicResolverCallerSession) Addr(node [32]byte) (common.Address, error) { - return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node) -} - -// Content is a free data retrieval call binding the contract method 0x2dff6941. -// -// Solidity: function content(node bytes32) constant returns(ret bytes32) -func (_PublicResolver *PublicResolverCaller) Content(opts *bind.CallOpts, node [32]byte) ([32]byte, error) { - var ( - ret0 = new([32]byte) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "content", node) - return *ret0, err -} - -// Content is a free data retrieval call binding the contract method 0x2dff6941. -// -// Solidity: function content(node bytes32) constant returns(ret bytes32) -func (_PublicResolver *PublicResolverSession) Content(node [32]byte) ([32]byte, error) { - return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node) -} - -// Content is a free data retrieval call binding the contract method 0x2dff6941. -// -// Solidity: function content(node bytes32) constant returns(ret bytes32) -func (_PublicResolver *PublicResolverCallerSession) Content(node [32]byte) ([32]byte, error) { - return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node) -} - -// Name is a free data retrieval call binding the contract method 0x691f3431. -// -// Solidity: function name(node bytes32) constant returns(ret string) -func (_PublicResolver *PublicResolverCaller) Name(opts *bind.CallOpts, node [32]byte) (string, error) { - var ( - ret0 = new(string) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "name", node) - return *ret0, err -} - -// Name is a free data retrieval call binding the contract method 0x691f3431. -// -// Solidity: function name(node bytes32) constant returns(ret string) -func (_PublicResolver *PublicResolverSession) Name(node [32]byte) (string, error) { - return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) -} - -// Name is a free data retrieval call binding the contract method 0x691f3431. -// -// Solidity: function name(node bytes32) constant returns(ret string) -func (_PublicResolver *PublicResolverCallerSession) Name(node [32]byte) (string, error) { - return _PublicResolver.Contract.Name(&_PublicResolver.CallOpts, node) -} - -// Pubkey is a free data retrieval call binding the contract method 0xc8690233. -// -// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) -func (_PublicResolver *PublicResolverCaller) Pubkey(opts *bind.CallOpts, node [32]byte) (struct { - X [32]byte - Y [32]byte -}, error) { - ret := new(struct { - X [32]byte - Y [32]byte - }) - out := ret - err := _PublicResolver.contract.Call(opts, out, "pubkey", node) - return *ret, err -} - -// Pubkey is a free data retrieval call binding the contract method 0xc8690233. -// -// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) -func (_PublicResolver *PublicResolverSession) Pubkey(node [32]byte) (struct { - X [32]byte - Y [32]byte -}, error) { - return _PublicResolver.Contract.Pubkey(&_PublicResolver.CallOpts, node) -} - -// Pubkey is a free data retrieval call binding the contract method 0xc8690233. -// -// Solidity: function pubkey(node bytes32) constant returns(x bytes32, y bytes32) -func (_PublicResolver *PublicResolverCallerSession) Pubkey(node [32]byte) (struct { - X [32]byte - Y [32]byte -}, error) { - return _PublicResolver.Contract.Pubkey(&_PublicResolver.CallOpts, node) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) -func (_PublicResolver *PublicResolverCaller) SupportsInterface(opts *bind.CallOpts, interfaceID [4]byte) (bool, error) { - var ( - ret0 = new(bool) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "supportsInterface", interfaceID) - return *ret0, err -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) -func (_PublicResolver *PublicResolverSession) SupportsInterface(interfaceID [4]byte) (bool, error) { - return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) -} - -// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. -// -// Solidity: function supportsInterface(interfaceID bytes4) constant returns(bool) -func (_PublicResolver *PublicResolverCallerSession) SupportsInterface(interfaceID [4]byte) (bool, error) { - return _PublicResolver.Contract.SupportsInterface(&_PublicResolver.CallOpts, interfaceID) -} - -// Text is a free data retrieval call binding the contract method 0x59d1d43c. -// -// Solidity: function text(node bytes32, key string) constant returns(ret string) -func (_PublicResolver *PublicResolverCaller) Text(opts *bind.CallOpts, node [32]byte, key string) (string, error) { - var ( - ret0 = new(string) - ) - out := ret0 - err := _PublicResolver.contract.Call(opts, out, "text", node, key) - return *ret0, err -} - -// Text is a free data retrieval call binding the contract method 0x59d1d43c. -// -// Solidity: function text(node bytes32, key string) constant returns(ret string) -func (_PublicResolver *PublicResolverSession) Text(node [32]byte, key string) (string, error) { - return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) -} - -// Text is a free data retrieval call binding the contract method 0x59d1d43c. -// -// Solidity: function text(node bytes32, key string) constant returns(ret string) -func (_PublicResolver *PublicResolverCallerSession) Text(node [32]byte, key string) (string, error) { - return _PublicResolver.Contract.Text(&_PublicResolver.CallOpts, node, key) -} - -// SetABI is a paid mutator transaction binding the contract method 0x623195b0. -// -// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() -func (_PublicResolver *PublicResolverTransactor) SetABI(opts *bind.TransactOpts, node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setABI", node, contentType, data) -} - -// SetABI is a paid mutator transaction binding the contract method 0x623195b0. -// -// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() -func (_PublicResolver *PublicResolverSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) -} - -// SetABI is a paid mutator transaction binding the contract method 0x623195b0. -// -// Solidity: function setABI(node bytes32, contentType uint256, data bytes) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetABI(node [32]byte, contentType *big.Int, data []byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetABI(&_PublicResolver.TransactOpts, node, contentType, data) -} - -// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. -// -// Solidity: function setAddr(node bytes32, addr address) returns() -func (_PublicResolver *PublicResolverTransactor) SetAddr(opts *bind.TransactOpts, node [32]byte, addr common.Address) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setAddr", node, addr) -} - -// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. -// -// Solidity: function setAddr(node bytes32, addr address) returns() -func (_PublicResolver *PublicResolverSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { - return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) -} - -// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00. -// -// Solidity: function setAddr(node bytes32, addr address) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) { - return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr) -} - -// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. -// -// Solidity: function setContent(node bytes32, hash bytes32) returns() -func (_PublicResolver *PublicResolverTransactor) SetContent(opts *bind.TransactOpts, node [32]byte, hash [32]byte) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setContent", node, hash) -} - -// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. -// -// Solidity: function setContent(node bytes32, hash bytes32) returns() -func (_PublicResolver *PublicResolverSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash) -} - -// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6. -// -// Solidity: function setContent(node bytes32, hash bytes32) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash) -} - -// SetName is a paid mutator transaction binding the contract method 0x77372213. -// -// Solidity: function setName(node bytes32, name string) returns() -func (_PublicResolver *PublicResolverTransactor) SetName(opts *bind.TransactOpts, node [32]byte, name string) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setName", node, name) -} - -// SetName is a paid mutator transaction binding the contract method 0x77372213. -// -// Solidity: function setName(node bytes32, name string) returns() -func (_PublicResolver *PublicResolverSession) SetName(node [32]byte, name string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) -} - -// SetName is a paid mutator transaction binding the contract method 0x77372213. -// -// Solidity: function setName(node bytes32, name string) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetName(node [32]byte, name string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetName(&_PublicResolver.TransactOpts, node, name) -} - -// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. -// -// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() -func (_PublicResolver *PublicResolverTransactor) SetPubkey(opts *bind.TransactOpts, node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setPubkey", node, x, y) -} - -// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. -// -// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() -func (_PublicResolver *PublicResolverSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) -} - -// SetPubkey is a paid mutator transaction binding the contract method 0x29cd62ea. -// -// Solidity: function setPubkey(node bytes32, x bytes32, y bytes32) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetPubkey(node [32]byte, x [32]byte, y [32]byte) (*types.Transaction, error) { - return _PublicResolver.Contract.SetPubkey(&_PublicResolver.TransactOpts, node, x, y) -} - -// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. -// -// Solidity: function setText(node bytes32, key string, value string) returns() -func (_PublicResolver *PublicResolverTransactor) SetText(opts *bind.TransactOpts, node [32]byte, key string, value string) (*types.Transaction, error) { - return _PublicResolver.contract.Transact(opts, "setText", node, key, value) -} - -// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. -// -// Solidity: function setText(node bytes32, key string, value string) returns() -func (_PublicResolver *PublicResolverSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) -} - -// SetText is a paid mutator transaction binding the contract method 0x10f13a8c. -// -// Solidity: function setText(node bytes32, key string, value string) returns() -func (_PublicResolver *PublicResolverTransactorSession) SetText(node [32]byte, key string, value string) (*types.Transaction, error) { - return _PublicResolver.Contract.SetText(&_PublicResolver.TransactOpts, node, key, value) -} - -// PublicResolverABIChangedIterator is returned from FilterABIChanged and is used to iterate over the raw logs and unpacked data for ABIChanged events raised by the PublicResolver contract. -type PublicResolverABIChangedIterator struct { - Event *PublicResolverABIChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverABIChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverABIChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverABIChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *PublicResolverABIChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverABIChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverABIChanged represents a ABIChanged event raised by the PublicResolver contract. -type PublicResolverABIChanged struct { - Node [32]byte - ContentType *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterABIChanged is a free log retrieval operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. -// -// Solidity: event ABIChanged(node indexed bytes32, contentType indexed uint256) -func (_PublicResolver *PublicResolverFilterer) FilterABIChanged(opts *bind.FilterOpts, node [][32]byte, contentType []*big.Int) (*PublicResolverABIChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var contentTypeRule []interface{} - for _, contentTypeItem := range contentType { - contentTypeRule = append(contentTypeRule, contentTypeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ABIChanged", nodeRule, contentTypeRule) - if err != nil { - return nil, err - } - return &PublicResolverABIChangedIterator{contract: _PublicResolver.contract, event: "ABIChanged", logs: logs, sub: sub}, nil -} - -// WatchABIChanged is a free log subscription operation binding the contract event 0xaa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe3. -// -// Solidity: event ABIChanged(node indexed bytes32, contentType indexed uint256) -func (_PublicResolver *PublicResolverFilterer) WatchABIChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverABIChanged, node [][32]byte, contentType []*big.Int) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var contentTypeRule []interface{} - for _, contentTypeItem := range contentType { - contentTypeRule = append(contentTypeRule, contentTypeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ABIChanged", nodeRule, contentTypeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverABIChanged) - if err := _PublicResolver.contract.UnpackLog(event, "ABIChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverAddrChangedIterator is returned from FilterAddrChanged and is used to iterate over the raw logs and unpacked data for AddrChanged events raised by the PublicResolver contract. -type PublicResolverAddrChangedIterator struct { - Event *PublicResolverAddrChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverAddrChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverAddrChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverAddrChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *PublicResolverAddrChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverAddrChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverAddrChanged represents a AddrChanged event raised by the PublicResolver contract. -type PublicResolverAddrChanged struct { - Node [32]byte - A common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAddrChanged is a free log retrieval operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. -// -// Solidity: event AddrChanged(node indexed bytes32, a address) -func (_PublicResolver *PublicResolverFilterer) FilterAddrChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverAddrChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "AddrChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverAddrChangedIterator{contract: _PublicResolver.contract, event: "AddrChanged", logs: logs, sub: sub}, nil -} - -// WatchAddrChanged is a free log subscription operation binding the contract event 0x52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd2. -// -// Solidity: event AddrChanged(node indexed bytes32, a address) -func (_PublicResolver *PublicResolverFilterer) WatchAddrChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverAddrChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "AddrChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverAddrChanged) - if err := _PublicResolver.contract.UnpackLog(event, "AddrChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverContentChangedIterator is returned from FilterContentChanged and is used to iterate over the raw logs and unpacked data for ContentChanged events raised by the PublicResolver contract. -type PublicResolverContentChangedIterator struct { - Event *PublicResolverContentChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverContentChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverContentChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverContentChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *PublicResolverContentChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverContentChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverContentChanged represents a ContentChanged event raised by the PublicResolver contract. -type PublicResolverContentChanged struct { - Node [32]byte - Hash [32]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterContentChanged is a free log retrieval operation binding the contract event 0x0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc. -// -// Solidity: event ContentChanged(node indexed bytes32, hash bytes32) -func (_PublicResolver *PublicResolverFilterer) FilterContentChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverContentChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "ContentChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverContentChangedIterator{contract: _PublicResolver.contract, event: "ContentChanged", logs: logs, sub: sub}, nil -} - -// WatchContentChanged is a free log subscription operation binding the contract event 0x0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc. -// -// Solidity: event ContentChanged(node indexed bytes32, hash bytes32) -func (_PublicResolver *PublicResolverFilterer) WatchContentChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverContentChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "ContentChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverContentChanged) - if err := _PublicResolver.contract.UnpackLog(event, "ContentChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverNameChangedIterator is returned from FilterNameChanged and is used to iterate over the raw logs and unpacked data for NameChanged events raised by the PublicResolver contract. -type PublicResolverNameChangedIterator struct { - Event *PublicResolverNameChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverNameChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverNameChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverNameChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *PublicResolverNameChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverNameChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverNameChanged represents a NameChanged event raised by the PublicResolver contract. -type PublicResolverNameChanged struct { - Node [32]byte - Name string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterNameChanged is a free log retrieval operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. -// -// Solidity: event NameChanged(node indexed bytes32, name string) -func (_PublicResolver *PublicResolverFilterer) FilterNameChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverNameChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "NameChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverNameChangedIterator{contract: _PublicResolver.contract, event: "NameChanged", logs: logs, sub: sub}, nil -} - -// WatchNameChanged is a free log subscription operation binding the contract event 0xb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7. -// -// Solidity: event NameChanged(node indexed bytes32, name string) -func (_PublicResolver *PublicResolverFilterer) WatchNameChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverNameChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "NameChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverNameChanged) - if err := _PublicResolver.contract.UnpackLog(event, "NameChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverPubkeyChangedIterator is returned from FilterPubkeyChanged and is used to iterate over the raw logs and unpacked data for PubkeyChanged events raised by the PublicResolver contract. -type PublicResolverPubkeyChangedIterator struct { - Event *PublicResolverPubkeyChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverPubkeyChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverPubkeyChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverPubkeyChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *PublicResolverPubkeyChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverPubkeyChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverPubkeyChanged represents a PubkeyChanged event raised by the PublicResolver contract. -type PublicResolverPubkeyChanged struct { - Node [32]byte - X [32]byte - Y [32]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterPubkeyChanged is a free log retrieval operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. -// -// Solidity: event PubkeyChanged(node indexed bytes32, x bytes32, y bytes32) -func (_PublicResolver *PublicResolverFilterer) FilterPubkeyChanged(opts *bind.FilterOpts, node [][32]byte) (*PublicResolverPubkeyChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "PubkeyChanged", nodeRule) - if err != nil { - return nil, err - } - return &PublicResolverPubkeyChangedIterator{contract: _PublicResolver.contract, event: "PubkeyChanged", logs: logs, sub: sub}, nil -} - -// WatchPubkeyChanged is a free log subscription operation binding the contract event 0x1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46. -// -// Solidity: event PubkeyChanged(node indexed bytes32, x bytes32, y bytes32) -func (_PublicResolver *PublicResolverFilterer) WatchPubkeyChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverPubkeyChanged, node [][32]byte) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "PubkeyChanged", nodeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverPubkeyChanged) - if err := _PublicResolver.contract.UnpackLog(event, "PubkeyChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// PublicResolverTextChangedIterator is returned from FilterTextChanged and is used to iterate over the raw logs and unpacked data for TextChanged events raised by the PublicResolver contract. -type PublicResolverTextChangedIterator struct { - Event *PublicResolverTextChanged // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *PublicResolverTextChangedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(PublicResolverTextChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(PublicResolverTextChanged) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *PublicResolverTextChangedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *PublicResolverTextChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// PublicResolverTextChanged represents a TextChanged event raised by the PublicResolver contract. -type PublicResolverTextChanged struct { - Node [32]byte - IndexedKey common.Hash - Key string - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTextChanged is a free log retrieval operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. -// -// Solidity: event TextChanged(node indexed bytes32, indexedKey indexed string, key string) -func (_PublicResolver *PublicResolverFilterer) FilterTextChanged(opts *bind.FilterOpts, node [][32]byte, indexedKey []string) (*PublicResolverTextChangedIterator, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var indexedKeyRule []interface{} - for _, indexedKeyItem := range indexedKey { - indexedKeyRule = append(indexedKeyRule, indexedKeyItem) - } - - logs, sub, err := _PublicResolver.contract.FilterLogs(opts, "TextChanged", nodeRule, indexedKeyRule) - if err != nil { - return nil, err - } - return &PublicResolverTextChangedIterator{contract: _PublicResolver.contract, event: "TextChanged", logs: logs, sub: sub}, nil -} - -// WatchTextChanged is a free log subscription operation binding the contract event 0xd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a7550. -// -// Solidity: event TextChanged(node indexed bytes32, indexedKey indexed string, key string) -func (_PublicResolver *PublicResolverFilterer) WatchTextChanged(opts *bind.WatchOpts, sink chan<- *PublicResolverTextChanged, node [][32]byte, indexedKey []string) (event.Subscription, error) { - - var nodeRule []interface{} - for _, nodeItem := range node { - nodeRule = append(nodeRule, nodeItem) - } - var indexedKeyRule []interface{} - for _, indexedKeyItem := range indexedKey { - indexedKeyRule = append(indexedKeyRule, indexedKeyItem) - } - - logs, sub, err := _PublicResolver.contract.WatchLogs(opts, "TextChanged", nodeRule, indexedKeyRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(PublicResolverTextChanged) - if err := _PublicResolver.contract.UnpackLog(event, "TextChanged", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/p2p/protocols/accounting.go b/p2p/protocols/accounting.go deleted file mode 100644 index 558247254a..0000000000 --- a/p2p/protocols/accounting.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package protocols - -import ( - "time" - - "github.com/ethereum/go-ethereum/metrics" -) - -// define some metrics -var ( - // All metrics are cumulative - - // total amount of units credited - mBalanceCredit = metrics.NewRegisteredCounterForced("account.balance.credit", metrics.AccountingRegistry) - // total amount of units debited - mBalanceDebit = metrics.NewRegisteredCounterForced("account.balance.debit", metrics.AccountingRegistry) - // total amount of bytes credited - mBytesCredit = metrics.NewRegisteredCounterForced("account.bytes.credit", metrics.AccountingRegistry) - // total amount of bytes debited - mBytesDebit = metrics.NewRegisteredCounterForced("account.bytes.debit", metrics.AccountingRegistry) - // total amount of credited messages - mMsgCredit = metrics.NewRegisteredCounterForced("account.msg.credit", metrics.AccountingRegistry) - // total amount of debited messages - mMsgDebit = metrics.NewRegisteredCounterForced("account.msg.debit", metrics.AccountingRegistry) - // how many times local node had to drop remote peers - mPeerDrops = metrics.NewRegisteredCounterForced("account.peerdrops", metrics.AccountingRegistry) - // how many times local node overdrafted and dropped - mSelfDrops = metrics.NewRegisteredCounterForced("account.selfdrops", metrics.AccountingRegistry) -) - -// Prices defines how prices are being passed on to the accounting instance -type Prices interface { - // Return the Price for a message - Price(interface{}) *Price -} - -type Payer bool - -const ( - Sender = Payer(true) - Receiver = Payer(false) -) - -// Price represents the costs of a message -type Price struct { - Value uint64 - PerByte bool // True if the price is per byte or for unit - Payer Payer -} - -// For gives back the price for a message -// A protocol provides the message price in absolute value -// This method then returns the correct signed amount, -// depending on who pays, which is identified by the `payer` argument: -// `Send` will pass a `Sender` payer, `Receive` will pass the `Receiver` argument. -// Thus: If Sending and sender pays, amount positive, otherwise negative -// If Receiving, and receiver pays, amount positive, otherwise negative -func (p *Price) For(payer Payer, size uint32) int64 { - price := p.Value - if p.PerByte { - price *= uint64(size) - } - if p.Payer == payer { - return 0 - int64(price) - } - return int64(price) -} - -// Balance is the actual accounting instance -// Balance defines the operations needed for accounting -// Implementations internally maintain the balance for every peer -type Balance interface { - // Adds amount to the local balance with remote node `peer`; - // positive amount = credit local node - // negative amount = debit local node - Add(amount int64, peer *Peer) error -} - -// Accounting implements the Hook interface -// It interfaces to the balances through the Balance interface, -// while interfacing with protocols and its prices through the Prices interface -type Accounting struct { - Balance // interface to accounting logic - Prices // interface to prices logic -} - -func NewAccounting(balance Balance, po Prices) *Accounting { - ah := &Accounting{ - Prices: po, - Balance: balance, - } - return ah -} - -// SetupAccountingMetrics uses a separate registry for p2p accounting metrics; -// this registry should be independent of any other metrics as it persists at different endpoints. -// It also starts the persisting go-routine which -// at the passed interval writes the metrics to a LevelDB -func SetupAccountingMetrics(reportInterval time.Duration, path string) *AccountingMetrics { - // create the DB and start persisting - return NewAccountingMetrics(metrics.AccountingRegistry, reportInterval, path) -} - -// Send takes a peer, a size and a msg and -// - calculates the cost for the local node sending a msg of size to peer using the Prices interface -// - credits/debits local node using balance interface -func (ah *Accounting) Send(peer *Peer, size uint32, msg interface{}) error { - // get the price for a message (through the protocol spec) - price := ah.Price(msg) - // this message doesn't need accounting - if price == nil { - return nil - } - // evaluate the price for sending messages - costToLocalNode := price.For(Sender, size) - // do the accounting - err := ah.Add(costToLocalNode, peer) - // record metrics: just increase counters for user-facing metrics - ah.doMetrics(costToLocalNode, size, err) - return err -} - -// Receive takes a peer, a size and a msg and -// - calculates the cost for the local node receiving a msg of size from peer using the Prices interface -// - credits/debits local node using balance interface -func (ah *Accounting) Receive(peer *Peer, size uint32, msg interface{}) error { - // get the price for a message (through the protocol spec) - price := ah.Price(msg) - // this message doesn't need accounting - if price == nil { - return nil - } - // evaluate the price for receiving messages - costToLocalNode := price.For(Receiver, size) - // do the accounting - err := ah.Add(costToLocalNode, peer) - // record metrics: just increase counters for user-facing metrics - ah.doMetrics(costToLocalNode, size, err) - return err -} - -// record some metrics -// this is not an error handling. `err` is returned by both `Send` and `Receive` -// `err` will only be non-nil if a limit has been violated (overdraft), in which case the peer has been dropped. -// if the limit has been violated and `err` is thus not nil: -// * if the price is positive, local node has been credited; thus `err` implicitly signals the REMOTE has been dropped -// * if the price is negative, local node has been debited, thus `err` implicitly signals LOCAL node "overdraft" -func (ah *Accounting) doMetrics(price int64, size uint32, err error) { - if price > 0 { - mBalanceCredit.Inc(price) - mBytesCredit.Inc(int64(size)) - mMsgCredit.Inc(1) - if err != nil { - // increase the number of times a remote node has been dropped due to "overdraft" - mPeerDrops.Inc(1) - } - } else { - mBalanceDebit.Inc(price) - mBytesDebit.Inc(int64(size)) - mMsgDebit.Inc(1) - if err != nil { - // increase the number of times the local node has done an "overdraft" in respect to other nodes - mSelfDrops.Inc(1) - } - } -} diff --git a/p2p/protocols/accounting_api.go b/p2p/protocols/accounting_api.go deleted file mode 100644 index 48e2af9fea..0000000000 --- a/p2p/protocols/accounting_api.go +++ /dev/null @@ -1,94 +0,0 @@ -package protocols - -import ( - "errors" -) - -// Textual version number of accounting API -const AccountingVersion = "1.0" - -var errNoAccountingMetrics = errors.New("accounting metrics not enabled") - -// AccountingApi provides an API to access account related information -type AccountingApi struct { - metrics *AccountingMetrics -} - -// NewAccountingApi creates a new AccountingApi -// m will be used to check if accounting metrics are enabled -func NewAccountingApi(m *AccountingMetrics) *AccountingApi { - return &AccountingApi{m} -} - -// Balance returns local node balance (units credited - units debited) -func (self *AccountingApi) Balance() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - balance := mBalanceCredit.Count() - mBalanceDebit.Count() - return balance, nil -} - -// BalanceCredit returns total amount of units credited by local node -func (self *AccountingApi) BalanceCredit() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mBalanceCredit.Count(), nil -} - -// BalanceCredit returns total amount of units debited by local node -func (self *AccountingApi) BalanceDebit() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mBalanceDebit.Count(), nil -} - -// BytesCredit returns total amount of bytes credited by local node -func (self *AccountingApi) BytesCredit() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mBytesCredit.Count(), nil -} - -// BalanceCredit returns total amount of bytes debited by local node -func (self *AccountingApi) BytesDebit() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mBytesDebit.Count(), nil -} - -// MsgCredit returns total amount of messages credited by local node -func (self *AccountingApi) MsgCredit() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mMsgCredit.Count(), nil -} - -// MsgDebit returns total amount of messages debited by local node -func (self *AccountingApi) MsgDebit() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mMsgDebit.Count(), nil -} - -// PeerDrops returns number of times when local node had to drop remote peers -func (self *AccountingApi) PeerDrops() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mPeerDrops.Count(), nil -} - -// SelfDrops returns number of times when local node was overdrafted and dropped -func (self *AccountingApi) SelfDrops() (int64, error) { - if self.metrics == nil { - return 0, errNoAccountingMetrics - } - return mSelfDrops.Count(), nil -} diff --git a/p2p/protocols/accounting_simulation_test.go b/p2p/protocols/accounting_simulation_test.go deleted file mode 100644 index 464b598920..0000000000 --- a/p2p/protocols/accounting_simulation_test.go +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package protocols - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - "math/rand" - "os" - "path/filepath" - "reflect" - "sync" - "testing" - "time" - - "github.com/mattn/go-colorable" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -const ( - content = "123456789" -) - -var ( - nodes = flag.Int("nodes", 30, "number of nodes to create (default 30)") - msgs = flag.Int("msgs", 100, "number of messages sent by node (default 100)") - loglevel = flag.Int("loglevel", 0, "verbosity of logs") - rawlog = flag.Bool("rawlog", false, "remove terminal formatting from logs") -) - -func init() { - flag.Parse() - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(!*rawlog)))) -} - -//TestAccountingSimulation runs a p2p/simulations simulation -//It creates a *nodes number of nodes, connects each one with each other, -//then sends out a random selection of messages up to *msgs amount of messages -//from the test protocol spec. -//The spec has some accounted messages defined through the Prices interface. -//The test does accounting for all the message exchanged, and then checks -//that every node has the same balance with a peer, but with opposite signs. -//Balance(AwithB) = 0 - Balance(BwithA) or Abs|Balance(AwithB)| == Abs|Balance(BwithA)| -func TestAccountingSimulation(t *testing.T) { - //setup the balances objects for every node - bal := newBalances(*nodes) - //setup the metrics system or tests will fail trying to write metrics - dir, err := ioutil.TempDir("", "account-sim") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - SetupAccountingMetrics(1*time.Second, filepath.Join(dir, "metrics.db")) - //define the node.Service for this test - services := adapters.Services{ - "accounting": func(ctx *adapters.ServiceContext) (node.Service, error) { - return bal.newNode(), nil - }, - } - //setup the simulation - adapter := adapters.NewSimAdapter(services) - net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{DefaultService: "accounting"}) - defer net.Shutdown() - - // we send msgs messages per node, wait for all messages to arrive - bal.wg.Add(*nodes * *msgs) - trigger := make(chan enode.ID) - go func() { - // wait for all of them to arrive - bal.wg.Wait() - // then trigger a check - // the selected node for the trigger is irrelevant, - // we just want to trigger the end of the simulation - trigger <- net.Nodes[0].ID() - }() - - // create nodes and start them - for i := 0; i < *nodes; i++ { - conf := adapters.RandomNodeConfig() - bal.id2n[conf.ID] = i - if _, err := net.NewNodeWithConfig(conf); err != nil { - t.Fatal(err) - } - if err := net.Start(conf.ID); err != nil { - t.Fatal(err) - } - } - // fully connect nodes - for i, n := range net.Nodes { - for _, m := range net.Nodes[i+1:] { - if err := net.Connect(n.ID(), m.ID()); err != nil { - t.Fatal(err) - } - } - } - - // empty action - action := func(ctx context.Context) error { - return nil - } - // check always checks out - check := func(ctx context.Context, id enode.ID) (bool, error) { - return true, nil - } - - // run simulation - timeout := 30 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{ - Action: action, - Trigger: trigger, - Expect: &simulations.Expectation{ - Nodes: []enode.ID{net.Nodes[0].ID()}, - Check: check, - }, - }) - - if result.Error != nil { - t.Fatal(result.Error) - } - - // check if balance matrix is symmetric - if err := bal.symmetric(); err != nil { - t.Fatal(err) - } -} - -// matrix is a matrix of nodes and its balances -// matrix is in fact a linear array of size n*n, -// so the balance for any node A with B is at index -// A*n + B, while the balance of node B with A is at -// B*n + A -// (n entries in the array will not be filled - -// the balance of a node with itself) -type matrix struct { - n int //number of nodes - m []int64 //array of balances - lock sync.Mutex -} - -// create a new matrix -func newMatrix(n int) *matrix { - return &matrix{ - n: n, - m: make([]int64, n*n), - } -} - -// called from the testBalance's Add accounting function: register balance change -func (m *matrix) add(i, j int, v int64) error { - // index for the balance of local node i with remote nodde j is - // i * number of nodes + remote node - mi := i*m.n + j - // register that balance - m.lock.Lock() - m.m[mi] += v - m.lock.Unlock() - return nil -} - -// check that the balances are symmetric: -// balance of node i with node j is the same as j with i but with inverted signs -func (m *matrix) symmetric() error { - //iterate all nodes - for i := 0; i < m.n; i++ { - //iterate starting +1 - for j := i + 1; j < m.n; j++ { - log.Debug("bal", "1", i, "2", j, "i,j", m.m[i*m.n+j], "j,i", m.m[j*m.n+i]) - if m.m[i*m.n+j] != -m.m[j*m.n+i] { - return fmt.Errorf("value mismatch. m[%v, %v] = %v; m[%v, %v] = %v", i, j, m.m[i*m.n+j], j, i, m.m[j*m.n+i]) - } - } - } - return nil -} - -// all the balances -type balances struct { - i int - *matrix - id2n map[enode.ID]int - wg *sync.WaitGroup -} - -func newBalances(n int) *balances { - return &balances{ - matrix: newMatrix(n), - id2n: make(map[enode.ID]int), - wg: &sync.WaitGroup{}, - } -} - -// create a new testNode for every node created as part of the service -func (b *balances) newNode() *testNode { - defer func() { b.i++ }() - return &testNode{ - bal: b, - i: b.i, - peers: make([]*testPeer, b.n), //a node will be connected to n-1 peers - } -} - -type testNode struct { - bal *balances - i int - lock sync.Mutex - peers []*testPeer - peerCount int -} - -// do the accounting for the peer's test protocol -// testNode implements protocols.Balance -func (t *testNode) Add(a int64, p *Peer) error { - //get the index for the remote peer - remote := t.bal.id2n[p.ID()] - log.Debug("add", "local", t.i, "remote", remote, "amount", a) - return t.bal.add(t.i, remote, a) -} - -//run the p2p protocol -//for every node, represented by testNode, create a remote testPeer -func (t *testNode) run(p *p2p.Peer, rw p2p.MsgReadWriter) error { - spec := createTestSpec() - //create accounting hook - spec.Hook = NewAccounting(t, &dummyPrices{}) - - //create a peer for this node - tp := &testPeer{NewPeer(p, rw, spec), t.i, t.bal.id2n[p.ID()], t.bal.wg} - t.lock.Lock() - t.peers[t.bal.id2n[p.ID()]] = tp - t.peerCount++ - if t.peerCount == t.bal.n-1 { - //when all peer connections are established, start sending messages from this peer - go t.send() - } - t.lock.Unlock() - return tp.Run(tp.handle) -} - -// p2p message receive handler function -func (tp *testPeer) handle(ctx context.Context, msg interface{}) error { - tp.wg.Done() - log.Debug("receive", "from", tp.remote, "to", tp.local, "type", reflect.TypeOf(msg), "msg", msg) - return nil -} - -type testPeer struct { - *Peer - local, remote int - wg *sync.WaitGroup -} - -func (t *testNode) send() { - log.Debug("start sending") - for i := 0; i < *msgs; i++ { - //determine randomly to which peer to send - whom := rand.Intn(t.bal.n - 1) - if whom >= t.i { - whom++ - } - t.lock.Lock() - p := t.peers[whom] - t.lock.Unlock() - - //determine a random message from the spec's messages to be sent - which := rand.Intn(len(p.spec.Messages)) - msg := p.spec.Messages[which] - switch msg.(type) { - case *perBytesMsgReceiverPays: - msg = &perBytesMsgReceiverPays{Content: content[:rand.Intn(len(content))]} - case *perBytesMsgSenderPays: - msg = &perBytesMsgSenderPays{Content: content[:rand.Intn(len(content))]} - } - log.Debug("send", "from", t.i, "to", whom, "type", reflect.TypeOf(msg), "msg", msg) - p.Send(context.TODO(), msg) - } -} - -// define the protocol -func (t *testNode) Protocols() []p2p.Protocol { - return []p2p.Protocol{{ - Length: 100, - Run: t.run, - }} -} - -func (t *testNode) APIs() []rpc.API { - return nil -} - -func (t *testNode) Start(server *p2p.Server) error { - return nil -} - -func (t *testNode) Stop() error { - return nil -} diff --git a/p2p/protocols/accounting_test.go b/p2p/protocols/accounting_test.go deleted file mode 100644 index 3810ae2c9b..0000000000 --- a/p2p/protocols/accounting_test.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package protocols - -import ( - "testing" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rlp" -) - -//dummy Balance implementation -type dummyBalance struct { - amount int64 - peer *Peer -} - -//dummy Prices implementation -type dummyPrices struct{} - -//a dummy message which needs size based accounting -//sender pays -type perBytesMsgSenderPays struct { - Content string -} - -//a dummy message which needs size based accounting -//receiver pays -type perBytesMsgReceiverPays struct { - Content string -} - -//a dummy message which is paid for per unit -//sender pays -type perUnitMsgSenderPays struct{} - -//receiver pays -type perUnitMsgReceiverPays struct{} - -//a dummy message which has zero as its price -type zeroPriceMsg struct{} - -//a dummy message which has no accounting -type nilPriceMsg struct{} - -//return the price for the defined messages -func (d *dummyPrices) Price(msg interface{}) *Price { - switch msg.(type) { - //size based message cost, receiver pays - case *perBytesMsgReceiverPays: - return &Price{ - PerByte: true, - Value: uint64(100), - Payer: Receiver, - } - //size based message cost, sender pays - case *perBytesMsgSenderPays: - return &Price{ - PerByte: true, - Value: uint64(100), - Payer: Sender, - } - //unitary cost, receiver pays - case *perUnitMsgReceiverPays: - return &Price{ - PerByte: false, - Value: uint64(99), - Payer: Receiver, - } - //unitary cost, sender pays - case *perUnitMsgSenderPays: - return &Price{ - PerByte: false, - Value: uint64(99), - Payer: Sender, - } - case *zeroPriceMsg: - return &Price{ - PerByte: false, - Value: uint64(0), - Payer: Sender, - } - case *nilPriceMsg: - return nil - } - return nil -} - -//dummy accounting implementation, only stores values for later check -func (d *dummyBalance) Add(amount int64, peer *Peer) error { - d.amount = amount - d.peer = peer - return nil -} - -type testCase struct { - msg interface{} - size uint32 - sendResult int64 - recvResult int64 -} - -//lowest level unit test -func TestBalance(t *testing.T) { - //create instances - balance := &dummyBalance{} - prices := &dummyPrices{} - //create the spec - spec := createTestSpec() - //create the accounting hook for the spec - acc := NewAccounting(balance, prices) - //create a peer - id := adapters.RandomNodeConfig().ID - p := p2p.NewPeer(id, "testPeer", nil) - peer := NewPeer(p, &dummyRW{}, spec) - //price depends on size, receiver pays - msg := &perBytesMsgReceiverPays{Content: "testBalance"} - size, _ := rlp.EncodeToBytes(msg) - - testCases := []testCase{ - { - msg, - uint32(len(size)), - int64(len(size) * 100), - int64(len(size) * -100), - }, - { - &perBytesMsgSenderPays{Content: "testBalance"}, - uint32(len(size)), - int64(len(size) * -100), - int64(len(size) * 100), - }, - { - &perUnitMsgSenderPays{}, - 0, - int64(-99), - int64(99), - }, - { - &perUnitMsgReceiverPays{}, - 0, - int64(99), - int64(-99), - }, - { - &zeroPriceMsg{}, - 0, - int64(0), - int64(0), - }, - { - &nilPriceMsg{}, - 0, - int64(0), - int64(0), - }, - } - checkAccountingTestCases(t, testCases, acc, peer, balance, true) - checkAccountingTestCases(t, testCases, acc, peer, balance, false) -} - -func checkAccountingTestCases(t *testing.T, cases []testCase, acc *Accounting, peer *Peer, balance *dummyBalance, send bool) { - for _, c := range cases { - var err error - var expectedResult int64 - //reset balance before every check - balance.amount = 0 - if send { - err = acc.Send(peer, c.size, c.msg) - expectedResult = c.sendResult - } else { - err = acc.Receive(peer, c.size, c.msg) - expectedResult = c.recvResult - } - - checkResults(t, err, balance, peer, expectedResult) - } -} - -func checkResults(t *testing.T, err error, balance *dummyBalance, peer *Peer, result int64) { - if err != nil { - t.Fatal(err) - } - if balance.peer != peer { - t.Fatalf("expected Add to be called with peer %v, got %v", peer, balance.peer) - } - if balance.amount != result { - t.Fatalf("Expected balance to be %d but is %d", result, balance.amount) - } -} - -//create a test spec -func createTestSpec() *Spec { - spec := &Spec{ - Name: "test", - Version: 42, - MaxMsgSize: 10 * 1024, - Messages: []interface{}{ - &perBytesMsgReceiverPays{}, - &perBytesMsgSenderPays{}, - &perUnitMsgReceiverPays{}, - &perUnitMsgSenderPays{}, - &zeroPriceMsg{}, - &nilPriceMsg{}, - }, - } - return spec -} diff --git a/p2p/protocols/protocol.go b/p2p/protocols/protocol.go deleted file mode 100644 index a9a00984d1..0000000000 --- a/p2p/protocols/protocol.go +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/* -Package protocols is an extension to p2p. It offers a user friendly simple way to define -devp2p subprotocols by abstracting away code standardly shared by protocols. - -* automate assigments of code indexes to messages -* automate RLP decoding/encoding based on reflecting -* provide the forever loop to read incoming messages -* standardise error handling related to communication -* standardised handshake negotiation -* TODO: automatic generation of wire protocol specification for peers - -*/ -package protocols - -import ( - "bufio" - "bytes" - "context" - "fmt" - "io" - "reflect" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/swarm/spancontext" - "github.com/ethereum/go-ethereum/swarm/tracing" - opentracing "github.com/opentracing/opentracing-go" -) - -// error codes used by this protocol scheme -const ( - ErrMsgTooLong = iota - ErrDecode - ErrWrite - ErrInvalidMsgCode - ErrInvalidMsgType - ErrHandshake - ErrNoHandler - ErrHandler -) - -// error description strings associated with the codes -var errorToString = map[int]string{ - ErrMsgTooLong: "Message too long", - ErrDecode: "Invalid message (RLP error)", - ErrWrite: "Error sending message", - ErrInvalidMsgCode: "Invalid message code", - ErrInvalidMsgType: "Invalid message type", - ErrHandshake: "Handshake error", - ErrNoHandler: "No handler registered error", - ErrHandler: "Message handler error", -} - -/* -Error implements the standard go error interface. -Use: - - errorf(code, format, params ...interface{}) - -Prints as: - - :
- -where description is given by code in errorToString -and details is fmt.Sprintf(format, params...) - -exported field Code can be checked -*/ -type Error struct { - Code int - message string - format string - params []interface{} -} - -func (e Error) Error() (message string) { - if len(e.message) == 0 { - name, ok := errorToString[e.Code] - if !ok { - panic("invalid message code") - } - e.message = name - if e.format != "" { - e.message += ": " + fmt.Sprintf(e.format, e.params...) - } - } - return e.message -} - -func errorf(code int, format string, params ...interface{}) *Error { - return &Error{ - Code: code, - format: format, - params: params, - } -} - -// WrappedMsg is used to propagate marshalled context alongside message payloads -type WrappedMsg struct { - Context []byte - Size uint32 - Payload []byte -} - -//For accounting, the design is to allow the Spec to describe which and how its messages are priced -//To access this functionality, we provide a Hook interface which will call accounting methods -//NOTE: there could be more such (horizontal) hooks in the future -type Hook interface { - //A hook for sending messages - Send(peer *Peer, size uint32, msg interface{}) error - //A hook for receiving messages - Receive(peer *Peer, size uint32, msg interface{}) error -} - -// Spec is a protocol specification including its name and version as well as -// the types of messages which are exchanged -type Spec struct { - // Name is the name of the protocol, often a three-letter word - Name string - - // Version is the version number of the protocol - Version uint - - // MaxMsgSize is the maximum accepted length of the message payload - MaxMsgSize uint32 - - // Messages is a list of message data types which this protocol uses, with - // each message type being sent with its array index as the code (so - // [&foo{}, &bar{}, &baz{}] would send foo, bar and baz with codes - // 0, 1 and 2 respectively) - // each message must have a single unique data type - Messages []interface{} - - //hook for accounting (could be extended to multiple hooks in the future) - Hook Hook - - initOnce sync.Once - codes map[reflect.Type]uint64 - types map[uint64]reflect.Type -} - -func (s *Spec) init() { - s.initOnce.Do(func() { - s.codes = make(map[reflect.Type]uint64, len(s.Messages)) - s.types = make(map[uint64]reflect.Type, len(s.Messages)) - for i, msg := range s.Messages { - code := uint64(i) - typ := reflect.TypeOf(msg) - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - } - s.codes[typ] = code - s.types[code] = typ - } - }) -} - -// Length returns the number of message types in the protocol -func (s *Spec) Length() uint64 { - return uint64(len(s.Messages)) -} - -// GetCode returns the message code of a type, and boolean second argument is -// false if the message type is not found -func (s *Spec) GetCode(msg interface{}) (uint64, bool) { - s.init() - typ := reflect.TypeOf(msg) - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - } - code, ok := s.codes[typ] - return code, ok -} - -// NewMsg construct a new message type given the code -func (s *Spec) NewMsg(code uint64) (interface{}, bool) { - s.init() - typ, ok := s.types[code] - if !ok { - return nil, false - } - return reflect.New(typ).Interface(), true -} - -// Peer represents a remote peer or protocol instance that is running on a peer connection with -// a remote peer -type Peer struct { - *p2p.Peer // the p2p.Peer object representing the remote - rw p2p.MsgReadWriter // p2p.MsgReadWriter to send messages to and read messages from - spec *Spec -} - -// NewPeer constructs a new peer -// this constructor is called by the p2p.Protocol#Run function -// the first two arguments are the arguments passed to p2p.Protocol.Run function -// the third argument is the Spec describing the protocol -func NewPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *Spec) *Peer { - return &Peer{ - Peer: p, - rw: rw, - spec: spec, - } -} - -// Run starts the forever loop that handles incoming messages -// called within the p2p.Protocol#Run function -// the handler argument is a function which is called for each message received -// from the remote peer, a returned error causes the loop to exit -// resulting in disconnection -func (p *Peer) Run(handler func(ctx context.Context, msg interface{}) error) error { - for { - if err := p.handleIncoming(handler); err != nil { - if err != io.EOF { - metrics.GetOrRegisterCounter("peer.handleincoming.error", nil).Inc(1) - log.Error("peer.handleIncoming", "err", err) - } - - return err - } - } -} - -// Drop disconnects a peer. -// TODO: may need to implement protocol drop only? don't want to kick off the peer -// if they are useful for other protocols -func (p *Peer) Drop() { - p.Disconnect(p2p.DiscSubprotocolError) -} - -// Send takes a message, encodes it in RLP, finds the right message code and sends the -// message off to the peer -// this low level call will be wrapped by libraries providing routed or broadcast sends -// but often just used to forward and push messages to directly connected peers -func (p *Peer) Send(ctx context.Context, msg interface{}) error { - defer metrics.GetOrRegisterResettingTimer("peer.send_t", nil).UpdateSince(time.Now()) - metrics.GetOrRegisterCounter("peer.send", nil).Inc(1) - metrics.GetOrRegisterCounter(fmt.Sprintf("peer.send.%T", msg), nil).Inc(1) - - var b bytes.Buffer - if tracing.Enabled { - writer := bufio.NewWriter(&b) - - tracer := opentracing.GlobalTracer() - - sctx := spancontext.FromContext(ctx) - - if sctx != nil { - err := tracer.Inject( - sctx, - opentracing.Binary, - writer) - if err != nil { - return err - } - } - - writer.Flush() - } - - r, err := rlp.EncodeToBytes(msg) - if err != nil { - return err - } - - wmsg := WrappedMsg{ - Context: b.Bytes(), - Size: uint32(len(r)), - Payload: r, - } - - //if the accounting hook is set, call it - if p.spec.Hook != nil { - err := p.spec.Hook.Send(p, wmsg.Size, msg) - if err != nil { - p.Drop() - return err - } - } - - code, found := p.spec.GetCode(msg) - if !found { - return errorf(ErrInvalidMsgType, "%v", code) - } - return p2p.Send(p.rw, code, wmsg) -} - -// handleIncoming(code) -// is called each cycle of the main forever loop that dispatches incoming messages -// if this returns an error the loop returns and the peer is disconnected with the error -// this generic handler -// * checks message size, -// * checks for out-of-range message codes, -// * handles decoding with reflection, -// * call handlers as callbacks -func (p *Peer) handleIncoming(handle func(ctx context.Context, msg interface{}) error) error { - msg, err := p.rw.ReadMsg() - if err != nil { - return err - } - // make sure that the payload has been fully consumed - defer msg.Discard() - - if msg.Size > p.spec.MaxMsgSize { - return errorf(ErrMsgTooLong, "%v > %v", msg.Size, p.spec.MaxMsgSize) - } - - // unmarshal wrapped msg, which might contain context - var wmsg WrappedMsg - err = msg.Decode(&wmsg) - if err != nil { - log.Error(err.Error()) - return err - } - - ctx := context.Background() - - // if tracing is enabled and the context coming within the request is - // not empty, try to unmarshal it - if tracing.Enabled && len(wmsg.Context) > 0 { - var sctx opentracing.SpanContext - - tracer := opentracing.GlobalTracer() - sctx, err = tracer.Extract( - opentracing.Binary, - bytes.NewReader(wmsg.Context)) - if err != nil { - log.Error(err.Error()) - return err - } - - ctx = spancontext.WithContext(ctx, sctx) - } - - val, ok := p.spec.NewMsg(msg.Code) - if !ok { - return errorf(ErrInvalidMsgCode, "%v", msg.Code) - } - if err := rlp.DecodeBytes(wmsg.Payload, val); err != nil { - return errorf(ErrDecode, "<= %v: %v", msg, err) - } - - //if the accounting hook is set, call it - if p.spec.Hook != nil { - err := p.spec.Hook.Receive(p, wmsg.Size, val) - if err != nil { - return err - } - } - - // call the registered handler callbacks - // a registered callback take the decoded message as argument as an interface - // which the handler is supposed to cast to the appropriate type - // it is entirely safe not to check the cast in the handler since the handler is - // chosen based on the proper type in the first place - if err := handle(ctx, val); err != nil { - return errorf(ErrHandler, "(msg code %v): %v", msg.Code, err) - } - return nil -} - -// Handshake negotiates a handshake on the peer connection -// * arguments -// * context -// * the local handshake to be sent to the remote peer -// * function to be called on the remote handshake (can be nil) -// * expects a remote handshake back of the same type -// * the dialing peer needs to send the handshake first and then waits for remote -// * the listening peer waits for the remote handshake and then sends it -// returns the remote handshake and an error -func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interface{}) error) (interface{}, error) { - if _, ok := p.spec.GetCode(hs); !ok { - return nil, errorf(ErrHandshake, "unknown handshake message type: %T", hs) - } - - var rhs interface{} - errc := make(chan error, 2) - handle := func(ctx context.Context, msg interface{}) error { - rhs = msg - if verify != nil { - return verify(rhs) - } - return nil - } - send := func() { errc <- p.Send(ctx, hs) } - receive := func() { errc <- p.handleIncoming(handle) } - - go func() { - if p.Inbound() { - receive() - send() - } else { - send() - receive() - } - }() - - for i := 0; i < 2; i++ { - var err error - select { - case err = <-errc: - case <-ctx.Done(): - err = ctx.Err() - } - if err != nil { - return nil, errorf(ErrHandshake, err.Error()) - } - } - return rhs, nil -} - -// HasCap returns true if Peer has a capability -// with provided name. -func (p *Peer) HasCap(capName string) (yes bool) { - if p == nil || p.Peer == nil { - return false - } - for _, c := range p.Caps() { - if c.Name == capName { - return true - } - } - return false -} diff --git a/p2p/protocols/protocol_test.go b/p2p/protocols/protocol_test.go deleted file mode 100644 index 00526b97a7..0000000000 --- a/p2p/protocols/protocol_test.go +++ /dev/null @@ -1,624 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package protocols - -import ( - "bytes" - "context" - "errors" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/rlp" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" -) - -// handshake message type -type hs0 struct { - C uint -} - -// message to kill/drop the peer with nodeID -type kill struct { - C enode.ID -} - -// message to drop connection -type drop struct { -} - -/// protoHandshake represents module-independent aspects of the protocol and is -// the first message peers send and receive as part the initial exchange -type protoHandshake struct { - Version uint // local and remote peer should have identical version - NetworkID string // local and remote peer should have identical network id -} - -// checkProtoHandshake verifies local and remote protoHandshakes match -func checkProtoHandshake(testVersion uint, testNetworkID string) func(interface{}) error { - return func(rhs interface{}) error { - remote := rhs.(*protoHandshake) - if remote.NetworkID != testNetworkID { - return fmt.Errorf("%s (!= %s)", remote.NetworkID, testNetworkID) - } - - if remote.Version != testVersion { - return fmt.Errorf("%d (!= %d)", remote.Version, testVersion) - } - return nil - } -} - -// newProtocol sets up a protocol -// the run function here demonstrates a typical protocol using peerPool, handshake -// and messages registered to handlers -func newProtocol(pp *p2ptest.TestPeerPool) func(*p2p.Peer, p2p.MsgReadWriter) error { - spec := &Spec{ - Name: "test", - Version: 42, - MaxMsgSize: 10 * 1024, - Messages: []interface{}{ - protoHandshake{}, - hs0{}, - kill{}, - drop{}, - }, - } - return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := NewPeer(p, rw, spec) - - // initiate one-off protohandshake and check validity - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - phs := &protoHandshake{42, "420"} - hsCheck := checkProtoHandshake(phs.Version, phs.NetworkID) - _, err := peer.Handshake(ctx, phs, hsCheck) - if err != nil { - return err - } - - lhs := &hs0{42} - // module handshake demonstrating a simple repeatable exchange of same-type message - hs, err := peer.Handshake(ctx, lhs, nil) - if err != nil { - return err - } - - if rmhs := hs.(*hs0); rmhs.C > lhs.C { - return fmt.Errorf("handshake mismatch remote %v > local %v", rmhs.C, lhs.C) - } - - handle := func(ctx context.Context, msg interface{}) error { - switch msg := msg.(type) { - - case *protoHandshake: - return errors.New("duplicate handshake") - - case *hs0: - rhs := msg - if rhs.C > lhs.C { - return fmt.Errorf("handshake mismatch remote %v > local %v", rhs.C, lhs.C) - } - lhs.C += rhs.C - return peer.Send(ctx, lhs) - - case *kill: - // demonstrates use of peerPool, killing another peer connection as a response to a message - id := msg.C - pp.Get(id).Drop() - return nil - - case *drop: - // for testing we can trigger self induced disconnect upon receiving drop message - return errors.New("dropped") - - default: - return fmt.Errorf("unknown message type: %T", msg) - } - } - - pp.Add(peer) - defer pp.Remove(peer) - return peer.Run(handle) - } -} - -func protocolTester(pp *p2ptest.TestPeerPool) *p2ptest.ProtocolTester { - prvkey, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - return p2ptest.NewProtocolTester(prvkey, 2, newProtocol(pp)) -} - -func protoHandshakeExchange(id enode.ID, proto *protoHandshake) []p2ptest.Exchange { - - return []p2ptest.Exchange{ - { - Expects: []p2ptest.Expect{ - { - Code: 0, - Msg: &protoHandshake{42, "420"}, - Peer: id, - }, - }, - }, - { - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: proto, - Peer: id, - }, - }, - }, - } -} - -func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) { - t.Helper() - pp := p2ptest.NewTestPeerPool() - s := protocolTester(pp) - defer s.Stop() - - // TODO: make this more than one handshake - node := s.Nodes[0] - if err := s.TestExchanges(protoHandshakeExchange(node.ID(), proto)...); err != nil { - t.Fatal(err) - } - var disconnects []*p2ptest.Disconnect - for i, err := range errs { - disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err}) - } - if err := s.TestDisconnected(disconnects...); err != nil { - t.Fatal(err) - } -} - -type dummyHook struct { - peer *Peer - size uint32 - msg interface{} - send bool - err error - waitC chan struct{} - mu sync.Mutex -} - -type dummyMsg struct { - Content string -} - -func (d *dummyHook) Send(peer *Peer, size uint32, msg interface{}) error { - d.mu.Lock() - defer d.mu.Unlock() - - d.peer = peer - d.size = size - d.msg = msg - d.send = true - return d.err -} - -func (d *dummyHook) Receive(peer *Peer, size uint32, msg interface{}) error { - d.mu.Lock() - defer d.mu.Unlock() - - d.peer = peer - d.size = size - d.msg = msg - d.send = false - d.waitC <- struct{}{} - return d.err -} - -func TestProtocolHook(t *testing.T) { - testHook := &dummyHook{ - waitC: make(chan struct{}, 1), - } - spec := &Spec{ - Name: "test", - Version: 42, - MaxMsgSize: 10 * 1024, - Messages: []interface{}{ - dummyMsg{}, - }, - Hook: testHook, - } - - runFunc := func(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := NewPeer(p, rw, spec) - ctx := context.TODO() - err := peer.Send(ctx, &dummyMsg{ - Content: "handshake"}) - - if err != nil { - t.Fatal(err) - } - - handle := func(ctx context.Context, msg interface{}) error { - return nil - } - - return peer.Run(handle) - } - - prvkey, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - tester := p2ptest.NewProtocolTester(prvkey, 2, runFunc) - defer tester.Stop() - err = tester.TestExchanges(p2ptest.Exchange{ - Expects: []p2ptest.Expect{ - { - Code: 0, - Msg: &dummyMsg{Content: "handshake"}, - Peer: tester.Nodes[0].ID(), - }, - }, - }) - if err != nil { - t.Fatal(err) - } - testHook.mu.Lock() - if testHook.msg == nil || testHook.msg.(*dummyMsg).Content != "handshake" { - t.Fatal("Expected msg to be set, but it is not") - } - if !testHook.send { - t.Fatal("Expected a send message, but it is not") - } - if testHook.peer == nil { - t.Fatal("Expected peer to be set, is nil") - } - if peerId := testHook.peer.ID(); peerId != tester.Nodes[0].ID() && peerId != tester.Nodes[1].ID() { - t.Fatalf("Expected peer ID to be set correctly, but it is not (got %v, exp %v or %v", peerId, tester.Nodes[0].ID(), tester.Nodes[1].ID()) - } - if testHook.size != 11 { //11 is the length of the encoded message - t.Fatalf("Expected size to be %d, but it is %d ", 1, testHook.size) - } - testHook.mu.Unlock() - - err = tester.TestExchanges(p2ptest.Exchange{ - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: &dummyMsg{Content: "response"}, - Peer: tester.Nodes[1].ID(), - }, - }, - }) - - <-testHook.waitC - - if err != nil { - t.Fatal(err) - } - - testHook.mu.Lock() - if testHook.msg == nil || testHook.msg.(*dummyMsg).Content != "response" { - t.Fatal("Expected msg to be set, but it is not") - } - if testHook.send { - t.Fatal("Expected a send message, but it is not") - } - if testHook.peer == nil || testHook.peer.ID() != tester.Nodes[1].ID() { - t.Fatal("Expected peer ID to be set correctly, but it is not") - } - if testHook.size != 10 { //11 is the length of the encoded message - t.Fatalf("Expected size to be %d, but it is %d ", 1, testHook.size) - } - testHook.mu.Unlock() - - testHook.err = fmt.Errorf("dummy error") - err = tester.TestExchanges(p2ptest.Exchange{ - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: &dummyMsg{Content: "response"}, - Peer: tester.Nodes[1].ID(), - }, - }, - }) - - <-testHook.waitC - - time.Sleep(100 * time.Millisecond) - err = tester.TestDisconnected(&p2ptest.Disconnect{Peer: tester.Nodes[1].ID(), Error: testHook.err}) - if err != nil { - t.Fatalf("Expected a specific disconnect error, but got different one: %v", err) - } -} - -//We need to test that if the hook is not defined, then message infrastructure -//(send,receive) still works -func TestNoHook(t *testing.T) { - //create a test spec - spec := createTestSpec() - //a random node - id := adapters.RandomNodeConfig().ID - //a peer - p := p2p.NewPeer(id, "testPeer", nil) - rw := &dummyRW{} - peer := NewPeer(p, rw, spec) - ctx := context.TODO() - msg := &perBytesMsgSenderPays{Content: "testBalance"} - //send a message - - if err := peer.Send(ctx, msg); err != nil { - t.Fatal(err) - } - //simulate receiving a message - rw.msg = msg - handler := func(ctx context.Context, msg interface{}) error { - return nil - } - - if err := peer.handleIncoming(handler); err != nil { - t.Fatal(err) - } -} - -func TestProtoHandshakeVersionMismatch(t *testing.T) { - runProtoHandshake(t, &protoHandshake{41, "420"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 41 (!= 42)").Error())) -} - -func TestProtoHandshakeNetworkIDMismatch(t *testing.T) { - runProtoHandshake(t, &protoHandshake{42, "421"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 421 (!= 420)").Error())) -} - -func TestProtoHandshakeSuccess(t *testing.T) { - runProtoHandshake(t, &protoHandshake{42, "420"}) -} - -func moduleHandshakeExchange(id enode.ID, resp uint) []p2ptest.Exchange { - - return []p2ptest.Exchange{ - { - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &hs0{42}, - Peer: id, - }, - }, - }, - { - Triggers: []p2ptest.Trigger{ - { - Code: 1, - Msg: &hs0{resp}, - Peer: id, - }, - }, - }, - } -} - -func runModuleHandshake(t *testing.T, resp uint, errs ...error) { - t.Helper() - pp := p2ptest.NewTestPeerPool() - s := protocolTester(pp) - defer s.Stop() - - node := s.Nodes[0] - if err := s.TestExchanges(protoHandshakeExchange(node.ID(), &protoHandshake{42, "420"})...); err != nil { - t.Fatal(err) - } - if err := s.TestExchanges(moduleHandshakeExchange(node.ID(), resp)...); err != nil { - t.Fatal(err) - } - var disconnects []*p2ptest.Disconnect - for i, err := range errs { - disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err}) - } - if err := s.TestDisconnected(disconnects...); err != nil { - t.Fatal(err) - } -} - -func TestModuleHandshakeError(t *testing.T) { - runModuleHandshake(t, 43, fmt.Errorf("handshake mismatch remote 43 > local 42")) -} - -func TestModuleHandshakeSuccess(t *testing.T) { - runModuleHandshake(t, 42) -} - -// testing complex interactions over multiple peers, relaying, dropping -func testMultiPeerSetup(a, b enode.ID) []p2ptest.Exchange { - - return []p2ptest.Exchange{ - { - Label: "primary handshake", - Expects: []p2ptest.Expect{ - { - Code: 0, - Msg: &protoHandshake{42, "420"}, - Peer: a, - }, - { - Code: 0, - Msg: &protoHandshake{42, "420"}, - Peer: b, - }, - }, - }, - { - Label: "module handshake", - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: &protoHandshake{42, "420"}, - Peer: a, - }, - { - Code: 0, - Msg: &protoHandshake{42, "420"}, - Peer: b, - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &hs0{42}, - Peer: a, - }, - { - Code: 1, - Msg: &hs0{42}, - Peer: b, - }, - }, - }, - - {Label: "alternative module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{41}, Peer: a}, - {Code: 1, Msg: &hs0{41}, Peer: b}}}, - {Label: "repeated module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{1}, Peer: a}}}, - {Label: "receiving repeated module handshake", Expects: []p2ptest.Expect{{Code: 1, Msg: &hs0{43}, Peer: a}}}} -} - -func runMultiplePeers(t *testing.T, peer int, errs ...error) { - t.Helper() - pp := p2ptest.NewTestPeerPool() - s := protocolTester(pp) - defer s.Stop() - - if err := s.TestExchanges(testMultiPeerSetup(s.Nodes[0].ID(), s.Nodes[1].ID())...); err != nil { - t.Fatal(err) - } - // after some exchanges of messages, we can test state changes - // here this is simply demonstrated by the peerPool - // after the handshake negotiations peers must be added to the pool - // time.Sleep(1) - tick := time.NewTicker(10 * time.Millisecond) - timeout := time.NewTimer(1 * time.Second) -WAIT: - for { - select { - case <-tick.C: - if pp.Has(s.Nodes[0].ID()) { - break WAIT - } - case <-timeout.C: - t.Fatal("timeout") - } - } - if !pp.Has(s.Nodes[1].ID()) { - t.Fatalf("missing peer test-1: %v (%v)", pp, s.Nodes) - } - - // peer 0 sends kill request for peer with index - err := s.TestExchanges(p2ptest.Exchange{ - Triggers: []p2ptest.Trigger{ - { - Code: 2, - Msg: &kill{s.Nodes[peer].ID()}, - Peer: s.Nodes[0].ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - - // the peer not killed sends a drop request - err = s.TestExchanges(p2ptest.Exchange{ - Triggers: []p2ptest.Trigger{ - { - Code: 3, - Msg: &drop{}, - Peer: s.Nodes[(peer+1)%2].ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - - // check the actual discconnect errors on the individual peers - var disconnects []*p2ptest.Disconnect - for i, err := range errs { - disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err}) - } - if err := s.TestDisconnected(disconnects...); err != nil { - t.Fatal(err) - } - // test if disconnected peers have been removed from peerPool - if pp.Has(s.Nodes[peer].ID()) { - t.Fatalf("peer test-%v not dropped: %v (%v)", peer, pp, s.Nodes) - } - -} -func TestMultiplePeersDropSelf(t *testing.T) { - runMultiplePeers(t, 0, - fmt.Errorf("subprotocol error"), - fmt.Errorf("Message handler error: (msg code 3): dropped"), - ) -} - -func TestMultiplePeersDropOther(t *testing.T) { - runMultiplePeers(t, 1, - fmt.Errorf("Message handler error: (msg code 3): dropped"), - fmt.Errorf("subprotocol error"), - ) -} - -//dummy implementation of a MsgReadWriter -//this allows for quick and easy unit tests without -//having to build up the complete protocol -type dummyRW struct { - msg interface{} - size uint32 - code uint64 -} - -func (d *dummyRW) WriteMsg(msg p2p.Msg) error { - return nil -} - -func (d *dummyRW) ReadMsg() (p2p.Msg, error) { - enc := bytes.NewReader(d.getDummyMsg()) - return p2p.Msg{ - Code: d.code, - Size: d.size, - Payload: enc, - ReceivedAt: time.Now(), - }, nil -} - -func (d *dummyRW) getDummyMsg() []byte { - r, _ := rlp.EncodeToBytes(d.msg) - var b bytes.Buffer - wmsg := WrappedMsg{ - Context: b.Bytes(), - Size: uint32(len(r)), - Payload: r, - } - rr, _ := rlp.EncodeToBytes(wmsg) - d.size = uint32(len(rr)) - return rr -} diff --git a/p2p/protocols/reporter.go b/p2p/protocols/reporter.go deleted file mode 100644 index 9612b4a4d5..0000000000 --- a/p2p/protocols/reporter.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package protocols - -import ( - "encoding/binary" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - - "github.com/syndtr/goleveldb/leveldb" -) - -//AccountMetrics abstracts away the metrics DB and -//the reporter to persist metrics -type AccountingMetrics struct { - reporter *reporter -} - -//Close will be called when the node is being shutdown -//for a graceful cleanup -func (am *AccountingMetrics) Close() { - close(am.reporter.quit) - // wait for reporter loop to finish saving metrics - // before reporter database is closed - select { - case <-time.After(10 * time.Second): - log.Error("accounting metrics reporter timeout") - case <-am.reporter.done: - } - am.reporter.db.Close() -} - -//reporter is an internal structure used to write p2p accounting related -//metrics to a LevelDB. It will periodically write the accrued metrics to the DB. -type reporter struct { - reg metrics.Registry //the registry for these metrics (independent of other metrics) - interval time.Duration //duration at which the reporter will persist metrics - db *leveldb.DB //the actual DB - quit chan struct{} //quit the reporter loop - done chan struct{} //signal that reporter loop is done -} - -//NewMetricsDB creates a new LevelDB instance used to persist metrics defined -//inside p2p/protocols/accounting.go -func NewAccountingMetrics(r metrics.Registry, d time.Duration, path string) *AccountingMetrics { - var val = make([]byte, 8) - var err error - - //Create the LevelDB - db, err := leveldb.OpenFile(path, nil) - if err != nil { - log.Error(err.Error()) - return nil - } - - //Check for all defined metrics that there is a value in the DB - //If there is, assign it to the metric. This means that the node - //has been running before and that metrics have been persisted. - metricsMap := map[string]metrics.Counter{ - "account.balance.credit": mBalanceCredit, - "account.balance.debit": mBalanceDebit, - "account.bytes.credit": mBytesCredit, - "account.bytes.debit": mBytesDebit, - "account.msg.credit": mMsgCredit, - "account.msg.debit": mMsgDebit, - "account.peerdrops": mPeerDrops, - "account.selfdrops": mSelfDrops, - } - //iterate the map and get the values - for key, metric := range metricsMap { - val, err = db.Get([]byte(key), nil) - //until the first time a value is being written, - //this will return an error. - //it could be beneficial though to log errors later, - //but that would require a different logic - if err == nil { - metric.Inc(int64(binary.BigEndian.Uint64(val))) - } - } - - //create the reporter - rep := &reporter{ - reg: r, - interval: d, - db: db, - quit: make(chan struct{}), - done: make(chan struct{}), - } - - //run the go routine - go rep.run() - - m := &AccountingMetrics{ - reporter: rep, - } - - return m -} - -//run is the goroutine which periodically sends the metrics to the configured LevelDB -func (r *reporter) run() { - // signal that the reporter loop is done - defer close(r.done) - - intervalTicker := time.NewTicker(r.interval) - - for { - select { - case <-intervalTicker.C: - //at each tick send the metrics - if err := r.save(); err != nil { - log.Error("unable to send metrics to LevelDB", "err", err) - //If there is an error in writing, exit the routine; we assume here that the error is - //severe and don't attempt to write again. - //Also, this should prevent leaking when the node is stopped - return - } - case <-r.quit: - //graceful shutdown - if err := r.save(); err != nil { - log.Error("unable to send metrics to LevelDB", "err", err) - } - return - } - } -} - -//send the metrics to the DB -func (r *reporter) save() error { - //create a LevelDB Batch - batch := leveldb.Batch{} - //for each metric in the registry (which is independent)... - r.reg.Each(func(name string, i interface{}) { - metric, ok := i.(metrics.Counter) - if ok { - //assuming every metric here to be a Counter (separate registry) - //...create a snapshot... - ms := metric.Snapshot() - byteVal := make([]byte, 8) - binary.BigEndian.PutUint64(byteVal, uint64(ms.Count())) - //...and save the value to the DB - batch.Put([]byte(name), byteVal) - } - }) - return r.db.Write(&batch, nil) -} diff --git a/p2p/protocols/reporter_test.go b/p2p/protocols/reporter_test.go deleted file mode 100644 index 9b0da09b79..0000000000 --- a/p2p/protocols/reporter_test.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package protocols - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" -) - -//TestReporter tests that the metrics being collected for p2p accounting -//are being persisted and available after restart of a node. -//It simulates restarting by just recreating the DB as if the node had restarted. -func TestReporter(t *testing.T) { - //create a test directory - dir, err := ioutil.TempDir("", "reporter-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - //setup the metrics - log.Debug("Setting up metrics first time") - reportInterval := 2 * time.Millisecond - metrics := SetupAccountingMetrics(reportInterval, filepath.Join(dir, "test.db")) - log.Debug("Done.") - - //change metrics - mBalanceCredit.Inc(12) - mBytesCredit.Inc(34) - mMsgDebit.Inc(9) - - //store expected metrics - expectedBalanceCredit := mBalanceCredit.Count() - expectedBytesCredit := mBytesCredit.Count() - expectedMsgDebit := mMsgDebit.Count() - - //give the reporter time to write the metrics to DB - time.Sleep(20 * time.Millisecond) - - //close the DB also, or we can't create a new one - metrics.Close() - - //clear the metrics - this effectively simulates the node having shut down... - mBalanceCredit.Clear() - mBytesCredit.Clear() - mMsgDebit.Clear() - - //setup the metrics again - log.Debug("Setting up metrics second time") - metrics = SetupAccountingMetrics(reportInterval, filepath.Join(dir, "test.db")) - defer metrics.Close() - log.Debug("Done.") - - //now check the metrics, they should have the same value as before "shutdown" - if mBalanceCredit.Count() != expectedBalanceCredit { - t.Fatalf("Expected counter to be %d, but is %d", expectedBalanceCredit, mBalanceCredit.Count()) - } - if mBytesCredit.Count() != expectedBytesCredit { - t.Fatalf("Expected counter to be %d, but is %d", expectedBytesCredit, mBytesCredit.Count()) - } - if mMsgDebit.Count() != expectedMsgDebit { - t.Fatalf("Expected counter to be %d, but is %d", expectedMsgDebit, mMsgDebit.Count()) - } -} diff --git a/swarm/AUTHORS b/swarm/AUTHORS deleted file mode 100644 index f7232f07ce..0000000000 --- a/swarm/AUTHORS +++ /dev/null @@ -1,35 +0,0 @@ -# Core team members - -Viktor Trón - @zelig -Louis Holbrook - @nolash -Lewis Marshall - @lmars -Anton Evangelatov - @nonsense -Janoš Guljaš - @janos -Balint Gabor - @gbalint -Elad Nachmias - @justelad -Daniel A. Nagy - @nagydani -Aron Fischer - @homotopycolimit -Fabio Barone - @holisticode -Zahoor Mohamed - @jmozah -Zsolt Felföldi - @zsfelfoldi - -# External contributors - -Kiel Barry -Gary Rong -Jared Wasinger -Leon Stanko -Javier Peletier [epiclabs.io] -Bartek Borkowski [tungsten-labs.com] -Shane Howley [mainframe.com] -Doug Leonard [mainframe.com] -Ivan Daniluk [status.im] -Felix Lange [EF] -Martin Holst Swende [EF] -Guillaume Ballet [EF] -ligi [EF] -Christopher Dro [blick-labs.com] -Sergii Bomko [ledgerleopard.com] -Domino Valdano -Rafael Matias -Coogan Brennan \ No newline at end of file diff --git a/swarm/OWNERS b/swarm/OWNERS deleted file mode 100644 index 4b9ca96ebe..0000000000 --- a/swarm/OWNERS +++ /dev/null @@ -1,25 +0,0 @@ -# Ownership by go packages - -swarm -├── api ─────────────────── ethersphere -├── bmt ─────────────────── @zelig -├── dev ─────────────────── @lmars -├── fuse ────────────────── @jmozah, @holisticode -├── grafana_dashboards ──── @nonsense -├── metrics ─────────────── @nonsense, @holisticode -├── network ─────────────── ethersphere -│ ├── bitvector ───────── @zelig, @janos, @gbalint -│ ├── priorityqueue ───── @zelig, @janos, @gbalint -│ ├── simulations ─────── @zelig -│ └── stream ──────────── @janos, @zelig, @gbalint, @holisticode, @justelad -│ ├── intervals ───── @janos -│ └── testing ─────── @zelig -├── pot ─────────────────── @zelig -├── pss ─────────────────── @nolash, @zelig, @nonsense -├── services ────────────── @zelig -├── state ───────────────── @justelad -├── storage ─────────────── ethersphere -│ ├── encryption ──────── @gbalint, @zelig, @nagydani -│ ├── mock ────────────── @janos -│ └── feed ────────────── @nolash, @jpeletier -└── testutil ────────────── @lmars \ No newline at end of file diff --git a/swarm/README.md b/swarm/README.md index e81963217f..2658831813 100644 --- a/swarm/README.md +++ b/swarm/README.md @@ -1,244 +1,7 @@ -## Swarm +# Swarm -[https://swarm.ethereum.org](https://swarm.ethereum.org) +https://swarm.ethereum.org Swarm is a distributed storage platform and content distribution service, a native base layer service of the ethereum web3 stack. The primary objective of Swarm is to provide a decentralized and redundant store for dapp code and data as well as block chain and state data. Swarm is also set out to provide various base layer services for web3, including node-to-node messaging, media streaming, decentralised database services and scalable state-channel infrastructure for decentralised service economies. -[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethersphere/orange-lounge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -## Table of Contents - -* [Building the source](#building-the-source) -* [Running Swarm](#running-swarm) -* [Documentation](#documentation) -* [Developers Guide](#developers-guide) - * [Go Environment](#development-environment) - * [Vendored Dependencies](#vendored-dependencies) - * [Testing](#testing) - * [Profiling Swarm](#profiling-swarm) - * [Metrics and Instrumentation in Swarm](#metrics-and-instrumentation-in-swarm) -* [Public Gateways](#public-gateways) -* [Swarm Dapps](#swarm-dapps) -* [Contributing](#contributing) -* [License](#license) - -## Building the source - -Building Swarm requires Go (version 1.10 or later). - - go get -d github.com/ethereum/go-ethereum - - go install github.com/ethereum/go-ethereum/cmd/swarm - -## Running Swarm - -Going through all the possible command line flags is out of scope here, but we've enumerated a few common parameter combos to get you up to speed quickly on how you can run your own Swarm node. - -To run Swarm you need an Ethereum account. You can create a new account by running the following command: - - geth account new - -You will be prompted for a password: - - Your new account is locked with a password. Please give a password. Do not forget this password. - Passphrase: - Repeat passphrase: - -Once you have specified the password, the output will be the Ethereum address representing that account. For example: - - Address: {2f1cd699b0bf461dcfbf0098ad8f5587b038f0f1} - -Using this account, connect to Swarm with - - swarm --bzzaccount - - # in our example - - swarm --bzzaccount 2f1cd699b0bf461dcfbf0098ad8f5587b038f0f1 - - -### Verifying that your local Swarm node is running - -When running, Swarm is accessible through an HTTP API on port 8500. - -Confirm that it is up and running by pointing your browser to http://localhost:8500 - -### Ethereum Name Service resolution - -The Ethereum Name Service is the Ethereum equivalent of DNS in the classic web. In order to use ENS to resolve names to Swarm content hashes (e.g. `bzz://theswarm.eth`), `swarm` has to connect to a `geth` instance, which is synced with the Ethereum mainnet. This is done using the `--ens-api` flag. - - swarm --bzzaccount \ - --ens-api '$HOME/.ethereum/geth.ipc' - - # in our example - - swarm --bzzaccount 2f1cd699b0bf461dcfbf0098ad8f5587b038f0f1 \ - --ens-api '$HOME/.ethereum/geth.ipc' - -For more information on usage, features or command line flags, please consult the Documentation. - - -## Documentation - -Swarm documentation can be found at [https://swarm-guide.readthedocs.io](https://swarm-guide.readthedocs.io). - - -## Developers Guide - -### Go Environment - -We assume that you have Go v1.10 installed, and `GOPATH` is set. - -You must have your working copy under `$GOPATH/src/github.com/ethereum/go-ethereum`. - -Most likely you will be working from your fork of `go-ethereum`, let's say from `github.com/nirname/go-ethereum`. Clone or move your fork into the right place: - -``` -git clone git@github.com:nirname/go-ethereum.git $GOPATH/src/github.com/ethereum/go-ethereum -``` - - -### Vendored Dependencies - -All dependencies are tracked in the `vendor` directory. We use `govendor` to manage them. - -If you want to add a new dependency, run `govendor fetch `, then commit the result. - -If you want to update all dependencies to their latest upstream version, run `govendor fetch +v`. - - -### Testing - -This section explains how to run unit, integration, and end-to-end tests in your development sandbox. - -Testing one library: - -``` -go test -v -cpu 4 ./swarm/api -``` - -Note: Using options -cpu (number of cores allowed) and -v (logging even if no error) is recommended. - -Testing only some methods: - -``` -go test -v -cpu 4 ./eth -run TestMethod -``` - -Note: here all tests with prefix TestMethod will be run, so if you got TestMethod, TestMethod1, then both! - -Running benchmarks: - -``` -go test -v -cpu 4 -bench . -run BenchmarkJoin -``` - - -### Profiling Swarm - -This section explains how to add Go `pprof` profiler to Swarm - -If `swarm` is started with the `--pprof` option, a debugging HTTP server is made available on port 6060. - -You can bring up http://localhost:6060/debug/pprof to see the heap, running routines etc. - -By clicking full goroutine stack dump (clicking http://localhost:6060/debug/pprof/goroutine?debug=2) you can generate trace that is useful for debugging. - - -### Metrics and Instrumentation in Swarm - -This section explains how to visualize and use existing Swarm metrics and how to instrument Swarm with a new metric. - -Swarm metrics system is based on the `go-metrics` library. - -The most common types of measurements we use in Swarm are `counters` and `resetting timers`. Consult the `go-metrics` documentation for full reference of available types. - -``` -# incrementing a counter -metrics.GetOrRegisterCounter("network.stream.received_chunks", nil).Inc(1) - -# measuring latency with a resetting timer -start := time.Now() -t := metrics.GetOrRegisterResettingTimer("http.request.GET.time"), nil) -... -t := UpdateSince(start) -``` - -#### Visualizing metrics - -Swarm supports an InfluxDB exporter. Consult the help section to learn about the command line arguments used to configure it: - -``` -swarm --help | grep metrics -``` - -We use Grafana and InfluxDB to visualise metrics reported by Swarm. We keep our Grafana dashboards under version control at `./swarm/grafana_dashboards`. You could use them or design your own. - -We have built a tool to help with automatic start of Grafana and InfluxDB and provisioning of dashboards at https://github.com/nonsense/stateth , which requires that you have Docker installed. - -Once you have `stateth` installed, and you have Docker running locally, you have to: - -1. Run `stateth` and keep it running in the background -``` -stateth --rm --grafana-dashboards-folder $GOPATH/src/github.com/ethereum/go-ethereum/swarm/grafana_dashboards --influxdb-database metrics -``` - -2. Run `swarm` with at least the following params: -``` ---metrics \ ---metrics.influxdb.export \ ---metrics.influxdb.endpoint "http://localhost:8086" \ ---metrics.influxdb.username "admin" \ ---metrics.influxdb.password "admin" \ ---metrics.influxdb.database "metrics" -``` - -3. Open Grafana at http://localhost:3000 and view the dashboards to gain insight into Swarm. - - -## Public Gateways - -Swarm offers a local HTTP proxy API that Dapps can use to interact with Swarm. The Ethereum Foundation is hosting a public gateway, which allows free access so that people can try Swarm without running their own node. - -The Swarm public gateways are temporary and users should not rely on their existence for production services. - -The Swarm public gateway can be found at https://swarm-gateways.net and is always running the latest `stable` Swarm release. - -## Swarm Dapps - -You can find a few reference Swarm decentralised applications at: https://swarm-gateways.net/bzz:/swarmapps.eth - -Their source code can be found at: https://github.com/ethersphere/swarm-dapps - -## Contributing - -Thank you for considering to help out with the source code! We welcome contributions from -anyone on the internet, and are grateful for even the smallest of fixes! - -If you'd like to contribute to Swarm, please fork, fix, commit and send a pull request -for the maintainers to review and merge into the main code base. If you wish to submit more -complex changes though, please check up with the core devs first on [our Swarm gitter channel](https://gitter.im/ethersphere/orange-lounge) -to ensure those changes are in line with the general philosophy of the project and/or get some -early feedback which can make both your efforts much lighter as well as our review and merge -procedures quick and simple. - -Please make sure your contributions adhere to our coding guidelines: - - * Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). - * Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. - * Pull requests need to be based on and opened against the `master` branch. - * [Code review guidelines](https://github.com/ethereum/go-ethereum/wiki/Code-Review-Guidelines). - * Commit messages should be prefixed with the package(s) they modify. - * E.g. "swarm/fuse: ignore default manifest entry" - - -## License - -The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the -[GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html), also -included in our repository in the `COPYING.LESSER` file. - -The go-ethereum binaries (i.e. all code inside of the `cmd` directory) is licensed under the -[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also included -in our repository in the `COPYING` file. +**Note**: The codebase has been moved to [ethersphere/swarm](https://github.com/ethersphere/swarm) diff --git a/swarm/api/act.go b/swarm/api/act.go deleted file mode 100644 index a79f1944b9..0000000000 --- a/swarm/api/act.go +++ /dev/null @@ -1,538 +0,0 @@ -package api - -import ( - "context" - "crypto/ecdsa" - "crypto/rand" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/sctx" - "github.com/ethereum/go-ethereum/swarm/storage" - "golang.org/x/crypto/scrypt" - "golang.org/x/crypto/sha3" - cli "gopkg.in/urfave/cli.v1" -) - -var ( - ErrDecrypt = errors.New("cant decrypt - forbidden") - ErrUnknownAccessType = errors.New("unknown access type (or not implemented)") - ErrDecryptDomainForbidden = errors.New("decryption request domain forbidden - can only decrypt on localhost") - AllowedDecryptDomains = []string{ - "localhost", - "127.0.0.1", - } -) - -const EmptyCredentials = "" - -type AccessEntry struct { - Type AccessType - Publisher string - Salt []byte - Act string - KdfParams *KdfParams -} - -type DecryptFunc func(*ManifestEntry) error - -func (a *AccessEntry) MarshalJSON() (out []byte, err error) { - - return json.Marshal(struct { - Type AccessType `json:"type,omitempty"` - Publisher string `json:"publisher,omitempty"` - Salt string `json:"salt,omitempty"` - Act string `json:"act,omitempty"` - KdfParams *KdfParams `json:"kdf_params,omitempty"` - }{ - Type: a.Type, - Publisher: a.Publisher, - Salt: hex.EncodeToString(a.Salt), - Act: a.Act, - KdfParams: a.KdfParams, - }) - -} - -func (a *AccessEntry) UnmarshalJSON(value []byte) error { - v := struct { - Type AccessType `json:"type,omitempty"` - Publisher string `json:"publisher,omitempty"` - Salt string `json:"salt,omitempty"` - Act string `json:"act,omitempty"` - KdfParams *KdfParams `json:"kdf_params,omitempty"` - }{} - - err := json.Unmarshal(value, &v) - if err != nil { - return err - } - a.Act = v.Act - a.KdfParams = v.KdfParams - a.Publisher = v.Publisher - a.Salt, err = hex.DecodeString(v.Salt) - if err != nil { - return err - } - if len(a.Salt) != 32 { - return errors.New("salt should be 32 bytes long") - } - a.Type = v.Type - return nil -} - -type KdfParams struct { - N int `json:"n"` - P int `json:"p"` - R int `json:"r"` -} - -type AccessType string - -const AccessTypePass = AccessType("pass") -const AccessTypePK = AccessType("pk") -const AccessTypeACT = AccessType("act") - -// NewAccessEntryPassword creates a manifest AccessEntry in order to create an ACT protected by a password -func NewAccessEntryPassword(salt []byte, kdfParams *KdfParams) (*AccessEntry, error) { - if len(salt) != 32 { - return nil, fmt.Errorf("salt should be 32 bytes long") - } - return &AccessEntry{ - Type: AccessTypePass, - Salt: salt, - KdfParams: kdfParams, - }, nil -} - -// NewAccessEntryPK creates a manifest AccessEntry in order to create an ACT protected by a pair of Elliptic Curve keys -func NewAccessEntryPK(publisher string, salt []byte) (*AccessEntry, error) { - if len(publisher) != 66 { - return nil, fmt.Errorf("publisher should be 66 characters long, got %d", len(publisher)) - } - if len(salt) != 32 { - return nil, fmt.Errorf("salt should be 32 bytes long") - } - return &AccessEntry{ - Type: AccessTypePK, - Publisher: publisher, - Salt: salt, - }, nil -} - -// NewAccessEntryACT creates a manifest AccessEntry in order to create an ACT protected by a combination of EC keys and passwords -func NewAccessEntryACT(publisher string, salt []byte, act string) (*AccessEntry, error) { - if len(salt) != 32 { - return nil, fmt.Errorf("salt should be 32 bytes long") - } - if len(publisher) != 66 { - return nil, fmt.Errorf("publisher should be 66 characters long") - } - - return &AccessEntry{ - Type: AccessTypeACT, - Publisher: publisher, - Salt: salt, - Act: act, - KdfParams: DefaultKdfParams, - }, nil -} - -// NOOPDecrypt is a generic decrypt function that is passed into the API in places where real ACT decryption capabilities are -// either unwanted, or alternatively, cannot be implemented in the immediate scope -func NOOPDecrypt(*ManifestEntry) error { - return nil -} - -var DefaultKdfParams = NewKdfParams(262144, 1, 8) - -// NewKdfParams returns a KdfParams struct with the given scrypt params -func NewKdfParams(n, p, r int) *KdfParams { - - return &KdfParams{ - N: n, - P: p, - R: r, - } -} - -// NewSessionKeyPassword creates a session key based on a shared secret (password) and the given salt -// and kdf parameters in the access entry -func NewSessionKeyPassword(password string, accessEntry *AccessEntry) ([]byte, error) { - if accessEntry.Type != AccessTypePass && accessEntry.Type != AccessTypeACT { - return nil, errors.New("incorrect access entry type") - - } - return sessionKeyPassword(password, accessEntry.Salt, accessEntry.KdfParams) -} - -func sessionKeyPassword(password string, salt []byte, kdfParams *KdfParams) ([]byte, error) { - return scrypt.Key( - []byte(password), - salt, - kdfParams.N, - kdfParams.R, - kdfParams.P, - 32, - ) -} - -// NewSessionKeyPK creates a new ACT Session Key using an ECDH shared secret for the given key pair and the given salt value -func NewSessionKeyPK(private *ecdsa.PrivateKey, public *ecdsa.PublicKey, salt []byte) ([]byte, error) { - granteePubEcies := ecies.ImportECDSAPublic(public) - privateKey := ecies.ImportECDSA(private) - - bytes, err := privateKey.GenerateShared(granteePubEcies, 16, 16) - if err != nil { - return nil, err - } - bytes = append(salt, bytes...) - sessionKey := crypto.Keccak256(bytes) - return sessionKey, nil -} - -func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.PrivateKey) DecryptFunc { - return func(m *ManifestEntry) error { - if m.Access == nil { - return nil - } - - allowed := false - requestDomain := sctx.GetHost(ctx) - for _, v := range AllowedDecryptDomains { - if strings.Contains(requestDomain, v) { - allowed = true - } - } - - if !allowed { - return ErrDecryptDomainForbidden - } - - switch m.Access.Type { - case "pass": - if credentials != "" { - key, err := NewSessionKeyPassword(credentials, m.Access) - if err != nil { - return err - } - - ref, err := hex.DecodeString(m.Hash) - if err != nil { - return err - } - - enc := NewRefEncryption(len(ref) - 8) - decodedRef, err := enc.Decrypt(ref, key) - if err != nil { - return ErrDecrypt - } - - m.Hash = hex.EncodeToString(decodedRef) - m.Access = nil - return nil - } - return ErrDecrypt - case "pk": - publisherBytes, err := hex.DecodeString(m.Access.Publisher) - if err != nil { - return ErrDecrypt - } - publisher, err := crypto.DecompressPubkey(publisherBytes) - if err != nil { - return ErrDecrypt - } - key, err := NewSessionKeyPK(pk, publisher, m.Access.Salt) - if err != nil { - return ErrDecrypt - } - ref, err := hex.DecodeString(m.Hash) - if err != nil { - return err - } - - enc := NewRefEncryption(len(ref) - 8) - decodedRef, err := enc.Decrypt(ref, key) - if err != nil { - return ErrDecrypt - } - - m.Hash = hex.EncodeToString(decodedRef) - m.Access = nil - return nil - case "act": - var ( - sessionKey []byte - err error - ) - - publisherBytes, err := hex.DecodeString(m.Access.Publisher) - if err != nil { - return ErrDecrypt - } - publisher, err := crypto.DecompressPubkey(publisherBytes) - if err != nil { - return ErrDecrypt - } - - sessionKey, err = NewSessionKeyPK(pk, publisher, m.Access.Salt) - if err != nil { - return ErrDecrypt - } - - found, ciphertext, decryptionKey, err := a.getACTDecryptionKey(ctx, storage.Address(common.Hex2Bytes(m.Access.Act)), sessionKey) - if err != nil { - return err - } - if !found { - // try to fall back to password - if credentials != "" { - sessionKey, err = NewSessionKeyPassword(credentials, m.Access) - if err != nil { - return err - } - found, ciphertext, decryptionKey, err = a.getACTDecryptionKey(ctx, storage.Address(common.Hex2Bytes(m.Access.Act)), sessionKey) - if err != nil { - return err - } - if !found { - return ErrDecrypt - } - } else { - return ErrDecrypt - } - } - enc := NewRefEncryption(len(ciphertext) - 8) - decodedRef, err := enc.Decrypt(ciphertext, decryptionKey) - if err != nil { - return ErrDecrypt - } - - ref, err := hex.DecodeString(m.Hash) - if err != nil { - return err - } - - enc = NewRefEncryption(len(ref) - 8) - decodedMainRef, err := enc.Decrypt(ref, decodedRef) - if err != nil { - return ErrDecrypt - } - m.Hash = hex.EncodeToString(decodedMainRef) - m.Access = nil - return nil - } - return ErrUnknownAccessType - } -} - -func (a *API) getACTDecryptionKey(ctx context.Context, actManifestAddress storage.Address, sessionKey []byte) (found bool, ciphertext, decryptionKey []byte, err error) { - hasher := sha3.NewLegacyKeccak256() - hasher.Write(append(sessionKey, 0)) - lookupKey := hasher.Sum(nil) - hasher.Reset() - - hasher.Write(append(sessionKey, 1)) - accessKeyDecryptionKey := hasher.Sum(nil) - hasher.Reset() - - lk := hex.EncodeToString(lookupKey) - list, err := a.GetManifestList(ctx, NOOPDecrypt, actManifestAddress, lk) - if err != nil { - return false, nil, nil, err - } - for _, v := range list.Entries { - if v.Path == lk { - cipherTextBytes, err := hex.DecodeString(v.Hash) - if err != nil { - return false, nil, nil, err - } - return true, cipherTextBytes, accessKeyDecryptionKey, nil - } - } - return false, nil, nil, nil -} - -func GenerateAccessControlManifest(ctx *cli.Context, ref string, accessKey []byte, ae *AccessEntry) (*Manifest, error) { - refBytes, err := hex.DecodeString(ref) - if err != nil { - return nil, err - } - // encrypt ref with accessKey - enc := NewRefEncryption(len(refBytes)) - encrypted, err := enc.Encrypt(refBytes, accessKey) - if err != nil { - return nil, err - } - - m := &Manifest{ - Entries: []ManifestEntry{ - { - Hash: hex.EncodeToString(encrypted), - ContentType: ManifestType, - ModTime: time.Now(), - Access: ae, - }, - }, - } - - return m, nil -} - -// DoPK is a helper function to the CLI API that handles the entire business logic for -// creating a session key and access entry given the cli context, ec keys and salt -func DoPK(ctx *cli.Context, privateKey *ecdsa.PrivateKey, granteePublicKey string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) { - if granteePublicKey == "" { - return nil, nil, errors.New("need a grantee Public Key") - } - b, err := hex.DecodeString(granteePublicKey) - if err != nil { - log.Error("error decoding grantee public key", "err", err) - return nil, nil, err - } - - granteePub, err := crypto.DecompressPubkey(b) - if err != nil { - log.Error("error decompressing grantee public key", "err", err) - return nil, nil, err - } - - sessionKey, err = NewSessionKeyPK(privateKey, granteePub, salt) - if err != nil { - log.Error("error getting session key", "err", err) - return nil, nil, err - } - - ae, err = NewAccessEntryPK(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt) - if err != nil { - log.Error("error generating access entry", "err", err) - return nil, nil, err - } - - return sessionKey, ae, nil -} - -// DoACT is a helper function to the CLI API that handles the entire business logic for -// creating a access key, access entry and ACT manifest (including uploading it) given the cli context, ec keys, password grantees and salt -func DoACT(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees []string, encryptPasswords []string) (accessKey []byte, ae *AccessEntry, actManifest *Manifest, err error) { - if len(grantees) == 0 && len(encryptPasswords) == 0 { - return nil, nil, nil, errors.New("did not get any grantee public keys or any encryption passwords") - } - - publisherPub := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)) - grantees = append(grantees, publisherPub) - - accessKey = make([]byte, 32) - if _, err := io.ReadFull(rand.Reader, salt); err != nil { - panic("reading from crypto/rand failed: " + err.Error()) - } - if _, err := io.ReadFull(rand.Reader, accessKey); err != nil { - panic("reading from crypto/rand failed: " + err.Error()) - } - - lookupPathEncryptedAccessKeyMap := make(map[string]string) - i := 0 - for _, v := range grantees { - i++ - if v == "" { - return nil, nil, nil, errors.New("need a grantee Public Key") - } - b, err := hex.DecodeString(v) - if err != nil { - log.Error("error decoding grantee public key", "err", err) - return nil, nil, nil, err - } - - granteePub, err := crypto.DecompressPubkey(b) - if err != nil { - log.Error("error decompressing grantee public key", "err", err) - return nil, nil, nil, err - } - sessionKey, err := NewSessionKeyPK(privateKey, granteePub, salt) - if err != nil { - return nil, nil, nil, err - } - - hasher := sha3.NewLegacyKeccak256() - hasher.Write(append(sessionKey, 0)) - lookupKey := hasher.Sum(nil) - - hasher.Reset() - hasher.Write(append(sessionKey, 1)) - - accessKeyEncryptionKey := hasher.Sum(nil) - - enc := NewRefEncryption(len(accessKey)) - encryptedAccessKey, err := enc.Encrypt(accessKey, accessKeyEncryptionKey) - if err != nil { - return nil, nil, nil, err - } - lookupPathEncryptedAccessKeyMap[hex.EncodeToString(lookupKey)] = hex.EncodeToString(encryptedAccessKey) - } - - for _, pass := range encryptPasswords { - sessionKey, err := sessionKeyPassword(pass, salt, DefaultKdfParams) - if err != nil { - return nil, nil, nil, err - } - hasher := sha3.NewLegacyKeccak256() - hasher.Write(append(sessionKey, 0)) - lookupKey := hasher.Sum(nil) - - hasher.Reset() - hasher.Write(append(sessionKey, 1)) - - accessKeyEncryptionKey := hasher.Sum(nil) - - enc := NewRefEncryption(len(accessKey)) - encryptedAccessKey, err := enc.Encrypt(accessKey, accessKeyEncryptionKey) - if err != nil { - return nil, nil, nil, err - } - lookupPathEncryptedAccessKeyMap[hex.EncodeToString(lookupKey)] = hex.EncodeToString(encryptedAccessKey) - } - - m := &Manifest{ - Entries: []ManifestEntry{}, - } - - for k, v := range lookupPathEncryptedAccessKeyMap { - m.Entries = append(m.Entries, ManifestEntry{ - Path: k, - Hash: v, - ContentType: "text/plain", - }) - } - - ae, err = NewAccessEntryACT(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt, "") - if err != nil { - return nil, nil, nil, err - } - - return accessKey, ae, m, nil -} - -// DoPassword is a helper function to the CLI API that handles the entire business logic for -// creating a session key and an access entry given the cli context, password and salt. -// By default - DefaultKdfParams are used as the scrypt params -func DoPassword(ctx *cli.Context, password string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) { - ae, err = NewAccessEntryPassword(salt, DefaultKdfParams) - if err != nil { - return nil, nil, err - } - - sessionKey, err = NewSessionKeyPassword(password, ae) - if err != nil { - return nil, nil, err - } - return sessionKey, ae, nil -} diff --git a/swarm/api/api.go b/swarm/api/api.go deleted file mode 100644 index 96fb86e1cc..0000000000 --- a/swarm/api/api.go +++ /dev/null @@ -1,993 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -//go:generate mimegen --types=./../../cmd/swarm/mimegen/mime.types --package=api --out=gen_mime.go -//go:generate gofmt -s -w gen_mime.go - -import ( - "archive/tar" - "context" - "crypto/ecdsa" - "encoding/hex" - "errors" - "fmt" - "io" - "math/big" - "net/http" - "path" - "strings" - - "bytes" - "mime" - "path/filepath" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/ens" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/spancontext" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" - - opentracing "github.com/opentracing/opentracing-go" -) - -var ( - apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil) - apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil) - apiGetCount = metrics.NewRegisteredCounter("api.get.count", nil) - apiGetNotFound = metrics.NewRegisteredCounter("api.get.notfound", nil) - apiGetHTTP300 = metrics.NewRegisteredCounter("api.get.http.300", nil) - apiManifestUpdateCount = metrics.NewRegisteredCounter("api.manifestupdate.count", nil) - apiManifestUpdateFail = metrics.NewRegisteredCounter("api.manifestupdate.fail", nil) - apiManifestListCount = metrics.NewRegisteredCounter("api.manifestlist.count", nil) - apiManifestListFail = metrics.NewRegisteredCounter("api.manifestlist.fail", nil) - apiDeleteCount = metrics.NewRegisteredCounter("api.delete.count", nil) - apiDeleteFail = metrics.NewRegisteredCounter("api.delete.fail", nil) - apiGetTarCount = metrics.NewRegisteredCounter("api.gettar.count", nil) - apiGetTarFail = metrics.NewRegisteredCounter("api.gettar.fail", nil) - apiUploadTarCount = metrics.NewRegisteredCounter("api.uploadtar.count", nil) - apiUploadTarFail = metrics.NewRegisteredCounter("api.uploadtar.fail", nil) - apiModifyCount = metrics.NewRegisteredCounter("api.modify.count", nil) - apiModifyFail = metrics.NewRegisteredCounter("api.modify.fail", nil) - apiAddFileCount = metrics.NewRegisteredCounter("api.addfile.count", nil) - apiAddFileFail = metrics.NewRegisteredCounter("api.addfile.fail", nil) - apiRmFileCount = metrics.NewRegisteredCounter("api.removefile.count", nil) - apiRmFileFail = metrics.NewRegisteredCounter("api.removefile.fail", nil) - apiAppendFileCount = metrics.NewRegisteredCounter("api.appendfile.count", nil) - apiAppendFileFail = metrics.NewRegisteredCounter("api.appendfile.fail", nil) - apiGetInvalid = metrics.NewRegisteredCounter("api.get.invalid", nil) -) - -// Resolver interface resolve a domain name to a hash using ENS -type Resolver interface { - Resolve(string) (common.Hash, error) -} - -// ResolveValidator is used to validate the contained Resolver -type ResolveValidator interface { - Resolver - Owner(node [32]byte) (common.Address, error) - HeaderByNumber(context.Context, *big.Int) (*types.Header, error) -} - -// NoResolverError is returned by MultiResolver.Resolve if no resolver -// can be found for the address. -type NoResolverError struct { - TLD string -} - -// NewNoResolverError creates a NoResolverError for the given top level domain -func NewNoResolverError(tld string) *NoResolverError { - return &NoResolverError{TLD: tld} -} - -// Error NoResolverError implements error -func (e *NoResolverError) Error() string { - if e.TLD == "" { - return "no ENS resolver" - } - return fmt.Sprintf("no ENS endpoint configured to resolve .%s TLD names", e.TLD) -} - -// MultiResolver is used to resolve URL addresses based on their TLDs. -// Each TLD can have multiple resolvers, and the resolution from the -// first one in the sequence will be returned. -type MultiResolver struct { - resolvers map[string][]ResolveValidator - nameHash func(string) common.Hash -} - -// MultiResolverOption sets options for MultiResolver and is used as -// arguments for its constructor. -type MultiResolverOption func(*MultiResolver) - -// MultiResolverOptionWithResolver adds a Resolver to a list of resolvers -// for a specific TLD. If TLD is an empty string, the resolver will be added -// to the list of default resolver, the ones that will be used for resolution -// of addresses which do not have their TLD resolver specified. -func MultiResolverOptionWithResolver(r ResolveValidator, tld string) MultiResolverOption { - return func(m *MultiResolver) { - m.resolvers[tld] = append(m.resolvers[tld], r) - } -} - -// NewMultiResolver creates a new instance of MultiResolver. -func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) { - m = &MultiResolver{ - resolvers: make(map[string][]ResolveValidator), - nameHash: ens.EnsNode, - } - for _, o := range opts { - o(m) - } - return m -} - -// Resolve resolves address by choosing a Resolver by TLD. -// If there are more default Resolvers, or for a specific TLD, -// the Hash from the first one which does not return error -// will be returned. -func (m *MultiResolver) Resolve(addr string) (h common.Hash, err error) { - rs, err := m.getResolveValidator(addr) - if err != nil { - return h, err - } - for _, r := range rs { - h, err = r.Resolve(addr) - if err == nil { - return - } - } - return -} - -// getResolveValidator uses the hostname to retrieve the resolver associated with the top level domain -func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, error) { - rs := m.resolvers[""] - tld := path.Ext(name) - if tld != "" { - tld = tld[1:] - rstld, ok := m.resolvers[tld] - if ok { - return rstld, nil - } - } - if len(rs) == 0 { - return rs, NewNoResolverError(tld) - } - return rs, nil -} - -/* -API implements webserver/file system related content storage and retrieval -on top of the FileStore -it is the public interface of the FileStore which is included in the ethereum stack -*/ -type API struct { - feed *feed.Handler - fileStore *storage.FileStore - dns Resolver - Tags *chunk.Tags - Decryptor func(context.Context, string) DecryptFunc -} - -// NewAPI the api constructor initialises a new API instance. -func NewAPI(fileStore *storage.FileStore, dns Resolver, feedHandler *feed.Handler, pk *ecdsa.PrivateKey, tags *chunk.Tags) (self *API) { - self = &API{ - fileStore: fileStore, - dns: dns, - feed: feedHandler, - Tags: tags, - Decryptor: func(ctx context.Context, credentials string) DecryptFunc { - return self.doDecrypt(ctx, credentials, pk) - }, - } - return -} - -// Retrieve FileStore reader API -func (a *API) Retrieve(ctx context.Context, addr storage.Address) (reader storage.LazySectionReader, isEncrypted bool) { - return a.fileStore.Retrieve(ctx, addr) -} - -// Store wraps the Store API call of the embedded FileStore -func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr storage.Address, wait func(ctx context.Context) error, err error) { - log.Debug("api.store", "size", size) - return a.fileStore.Store(ctx, data, size, toEncrypt) -} - -// Resolve a name into a content-addressed hash -// where address could be an ENS name, or a content addressed hash -func (a *API) Resolve(ctx context.Context, address string) (storage.Address, error) { - // if DNS is not configured, return an error - if a.dns == nil { - if hashMatcher.MatchString(address) { - return common.Hex2Bytes(address), nil - } - apiResolveFail.Inc(1) - return nil, fmt.Errorf("no DNS to resolve name: %q", address) - } - // try and resolve the address - resolved, err := a.dns.Resolve(address) - if err != nil { - if hashMatcher.MatchString(address) { - return common.Hex2Bytes(address), nil - } - return nil, err - } - return resolved[:], nil -} - -// Resolve resolves a URI to an Address using the MultiResolver. -func (a *API) ResolveURI(ctx context.Context, uri *URI, credentials string) (storage.Address, error) { - apiResolveCount.Inc(1) - log.Trace("resolving", "uri", uri.Addr) - - var sp opentracing.Span - ctx, sp = spancontext.StartSpan( - ctx, - "api.resolve") - defer sp.Finish() - - // if the URI is immutable, check if the address looks like a hash - if uri.Immutable() { - key := uri.Address() - if key == nil { - return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr) - } - return key, nil - } - - addr, err := a.Resolve(ctx, uri.Addr) - if err != nil { - return nil, err - } - - if uri.Path == "" { - return addr, nil - } - walker, err := a.NewManifestWalker(ctx, addr, a.Decryptor(ctx, credentials), nil) - if err != nil { - return nil, err - } - var entry *ManifestEntry - walker.Walk(func(e *ManifestEntry) error { - // if the entry matches the path, set entry and stop - // the walk - if e.Path == uri.Path { - entry = e - // return an error to cancel the walk - return errors.New("found") - } - // ignore non-manifest files - if e.ContentType != ManifestType { - return nil - } - // if the manifest's path is a prefix of the - // requested path, recurse into it by returning - // nil and continuing the walk - if strings.HasPrefix(uri.Path, e.Path) { - return nil - } - return ErrSkipManifest - }) - if entry == nil { - return nil, errors.New("not found") - } - addr = storage.Address(common.Hex2Bytes(entry.Hash)) - return addr, nil -} - -// Get uses iterative manifest retrieval and prefix matching -// to resolve basePath to content using FileStore retrieve -// it returns a section reader, mimeType, status, the key of the actual content and an error -func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage.Address, path string) (reader storage.LazySectionReader, mimeType string, status int, contentAddr storage.Address, err error) { - log.Debug("api.get", "key", manifestAddr, "path", path) - apiGetCount.Inc(1) - trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, decrypt) - if err != nil { - apiGetNotFound.Inc(1) - status = http.StatusNotFound - return nil, "", http.StatusNotFound, nil, err - } - - log.Debug("trie getting entry", "key", manifestAddr, "path", path) - entry, _ := trie.getEntry(path) - - if entry != nil { - log.Debug("trie got entry", "key", manifestAddr, "path", path, "entry.Hash", entry.Hash) - - if entry.ContentType == ManifestType { - log.Debug("entry is manifest", "key", manifestAddr, "new key", entry.Hash) - adr, err := hex.DecodeString(entry.Hash) - if err != nil { - return nil, "", 0, nil, err - } - return a.Get(ctx, decrypt, adr, entry.Path) - } - - // we need to do some extra work if this is a Swarm feed manifest - if entry.ContentType == FeedContentType { - if entry.Feed == nil { - return reader, mimeType, status, nil, fmt.Errorf("Cannot decode Feed in manifest") - } - _, err := a.feed.Lookup(ctx, feed.NewQueryLatest(entry.Feed, lookup.NoClue)) - if err != nil { - apiGetNotFound.Inc(1) - status = http.StatusNotFound - log.Debug(fmt.Sprintf("get feed update content error: %v", err)) - return reader, mimeType, status, nil, err - } - // get the data of the update - _, contentAddr, err := a.feed.GetContent(entry.Feed) - if err != nil { - apiGetNotFound.Inc(1) - status = http.StatusNotFound - log.Warn(fmt.Sprintf("get feed update content error: %v", err)) - return reader, mimeType, status, nil, err - } - - // extract content hash - if len(contentAddr) != storage.AddressLength { - apiGetInvalid.Inc(1) - status = http.StatusUnprocessableEntity - errorMessage := fmt.Sprintf("invalid swarm hash in feed update. Expected %d bytes. Got %d", storage.AddressLength, len(contentAddr)) - log.Warn(errorMessage) - return reader, mimeType, status, nil, errors.New(errorMessage) - } - manifestAddr = storage.Address(contentAddr) - log.Trace("feed update contains swarm hash", "key", manifestAddr) - - // get the manifest the swarm hash points to - trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, NOOPDecrypt) - if err != nil { - apiGetNotFound.Inc(1) - status = http.StatusNotFound - log.Warn(fmt.Sprintf("loadManifestTrie (feed update) error: %v", err)) - return reader, mimeType, status, nil, err - } - - // finally, get the manifest entry - // it will always be the entry on path "" - entry, _ = trie.getEntry(path) - if entry == nil { - status = http.StatusNotFound - apiGetNotFound.Inc(1) - err = fmt.Errorf("manifest (feed update) entry for '%s' not found", path) - log.Trace("manifest (feed update) entry not found", "key", manifestAddr, "path", path) - return reader, mimeType, status, nil, err - } - } - - // regardless of feed update manifests or normal manifests we will converge at this point - // get the key the manifest entry points to and serve it if it's unambiguous - contentAddr = common.Hex2Bytes(entry.Hash) - status = entry.Status - if status == http.StatusMultipleChoices { - apiGetHTTP300.Inc(1) - return nil, entry.ContentType, status, contentAddr, err - } - mimeType = entry.ContentType - log.Debug("content lookup key", "key", contentAddr, "mimetype", mimeType) - reader, _ = a.fileStore.Retrieve(ctx, contentAddr) - } else { - // no entry found - status = http.StatusNotFound - apiGetNotFound.Inc(1) - err = fmt.Errorf("Not found: could not find resource '%s'", path) - log.Trace("manifest entry not found", "key", contentAddr, "path", path) - } - return -} - -func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Address, error) { - apiDeleteCount.Inc(1) - uri, err := Parse("bzz:/" + addr) - if err != nil { - apiDeleteFail.Inc(1) - return nil, err - } - key, err := a.ResolveURI(ctx, uri, EmptyCredentials) - - if err != nil { - return nil, err - } - newKey, err := a.UpdateManifest(ctx, key, func(mw *ManifestWriter) error { - log.Debug(fmt.Sprintf("removing %s from manifest %s", path, key.Log())) - return mw.RemoveEntry(path) - }) - if err != nil { - apiDeleteFail.Inc(1) - return nil, err - } - - return newKey, nil -} - -// GetDirectoryTar fetches a requested directory as a tarstream -// it returns an io.Reader and an error. Do not forget to Close() the returned ReadCloser -func (a *API) GetDirectoryTar(ctx context.Context, decrypt DecryptFunc, uri *URI) (io.ReadCloser, error) { - apiGetTarCount.Inc(1) - addr, err := a.Resolve(ctx, uri.Addr) - if err != nil { - return nil, err - } - walker, err := a.NewManifestWalker(ctx, addr, decrypt, nil) - if err != nil { - apiGetTarFail.Inc(1) - return nil, err - } - - piper, pipew := io.Pipe() - - tw := tar.NewWriter(pipew) - - go func() { - err := walker.Walk(func(entry *ManifestEntry) error { - // ignore manifests (walk will recurse into them) - if entry.ContentType == ManifestType { - return nil - } - - // retrieve the entry's key and size - reader, _ := a.Retrieve(ctx, storage.Address(common.Hex2Bytes(entry.Hash))) - size, err := reader.Size(ctx, nil) - if err != nil { - return err - } - - // write a tar header for the entry - hdr := &tar.Header{ - Name: entry.Path, - Mode: entry.Mode, - Size: size, - ModTime: entry.ModTime, - Xattrs: map[string]string{ - "user.swarm.content-type": entry.ContentType, - }, - } - - if err := tw.WriteHeader(hdr); err != nil { - return err - } - - // copy the file into the tar stream - n, err := io.Copy(tw, io.LimitReader(reader, hdr.Size)) - if err != nil { - return err - } else if n != size { - return fmt.Errorf("error writing %s: expected %d bytes but sent %d", entry.Path, size, n) - } - - return nil - }) - // close tar writer before closing pipew - // to flush remaining data to pipew - // regardless of error value - tw.Close() - if err != nil { - apiGetTarFail.Inc(1) - pipew.CloseWithError(err) - } else { - pipew.Close() - } - }() - - return piper, nil -} - -// GetManifestList lists the manifest entries for the specified address and prefix -// and returns it as a ManifestList -func (a *API) GetManifestList(ctx context.Context, decryptor DecryptFunc, addr storage.Address, prefix string) (list ManifestList, err error) { - apiManifestListCount.Inc(1) - walker, err := a.NewManifestWalker(ctx, addr, decryptor, nil) - if err != nil { - apiManifestListFail.Inc(1) - return ManifestList{}, err - } - - err = walker.Walk(func(entry *ManifestEntry) error { - // handle non-manifest files - if entry.ContentType != ManifestType { - // ignore the file if it doesn't have the specified prefix - if !strings.HasPrefix(entry.Path, prefix) { - return nil - } - - // if the path after the prefix contains a slash, add a - // common prefix to the list, otherwise add the entry - suffix := strings.TrimPrefix(entry.Path, prefix) - if index := strings.Index(suffix, "/"); index > -1 { - list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) - return nil - } - if entry.Path == "" { - entry.Path = "/" - } - list.Entries = append(list.Entries, entry) - return nil - } - - // if the manifest's path is a prefix of the specified prefix - // then just recurse into the manifest by returning nil and - // continuing the walk - if strings.HasPrefix(prefix, entry.Path) { - return nil - } - - // if the manifest's path has the specified prefix, then if the - // path after the prefix contains a slash, add a common prefix - // to the list and skip the manifest, otherwise recurse into - // the manifest by returning nil and continuing the walk - if strings.HasPrefix(entry.Path, prefix) { - suffix := strings.TrimPrefix(entry.Path, prefix) - if index := strings.Index(suffix, "/"); index > -1 { - list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) - return ErrSkipManifest - } - return nil - } - - // the manifest neither has the prefix or needs recursing in to - // so just skip it - return ErrSkipManifest - }) - - if err != nil { - apiManifestListFail.Inc(1) - return ManifestList{}, err - } - - return list, nil -} - -func (a *API) UpdateManifest(ctx context.Context, addr storage.Address, update func(mw *ManifestWriter) error) (storage.Address, error) { - apiManifestUpdateCount.Inc(1) - mw, err := a.NewManifestWriter(ctx, addr, nil) - if err != nil { - apiManifestUpdateFail.Inc(1) - return nil, err - } - - if err := update(mw); err != nil { - apiManifestUpdateFail.Inc(1) - return nil, err - } - - addr, err = mw.Store() - if err != nil { - apiManifestUpdateFail.Inc(1) - return nil, err - } - log.Debug(fmt.Sprintf("generated manifest %s", addr)) - return addr, nil -} - -// Modify loads manifest and checks the content hash before recalculating and storing the manifest. -func (a *API) Modify(ctx context.Context, addr storage.Address, path, contentHash, contentType string) (storage.Address, error) { - apiModifyCount.Inc(1) - quitC := make(chan bool) - trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) - if err != nil { - apiModifyFail.Inc(1) - return nil, err - } - if contentHash != "" { - entry := newManifestTrieEntry(&ManifestEntry{ - Path: path, - ContentType: contentType, - }, nil) - entry.Hash = contentHash - trie.addEntry(entry, quitC) - } else { - trie.deleteEntry(path, quitC) - } - - if err := trie.recalcAndStore(); err != nil { - apiModifyFail.Inc(1) - return nil, err - } - return trie.ref, nil -} - -// AddFile creates a new manifest entry, adds it to swarm, then adds a file to swarm. -func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content []byte, nameresolver bool) (storage.Address, string, error) { - apiAddFileCount.Inc(1) - - uri, err := Parse("bzz:/" + mhash) - if err != nil { - apiAddFileFail.Inc(1) - return nil, "", err - } - mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) - if err != nil { - apiAddFileFail.Inc(1) - return nil, "", err - } - - // trim the root dir we added - if path[:1] == "/" { - path = path[1:] - } - - entry := &ManifestEntry{ - Path: filepath.Join(path, fname), - ContentType: mime.TypeByExtension(filepath.Ext(fname)), - Mode: 0700, - Size: int64(len(content)), - ModTime: time.Now(), - } - - mw, err := a.NewManifestWriter(ctx, mkey, nil) - if err != nil { - apiAddFileFail.Inc(1) - return nil, "", err - } - - fkey, err := mw.AddEntry(ctx, bytes.NewReader(content), entry) - if err != nil { - apiAddFileFail.Inc(1) - return nil, "", err - } - - newMkey, err := mw.Store() - if err != nil { - apiAddFileFail.Inc(1) - return nil, "", err - - } - - return fkey, newMkey.String(), nil -} - -func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath, defaultPath string, mw *ManifestWriter) (storage.Address, error) { - apiUploadTarCount.Inc(1) - var contentKey storage.Address - tr := tar.NewReader(bodyReader) - defer bodyReader.Close() - var defaultPathFound bool - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } else if err != nil { - apiUploadTarFail.Inc(1) - return nil, fmt.Errorf("error reading tar stream: %s", err) - } - - // only store regular files - if !hdr.FileInfo().Mode().IsRegular() { - continue - } - - // add the entry under the path from the request - manifestPath := path.Join(manifestPath, hdr.Name) - contentType := hdr.Xattrs["user.swarm.content-type"] - if contentType == "" { - contentType = mime.TypeByExtension(filepath.Ext(hdr.Name)) - } - //DetectContentType("") - entry := &ManifestEntry{ - Path: manifestPath, - ContentType: contentType, - Mode: hdr.Mode, - Size: hdr.Size, - ModTime: hdr.ModTime, - } - contentKey, err = mw.AddEntry(ctx, tr, entry) - if err != nil { - apiUploadTarFail.Inc(1) - return nil, fmt.Errorf("error adding manifest entry from tar stream: %s", err) - } - if hdr.Name == defaultPath { - contentType := hdr.Xattrs["user.swarm.content-type"] - if contentType == "" { - contentType = mime.TypeByExtension(filepath.Ext(hdr.Name)) - } - - entry := &ManifestEntry{ - Hash: contentKey.Hex(), - Path: "", // default entry - ContentType: contentType, - Mode: hdr.Mode, - Size: hdr.Size, - ModTime: hdr.ModTime, - } - contentKey, err = mw.AddEntry(ctx, nil, entry) - if err != nil { - apiUploadTarFail.Inc(1) - return nil, fmt.Errorf("error adding default manifest entry from tar stream: %s", err) - } - defaultPathFound = true - } - } - if defaultPath != "" && !defaultPathFound { - return contentKey, fmt.Errorf("default path %q not found", defaultPath) - } - return contentKey, nil -} - -// RemoveFile removes a file entry in a manifest. -func (a *API) RemoveFile(ctx context.Context, mhash string, path string, fname string, nameresolver bool) (string, error) { - apiRmFileCount.Inc(1) - - uri, err := Parse("bzz:/" + mhash) - if err != nil { - apiRmFileFail.Inc(1) - return "", err - } - mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) - if err != nil { - apiRmFileFail.Inc(1) - return "", err - } - - // trim the root dir we added - if path[:1] == "/" { - path = path[1:] - } - - mw, err := a.NewManifestWriter(ctx, mkey, nil) - if err != nil { - apiRmFileFail.Inc(1) - return "", err - } - - err = mw.RemoveEntry(filepath.Join(path, fname)) - if err != nil { - apiRmFileFail.Inc(1) - return "", err - } - - newMkey, err := mw.Store() - if err != nil { - apiRmFileFail.Inc(1) - return "", err - - } - - return newMkey.String(), nil -} - -// AppendFile removes old manifest, appends file entry to new manifest and adds it to Swarm. -func (a *API) AppendFile(ctx context.Context, mhash, path, fname string, existingSize int64, content []byte, oldAddr storage.Address, offset int64, addSize int64, nameresolver bool) (storage.Address, string, error) { - apiAppendFileCount.Inc(1) - - buffSize := offset + addSize - if buffSize < existingSize { - buffSize = existingSize - } - - buf := make([]byte, buffSize) - - oldReader, _ := a.Retrieve(ctx, oldAddr) - io.ReadAtLeast(oldReader, buf, int(offset)) - - newReader := bytes.NewReader(content) - io.ReadAtLeast(newReader, buf[offset:], int(addSize)) - - if buffSize < existingSize { - io.ReadAtLeast(oldReader, buf[addSize:], int(buffSize)) - } - - combinedReader := bytes.NewReader(buf) - totalSize := int64(len(buf)) - - // TODO(jmozah): to append using pyramid chunker when it is ready - //oldReader := a.Retrieve(oldKey) - //newReader := bytes.NewReader(content) - //combinedReader := io.MultiReader(oldReader, newReader) - - uri, err := Parse("bzz:/" + mhash) - if err != nil { - apiAppendFileFail.Inc(1) - return nil, "", err - } - mkey, err := a.ResolveURI(ctx, uri, EmptyCredentials) - if err != nil { - apiAppendFileFail.Inc(1) - return nil, "", err - } - - // trim the root dir we added - if path[:1] == "/" { - path = path[1:] - } - - mw, err := a.NewManifestWriter(ctx, mkey, nil) - if err != nil { - apiAppendFileFail.Inc(1) - return nil, "", err - } - - err = mw.RemoveEntry(filepath.Join(path, fname)) - if err != nil { - apiAppendFileFail.Inc(1) - return nil, "", err - } - - entry := &ManifestEntry{ - Path: filepath.Join(path, fname), - ContentType: mime.TypeByExtension(filepath.Ext(fname)), - Mode: 0700, - Size: totalSize, - ModTime: time.Now(), - } - - fkey, err := mw.AddEntry(ctx, io.Reader(combinedReader), entry) - if err != nil { - apiAppendFileFail.Inc(1) - return nil, "", err - } - - newMkey, err := mw.Store() - if err != nil { - apiAppendFileFail.Inc(1) - return nil, "", err - - } - - return fkey, newMkey.String(), nil -} - -// BuildDirectoryTree used by swarmfs_unix -func (a *API) BuildDirectoryTree(ctx context.Context, mhash string, nameresolver bool) (addr storage.Address, manifestEntryMap map[string]*manifestTrieEntry, err error) { - - uri, err := Parse("bzz:/" + mhash) - if err != nil { - return nil, nil, err - } - addr, err = a.Resolve(ctx, uri.Addr) - if err != nil { - return nil, nil, err - } - - quitC := make(chan bool) - rootTrie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) - if err != nil { - return nil, nil, fmt.Errorf("can't load manifest %v: %v", addr.String(), err) - } - - manifestEntryMap = map[string]*manifestTrieEntry{} - err = rootTrie.listWithPrefix(uri.Path, quitC, func(entry *manifestTrieEntry, suffix string) { - manifestEntryMap[suffix] = entry - }) - - if err != nil { - return nil, nil, fmt.Errorf("list with prefix failed %v: %v", addr.String(), err) - } - return addr, manifestEntryMap, nil -} - -// FeedsLookup finds Swarm feeds updates at specific points in time, or the latest update -func (a *API) FeedsLookup(ctx context.Context, query *feed.Query) ([]byte, error) { - _, err := a.feed.Lookup(ctx, query) - if err != nil { - return nil, err - } - var data []byte - _, data, err = a.feed.GetContent(&query.Feed) - if err != nil { - return nil, err - } - return data, nil -} - -// FeedsNewRequest creates a Request object to update a specific feed -func (a *API) FeedsNewRequest(ctx context.Context, feed *feed.Feed) (*feed.Request, error) { - return a.feed.NewRequest(ctx, feed) -} - -// FeedsUpdate publishes a new update on the given feed -func (a *API) FeedsUpdate(ctx context.Context, request *feed.Request) (storage.Address, error) { - return a.feed.Update(ctx, request) -} - -// ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails -var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest") - -// ErrNotAFeedManifest is returned when the address provided returned something other than a valid manifest -var ErrNotAFeedManifest = errors.New("Not a feed manifest") - -// ResolveFeedManifest retrieves the Swarm feed manifest for the given address, and returns the referenced Feed. -func (a *API) ResolveFeedManifest(ctx context.Context, addr storage.Address) (*feed.Feed, error) { - trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt) - if err != nil { - return nil, ErrCannotLoadFeedManifest - } - - entry, _ := trie.getEntry("") - if entry.ContentType != FeedContentType { - return nil, ErrNotAFeedManifest - } - - return entry.Feed, nil -} - -// ErrCannotResolveFeedURI is returned when the ENS resolver is not able to translate a name to a Swarm feed -var ErrCannotResolveFeedURI = errors.New("Cannot resolve Feed URI") - -// ErrCannotResolveFeed is returned when values provided are not enough or invalid to recreate a -// feed out of them. -var ErrCannotResolveFeed = errors.New("Cannot resolve Feed") - -// ResolveFeed attempts to extract feed information out of the manifest, if provided -// If not, it attempts to extract the feed out of a set of key-value pairs -func (a *API) ResolveFeed(ctx context.Context, uri *URI, values feed.Values) (*feed.Feed, error) { - var fd *feed.Feed - var err error - if uri.Addr != "" { - // resolve the content key. - manifestAddr := uri.Address() - if manifestAddr == nil { - manifestAddr, err = a.Resolve(ctx, uri.Addr) - if err != nil { - return nil, ErrCannotResolveFeedURI - } - } - - // get the Swarm feed from the manifest - fd, err = a.ResolveFeedManifest(ctx, manifestAddr) - if err != nil { - return nil, err - } - log.Debug("handle.get.feed: resolved", "manifestkey", manifestAddr, "feed", fd.Hex()) - } else { - var f feed.Feed - if err := f.FromValues(values); err != nil { - return nil, ErrCannotResolveFeed - - } - fd = &f - } - return fd, nil -} - -// MimeOctetStream default value of http Content-Type header -const MimeOctetStream = "application/octet-stream" - -// DetectContentType by file file extension, or fallback to content sniff -func DetectContentType(fileName string, f io.ReadSeeker) (string, error) { - ctype := mime.TypeByExtension(filepath.Ext(fileName)) - if ctype != "" { - return ctype, nil - } - - // save/rollback to get content probe from begin of file - currentPosition, err := f.Seek(0, io.SeekCurrent) - if err != nil { - return MimeOctetStream, fmt.Errorf("seeker can't seek, %s", err) - } - - // read a chunk to decide between utf-8 text and binary - var buf [512]byte - n, _ := f.Read(buf[:]) - ctype = http.DetectContentType(buf[:n]) - - _, err = f.Seek(currentPosition, io.SeekStart) // rewind to output whole file - if err != nil { - return MimeOctetStream, fmt.Errorf("seeker can't seek, %s", err) - } - - return ctype, nil -} diff --git a/swarm/api/api_test.go b/swarm/api/api_test.go deleted file mode 100644 index 4a5f923626..0000000000 --- a/swarm/api/api_test.go +++ /dev/null @@ -1,576 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "bytes" - "context" - crand "crypto/rand" - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "math/big" - "os" - "strings" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/sctx" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -func init() { - loglevel := flag.Int("loglevel", 2, "loglevel") - flag.Parse() - log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) -} - -func testAPI(t *testing.T, f func(*API, *chunk.Tags, bool)) { - for _, v := range []bool{true, false} { - datadir, err := ioutil.TempDir("", "bzz-test") - if err != nil { - t.Fatalf("unable to create temp dir: %v", err) - } - defer os.RemoveAll(datadir) - tags := chunk.NewTags() - fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32), tags) - if err != nil { - return - } - api := NewAPI(fileStore, nil, nil, nil, tags) - f(api, tags, v) - } -} - -type testResponse struct { - reader storage.LazySectionReader - *Response -} - -type Response struct { - MimeType string - Status int - Size int64 - Content string -} - -func checkResponse(t *testing.T, resp *testResponse, exp *Response) { - - if resp.MimeType != exp.MimeType { - t.Errorf("incorrect mimeType. expected '%s', got '%s'", exp.MimeType, resp.MimeType) - } - if resp.Status != exp.Status { - t.Errorf("incorrect status. expected '%d', got '%d'", exp.Status, resp.Status) - } - if resp.Size != exp.Size { - t.Errorf("incorrect size. expected '%d', got '%d'", exp.Size, resp.Size) - } - if resp.reader != nil { - content := make([]byte, resp.Size) - read, _ := resp.reader.Read(content) - if int64(read) != exp.Size { - t.Errorf("incorrect content length. expected '%d...', got '%d...'", read, exp.Size) - } - resp.Content = string(content) - } - if resp.Content != exp.Content { - // if !bytes.Equal(resp.Content, exp.Content) - t.Errorf("incorrect content. expected '%s...', got '%s...'", string(exp.Content), string(resp.Content)) - } -} - -// func expResponse(content []byte, mimeType string, status int) *Response { -func expResponse(content string, mimeType string, status int) *Response { - log.Trace(fmt.Sprintf("expected content (%v): %v ", len(content), content)) - return &Response{mimeType, status, int64(len(content)), content} -} - -func testGet(t *testing.T, api *API, bzzhash, path string) *testResponse { - addr := storage.Address(common.Hex2Bytes(bzzhash)) - reader, mimeType, status, _, err := api.Get(context.TODO(), NOOPDecrypt, addr, path) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - quitC := make(chan bool) - size, err := reader.Size(context.TODO(), quitC) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - log.Trace(fmt.Sprintf("reader size: %v ", size)) - s := make([]byte, size) - _, err = reader.Read(s) - if err != io.EOF { - t.Fatalf("unexpected error: %v", err) - } - reader.Seek(0, 0) - return &testResponse{reader, &Response{mimeType, status, size, string(s)}} -} - -func TestApiPut(t *testing.T) { - testAPI(t, func(api *API, tags *chunk.Tags, toEncrypt bool) { - content := "hello" - exp := expResponse(content, "text/plain", 0) - ctx := context.TODO() - addr, wait, err := putString(ctx, api, content, exp.MimeType, toEncrypt) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - err = wait(ctx) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - resp := testGet(t, api, addr.Hex(), "") - checkResponse(t, resp, exp) - tag := tags.All()[0] - testutil.CheckTag(t, tag, 2, 2, 0, 2) //1 chunk data, 1 chunk manifest - }) -} - -// TestApiTagLarge tests that the the number of chunks counted is larger for a larger input -func TestApiTagLarge(t *testing.T) { - const contentLength = 4096 * 4095 - testAPI(t, func(api *API, tags *chunk.Tags, toEncrypt bool) { - randomContentReader := io.LimitReader(crand.Reader, int64(contentLength)) - tag, err := api.Tags.New("unnamed-tag", 0) - if err != nil { - t.Fatal(err) - } - ctx := sctx.SetTag(context.Background(), tag.Uid) - key, waitContent, err := api.Store(ctx, randomContentReader, int64(contentLength), toEncrypt) - if err != nil { - t.Fatal(err) - } - err = waitContent(ctx) - if err != nil { - t.Fatal(err) - } - tag.DoneSplit(key) - - if toEncrypt { - tag := tags.All()[0] - expect := int64(4095 + 64 + 1) - testutil.CheckTag(t, tag, expect, expect, 0, expect) - } else { - tag := tags.All()[0] - expect := int64(4095 + 32 + 1) - testutil.CheckTag(t, tag, expect, expect, 0, expect) - } - }) -} - -// testResolver implements the Resolver interface and either returns the given -// hash if it is set, or returns a "name not found" error -type testResolveValidator struct { - hash *common.Hash -} - -func newTestResolveValidator(addr string) *testResolveValidator { - r := &testResolveValidator{} - if addr != "" { - hash := common.HexToHash(addr) - r.hash = &hash - } - return r -} - -func (t *testResolveValidator) Resolve(addr string) (common.Hash, error) { - if t.hash == nil { - return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr) - } - return *t.hash, nil -} - -func (t *testResolveValidator) Owner(node [32]byte) (addr common.Address, err error) { - return -} -func (t *testResolveValidator) HeaderByNumber(context.Context, *big.Int) (header *types.Header, err error) { - return -} - -// TestAPIResolve tests resolving URIs which can either contain content hashes -// or ENS names -func TestAPIResolve(t *testing.T) { - ensAddr := "swarm.eth" - hashAddr := "1111111111111111111111111111111111111111111111111111111111111111" - resolvedAddr := "2222222222222222222222222222222222222222222222222222222222222222" - doesResolve := newTestResolveValidator(resolvedAddr) - doesntResolve := newTestResolveValidator("") - - type test struct { - desc string - dns Resolver - addr string - immutable bool - result string - expectErr error - } - - tests := []*test{ - { - desc: "DNS not configured, hash address, returns hash address", - dns: nil, - addr: hashAddr, - result: hashAddr, - }, - { - desc: "DNS not configured, ENS address, returns error", - dns: nil, - addr: ensAddr, - expectErr: errors.New(`no DNS to resolve name: "swarm.eth"`), - }, - { - desc: "DNS configured, hash address, hash resolves, returns resolved address", - dns: doesResolve, - addr: hashAddr, - result: resolvedAddr, - }, - { - desc: "DNS configured, immutable hash address, hash resolves, returns hash address", - dns: doesResolve, - addr: hashAddr, - immutable: true, - result: hashAddr, - }, - { - desc: "DNS configured, hash address, hash doesn't resolve, returns hash address", - dns: doesntResolve, - addr: hashAddr, - result: hashAddr, - }, - { - desc: "DNS configured, ENS address, name resolves, returns resolved address", - dns: doesResolve, - addr: ensAddr, - result: resolvedAddr, - }, - { - desc: "DNS configured, immutable ENS address, name resolves, returns error", - dns: doesResolve, - addr: ensAddr, - immutable: true, - expectErr: errors.New(`immutable address not a content hash: "swarm.eth"`), - }, - { - desc: "DNS configured, ENS address, name doesn't resolve, returns error", - dns: doesntResolve, - addr: ensAddr, - expectErr: errors.New(`DNS name not found: "swarm.eth"`), - }, - } - for _, x := range tests { - t.Run(x.desc, func(t *testing.T) { - api := &API{dns: x.dns} - uri := &URI{Addr: x.addr, Scheme: "bzz"} - if x.immutable { - uri.Scheme = "bzz-immutable" - } - res, err := api.ResolveURI(context.TODO(), uri, "") - if err == nil { - if x.expectErr != nil { - t.Fatalf("expected error %q, got result %q", x.expectErr, res) - } - if res.String() != x.result { - t.Fatalf("expected result %q, got %q", x.result, res) - } - } else { - if x.expectErr == nil { - t.Fatalf("expected no error, got %q", err) - } - if err.Error() != x.expectErr.Error() { - t.Fatalf("expected error %q, got %q", x.expectErr, err) - } - } - }) - } -} - -func TestMultiResolver(t *testing.T) { - doesntResolve := newTestResolveValidator("") - - ethAddr := "swarm.eth" - ethHash := "0x2222222222222222222222222222222222222222222222222222222222222222" - ethResolve := newTestResolveValidator(ethHash) - - testAddr := "swarm.test" - testHash := "0x1111111111111111111111111111111111111111111111111111111111111111" - testResolve := newTestResolveValidator(testHash) - - tests := []struct { - desc string - r Resolver - addr string - result string - err error - }{ - { - desc: "No resolvers, returns error", - r: NewMultiResolver(), - err: NewNoResolverError(""), - }, - { - desc: "One default resolver, returns resolved address", - r: NewMultiResolver(MultiResolverOptionWithResolver(ethResolve, "")), - addr: ethAddr, - result: ethHash, - }, - { - desc: "Two default resolvers, returns resolved address", - r: NewMultiResolver( - MultiResolverOptionWithResolver(ethResolve, ""), - MultiResolverOptionWithResolver(ethResolve, ""), - ), - addr: ethAddr, - result: ethHash, - }, - { - desc: "Two default resolvers, first doesn't resolve, returns resolved address", - r: NewMultiResolver( - MultiResolverOptionWithResolver(doesntResolve, ""), - MultiResolverOptionWithResolver(ethResolve, ""), - ), - addr: ethAddr, - result: ethHash, - }, - { - desc: "Default resolver doesn't resolve, tld resolver resolve, returns resolved address", - r: NewMultiResolver( - MultiResolverOptionWithResolver(doesntResolve, ""), - MultiResolverOptionWithResolver(ethResolve, "eth"), - ), - addr: ethAddr, - result: ethHash, - }, - { - desc: "Three TLD resolvers, third resolves, returns resolved address", - r: NewMultiResolver( - MultiResolverOptionWithResolver(doesntResolve, "eth"), - MultiResolverOptionWithResolver(doesntResolve, "eth"), - MultiResolverOptionWithResolver(ethResolve, "eth"), - ), - addr: ethAddr, - result: ethHash, - }, - { - desc: "One TLD resolver doesn't resolve, returns error", - r: NewMultiResolver( - MultiResolverOptionWithResolver(doesntResolve, ""), - MultiResolverOptionWithResolver(ethResolve, "eth"), - ), - addr: ethAddr, - result: ethHash, - }, - { - desc: "One defautl and one TLD resolver, all doesn't resolve, returns error", - r: NewMultiResolver( - MultiResolverOptionWithResolver(doesntResolve, ""), - MultiResolverOptionWithResolver(doesntResolve, "eth"), - ), - addr: ethAddr, - result: ethHash, - err: errors.New(`DNS name not found: "swarm.eth"`), - }, - { - desc: "Two TLD resolvers, both resolve, returns resolved address", - r: NewMultiResolver( - MultiResolverOptionWithResolver(ethResolve, "eth"), - MultiResolverOptionWithResolver(testResolve, "test"), - ), - addr: testAddr, - result: testHash, - }, - { - desc: "One TLD resolver, no default resolver, returns error for different TLD", - r: NewMultiResolver( - MultiResolverOptionWithResolver(ethResolve, "eth"), - ), - addr: testAddr, - err: NewNoResolverError("test"), - }, - } - for _, x := range tests { - t.Run(x.desc, func(t *testing.T) { - res, err := x.r.Resolve(x.addr) - if err == nil { - if x.err != nil { - t.Fatalf("expected error %q, got result %q", x.err, res.Hex()) - } - if res.Hex() != x.result { - t.Fatalf("expected result %q, got %q", x.result, res.Hex()) - } - } else { - if x.err == nil { - t.Fatalf("expected no error, got %q", err) - } - if err.Error() != x.err.Error() { - t.Fatalf("expected error %q, got %q", x.err, err) - } - } - }) - } -} - -func TestDecryptOriginForbidden(t *testing.T) { - ctx := context.TODO() - ctx = sctx.SetHost(ctx, "swarm-gateways.net") - - me := &ManifestEntry{ - Access: &AccessEntry{Type: AccessTypePass}, - } - - api := NewAPI(nil, nil, nil, nil, chunk.NewTags()) - - f := api.Decryptor(ctx, "") - err := f(me) - if err != ErrDecryptDomainForbidden { - t.Fatalf("should fail with ErrDecryptDomainForbidden, got %v", err) - } -} - -func TestDecryptOrigin(t *testing.T) { - for _, v := range []struct { - host string - expectError error - }{ - { - host: "localhost", - expectError: ErrDecrypt, - }, - { - host: "127.0.0.1", - expectError: ErrDecrypt, - }, - { - host: "swarm-gateways.net", - expectError: ErrDecryptDomainForbidden, - }, - } { - ctx := context.TODO() - ctx = sctx.SetHost(ctx, v.host) - - me := &ManifestEntry{ - Access: &AccessEntry{Type: AccessTypePass}, - } - - api := NewAPI(nil, nil, nil, nil, chunk.NewTags()) - - f := api.Decryptor(ctx, "") - err := f(me) - if err != v.expectError { - t.Fatalf("should fail with %v, got %v", v.expectError, err) - } - } -} - -func TestDetectContentType(t *testing.T) { - for _, tc := range []struct { - file string - content string - expectedContentType string - }{ - { - file: "file-with-correct-css.css", - content: "body {background-color: orange}", - expectedContentType: "text/css; charset=utf-8", - }, - { - file: "empty-file.css", - content: "", - expectedContentType: "text/css; charset=utf-8", - }, - { - file: "empty-file.pdf", - content: "", - expectedContentType: "application/pdf", - }, - { - file: "empty-file.md", - content: "", - expectedContentType: "text/markdown; charset=utf-8", - }, - { - file: "empty-file-with-unknown-content.strangeext", - content: "", - expectedContentType: "text/plain; charset=utf-8", - }, - { - file: "file-with-unknown-extension-and-content.strangeext", - content: "Lorem Ipsum", - expectedContentType: "text/plain; charset=utf-8", - }, - { - file: "file-no-extension", - content: "Lorem Ipsum", - expectedContentType: "text/plain; charset=utf-8", - }, - { - file: "file-no-extension-no-content", - content: "", - expectedContentType: "text/plain; charset=utf-8", - }, - { - file: "css-file-with-html-inside.css", - content: "", - expectedContentType: "text/css; charset=utf-8", - }, - } { - t.Run(tc.file, func(t *testing.T) { - detected, err := DetectContentType(tc.file, bytes.NewReader([]byte(tc.content))) - if err != nil { - t.Fatal(err) - } - - if detected != tc.expectedContentType { - t.Fatalf("File: %s, Expected mime type %s, got %s", tc.file, tc.expectedContentType, detected) - } - - }) - } -} - -// putString provides singleton manifest creation on top of api.API -func putString(ctx context.Context, a *API, content string, contentType string, toEncrypt bool) (k storage.Address, wait func(context.Context) error, err error) { - r := strings.NewReader(content) - tag, err := a.Tags.New("unnamed-tag", 0) - - log.Trace("created new tag", "uid", tag.Uid) - - cCtx := sctx.SetTag(ctx, tag.Uid) - key, waitContent, err := a.Store(cCtx, r, int64(len(content)), toEncrypt) - if err != nil { - return nil, nil, err - } - manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType) - r = strings.NewReader(manifest) - key, waitManifest, err := a.Store(cCtx, r, int64(len(manifest)), toEncrypt) - if err != nil { - return nil, nil, err - } - tag.DoneSplit(key) - return key, func(ctx context.Context) error { - err := waitContent(ctx) - if err != nil { - return err - } - return waitManifest(ctx) - }, nil -} diff --git a/swarm/api/client/client.go b/swarm/api/client/client.go deleted file mode 100644 index 9ad0948f43..0000000000 --- a/swarm/api/client/client.go +++ /dev/null @@ -1,829 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package client - -import ( - "archive/tar" - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "mime/multipart" - "net/http" - "net/http/httptrace" - "net/textproto" - "net/url" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/api" - swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" - "github.com/ethereum/go-ethereum/swarm/spancontext" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/pborman/uuid" -) - -var ( - ErrUnauthorized = errors.New("unauthorized") -) - -func NewClient(gateway string) *Client { - return &Client{ - Gateway: gateway, - } -} - -// Client wraps interaction with a swarm HTTP gateway. -type Client struct { - Gateway string -} - -// UploadRaw uploads raw data to swarm and returns the resulting hash. If toEncrypt is true it -// uploads encrypted data -func (c *Client) UploadRaw(r io.Reader, size int64, toEncrypt bool) (string, error) { - if size <= 0 { - return "", errors.New("data size must be greater than zero") - } - addr := "" - if toEncrypt { - addr = "encrypt" - } - req, err := http.NewRequest("POST", c.Gateway+"/bzz-raw:/"+addr, r) - if err != nil { - return "", err - } - req.ContentLength = size - req.Header.Set(swarmhttp.SwarmTagHeaderName, fmt.Sprintf("raw_upload_%d", time.Now().Unix())) - - res, err := http.DefaultClient.Do(req) - if err != nil { - return "", err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return "", fmt.Errorf("unexpected HTTP status: %s", res.Status) - } - data, err := ioutil.ReadAll(res.Body) - if err != nil { - return "", err - } - return string(data), nil -} - -// DownloadRaw downloads raw data from swarm and it returns a ReadCloser and a bool whether the -// content was encrypted -func (c *Client) DownloadRaw(hash string) (io.ReadCloser, bool, error) { - uri := c.Gateway + "/bzz-raw:/" + hash - res, err := http.DefaultClient.Get(uri) - if err != nil { - return nil, false, err - } - if res.StatusCode != http.StatusOK { - res.Body.Close() - return nil, false, fmt.Errorf("unexpected HTTP status: %s", res.Status) - } - isEncrypted := (res.Header.Get("X-Decrypted") == "true") - return res.Body, isEncrypted, nil -} - -// File represents a file in a swarm manifest and is used for uploading and -// downloading content to and from swarm -type File struct { - io.ReadCloser - api.ManifestEntry - Tag string -} - -// Open opens a local file which can then be passed to client.Upload to upload -// it to swarm -func Open(path string) (*File, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - stat, err := f.Stat() - if err != nil { - f.Close() - return nil, err - } - - contentType, err := api.DetectContentType(f.Name(), f) - if err != nil { - return nil, err - } - - return &File{ - ReadCloser: f, - ManifestEntry: api.ManifestEntry{ - ContentType: contentType, - Mode: int64(stat.Mode()), - Size: stat.Size(), - ModTime: stat.ModTime(), - }, - Tag: filepath.Base(path), - }, nil -} - -// Upload uploads a file to swarm and either adds it to an existing manifest -// (if the manifest argument is non-empty) or creates a new manifest containing -// the file, returning the resulting manifest hash (the file will then be -// available at bzz://) -func (c *Client) Upload(file *File, manifest string, toEncrypt bool) (string, error) { - if file.Size <= 0 { - return "", errors.New("file size must be greater than zero") - } - return c.TarUpload(manifest, &FileUploader{file}, "", toEncrypt) -} - -// Download downloads a file with the given path from the swarm manifest with -// the given hash (i.e. it gets bzz://) -func (c *Client) Download(hash, path string) (*File, error) { - uri := c.Gateway + "/bzz:/" + hash + "/" + path - res, err := http.DefaultClient.Get(uri) - if err != nil { - return nil, err - } - if res.StatusCode != http.StatusOK { - res.Body.Close() - return nil, fmt.Errorf("unexpected HTTP status: %s", res.Status) - } - return &File{ - ReadCloser: res.Body, - ManifestEntry: api.ManifestEntry{ - ContentType: res.Header.Get("Content-Type"), - Size: res.ContentLength, - }, - }, nil -} - -// UploadDirectory uploads a directory tree to swarm and either adds the files -// to an existing manifest (if the manifest argument is non-empty) or creates a -// new manifest, returning the resulting manifest hash (files from the -// directory will then be available at bzz://path/to/file), with -// the file specified in defaultPath being uploaded to the root of the manifest -// (i.e. bzz://) -func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bool) (string, error) { - stat, err := os.Stat(dir) - if err != nil { - return "", err - } else if !stat.IsDir() { - return "", fmt.Errorf("not a directory: %s", dir) - } - if defaultPath != "" { - if _, err := os.Stat(filepath.Join(dir, defaultPath)); err != nil { - if os.IsNotExist(err) { - return "", fmt.Errorf("the default path %q was not found in the upload directory %q", defaultPath, dir) - } - return "", fmt.Errorf("default path: %v", err) - } - } - return c.TarUpload(manifest, &DirectoryUploader{dir}, defaultPath, toEncrypt) -} - -// DownloadDirectory downloads the files contained in a swarm manifest under -// the given path into a local directory (existing files will be overwritten) -func (c *Client) DownloadDirectory(hash, path, destDir, credentials string) error { - stat, err := os.Stat(destDir) - if err != nil { - return err - } else if !stat.IsDir() { - return fmt.Errorf("not a directory: %s", destDir) - } - - uri := c.Gateway + "/bzz:/" + hash + "/" + path - req, err := http.NewRequest("GET", uri, nil) - if err != nil { - return err - } - if credentials != "" { - req.SetBasicAuth("", credentials) - } - req.Header.Set("Accept", "application/x-tar") - res, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - switch res.StatusCode { - case http.StatusOK: - case http.StatusUnauthorized: - return ErrUnauthorized - default: - return fmt.Errorf("unexpected HTTP status: %s", res.Status) - } - tr := tar.NewReader(res.Body) - for { - hdr, err := tr.Next() - if err == io.EOF { - return nil - } else if err != nil { - return err - } - // ignore the default path file - if hdr.Name == "" { - continue - } - - dstPath := filepath.Join(destDir, filepath.Clean(strings.TrimPrefix(hdr.Name, path))) - if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil { - return err - } - var mode os.FileMode = 0644 - if hdr.Mode > 0 { - mode = os.FileMode(hdr.Mode) - } - dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) - if err != nil { - return err - } - n, err := io.Copy(dst, tr) - dst.Close() - if err != nil { - return err - } else if n != hdr.Size { - return fmt.Errorf("expected %s to be %d bytes but got %d", hdr.Name, hdr.Size, n) - } - } -} - -// DownloadFile downloads a single file into the destination directory -// if the manifest entry does not specify a file name - it will fallback -// to the hash of the file as a filename -func (c *Client) DownloadFile(hash, path, dest, credentials string) error { - hasDestinationFilename := false - if stat, err := os.Stat(dest); err == nil { - hasDestinationFilename = !stat.IsDir() - } else { - if os.IsNotExist(err) { - // does not exist - should be created - hasDestinationFilename = true - } else { - return fmt.Errorf("could not stat path: %v", err) - } - } - - manifestList, err := c.List(hash, path, credentials) - if err != nil { - return err - } - - switch len(manifestList.Entries) { - case 0: - return fmt.Errorf("could not find path requested at manifest address. make sure the path you've specified is correct") - case 1: - //continue - default: - return fmt.Errorf("got too many matches for this path") - } - - uri := c.Gateway + "/bzz:/" + hash + "/" + path - req, err := http.NewRequest("GET", uri, nil) - if err != nil { - return err - } - if credentials != "" { - req.SetBasicAuth("", credentials) - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - switch res.StatusCode { - case http.StatusOK: - case http.StatusUnauthorized: - return ErrUnauthorized - default: - return fmt.Errorf("unexpected HTTP status: expected 200 OK, got %d", res.StatusCode) - } - filename := "" - if hasDestinationFilename { - filename = dest - } else { - // try to assert - re := regexp.MustCompile("[^/]+$") //everything after last slash - - if results := re.FindAllString(path, -1); len(results) > 0 { - filename = results[len(results)-1] - } else { - if entry := manifestList.Entries[0]; entry.Path != "" && entry.Path != "/" { - filename = entry.Path - } else { - // assume hash as name if there's nothing from the command line - filename = hash - } - } - filename = filepath.Join(dest, filename) - } - filePath, err := filepath.Abs(filename) - if err != nil { - return err - } - - if err := os.MkdirAll(filepath.Dir(filePath), 0777); err != nil { - return err - } - - dst, err := os.Create(filename) - if err != nil { - return err - } - defer dst.Close() - - _, err = io.Copy(dst, res.Body) - return err -} - -// UploadManifest uploads the given manifest to swarm -func (c *Client) UploadManifest(m *api.Manifest, toEncrypt bool) (string, error) { - data, err := json.Marshal(m) - if err != nil { - return "", err - } - return c.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt) -} - -// DownloadManifest downloads a swarm manifest -func (c *Client) DownloadManifest(hash string) (*api.Manifest, bool, error) { - res, isEncrypted, err := c.DownloadRaw(hash) - if err != nil { - return nil, isEncrypted, err - } - defer res.Close() - var manifest api.Manifest - if err := json.NewDecoder(res).Decode(&manifest); err != nil { - return nil, isEncrypted, err - } - return &manifest, isEncrypted, nil -} - -// List list files in a swarm manifest which have the given prefix, grouping -// common prefixes using "/" as a delimiter. -// -// For example, if the manifest represents the following directory structure: -// -// file1.txt -// file2.txt -// dir1/file3.txt -// dir1/dir2/file4.txt -// -// Then: -// -// - a prefix of "" would return [dir1/, file1.txt, file2.txt] -// - a prefix of "file" would return [file1.txt, file2.txt] -// - a prefix of "dir1/" would return [dir1/dir2/, dir1/file3.txt] -// -// where entries ending with "/" are common prefixes. -func (c *Client) List(hash, prefix, credentials string) (*api.ManifestList, error) { - req, err := http.NewRequest(http.MethodGet, c.Gateway+"/bzz-list:/"+hash+"/"+prefix, nil) - if err != nil { - return nil, err - } - if credentials != "" { - req.SetBasicAuth("", credentials) - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - defer res.Body.Close() - switch res.StatusCode { - case http.StatusOK: - case http.StatusUnauthorized: - return nil, ErrUnauthorized - default: - return nil, fmt.Errorf("unexpected HTTP status: %s", res.Status) - } - var list api.ManifestList - if err := json.NewDecoder(res.Body).Decode(&list); err != nil { - return nil, err - } - return &list, nil -} - -// Uploader uploads files to swarm using a provided UploadFn -type Uploader interface { - Upload(UploadFn) error - Tag() string -} - -type UploaderFunc func(UploadFn) error - -func (u UploaderFunc) Upload(upload UploadFn) error { - return u(upload) -} - -func (u UploaderFunc) Tag() string { - return fmt.Sprintf("multipart_upload_%d", time.Now().Unix()) -} - -// DirectoryUploader implements Uploader -var _ Uploader = &DirectoryUploader{} - -// DirectoryUploader uploads all files in a directory, optionally uploading -// a file to the default path -type DirectoryUploader struct { - Dir string -} - -func (d *DirectoryUploader) Tag() string { - return filepath.Base(d.Dir) -} - -// Upload performs the upload of the directory and default path -func (d *DirectoryUploader) Upload(upload UploadFn) error { - return filepath.Walk(d.Dir, func(path string, f os.FileInfo, err error) error { - if err != nil { - return err - } - if f.IsDir() { - return nil - } - file, err := Open(path) - if err != nil { - return err - } - relPath, err := filepath.Rel(d.Dir, path) - if err != nil { - return err - } - file.Path = filepath.ToSlash(relPath) - return upload(file) - }) -} - -var _ Uploader = &FileUploader{} - -// FileUploader uploads a single file -type FileUploader struct { - File *File -} - -func (f *FileUploader) Tag() string { - return f.File.Tag -} - -// Upload performs the upload of the file -func (f *FileUploader) Upload(upload UploadFn) error { - return upload(f.File) -} - -// UploadFn is the type of function passed to an Uploader to perform the upload -// of a single file (for example, a directory uploader would call a provided -// UploadFn for each file in the directory tree) -type UploadFn func(file *File) error - -// TarUpload uses the given Uploader to upload files to swarm as a tar stream, -// returning the resulting manifest hash -func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, toEncrypt bool) (string, error) { - ctx, sp := spancontext.StartSpan(context.Background(), "api.client.tarupload") - defer sp.Finish() - - var tn time.Time - - reqR, reqW := io.Pipe() - defer reqR.Close() - addr := hash - - // If there is a hash already (a manifest), then that manifest will determine if the upload has - // to be encrypted or not. If there is no manifest then the toEncrypt parameter decides if - // there is encryption or not. - if hash == "" && toEncrypt { - // This is the built-in address for the encrypted upload endpoint - addr = "encrypt" - } - req, err := http.NewRequest("POST", c.Gateway+"/bzz:/"+addr, reqR) - if err != nil { - return "", err - } - - trace := GetClientTrace("swarm api client - upload tar", "api.client.uploadtar", uuid.New()[:8], &tn) - - req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) - transport := http.DefaultTransport - - req.Header.Set("Content-Type", "application/x-tar") - if defaultPath != "" { - q := req.URL.Query() - q.Set("defaultpath", defaultPath) - req.URL.RawQuery = q.Encode() - } - - tag := uploader.Tag() - if tag == "" { - tag = "unnamed_tag_" + fmt.Sprintf("%d", time.Now().Unix()) - } - log.Trace("setting upload tag", "tag", tag) - - req.Header.Set(swarmhttp.SwarmTagHeaderName, tag) - - // use 'Expect: 100-continue' so we don't send the request body if - // the server refuses the request - req.Header.Set("Expect", "100-continue") - - tw := tar.NewWriter(reqW) - - // define an UploadFn which adds files to the tar stream - uploadFn := func(file *File) error { - hdr := &tar.Header{ - Name: file.Path, - Mode: file.Mode, - Size: file.Size, - ModTime: file.ModTime, - Xattrs: map[string]string{ - "user.swarm.content-type": file.ContentType, - }, - } - if err := tw.WriteHeader(hdr); err != nil { - return err - } - _, err = io.Copy(tw, file) - return err - } - - // run the upload in a goroutine so we can send the request headers and - // wait for a '100 Continue' response before sending the tar stream - go func() { - err := uploader.Upload(uploadFn) - if err == nil { - err = tw.Close() - } - reqW.CloseWithError(err) - }() - tn = time.Now() - res, err := transport.RoundTrip(req) - if err != nil { - return "", err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return "", fmt.Errorf("unexpected HTTP status: %s", res.Status) - } - data, err := ioutil.ReadAll(res.Body) - if err != nil { - return "", err - } - return string(data), nil -} - -// MultipartUpload uses the given Uploader to upload files to swarm as a -// multipart form, returning the resulting manifest hash -func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error) { - reqR, reqW := io.Pipe() - defer reqR.Close() - req, err := http.NewRequest("POST", c.Gateway+"/bzz:/"+hash, reqR) - if err != nil { - return "", err - } - - // use 'Expect: 100-continue' so we don't send the request body if - // the server refuses the request - req.Header.Set("Expect", "100-continue") - - mw := multipart.NewWriter(reqW) - req.Header.Set("Content-Type", fmt.Sprintf("multipart/form-data; boundary=%q", mw.Boundary())) - req.Header.Set(swarmhttp.SwarmTagHeaderName, fmt.Sprintf("multipart_upload_%d", time.Now().Unix())) - - // define an UploadFn which adds files to the multipart form - uploadFn := func(file *File) error { - hdr := make(textproto.MIMEHeader) - hdr.Set("Content-Disposition", fmt.Sprintf("form-data; name=%q", file.Path)) - hdr.Set("Content-Type", file.ContentType) - hdr.Set("Content-Length", strconv.FormatInt(file.Size, 10)) - w, err := mw.CreatePart(hdr) - if err != nil { - return err - } - _, err = io.Copy(w, file) - return err - } - - // run the upload in a goroutine so we can send the request headers and - // wait for a '100 Continue' response before sending the multipart form - go func() { - err := uploader.Upload(uploadFn) - if err == nil { - err = mw.Close() - } - reqW.CloseWithError(err) - }() - - res, err := http.DefaultClient.Do(req) - if err != nil { - return "", err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return "", fmt.Errorf("unexpected HTTP status: %s", res.Status) - } - data, err := ioutil.ReadAll(res.Body) - if err != nil { - return "", err - } - return string(data), nil -} - -// ErrNoFeedUpdatesFound is returned when Swarm cannot find updates of the given feed -var ErrNoFeedUpdatesFound = errors.New("No updates found for this feed") - -// CreateFeedWithManifest creates a feed manifest, initializing it with the provided -// data -// Returns the resulting feed manifest address that you can use to include in an ENS Resolver (setContent) -// or reference future updates (Client.UpdateFeed) -func (c *Client) CreateFeedWithManifest(request *feed.Request) (string, error) { - responseStream, err := c.updateFeed(request, true) - if err != nil { - return "", err - } - defer responseStream.Close() - - body, err := ioutil.ReadAll(responseStream) - if err != nil { - return "", err - } - - var manifestAddress string - if err = json.Unmarshal(body, &manifestAddress); err != nil { - return "", err - } - return manifestAddress, nil -} - -// UpdateFeed allows you to set a new version of your content -func (c *Client) UpdateFeed(request *feed.Request) error { - _, err := c.updateFeed(request, false) - return err -} - -func (c *Client) updateFeed(request *feed.Request, createManifest bool) (io.ReadCloser, error) { - URL, err := url.Parse(c.Gateway) - if err != nil { - return nil, err - } - URL.Path = "/bzz-feed:/" - values := URL.Query() - body := request.AppendValues(values) - if createManifest { - values.Set("manifest", "1") - } - URL.RawQuery = values.Encode() - - req, err := http.NewRequest("POST", URL.String(), bytes.NewBuffer(body)) - if err != nil { - return nil, err - } - - res, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - - return res.Body, nil -} - -// QueryFeed returns a byte stream with the raw content of the feed update -// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver -// points to that address -func (c *Client) QueryFeed(query *feed.Query, manifestAddressOrDomain string) (io.ReadCloser, error) { - return c.queryFeed(query, manifestAddressOrDomain, false) -} - -// queryFeed returns a byte stream with the raw content of the feed update -// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver -// points to that address -// meta set to true will instruct the node return feed metainformation instead -func (c *Client) queryFeed(query *feed.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) { - URL, err := url.Parse(c.Gateway) - if err != nil { - return nil, err - } - URL.Path = "/bzz-feed:/" + manifestAddressOrDomain - values := URL.Query() - if query != nil { - query.AppendValues(values) //adds query parameters - } - if meta { - values.Set("meta", "1") - } - URL.RawQuery = values.Encode() - res, err := http.Get(URL.String()) - if err != nil { - return nil, err - } - - if res.StatusCode != http.StatusOK { - if res.StatusCode == http.StatusNotFound { - return nil, ErrNoFeedUpdatesFound - } - errorMessageBytes, err := ioutil.ReadAll(res.Body) - var errorMessage string - if err != nil { - errorMessage = "cannot retrieve error message: " + err.Error() - } else { - errorMessage = string(errorMessageBytes) - } - return nil, fmt.Errorf("Error retrieving feed updates: %s", errorMessage) - } - - return res.Body, nil -} - -// GetFeedRequest returns a structure that describes the referenced feed status -// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver -// points to that address -func (c *Client) GetFeedRequest(query *feed.Query, manifestAddressOrDomain string) (*feed.Request, error) { - - responseStream, err := c.queryFeed(query, manifestAddressOrDomain, true) - if err != nil { - return nil, err - } - defer responseStream.Close() - - body, err := ioutil.ReadAll(responseStream) - if err != nil { - return nil, err - } - - var metadata feed.Request - if err := metadata.UnmarshalJSON(body); err != nil { - return nil, err - } - return &metadata, nil -} - -func GetClientTrace(traceMsg, metricPrefix, ruid string, tn *time.Time) *httptrace.ClientTrace { - trace := &httptrace.ClientTrace{ - GetConn: func(_ string) { - log.Trace(traceMsg+" - http get", "event", "GetConn", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".getconn", nil).Update(time.Since(*tn)) - }, - GotConn: func(_ httptrace.GotConnInfo) { - log.Trace(traceMsg+" - http get", "event", "GotConn", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".gotconn", nil).Update(time.Since(*tn)) - }, - PutIdleConn: func(err error) { - log.Trace(traceMsg+" - http get", "event", "PutIdleConn", "ruid", ruid, "err", err) - metrics.GetOrRegisterResettingTimer(metricPrefix+".putidle", nil).Update(time.Since(*tn)) - }, - GotFirstResponseByte: func() { - log.Trace(traceMsg+" - http get", "event", "GotFirstResponseByte", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".firstbyte", nil).Update(time.Since(*tn)) - }, - Got100Continue: func() { - log.Trace(traceMsg, "event", "Got100Continue", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".got100continue", nil).Update(time.Since(*tn)) - }, - DNSStart: func(_ httptrace.DNSStartInfo) { - log.Trace(traceMsg, "event", "DNSStart", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".dnsstart", nil).Update(time.Since(*tn)) - }, - DNSDone: func(_ httptrace.DNSDoneInfo) { - log.Trace(traceMsg, "event", "DNSDone", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".dnsdone", nil).Update(time.Since(*tn)) - }, - ConnectStart: func(network, addr string) { - log.Trace(traceMsg, "event", "ConnectStart", "ruid", ruid, "network", network, "addr", addr) - metrics.GetOrRegisterResettingTimer(metricPrefix+".connectstart", nil).Update(time.Since(*tn)) - }, - ConnectDone: func(network, addr string, err error) { - log.Trace(traceMsg, "event", "ConnectDone", "ruid", ruid, "network", network, "addr", addr, "err", err) - metrics.GetOrRegisterResettingTimer(metricPrefix+".connectdone", nil).Update(time.Since(*tn)) - }, - WroteHeaders: func() { - log.Trace(traceMsg, "event", "WroteHeaders(request)", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".wroteheaders", nil).Update(time.Since(*tn)) - }, - Wait100Continue: func() { - log.Trace(traceMsg, "event", "Wait100Continue", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".wait100continue", nil).Update(time.Since(*tn)) - }, - WroteRequest: func(_ httptrace.WroteRequestInfo) { - log.Trace(traceMsg, "event", "WroteRequest", "ruid", ruid) - metrics.GetOrRegisterResettingTimer(metricPrefix+".wroterequest", nil).Update(time.Since(*tn)) - }, - } - return trace -} diff --git a/swarm/api/client/client_test.go b/swarm/api/client/client_test.go deleted file mode 100644 index 92489849c4..0000000000 --- a/swarm/api/client/client_test.go +++ /dev/null @@ -1,608 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package client - -import ( - "bytes" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "sort" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/swarm/api" - swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -func serverFunc(api *api.API) swarmhttp.TestServer { - return swarmhttp.NewServer(api, "") -} - -// TestClientUploadDownloadRaw test uploading and downloading raw data to swarm -func TestClientUploadDownloadRaw(t *testing.T) { - testClientUploadDownloadRaw(false, t) -} - -func TestClientUploadDownloadRawEncrypted(t *testing.T) { - if testutil.RaceEnabled { - t.Skip("flaky with -race on Travis") - // See: https://github.com/ethersphere/go-ethereum/issues/1254 - } - - testClientUploadDownloadRaw(true, t) -} - -func testClientUploadDownloadRaw(toEncrypt bool, t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - client := NewClient(srv.URL) - - // upload some raw data - data := []byte("foo123") - hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt) - if err != nil { - t.Fatal(err) - } - - // check the tag was created successfully - tag := srv.Tags.All()[0] - testutil.CheckTag(t, tag, 1, 1, 0, 1) - - // check we can download the same data - res, isEncrypted, err := client.DownloadRaw(hash) - if err != nil { - t.Fatal(err) - } - if isEncrypted != toEncrypt { - t.Fatalf("Expected encyption status %v got %v", toEncrypt, isEncrypted) - } - defer res.Close() - gotData, err := ioutil.ReadAll(res) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(gotData, data) { - t.Fatalf("expected downloaded data to be %q, got %q", data, gotData) - } -} - -// TestClientUploadDownloadFiles test uploading and downloading files to swarm -// manifests -func TestClientUploadDownloadFiles(t *testing.T) { - testClientUploadDownloadFiles(false, t) -} - -func TestClientUploadDownloadFilesEncrypted(t *testing.T) { - testClientUploadDownloadFiles(true, t) -} - -func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - client := NewClient(srv.URL) - upload := func(manifest, path string, data []byte) string { - file := &File{ - ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), - ManifestEntry: api.ManifestEntry{ - Path: path, - ContentType: "text/plain", - Size: int64(len(data)), - }, - } - hash, err := client.Upload(file, manifest, toEncrypt) - if err != nil { - t.Fatal(err) - } - return hash - } - checkDownload := func(manifest, path string, expected []byte) { - file, err := client.Download(manifest, path) - if err != nil { - t.Fatal(err) - } - defer file.Close() - if file.Size != int64(len(expected)) { - t.Fatalf("expected downloaded file to be %d bytes, got %d", len(expected), file.Size) - } - if file.ContentType != "text/plain" { - t.Fatalf("expected downloaded file to have type %q, got %q", "text/plain", file.ContentType) - } - data, err := ioutil.ReadAll(file) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(data, expected) { - t.Fatalf("expected downloaded data to be %q, got %q", expected, data) - } - } - - // upload a file to the root of a manifest - rootData := []byte("some-data") - rootHash := upload("", "", rootData) - - // check we can download the root file - checkDownload(rootHash, "", rootData) - - // upload another file to the same manifest - otherData := []byte("some-other-data") - newHash := upload(rootHash, "some/other/path", otherData) - - // check we can download both files from the new manifest - checkDownload(newHash, "", rootData) - checkDownload(newHash, "some/other/path", otherData) - - // replace the root file with different data - newHash = upload(newHash, "", otherData) - - // check both files have the other data - checkDownload(newHash, "", otherData) - checkDownload(newHash, "some/other/path", otherData) -} - -var testDirFiles = []string{ - "file1.txt", - "file2.txt", - "dir1/file3.txt", - "dir1/file4.txt", - "dir2/file5.txt", - "dir2/dir3/file6.txt", - "dir2/dir4/file7.txt", - "dir2/dir4/file8.txt", -} - -func newTestDirectory(t *testing.T) string { - dir, err := ioutil.TempDir("", "swarm-client-test") - if err != nil { - t.Fatal(err) - } - - for _, file := range testDirFiles { - path := filepath.Join(dir, file) - if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { - os.RemoveAll(dir) - t.Fatalf("error creating dir for %s: %s", path, err) - } - if err := ioutil.WriteFile(path, []byte(file), 0644); err != nil { - os.RemoveAll(dir) - t.Fatalf("error writing file %s: %s", path, err) - } - } - - return dir -} - -// TestClientUploadDownloadDirectory tests uploading and downloading a -// directory of files to a swarm manifest -func TestClientUploadDownloadDirectory(t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - dir := newTestDirectory(t) - defer os.RemoveAll(dir) - - // upload the directory - client := NewClient(srv.URL) - defaultPath := testDirFiles[0] - hash, err := client.UploadDirectory(dir, defaultPath, "", false) - if err != nil { - t.Fatalf("error uploading directory: %s", err) - } - - // check the tag was created successfully - tag := srv.Tags.All()[0] - testutil.CheckTag(t, tag, 9, 9, 0, 9) - - // check we can download the individual files - checkDownloadFile := func(path string, expected []byte) { - file, err := client.Download(hash, path) - if err != nil { - t.Fatal(err) - } - defer file.Close() - data, err := ioutil.ReadAll(file) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(data, expected) { - t.Fatalf("expected data to be %q, got %q", expected, data) - } - } - for _, file := range testDirFiles { - checkDownloadFile(file, []byte(file)) - } - - // check we can download the default path - checkDownloadFile("", []byte(testDirFiles[0])) - - // check we can download the directory - tmp, err := ioutil.TempDir("", "swarm-client-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmp) - if err := client.DownloadDirectory(hash, "", tmp, ""); err != nil { - t.Fatal(err) - } - for _, file := range testDirFiles { - data, err := ioutil.ReadFile(filepath.Join(tmp, file)) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(data, []byte(file)) { - t.Fatalf("expected data to be %q, got %q", file, data) - } - } -} - -// TestClientFileList tests listing files in a swarm manifest -func TestClientFileList(t *testing.T) { - testClientFileList(false, t) -} - -func TestClientFileListEncrypted(t *testing.T) { - testClientFileList(true, t) -} - -func testClientFileList(toEncrypt bool, t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - dir := newTestDirectory(t) - defer os.RemoveAll(dir) - - client := NewClient(srv.URL) - hash, err := client.UploadDirectory(dir, "", "", toEncrypt) - if err != nil { - t.Fatalf("error uploading directory: %s", err) - } - - ls := func(prefix string) []string { - list, err := client.List(hash, prefix, "") - if err != nil { - t.Fatal(err) - } - paths := make([]string, 0, len(list.CommonPrefixes)+len(list.Entries)) - paths = append(paths, list.CommonPrefixes...) - for _, entry := range list.Entries { - paths = append(paths, entry.Path) - } - sort.Strings(paths) - return paths - } - - tests := map[string][]string{ - "": {"dir1/", "dir2/", "file1.txt", "file2.txt"}, - "file": {"file1.txt", "file2.txt"}, - "file1": {"file1.txt"}, - "file2.txt": {"file2.txt"}, - "file12": {}, - "dir": {"dir1/", "dir2/"}, - "dir1": {"dir1/"}, - "dir1/": {"dir1/file3.txt", "dir1/file4.txt"}, - "dir1/file": {"dir1/file3.txt", "dir1/file4.txt"}, - "dir1/file3.txt": {"dir1/file3.txt"}, - "dir1/file34": {}, - "dir2/": {"dir2/dir3/", "dir2/dir4/", "dir2/file5.txt"}, - "dir2/file": {"dir2/file5.txt"}, - "dir2/dir": {"dir2/dir3/", "dir2/dir4/"}, - "dir2/dir3/": {"dir2/dir3/file6.txt"}, - "dir2/dir4/": {"dir2/dir4/file7.txt", "dir2/dir4/file8.txt"}, - "dir2/dir4/file": {"dir2/dir4/file7.txt", "dir2/dir4/file8.txt"}, - "dir2/dir4/file7.txt": {"dir2/dir4/file7.txt"}, - "dir2/dir4/file78": {}, - } - for prefix, expected := range tests { - actual := ls(prefix) - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("expected prefix %q to return %v, got %v", prefix, expected, actual) - } - } -} - -// TestClientMultipartUpload tests uploading files to swarm using a multipart -// upload -func TestClientMultipartUpload(t *testing.T) { - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - // define an uploader which uploads testDirFiles with some data - // note: this test should result in SEEN chunks. assert accordingly - data := []byte("some-data") - uploader := UploaderFunc(func(upload UploadFn) error { - for _, name := range testDirFiles { - file := &File{ - ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), - ManifestEntry: api.ManifestEntry{ - Path: name, - ContentType: "text/plain", - Size: int64(len(data)), - }, - } - if err := upload(file); err != nil { - return err - } - } - return nil - }) - - // upload the files as a multipart upload - client := NewClient(srv.URL) - hash, err := client.MultipartUpload("", uploader) - if err != nil { - t.Fatal(err) - } - - // check the tag was created successfully - tag := srv.Tags.All()[0] - testutil.CheckTag(t, tag, 9, 9, 7, 9) - - // check we can download the individual files - checkDownloadFile := func(path string) { - file, err := client.Download(hash, path) - if err != nil { - t.Fatal(err) - } - defer file.Close() - gotData, err := ioutil.ReadAll(file) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(gotData, data) { - t.Fatalf("expected data to be %q, got %q", data, gotData) - } - } - for _, file := range testDirFiles { - checkDownloadFile(file) - } -} - -func newTestSigner() (*feed.GenericSigner, error) { - privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") - if err != nil { - return nil, err - } - return feed.NewGenericSigner(privKey), nil -} - -// Test the transparent resolving of feed updates with bzz:// scheme -// -// First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update. -// This effectively uses a feed to store a pointer to content rather than the content itself -// Retrieving the update with the Swarm hash should return the manifest pointing directly to the data -// and raw retrieve of that hash should return the data -func TestClientBzzWithFeed(t *testing.T) { - - signer, _ := newTestSigner() - - // Initialize a Swarm test server - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - swarmClient := NewClient(srv.URL) - defer srv.Close() - - // put together some data for our test: - dataBytes := []byte(` - // - // Create some data our manifest will point to. Data that could be very big and wouldn't fit in a feed update. - // So what we are going to do is upload it to Swarm bzz:// and obtain a **manifest hash** pointing to it: - // - // MANIFEST HASH --> DATA - // - // Then, we store that **manifest hash** into a Swarm Feed update. Once we have done this, - // we can use the **feed manifest hash** in bzz:// instead, this way: bzz://feed-manifest-hash. - // - // FEED MANIFEST HASH --> MANIFEST HASH --> DATA - // - // Given that we can update the feed at any time with a new **manifest hash** but the **feed manifest hash** - // stays constant, we have effectively created a fixed address to changing content. (Applause) - // - // FEED MANIFEST HASH (the same) --> MANIFEST HASH(2) --> DATA(2) - // - `) - - // Create a virtual File out of memory containing the above data - f := &File{ - ReadCloser: ioutil.NopCloser(bytes.NewReader(dataBytes)), - ManifestEntry: api.ManifestEntry{ - ContentType: "text/plain", - Mode: 0660, - Size: int64(len(dataBytes)), - }, - } - - // upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded. - manifestAddressHex, err := swarmClient.Upload(f, "", false) - if err != nil { - t.Fatalf("Error creating manifest: %s", err) - } - - // convert the hex-encoded manifest hash to a 32-byte slice - manifestAddress := common.FromHex(manifestAddressHex) - - if len(manifestAddress) != storage.AddressLength { - t.Fatalf("Something went wrong. Got a hash of an unexpected length. Expected %d bytes. Got %d", storage.AddressLength, len(manifestAddress)) - } - - // Now create a **feed manifest**. For that, we need a topic: - topic, _ := feed.NewTopic("interesting topic indeed", nil) - - // Build a feed request to update data - request := feed.NewFirstRequest(topic) - - // Put the 32-byte address of the manifest into the feed update - request.SetData(manifestAddress) - - // Sign the update - if err := request.Sign(signer); err != nil { - t.Fatalf("Error signing update: %s", err) - } - - // Publish the update and at the same time request a **feed manifest** to be created - feedManifestAddressHex, err := swarmClient.CreateFeedWithManifest(request) - if err != nil { - t.Fatalf("Error creating feed manifest: %s", err) - } - - // Check we have received the exact **feed manifest** to be expected - // given the topic and user signing the updates: - correctFeedManifestAddrHex := "747c402e5b9dc715a25a4393147512167bab018a007fad7cdcd9adc7fce1ced2" - if feedManifestAddressHex != correctFeedManifestAddrHex { - t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctFeedManifestAddrHex, feedManifestAddressHex) - } - - // Check we get a not found error when trying to get feed updates with a made-up manifest - _, err = swarmClient.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") - if err != ErrNoFeedUpdatesFound { - t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err) - } - - // If we query the feed directly we should get **manifest hash** back: - reader, err := swarmClient.QueryFeed(nil, correctFeedManifestAddrHex) - if err != nil { - t.Fatalf("Error retrieving feed updates: %s", err) - } - defer reader.Close() - gotData, err := ioutil.ReadAll(reader) - if err != nil { - t.Fatal(err) - } - - //Check that indeed the **manifest hash** is retrieved - if !bytes.Equal(manifestAddress, gotData) { - t.Fatalf("Expected: %v, got %v", manifestAddress, gotData) - } - - // Now the final test we were looking for: Use bzz:// and that should resolve all manifests - // and return the original data directly: - f, err = swarmClient.Download(feedManifestAddressHex, "") - if err != nil { - t.Fatal(err) - } - gotData, err = ioutil.ReadAll(f) - if err != nil { - t.Fatal(err) - } - - // Check that we get back the original data: - if !bytes.Equal(dataBytes, gotData) { - t.Fatalf("Expected: %v, got %v", manifestAddress, gotData) - } -} - -// TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client. -func TestClientCreateUpdateFeed(t *testing.T) { - - signer, _ := newTestSigner() - - srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) - client := NewClient(srv.URL) - defer srv.Close() - - // set raw data for the feed update - databytes := []byte("En un lugar de La Mancha, de cuyo nombre no quiero acordarme...") - - // our feed topic name - topic, _ := feed.NewTopic("El Quijote", nil) - createRequest := feed.NewFirstRequest(topic) - - createRequest.SetData(databytes) - if err := createRequest.Sign(signer); err != nil { - t.Fatalf("Error signing update: %s", err) - } - - feedManifestHash, err := client.CreateFeedWithManifest(createRequest) - if err != nil { - t.Fatal(err) - } - - correctManifestAddrHex := "0e9b645ebc3da167b1d56399adc3276f7a08229301b72a03336be0e7d4b71882" - if feedManifestHash != correctManifestAddrHex { - t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) - } - - reader, err := client.QueryFeed(nil, correctManifestAddrHex) - if err != nil { - t.Fatalf("Error retrieving feed updates: %s", err) - } - defer reader.Close() - gotData, err := ioutil.ReadAll(reader) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(databytes, gotData) { - t.Fatalf("Expected: %v, got %v", databytes, gotData) - } - - // define different data - databytes = []byte("... no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero ...") - - updateRequest, err := client.GetFeedRequest(nil, correctManifestAddrHex) - if err != nil { - t.Fatalf("Error retrieving update request template: %s", err) - } - - updateRequest.SetData(databytes) - if err := updateRequest.Sign(signer); err != nil { - t.Fatalf("Error signing update: %s", err) - } - - if err = client.UpdateFeed(updateRequest); err != nil { - t.Fatalf("Error updating feed: %s", err) - } - - reader, err = client.QueryFeed(nil, correctManifestAddrHex) - if err != nil { - t.Fatalf("Error retrieving feed updates: %s", err) - } - defer reader.Close() - gotData, err = ioutil.ReadAll(reader) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(databytes, gotData) { - t.Fatalf("Expected: %v, got %v", databytes, gotData) - } - - // now try retrieving feed updates without a manifest - - fd := &feed.Feed{ - Topic: topic, - User: signer.Address(), - } - - lookupParams := feed.NewQueryLatest(fd, lookup.NoClue) - reader, err = client.QueryFeed(lookupParams, "") - if err != nil { - t.Fatalf("Error retrieving feed updates: %s", err) - } - defer reader.Close() - gotData, err = ioutil.ReadAll(reader) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(databytes, gotData) { - t.Fatalf("Expected: %v, got %v", databytes, gotData) - } -} diff --git a/swarm/api/config.go b/swarm/api/config.go deleted file mode 100644 index 3a87488ccc..0000000000 --- a/swarm/api/config.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "crypto/ecdsa" - "fmt" - "os" - "path/filepath" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/contracts/ens" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/pss" - "github.com/ethereum/go-ethereum/swarm/services/swap" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -const ( - DefaultHTTPListenAddr = "127.0.0.1" - DefaultHTTPPort = "8500" -) - -// separate bzz directories -// allow several bzz nodes running in parallel -type Config struct { - // serialised/persisted fields - *storage.FileStoreParams - - // LocalStore - ChunkDbPath string - DbCapacity uint64 - CacheCapacity uint - BaseKey []byte - - *network.HiveParams - Swap *swap.LocalProfile - Pss *pss.PssParams - Contract common.Address - EnsRoot common.Address - EnsAPIs []string - Path string - ListenAddr string - Port string - PublicKey string - BzzKey string - Enode *enode.Node `toml:"-"` - NetworkID uint64 - SwapEnabled bool - SyncEnabled bool - SyncingSkipCheck bool - DeliverySkipCheck bool - MaxStreamPeerServers int - LightNodeEnabled bool - BootnodeMode bool - SyncUpdateDelay time.Duration - SwapAPI string - Cors string - BzzAccount string - GlobalStoreAPI string - privateKey *ecdsa.PrivateKey -} - -//create a default config with all parameters to set to defaults -func NewConfig() (c *Config) { - - c = &Config{ - FileStoreParams: storage.NewFileStoreParams(), - HiveParams: network.NewHiveParams(), - Swap: swap.NewDefaultSwapParams(), - Pss: pss.NewPssParams(), - ListenAddr: DefaultHTTPListenAddr, - Port: DefaultHTTPPort, - Path: node.DefaultDataDir(), - EnsAPIs: nil, - EnsRoot: ens.TestNetAddress, - NetworkID: network.DefaultNetworkID, - SwapEnabled: false, - SyncEnabled: true, - SyncingSkipCheck: false, - MaxStreamPeerServers: 10000, - DeliverySkipCheck: true, - SyncUpdateDelay: 15 * time.Second, - SwapAPI: "", - } - - return -} - -//some config params need to be initialized after the complete -//config building phase is completed (e.g. due to overriding flags) -func (c *Config) Init(prvKey *ecdsa.PrivateKey, nodeKey *ecdsa.PrivateKey) error { - - // create swarm dir and record key - err := c.createAndSetPath(c.Path, prvKey) - if err != nil { - return fmt.Errorf("Error creating root swarm data directory: %v", err) - } - c.setKey(prvKey) - - // create the new enode record - // signed with the ephemeral node key - enodeParams := &network.EnodeParams{ - PrivateKey: prvKey, - EnodeKey: nodeKey, - Lightnode: c.LightNodeEnabled, - Bootnode: c.BootnodeMode, - } - c.Enode, err = network.NewEnode(enodeParams) - if err != nil { - return fmt.Errorf("Error creating enode: %v", err) - } - - // initialize components that depend on the swarm instance's private key - if c.SwapEnabled { - c.Swap.Init(c.Contract, prvKey) - } - - c.privateKey = prvKey - c.ChunkDbPath = filepath.Join(c.Path, "chunks") - c.BaseKey = common.FromHex(c.BzzKey) - - c.Pss = c.Pss.WithPrivateKey(c.privateKey) - return nil -} - -func (c *Config) ShiftPrivateKey() (privKey *ecdsa.PrivateKey) { - if c.privateKey != nil { - privKey = c.privateKey - c.privateKey = nil - } - return privKey -} - -func (c *Config) setKey(prvKey *ecdsa.PrivateKey) { - bzzkeybytes := network.PrivateKeyToBzzKey(prvKey) - pubkey := crypto.FromECDSAPub(&prvKey.PublicKey) - pubkeyhex := hexutil.Encode(pubkey) - keyhex := hexutil.Encode(bzzkeybytes) - - c.privateKey = prvKey - c.PublicKey = pubkeyhex - c.BzzKey = keyhex -} - -func (c *Config) createAndSetPath(datadirPath string, prvKey *ecdsa.PrivateKey) error { - address := crypto.PubkeyToAddress(prvKey.PublicKey) - bzzdirPath := filepath.Join(datadirPath, "bzz-"+common.Bytes2Hex(address.Bytes())) - err := os.MkdirAll(bzzdirPath, os.ModePerm) - if err != nil { - return err - } - c.Path = bzzdirPath - return nil -} diff --git a/swarm/api/config_test.go b/swarm/api/config_test.go deleted file mode 100644 index 82f29f8ea6..0000000000 --- a/swarm/api/config_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "reflect" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -func TestConfig(t *testing.T) { - - var hexprvkey = "65138b2aa745041b372153550584587da326ab440576b2a1191dd95cee30039c" - var hexnodekey = "75138b2aa745041b372153550584587da326ab440576b2a1191dd95cee30039c" - - prvkey, err := crypto.HexToECDSA(hexprvkey) - if err != nil { - t.Fatalf("failed to load private key: %v", err) - } - nodekey, err := crypto.HexToECDSA(hexnodekey) - if err != nil { - t.Fatalf("failed to load private key: %v", err) - } - - one := NewConfig() - two := NewConfig() - - if equal := reflect.DeepEqual(one, two); !equal { - t.Fatal("Two default configs are not equal") - } - - err = one.Init(prvkey, nodekey) - if err != nil { - t.Fatal(err) - } - - //the init function should set the following fields - if one.BzzKey == "" { - t.Fatal("Expected BzzKey to be set") - } - if one.PublicKey == "" { - t.Fatal("Expected PublicKey to be set") - } - if one.Swap.PayProfile.Beneficiary == (common.Address{}) && one.SwapEnabled { - t.Fatal("Failed to correctly initialize SwapParams") - } - if one.ChunkDbPath == one.Path { - t.Fatal("Failed to correctly initialize StoreParams") - } -} diff --git a/swarm/api/encrypt.go b/swarm/api/encrypt.go deleted file mode 100644 index 0d516b3d57..0000000000 --- a/swarm/api/encrypt.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "encoding/binary" - "errors" - - "github.com/ethereum/go-ethereum/swarm/storage/encryption" - "golang.org/x/crypto/sha3" -) - -type RefEncryption struct { - refSize int - span []byte -} - -func NewRefEncryption(refSize int) *RefEncryption { - span := make([]byte, 8) - binary.LittleEndian.PutUint64(span, uint64(refSize)) - return &RefEncryption{ - refSize: refSize, - span: span, - } -} - -func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) { - spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewLegacyKeccak256) - encryptedSpan, err := spanEncryption.Encrypt(re.span) - if err != nil { - return nil, err - } - dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewLegacyKeccak256) - encryptedData, err := dataEncryption.Encrypt(ref) - if err != nil { - return nil, err - } - encryptedRef := make([]byte, len(ref)+8) - copy(encryptedRef[:8], encryptedSpan) - copy(encryptedRef[8:], encryptedData) - - return encryptedRef, nil -} - -func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) { - spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewLegacyKeccak256) - decryptedSpan, err := spanEncryption.Decrypt(ref[:8]) - if err != nil { - return nil, err - } - - size := binary.LittleEndian.Uint64(decryptedSpan) - if size != uint64(len(ref)-8) { - return nil, errors.New("invalid span in encrypted reference") - } - - dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewLegacyKeccak256) - decryptedRef, err := dataEncryption.Decrypt(ref[8:]) - if err != nil { - return nil, err - } - - return decryptedRef, nil -} diff --git a/swarm/api/filesystem.go b/swarm/api/filesystem.go deleted file mode 100644 index 266ef71bec..0000000000 --- a/swarm/api/filesystem.go +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "bufio" - "context" - "fmt" - "io" - "os" - "path" - "path/filepath" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -const maxParallelFiles = 5 - -type FileSystem struct { - api *API -} - -func NewFileSystem(api *API) *FileSystem { - return &FileSystem{api} -} - -// Upload replicates a local directory as a manifest file and uploads it -// using FileStore store -// This function waits the chunks to be stored. -// TODO: localpath should point to a manifest -// -// DEPRECATED: Use the HTTP API instead -func (fs *FileSystem) Upload(lpath, index string, toEncrypt bool) (string, error) { - var list []*manifestTrieEntry - localpath, err := filepath.Abs(filepath.Clean(lpath)) - if err != nil { - return "", err - } - - f, err := os.Open(localpath) - if err != nil { - return "", err - } - stat, err := f.Stat() - if err != nil { - return "", err - } - - var start int - if stat.IsDir() { - start = len(localpath) - log.Debug(fmt.Sprintf("uploading '%s'", localpath)) - err = filepath.Walk(localpath, func(path string, info os.FileInfo, err error) error { - if (err == nil) && !info.IsDir() { - if len(path) <= start { - return fmt.Errorf("Path is too short") - } - if path[:start] != localpath { - return fmt.Errorf("Path prefix of '%s' does not match localpath '%s'", path, localpath) - } - entry := newManifestTrieEntry(&ManifestEntry{Path: filepath.ToSlash(path)}, nil) - list = append(list, entry) - } - return err - }) - if err != nil { - return "", err - } - } else { - dir := filepath.Dir(localpath) - start = len(dir) - if len(localpath) <= start { - return "", fmt.Errorf("Path is too short") - } - if localpath[:start] != dir { - return "", fmt.Errorf("Path prefix of '%s' does not match dir '%s'", localpath, dir) - } - entry := newManifestTrieEntry(&ManifestEntry{Path: filepath.ToSlash(localpath)}, nil) - list = append(list, entry) - } - - errors := make([]error, len(list)) - sem := make(chan bool, maxParallelFiles) - defer close(sem) - - for i, entry := range list { - sem <- true - go func(i int, entry *manifestTrieEntry) { - defer func() { <-sem }() - - f, err := os.Open(entry.Path) - if err != nil { - errors[i] = err - return - } - defer f.Close() - - stat, err := f.Stat() - if err != nil { - errors[i] = err - return - } - - var hash storage.Address - var wait func(context.Context) error - ctx := context.TODO() - hash, wait, err = fs.api.fileStore.Store(ctx, f, stat.Size(), toEncrypt) - if err != nil { - errors[i] = err - return - } - if hash != nil { - list[i].Hash = hash.Hex() - } - if err := wait(ctx); err != nil { - errors[i] = err - return - } - - list[i].ContentType, err = DetectContentType(f.Name(), f) - if err != nil { - errors[i] = err - return - } - - }(i, entry) - } - for i := 0; i < cap(sem); i++ { - sem <- true - } - - trie := &manifestTrie{ - fileStore: fs.api.fileStore, - } - quitC := make(chan bool) - for i, entry := range list { - if errors[i] != nil { - return "", errors[i] - } - entry.Path = RegularSlashes(entry.Path[start:]) - if entry.Path == index { - ientry := newManifestTrieEntry(&ManifestEntry{ - ContentType: entry.ContentType, - }, nil) - ientry.Hash = entry.Hash - trie.addEntry(ientry, quitC) - } - trie.addEntry(entry, quitC) - } - - err2 := trie.recalcAndStore() - var hs string - if err2 == nil { - hs = trie.ref.Hex() - } - return hs, err2 -} - -// Download replicates the manifest basePath structure on the local filesystem -// under localpath -// -// DEPRECATED: Use the HTTP API instead -func (fs *FileSystem) Download(bzzpath, localpath string) error { - lpath, err := filepath.Abs(filepath.Clean(localpath)) - if err != nil { - return err - } - err = os.MkdirAll(lpath, os.ModePerm) - if err != nil { - return err - } - - //resolving host and port - uri, err := Parse(path.Join("bzz:/", bzzpath)) - if err != nil { - return err - } - addr, err := fs.api.Resolve(context.TODO(), uri.Addr) - if err != nil { - return err - } - path := uri.Path - - if len(path) > 0 { - path += "/" - } - - quitC := make(chan bool) - trie, err := loadManifest(context.TODO(), fs.api.fileStore, addr, quitC, NOOPDecrypt) - if err != nil { - log.Warn(fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err)) - return err - } - - type downloadListEntry struct { - addr storage.Address - path string - } - - var list []*downloadListEntry - var mde error - - prevPath := lpath - err = trie.listWithPrefix(path, quitC, func(entry *manifestTrieEntry, suffix string) { - log.Trace(fmt.Sprintf("fs.Download: %#v", entry)) - - addr = common.Hex2Bytes(entry.Hash) - path := lpath + "/" + suffix - dir := filepath.Dir(path) - if dir != prevPath { - mde = os.MkdirAll(dir, os.ModePerm) - prevPath = dir - } - if (mde == nil) && (path != dir+"/") { - list = append(list, &downloadListEntry{addr: addr, path: path}) - } - }) - if err != nil { - return err - } - - wg := sync.WaitGroup{} - errC := make(chan error) - done := make(chan bool, maxParallelFiles) - for i, entry := range list { - select { - case done <- true: - wg.Add(1) - case <-quitC: - return fmt.Errorf("aborted") - } - go func(i int, entry *downloadListEntry) { - defer wg.Done() - err := retrieveToFile(quitC, fs.api.fileStore, entry.addr, entry.path) - if err != nil { - select { - case errC <- err: - case <-quitC: - } - return - } - <-done - }(i, entry) - } - go func() { - wg.Wait() - close(errC) - }() - select { - case err = <-errC: - return err - case <-quitC: - return fmt.Errorf("aborted") - } -} - -func retrieveToFile(quitC chan bool, fileStore *storage.FileStore, addr storage.Address, path string) error { - f, err := os.Create(path) // TODO: basePath separators - if err != nil { - return err - } - reader, _ := fileStore.Retrieve(context.TODO(), addr) - writer := bufio.NewWriter(f) - size, err := reader.Size(context.TODO(), quitC) - if err != nil { - return err - } - if _, err = io.CopyN(writer, reader, size); err != nil { - return err - } - if err := writer.Flush(); err != nil { - return err - } - return f.Close() -} diff --git a/swarm/api/filesystem_test.go b/swarm/api/filesystem_test.go deleted file mode 100644 index b8f37fdd57..0000000000 --- a/swarm/api/filesystem_test.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "bytes" - "context" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -var testDownloadDir, _ = ioutil.TempDir(os.TempDir(), "bzz-test") - -func testFileSystem(t *testing.T, f func(*FileSystem, bool)) { - testAPI(t, func(api *API, _ *chunk.Tags, toEncrypt bool) { - f(NewFileSystem(api), toEncrypt) - }) -} - -func readPath(t *testing.T, parts ...string) string { - file := filepath.Join(parts...) - content, err := ioutil.ReadFile(file) - - if err != nil { - t.Fatalf("unexpected error reading '%v': %v", file, err) - } - return string(content) -} - -func TestApiDirUpload0(t *testing.T) { - testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { - api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "", toEncrypt) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - content := readPath(t, "testdata", "test0", "index.html") - resp := testGet(t, api, bzzhash, "index.html") - exp := expResponse(content, "text/html; charset=utf-8", 0) - checkResponse(t, resp, exp) - - content = readPath(t, "testdata", "test0", "index.css") - resp = testGet(t, api, bzzhash, "index.css") - exp = expResponse(content, "text/css; charset=utf-8", 0) - checkResponse(t, resp, exp) - - addr := storage.Address(common.Hex2Bytes(bzzhash)) - _, _, _, _, err = api.Get(context.TODO(), NOOPDecrypt, addr, "") - if err == nil { - t.Fatalf("expected error: %v", err) - } - - downloadDir := filepath.Join(testDownloadDir, "test0") - defer os.RemoveAll(downloadDir) - err = fs.Download(bzzhash, downloadDir) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - newbzzhash, err := fs.Upload(downloadDir, "", toEncrypt) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - // TODO: currently the hash is not deterministic in the encrypted case - if !toEncrypt && bzzhash != newbzzhash { - t.Fatalf("download %v reuploaded has incorrect hash, expected %v, got %v", downloadDir, bzzhash, newbzzhash) - } - }) -} - -func TestApiDirUploadModify(t *testing.T) { - testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { - api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "", toEncrypt) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - addr := storage.Address(common.Hex2Bytes(bzzhash)) - addr, err = api.Modify(context.TODO(), addr, "index.html", "", "") - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - index, err := ioutil.ReadFile(filepath.Join("testdata", "test0", "index.html")) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - ctx := context.TODO() - hash, wait, err := api.Store(ctx, bytes.NewReader(index), int64(len(index)), toEncrypt) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - err = wait(ctx) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - addr, err = api.Modify(context.TODO(), addr, "index2.html", hash.Hex(), "text/html; charset=utf-8") - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - addr, err = api.Modify(context.TODO(), addr, "img/logo.png", hash.Hex(), "text/html; charset=utf-8") - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - bzzhash = addr.Hex() - - content := readPath(t, "testdata", "test0", "index.html") - resp := testGet(t, api, bzzhash, "index2.html") - exp := expResponse(content, "text/html; charset=utf-8", 0) - checkResponse(t, resp, exp) - - resp = testGet(t, api, bzzhash, "img/logo.png") - exp = expResponse(content, "text/html; charset=utf-8", 0) - checkResponse(t, resp, exp) - - content = readPath(t, "testdata", "test0", "index.css") - resp = testGet(t, api, bzzhash, "index.css") - exp = expResponse(content, "text/css; charset=utf-8", 0) - checkResponse(t, resp, exp) - - _, _, _, _, err = api.Get(context.TODO(), nil, addr, "") - if err == nil { - t.Errorf("expected error: %v", err) - } - }) -} - -func TestApiDirUploadWithRootFile(t *testing.T) { - testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { - api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0"), "index.html", toEncrypt) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - content := readPath(t, "testdata", "test0", "index.html") - resp := testGet(t, api, bzzhash, "") - exp := expResponse(content, "text/html; charset=utf-8", 0) - checkResponse(t, resp, exp) - }) -} - -func TestApiFileUpload(t *testing.T) { - testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { - api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0", "index.html"), "", toEncrypt) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - content := readPath(t, "testdata", "test0", "index.html") - resp := testGet(t, api, bzzhash, "index.html") - exp := expResponse(content, "text/html; charset=utf-8", 0) - checkResponse(t, resp, exp) - }) -} - -func TestApiFileUploadWithRootFile(t *testing.T) { - testFileSystem(t, func(fs *FileSystem, toEncrypt bool) { - api := fs.api - bzzhash, err := fs.Upload(filepath.Join("testdata", "test0", "index.html"), "index.html", toEncrypt) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - content := readPath(t, "testdata", "test0", "index.html") - resp := testGet(t, api, bzzhash, "") - exp := expResponse(content, "text/html; charset=utf-8", 0) - checkResponse(t, resp, exp) - }) -} diff --git a/swarm/api/gen_mime.go b/swarm/api/gen_mime.go deleted file mode 100644 index 109edeb506..0000000000 --- a/swarm/api/gen_mime.go +++ /dev/null @@ -1,1201 +0,0 @@ -// Code generated by github.com/ethereum/go-ethereum/cmd/swarm/mimegen. DO NOT EDIT. - -package api - -import "mime" - -func init() { - var mimeTypes = map[string]string{ - ".a2l": "application/A2L", - ".aml": "application/AML", - ".ez": "application/andrew-inset", - ".atf": "application/ATF", - ".atfx": "application/ATFX", - ".atxml": "application/ATXML", - ".atom": "application/atom+xml", - ".atomcat": "application/atomcat+xml", - ".atomdeleted": "application/atomdeleted+xml", - ".atomsvc": "application/atomsvc+xml", - ".apxml": "application/auth-policy+xml", - ".xdd": "application/bacnet-xdd+zip", - ".xcs": "application/calendar+xml", - ".cbor": "application/cbor", - ".ccmp": "application/ccmp+xml", - ".ccxml": "application/ccxml+xml", - ".cdfx": "application/CDFX+XML", - ".cdmia": "application/cdmi-capability", - ".cdmic": "application/cdmi-container", - ".cdmid": "application/cdmi-domain", - ".cdmio": "application/cdmi-object", - ".cdmiq": "application/cdmi-queue", - ".cea": "application/CEA", - ".cellml": "application/cellml+xml", - ".cml": "application/cellml+xml", - ".clue": "application/clue_info+xml", - ".cmsc": "application/cms", - ".cpl": "application/cpl+xml", - ".csrattrs": "application/csrattrs", - ".mpd": "application/dash+xml", - ".mpdd": "application/dashdelta", - ".davmount": "application/davmount+xml", - ".dcd": "application/DCD", - ".dcm": "application/dicom", - ".dii": "application/DII", - ".dit": "application/DIT", - ".xmls": "application/dskpp+xml", - ".dssc": "application/dssc+der", - ".xdssc": "application/dssc+xml", - ".dvc": "application/dvcs", - ".es": "application/ecmascript", - ".efi": "application/efi", - ".emma": "application/emma+xml", - ".emotionml": "application/emotionml+xml", - ".epub": "application/epub+zip", - ".exi": "application/exi", - ".finf": "application/fastinfoset", - ".fdt": "application/fdt+xml", - ".pfr": "application/font-tdpfr", - ".geojson": "application/geo+json", - ".gml": "application/gml+xml", - ".gz": "application/gzip", - ".tgz": "application/gzip", - ".stk": "application/hyperstudio", - ".ink": "application/inkml+xml", - ".inkml": "application/inkml+xml", - ".ipfix": "application/ipfix", - ".its": "application/its+xml", - ".js": "application/javascript", - ".jrd": "application/jrd+json", - ".json": "application/json", - ".json-patch": "application/json-patch+json", - ".jsonld": "application/ld+json", - ".lgr": "application/lgr+xml", - ".wlnk": "application/link-format", - ".lostxml": "application/lost+xml", - ".lostsyncxml": "application/lostsync+xml", - ".lxf": "application/LXF", - ".hqx": "application/mac-binhex40", - ".mads": "application/mads+xml", - ".mrc": "application/marc", - ".mrcx": "application/marcxml+xml", - ".nb": "application/mathematica", - ".ma": "application/mathematica", - ".mb": "application/mathematica", - ".mml": "application/mathml+xml", - ".mbox": "application/mbox", - ".meta4": "application/metalink4+xml", - ".mets": "application/mets+xml", - ".mf4": "application/MF4", - ".mods": "application/mods+xml", - ".m21": "application/mp21", - ".mp21": "application/mp21", - ".doc": "application/msword", - ".mxf": "application/mxf", - ".nq": "application/n-quads", - ".nt": "application/n-triples", - ".orq": "application/ocsp-request", - ".ors": "application/ocsp-response", - ".bin": "application/octet-stream", - ".lha": "application/octet-stream", - ".lzh": "application/octet-stream", - ".exe": "application/octet-stream", - ".class": "application/octet-stream", - ".so": "application/octet-stream", - ".dll": "application/octet-stream", - ".img": "application/octet-stream", - ".iso": "application/octet-stream", - ".oda": "application/oda", - ".odx": "application/ODX", - ".opf": "application/oebps-package+xml", - ".ogx": "application/ogg", - ".oxps": "application/oxps", - ".relo": "application/p2p-overlay+xml", - ".pdf": "application/pdf", - ".pdx": "application/PDX", - ".pgp": "application/pgp-encrypted", - ".sig": "application/pgp-signature", - ".p10": "application/pkcs10", - ".p12": "application/pkcs12", - ".pfx": "application/pkcs12", - ".p7m": "application/pkcs7-mime", - ".p7c": "application/pkcs7-mime", - ".p7s": "application/pkcs7-signature", - ".p8": "application/pkcs8", - ".cer": "application/pkix-cert", - ".crl": "application/pkix-crl", - ".pkipath": "application/pkix-pkipath", - ".pki": "application/pkixcmp", - ".pls": "application/pls+xml", - ".ps": "application/postscript", - ".eps": "application/postscript", - ".ai": "application/postscript", - ".provx": "application/provenance+xml", - ".cw": "application/prs.cww", - ".cww": "application/prs.cww", - ".hpub": "application/prs.hpub+zip", - ".rnd": "application/prs.nprend", - ".rct": "application/prs.nprend", - ".rdf-crypt": "application/prs.rdf-xml-crypt", - ".xsf": "application/prs.xsf+xml", - ".pskcxml": "application/pskc+xml", - ".rdf": "application/rdf+xml", - ".rif": "application/reginfo+xml", - ".rnc": "application/relax-ng-compact-syntax", - ".rld": "application/resource-lists-diff+xml", - ".rl": "application/resource-lists+xml", - ".rfcxml": "application/rfc+xml", - ".rs": "application/rls-services+xml", - ".gbr": "application/rpki-ghostbusters", - ".mft": "application/rpki-manifest", - ".roa": "application/rpki-roa", - ".rtf": "application/rtf", - ".scim": "application/scim+json", - ".scq": "application/scvp-cv-request", - ".scs": "application/scvp-cv-response", - ".spq": "application/scvp-vp-request", - ".spp": "application/scvp-vp-response", - ".sdp": "application/sdp", - ".soc": "application/sgml-open-catalog", - ".shf": "application/shf+xml", - ".siv": "application/sieve", - ".sieve": "application/sieve", - ".cl": "application/simple-filter+xml", - ".smil": "application/smil+xml", - ".smi": "application/smil+xml", - ".sml": "application/smil+xml", - ".rq": "application/sparql-query", - ".srx": "application/sparql-results+xml", - ".sql": "application/sql", - ".gram": "application/srgs", - ".grxml": "application/srgs+xml", - ".sru": "application/sru+xml", - ".ssml": "application/ssml+xml", - ".tau": "application/tamp-apex-update", - ".auc": "application/tamp-apex-update-confirm", - ".tcu": "application/tamp-community-update", - ".cuc": "application/tamp-community-update-confirm", - ".ter": "application/tamp-error", - ".tsa": "application/tamp-sequence-adjust", - ".sac": "application/tamp-sequence-adjust-confirm", - ".tur": "application/tamp-update", - ".tuc": "application/tamp-update-confirm", - ".tei": "application/tei+xml", - ".teiCorpus": "application/tei+xml", - ".odd": "application/tei+xml", - ".tfi": "application/thraud+xml", - ".tsq": "application/timestamp-query", - ".tsr": "application/timestamp-reply", - ".tsd": "application/timestamped-data", - ".trig": "application/trig", - ".ttml": "application/ttml+xml", - ".gsheet": "application/urc-grpsheet+xml", - ".rsheet": "application/urc-ressheet+xml", - ".td": "application/urc-targetdesc+xml", - ".uis": "application/urc-uisocketdesc+xml", - ".plb": "application/vnd.3gpp.pic-bw-large", - ".psb": "application/vnd.3gpp.pic-bw-small", - ".pvb": "application/vnd.3gpp.pic-bw-var", - ".sms": "application/vnd.3gpp2.sms", - ".tcap": "application/vnd.3gpp2.tcap", - ".imgcal": "application/vnd.3lightssoftware.imagescal", - ".pwn": "application/vnd.3M.Post-it-Notes", - ".aso": "application/vnd.accpac.simply.aso", - ".imp": "application/vnd.accpac.simply.imp", - ".acu": "application/vnd.acucobol", - ".atc": "application/vnd.acucorp", - ".acutc": "application/vnd.acucorp", - ".swf": "application/vnd.adobe.flash.movie", - ".fcdt": "application/vnd.adobe.formscentral.fcdt", - ".fxp": "application/vnd.adobe.fxp", - ".fxpl": "application/vnd.adobe.fxp", - ".xdp": "application/vnd.adobe.xdp+xml", - ".xfdf": "application/vnd.adobe.xfdf", - ".ahead": "application/vnd.ahead.space", - ".azf": "application/vnd.airzip.filesecure.azf", - ".azs": "application/vnd.airzip.filesecure.azs", - ".azw3": "application/vnd.amazon.mobi8-ebook", - ".acc": "application/vnd.americandynamics.acc", - ".ami": "application/vnd.amiga.ami", - ".apkg": "application/vnd.anki", - ".cii": "application/vnd.anser-web-certificate-issue-initiation", - ".fti": "application/vnd.anser-web-funds-transfer-initiation", - ".dist": "application/vnd.apple.installer+xml", - ".distz": "application/vnd.apple.installer+xml", - ".pkg": "application/vnd.apple.installer+xml", - ".mpkg": "application/vnd.apple.installer+xml", - ".m3u8": "application/vnd.apple.mpegurl", - ".swi": "application/vnd.aristanetworks.swi", - ".iota": "application/vnd.astraea-software.iota", - ".aep": "application/vnd.audiograph", - ".package": "application/vnd.autopackage", - ".bmml": "application/vnd.balsamiq.bmml+xml", - ".bmpr": "application/vnd.balsamiq.bmpr", - ".mpm": "application/vnd.blueice.multipass", - ".ep": "application/vnd.bluetooth.ep.oob", - ".le": "application/vnd.bluetooth.le.oob", - ".bmi": "application/vnd.bmi", - ".rep": "application/vnd.businessobjects", - ".tlclient": "application/vnd.cendio.thinlinc.clientconf", - ".cdxml": "application/vnd.chemdraw+xml", - ".pgn": "application/vnd.chess-pgn", - ".mmd": "application/vnd.chipnuts.karaoke-mmd", - ".cdy": "application/vnd.cinderella", - ".csl": "application/vnd.citationstyles.style+xml", - ".cla": "application/vnd.claymore", - ".rp9": "application/vnd.cloanto.rp9", - ".c4g": "application/vnd.clonk.c4group", - ".c4d": "application/vnd.clonk.c4group", - ".c4f": "application/vnd.clonk.c4group", - ".c4p": "application/vnd.clonk.c4group", - ".c4u": "application/vnd.clonk.c4group", - ".c11amc": "application/vnd.cluetrust.cartomobile-config", - ".c11amz": "application/vnd.cluetrust.cartomobile-config-pkg", - ".coffee": "application/vnd.coffeescript", - ".cbz": "application/vnd.comicbook+zip", - ".ica": "application/vnd.commerce-battelle", - ".icf": "application/vnd.commerce-battelle", - ".icd": "application/vnd.commerce-battelle", - ".ic0": "application/vnd.commerce-battelle", - ".ic1": "application/vnd.commerce-battelle", - ".ic2": "application/vnd.commerce-battelle", - ".ic3": "application/vnd.commerce-battelle", - ".ic4": "application/vnd.commerce-battelle", - ".ic5": "application/vnd.commerce-battelle", - ".ic6": "application/vnd.commerce-battelle", - ".ic7": "application/vnd.commerce-battelle", - ".ic8": "application/vnd.commerce-battelle", - ".csp": "application/vnd.commonspace", - ".cst": "application/vnd.commonspace", - ".cdbcmsg": "application/vnd.contact.cmsg", - ".ign": "application/vnd.coreos.ignition+json", - ".ignition": "application/vnd.coreos.ignition+json", - ".cmc": "application/vnd.cosmocaller", - ".clkx": "application/vnd.crick.clicker", - ".clkk": "application/vnd.crick.clicker.keyboard", - ".clkp": "application/vnd.crick.clicker.palette", - ".clkt": "application/vnd.crick.clicker.template", - ".clkw": "application/vnd.crick.clicker.wordbank", - ".wbs": "application/vnd.criticaltools.wbs+xml", - ".pml": "application/vnd.ctc-posml", - ".ppd": "application/vnd.cups-ppd", - ".curl": "application/vnd.curl", - ".dart": "application/vnd.dart", - ".rdz": "application/vnd.data-vision.rdz", - ".deb": "application/vnd.debian.binary-package", - ".udeb": "application/vnd.debian.binary-package", - ".uvf": "application/vnd.dece.data", - ".uvvf": "application/vnd.dece.data", - ".uvd": "application/vnd.dece.data", - ".uvvd": "application/vnd.dece.data", - ".uvt": "application/vnd.dece.ttml+xml", - ".uvvt": "application/vnd.dece.ttml+xml", - ".uvx": "application/vnd.dece.unspecified", - ".uvvx": "application/vnd.dece.unspecified", - ".uvz": "application/vnd.dece.zip", - ".uvvz": "application/vnd.dece.zip", - ".fe_launch": "application/vnd.denovo.fcselayout-link", - ".dsm": "application/vnd.desmume.movie", - ".dna": "application/vnd.dna", - ".docjson": "application/vnd.document+json", - ".scld": "application/vnd.doremir.scorecloud-binary-document", - ".dpg": "application/vnd.dpgraph", - ".mwc": "application/vnd.dpgraph", - ".dpgraph": "application/vnd.dpgraph", - ".dfac": "application/vnd.dreamfactory", - ".fla": "application/vnd.dtg.local.flash", - ".ait": "application/vnd.dvb.ait", - ".svc": "application/vnd.dvb.service", - ".geo": "application/vnd.dynageo", - ".dzr": "application/vnd.dzr", - ".mag": "application/vnd.ecowin.chart", - ".nml": "application/vnd.enliven", - ".esf": "application/vnd.epson.esf", - ".msf": "application/vnd.epson.msf", - ".qam": "application/vnd.epson.quickanime", - ".slt": "application/vnd.epson.salt", - ".ssf": "application/vnd.epson.ssf", - ".qcall": "application/vnd.ericsson.quickcall", - ".qca": "application/vnd.ericsson.quickcall", - ".espass": "application/vnd.espass-espass+zip", - ".es3": "application/vnd.eszigno3+xml", - ".et3": "application/vnd.eszigno3+xml", - ".asice": "application/vnd.etsi.asic-e+zip", - ".sce": "application/vnd.etsi.asic-e+zip", - ".asics": "application/vnd.etsi.asic-s+zip", - ".tst": "application/vnd.etsi.timestamp-token", - ".ez2": "application/vnd.ezpix-album", - ".ez3": "application/vnd.ezpix-package", - ".dim": "application/vnd.fastcopy-disk-image", - ".fdf": "application/vnd.fdf", - ".msd": "application/vnd.fdsn.mseed", - ".mseed": "application/vnd.fdsn.mseed", - ".seed": "application/vnd.fdsn.seed", - ".dataless": "application/vnd.fdsn.seed", - ".zfc": "application/vnd.filmit.zfc", - ".gph": "application/vnd.FloGraphIt", - ".ftc": "application/vnd.fluxtime.clip", - ".sfd": "application/vnd.font-fontforge-sfd", - ".fm": "application/vnd.framemaker", - ".fnc": "application/vnd.frogans.fnc", - ".ltf": "application/vnd.frogans.ltf", - ".fsc": "application/vnd.fsc.weblaunch", - ".oas": "application/vnd.fujitsu.oasys", - ".oa2": "application/vnd.fujitsu.oasys2", - ".oa3": "application/vnd.fujitsu.oasys3", - ".fg5": "application/vnd.fujitsu.oasysgp", - ".bh2": "application/vnd.fujitsu.oasysprs", - ".ddd": "application/vnd.fujixerox.ddd", - ".xdw": "application/vnd.fujixerox.docuworks", - ".xbd": "application/vnd.fujixerox.docuworks.binder", - ".xct": "application/vnd.fujixerox.docuworks.container", - ".fzs": "application/vnd.fuzzysheet", - ".txd": "application/vnd.genomatix.tuxedo", - ".g3": "application/vnd.geocube+xml", - ".g³": "application/vnd.geocube+xml", - ".ggb": "application/vnd.geogebra.file", - ".ggt": "application/vnd.geogebra.tool", - ".gex": "application/vnd.geometry-explorer", - ".gre": "application/vnd.geometry-explorer", - ".gxt": "application/vnd.geonext", - ".g2w": "application/vnd.geoplan", - ".g3w": "application/vnd.geospace", - ".gmx": "application/vnd.gmx", - ".kml": "application/vnd.google-earth.kml+xml", - ".kmz": "application/vnd.google-earth.kmz", - ".gqf": "application/vnd.grafeq", - ".gqs": "application/vnd.grafeq", - ".gac": "application/vnd.groove-account", - ".ghf": "application/vnd.groove-help", - ".gim": "application/vnd.groove-identity-message", - ".grv": "application/vnd.groove-injector", - ".gtm": "application/vnd.groove-tool-message", - ".tpl": "application/vnd.groove-tool-template", - ".vcg": "application/vnd.groove-vcard", - ".hal": "application/vnd.hal+xml", - ".zmm": "application/vnd.HandHeld-Entertainment+xml", - ".hbci": "application/vnd.hbci", - ".hbc": "application/vnd.hbci", - ".kom": "application/vnd.hbci", - ".upa": "application/vnd.hbci", - ".pkd": "application/vnd.hbci", - ".bpd": "application/vnd.hbci", - ".hdt": "application/vnd.hdt", - ".les": "application/vnd.hhe.lesson-player", - ".hpgl": "application/vnd.hp-HPGL", - ".hpi": "application/vnd.hp-hpid", - ".hpid": "application/vnd.hp-hpid", - ".hps": "application/vnd.hp-hps", - ".jlt": "application/vnd.hp-jlyt", - ".pcl": "application/vnd.hp-PCL", - ".sfd-hdstx": "application/vnd.hydrostatix.sof-data", - ".x3d": "application/vnd.hzn-3d-crossword", - ".emm": "application/vnd.ibm.electronic-media", - ".mpy": "application/vnd.ibm.MiniPay", - ".list3820": "application/vnd.ibm.modcap", - ".listafp": "application/vnd.ibm.modcap", - ".afp": "application/vnd.ibm.modcap", - ".pseg3820": "application/vnd.ibm.modcap", - ".irm": "application/vnd.ibm.rights-management", - ".sc": "application/vnd.ibm.secure-container", - ".icc": "application/vnd.iccprofile", - ".icm": "application/vnd.iccprofile", - ".1905.1": "application/vnd.ieee.1905", - ".igl": "application/vnd.igloader", - ".imf": "application/vnd.imagemeter.folder+zip", - ".imi": "application/vnd.imagemeter.image+zip", - ".ivp": "application/vnd.immervision-ivp", - ".ivu": "application/vnd.immervision-ivu", - ".imscc": "application/vnd.ims.imsccv1p1", - ".igm": "application/vnd.insors.igm", - ".xpw": "application/vnd.intercon.formnet", - ".xpx": "application/vnd.intercon.formnet", - ".i2g": "application/vnd.intergeo", - ".qbo": "application/vnd.intu.qbo", - ".qfx": "application/vnd.intu.qfx", - ".rcprofile": "application/vnd.ipunplugged.rcprofile", - ".irp": "application/vnd.irepository.package+xml", - ".xpr": "application/vnd.is-xpr", - ".fcs": "application/vnd.isac.fcs", - ".jam": "application/vnd.jam", - ".rms": "application/vnd.jcp.javame.midlet-rms", - ".jisp": "application/vnd.jisp", - ".joda": "application/vnd.joost.joda-archive", - ".ktz": "application/vnd.kahootz", - ".ktr": "application/vnd.kahootz", - ".karbon": "application/vnd.kde.karbon", - ".chrt": "application/vnd.kde.kchart", - ".kfo": "application/vnd.kde.kformula", - ".flw": "application/vnd.kde.kivio", - ".kon": "application/vnd.kde.kontour", - ".kpr": "application/vnd.kde.kpresenter", - ".kpt": "application/vnd.kde.kpresenter", - ".ksp": "application/vnd.kde.kspread", - ".kwd": "application/vnd.kde.kword", - ".kwt": "application/vnd.kde.kword", - ".htke": "application/vnd.kenameaapp", - ".kia": "application/vnd.kidspiration", - ".kne": "application/vnd.Kinar", - ".knp": "application/vnd.Kinar", - ".sdf": "application/vnd.Kinar", - ".skp": "application/vnd.koan", - ".skd": "application/vnd.koan", - ".skm": "application/vnd.koan", - ".skt": "application/vnd.koan", - ".sse": "application/vnd.kodak-descriptor", - ".lasjson": "application/vnd.las.las+json", - ".lasxml": "application/vnd.las.las+xml", - ".lbd": "application/vnd.llamagraphics.life-balance.desktop", - ".lbe": "application/vnd.llamagraphics.life-balance.exchange+xml", - ".123": "application/vnd.lotus-1-2-3", - ".wk4": "application/vnd.lotus-1-2-3", - ".wk3": "application/vnd.lotus-1-2-3", - ".wk1": "application/vnd.lotus-1-2-3", - ".apr": "application/vnd.lotus-approach", - ".vew": "application/vnd.lotus-approach", - ".prz": "application/vnd.lotus-freelance", - ".pre": "application/vnd.lotus-freelance", - ".nsf": "application/vnd.lotus-notes", - ".ntf": "application/vnd.lotus-notes", - ".ndl": "application/vnd.lotus-notes", - ".ns4": "application/vnd.lotus-notes", - ".ns3": "application/vnd.lotus-notes", - ".ns2": "application/vnd.lotus-notes", - ".nsh": "application/vnd.lotus-notes", - ".nsg": "application/vnd.lotus-notes", - ".or3": "application/vnd.lotus-organizer", - ".or2": "application/vnd.lotus-organizer", - ".org": "application/vnd.lotus-organizer", - ".scm": "application/vnd.lotus-screencam", - ".lwp": "application/vnd.lotus-wordpro", - ".sam": "application/vnd.lotus-wordpro", - ".portpkg": "application/vnd.macports.portpkg", - ".mvt": "application/vnd.mapbox-vector-tile", - ".mdc": "application/vnd.marlin.drm.mdcf", - ".mmdb": "application/vnd.maxmind.maxmind-db", - ".mcd": "application/vnd.mcd", - ".mc1": "application/vnd.medcalcdata", - ".cdkey": "application/vnd.mediastation.cdkey", - ".mwf": "application/vnd.MFER", - ".mfm": "application/vnd.mfmp", - ".flo": "application/vnd.micrografx.flo", - ".igx": "application/vnd.micrografx.igx", - ".mif": "application/vnd.mif", - ".daf": "application/vnd.Mobius.DAF", - ".dis": "application/vnd.Mobius.DIS", - ".mbk": "application/vnd.Mobius.MBK", - ".mqy": "application/vnd.Mobius.MQY", - ".msl": "application/vnd.Mobius.MSL", - ".plc": "application/vnd.Mobius.PLC", - ".txf": "application/vnd.Mobius.TXF", - ".mpn": "application/vnd.mophun.application", - ".mpc": "application/vnd.mophun.certificate", - ".xul": "application/vnd.mozilla.xul+xml", - ".3mf": "application/vnd.ms-3mfdocument", - ".cil": "application/vnd.ms-artgalry", - ".asf": "application/vnd.ms-asf", - ".cab": "application/vnd.ms-cab-compressed", - ".xls": "application/vnd.ms-excel", - ".xlm": "application/vnd.ms-excel", - ".xla": "application/vnd.ms-excel", - ".xlc": "application/vnd.ms-excel", - ".xlt": "application/vnd.ms-excel", - ".xlw": "application/vnd.ms-excel", - ".xltm": "application/vnd.ms-excel.template.macroEnabled.12", - ".xlam": "application/vnd.ms-excel.addin.macroEnabled.12", - ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12", - ".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12", - ".eot": "application/vnd.ms-fontobject", - ".chm": "application/vnd.ms-htmlhelp", - ".ims": "application/vnd.ms-ims", - ".lrm": "application/vnd.ms-lrm", - ".thmx": "application/vnd.ms-officetheme", - ".ppt": "application/vnd.ms-powerpoint", - ".pps": "application/vnd.ms-powerpoint", - ".pot": "application/vnd.ms-powerpoint", - ".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12", - ".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12", - ".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12", - ".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", - ".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12", - ".mpp": "application/vnd.ms-project", - ".mpt": "application/vnd.ms-project", - ".tnef": "application/vnd.ms-tnef", - ".tnf": "application/vnd.ms-tnef", - ".docm": "application/vnd.ms-word.document.macroEnabled.12", - ".dotm": "application/vnd.ms-word.template.macroEnabled.12", - ".wcm": "application/vnd.ms-works", - ".wdb": "application/vnd.ms-works", - ".wks": "application/vnd.ms-works", - ".wps": "application/vnd.ms-works", - ".wpl": "application/vnd.ms-wpl", - ".xps": "application/vnd.ms-xpsdocument", - ".msa": "application/vnd.msa-disk-image", - ".mseq": "application/vnd.mseq", - ".crtr": "application/vnd.multiad.creator", - ".cif": "application/vnd.multiad.creator.cif", - ".mus": "application/vnd.musician", - ".msty": "application/vnd.muvee.style", - ".taglet": "application/vnd.mynfc", - ".entity": "application/vnd.nervana", - ".request": "application/vnd.nervana", - ".bkm": "application/vnd.nervana", - ".kcm": "application/vnd.nervana", - ".nitf": "application/vnd.nitf", - ".nlu": "application/vnd.neurolanguage.nlu", - ".nds": "application/vnd.nintendo.nitro.rom", - ".sfc": "application/vnd.nintendo.snes.rom", - ".smc": "application/vnd.nintendo.snes.rom", - ".nnd": "application/vnd.noblenet-directory", - ".nns": "application/vnd.noblenet-sealer", - ".nnw": "application/vnd.noblenet-web", - ".ac": "application/vnd.nokia.n-gage.ac+xml", - ".ngdat": "application/vnd.nokia.n-gage.data", - ".n-gage": "application/vnd.nokia.n-gage.symbian.install", - ".rpst": "application/vnd.nokia.radio-preset", - ".rpss": "application/vnd.nokia.radio-presets", - ".edm": "application/vnd.novadigm.EDM", - ".edx": "application/vnd.novadigm.EDX", - ".ext": "application/vnd.novadigm.EXT", - ".odc": "application/vnd.oasis.opendocument.chart", - ".otc": "application/vnd.oasis.opendocument.chart-template", - ".odb": "application/vnd.oasis.opendocument.database", - ".odf": "application/vnd.oasis.opendocument.formula", - ".odg": "application/vnd.oasis.opendocument.graphics", - ".otg": "application/vnd.oasis.opendocument.graphics-template", - ".odi": "application/vnd.oasis.opendocument.image", - ".oti": "application/vnd.oasis.opendocument.image-template", - ".odp": "application/vnd.oasis.opendocument.presentation", - ".otp": "application/vnd.oasis.opendocument.presentation-template", - ".ods": "application/vnd.oasis.opendocument.spreadsheet", - ".ots": "application/vnd.oasis.opendocument.spreadsheet-template", - ".odt": "application/vnd.oasis.opendocument.text", - ".odm": "application/vnd.oasis.opendocument.text-master", - ".ott": "application/vnd.oasis.opendocument.text-template", - ".oth": "application/vnd.oasis.opendocument.text-web", - ".xo": "application/vnd.olpc-sugar", - ".dd2": "application/vnd.oma.dd2+xml", - ".tam": "application/vnd.onepager", - ".tamp": "application/vnd.onepagertamp", - ".tamx": "application/vnd.onepagertamx", - ".tat": "application/vnd.onepagertat", - ".tatp": "application/vnd.onepagertatp", - ".tatx": "application/vnd.onepagertatx", - ".obgx": "application/vnd.openblox.game+xml", - ".obg": "application/vnd.openblox.game-binary", - ".oeb": "application/vnd.openeye.oeb", - ".oxt": "application/vnd.openofficeorg.extension", - ".osm": "application/vnd.openstreetmap.data+xml", - ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", - ".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", - ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", - ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template", - ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", - ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", - ".ndc": "application/vnd.osa.netdeploy", - ".mgp": "application/vnd.osgeo.mapguide.package", - ".dp": "application/vnd.osgi.dp", - ".esa": "application/vnd.osgi.subsystem", - ".oxlicg": "application/vnd.oxli.countgraph", - ".prc": "application/vnd.palm", - ".pdb": "application/vnd.palm", - ".pqa": "application/vnd.palm", - ".oprc": "application/vnd.palm", - ".plp": "application/vnd.panoply", - ".paw": "application/vnd.pawaafile", - ".str": "application/vnd.pg.format", - ".ei6": "application/vnd.pg.osasli", - ".pil": "application/vnd.piaccess.application-license", - ".efif": "application/vnd.picsel", - ".wg": "application/vnd.pmi.widget", - ".plf": "application/vnd.pocketlearn", - ".pbd": "application/vnd.powerbuilder6", - ".preminet": "application/vnd.preminet", - ".box": "application/vnd.previewsystems.box", - ".vbox": "application/vnd.previewsystems.box", - ".mgz": "application/vnd.proteus.magazine", - ".qps": "application/vnd.publishare-delta-tree", - ".ptid": "application/vnd.pvi.ptid1", - ".bar": "application/vnd.qualcomm.brew-app-res", - ".qxd": "application/vnd.Quark.QuarkXPress", - ".qxt": "application/vnd.Quark.QuarkXPress", - ".qwd": "application/vnd.Quark.QuarkXPress", - ".qwt": "application/vnd.Quark.QuarkXPress", - ".qxl": "application/vnd.Quark.QuarkXPress", - ".qxb": "application/vnd.Quark.QuarkXPress", - ".quox": "application/vnd.quobject-quoxdocument", - ".quiz": "application/vnd.quobject-quoxdocument", - ".tree": "application/vnd.rainstor.data", - ".rar": "application/vnd.rar", - ".bed": "application/vnd.realvnc.bed", - ".mxl": "application/vnd.recordare.musicxml", - ".cryptonote": "application/vnd.rig.cryptonote", - ".link66": "application/vnd.route66.link66+xml", - ".st": "application/vnd.sailingtracker.track", - ".scd": "application/vnd.scribus", - ".sla": "application/vnd.scribus", - ".slaz": "application/vnd.scribus", - ".s3df": "application/vnd.sealed.3df", - ".scsf": "application/vnd.sealed.csf", - ".sdoc": "application/vnd.sealed.doc", - ".sdo": "application/vnd.sealed.doc", - ".s1w": "application/vnd.sealed.doc", - ".seml": "application/vnd.sealed.eml", - ".sem": "application/vnd.sealed.eml", - ".smht": "application/vnd.sealed.mht", - ".smh": "application/vnd.sealed.mht", - ".sppt": "application/vnd.sealed.ppt", - ".s1p": "application/vnd.sealed.ppt", - ".stif": "application/vnd.sealed.tiff", - ".sxls": "application/vnd.sealed.xls", - ".sxl": "application/vnd.sealed.xls", - ".s1e": "application/vnd.sealed.xls", - ".stml": "application/vnd.sealedmedia.softseal.html", - ".s1h": "application/vnd.sealedmedia.softseal.html", - ".spdf": "application/vnd.sealedmedia.softseal.pdf", - ".spd": "application/vnd.sealedmedia.softseal.pdf", - ".s1a": "application/vnd.sealedmedia.softseal.pdf", - ".see": "application/vnd.seemail", - ".sema": "application/vnd.sema", - ".semd": "application/vnd.semd", - ".semf": "application/vnd.semf", - ".ifm": "application/vnd.shana.informed.formdata", - ".itp": "application/vnd.shana.informed.formtemplate", - ".iif": "application/vnd.shana.informed.interchange", - ".ipk": "application/vnd.shana.informed.package", - ".twd": "application/vnd.SimTech-MindMapper", - ".twds": "application/vnd.SimTech-MindMapper", - ".mmf": "application/vnd.smaf", - ".notebook": "application/vnd.smart.notebook", - ".teacher": "application/vnd.smart.teacher", - ".fo": "application/vnd.software602.filler.form+xml", - ".zfo": "application/vnd.software602.filler.form-xml-zip", - ".sdkm": "application/vnd.solent.sdkm+xml", - ".sdkd": "application/vnd.solent.sdkm+xml", - ".dxp": "application/vnd.spotfire.dxp", - ".sfs": "application/vnd.spotfire.sfs", - ".smzip": "application/vnd.stepmania.package", - ".sm": "application/vnd.stepmania.stepchart", - ".wadl": "application/vnd.sun.wadl+xml", - ".sus": "application/vnd.sus-calendar", - ".susp": "application/vnd.sus-calendar", - ".xsm": "application/vnd.syncml+xml", - ".bdm": "application/vnd.syncml.dm+wbxml", - ".xdm": "application/vnd.syncml.dm+xml", - ".ddf": "application/vnd.syncml.dmddf+xml", - ".tao": "application/vnd.tao.intent-module-archive", - ".pcap": "application/vnd.tcpdump.pcap", - ".cap": "application/vnd.tcpdump.pcap", - ".dmp": "application/vnd.tcpdump.pcap", - ".qvd": "application/vnd.theqvd", - ".vfr": "application/vnd.tml", - ".viaframe": "application/vnd.tml", - ".tmo": "application/vnd.tmobile-livetv", - ".tpt": "application/vnd.trid.tpt", - ".mxs": "application/vnd.triscape.mxs", - ".tra": "application/vnd.trueapp", - ".ufdl": "application/vnd.ufdl", - ".ufd": "application/vnd.ufdl", - ".frm": "application/vnd.ufdl", - ".utz": "application/vnd.uiq.theme", - ".umj": "application/vnd.umajin", - ".unityweb": "application/vnd.unity", - ".uoml": "application/vnd.uoml+xml", - ".uo": "application/vnd.uoml+xml", - ".urim": "application/vnd.uri-map", - ".urimap": "application/vnd.uri-map", - ".vmt": "application/vnd.valve.source.material", - ".vcx": "application/vnd.vcx", - ".mxi": "application/vnd.vd-study", - ".study-inter": "application/vnd.vd-study", - ".model-inter": "application/vnd.vd-study", - ".vwx": "application/vnd.vectorworks", - ".vsc": "application/vnd.vidsoft.vidconference", - ".vsd": "application/vnd.visio", - ".vst": "application/vnd.visio", - ".vsw": "application/vnd.visio", - ".vss": "application/vnd.visio", - ".vis": "application/vnd.visionary", - ".vsf": "application/vnd.vsf", - ".sic": "application/vnd.wap.sic", - ".slc": "application/vnd.wap.slc", - ".wbxml": "application/vnd.wap.wbxml", - ".wmlc": "application/vnd.wap.wmlc", - ".wmlsc": "application/vnd.wap.wmlscriptc", - ".wtb": "application/vnd.webturbo", - ".p2p": "application/vnd.wfa.p2p", - ".wsc": "application/vnd.wfa.wsc", - ".wmc": "application/vnd.wmc", - ".m": "application/vnd.wolfram.mathematica.package", - ".nbp": "application/vnd.wolfram.player", - ".wpd": "application/vnd.wordperfect", - ".wqd": "application/vnd.wqd", - ".stf": "application/vnd.wt.stf", - ".wv": "application/vnd.wv.csp+wbxml", - ".xar": "application/vnd.xara", - ".xfdl": "application/vnd.xfdl", - ".xfd": "application/vnd.xfdl", - ".cpkg": "application/vnd.xmpie.cpkg", - ".dpkg": "application/vnd.xmpie.dpkg", - ".ppkg": "application/vnd.xmpie.ppkg", - ".xlim": "application/vnd.xmpie.xlim", - ".hvd": "application/vnd.yamaha.hv-dic", - ".hvs": "application/vnd.yamaha.hv-script", - ".hvp": "application/vnd.yamaha.hv-voice", - ".osf": "application/vnd.yamaha.openscoreformat", - ".saf": "application/vnd.yamaha.smaf-audio", - ".spf": "application/vnd.yamaha.smaf-phrase", - ".yme": "application/vnd.yaoweme", - ".cmp": "application/vnd.yellowriver-custom-menu", - ".zir": "application/vnd.zul", - ".zirz": "application/vnd.zul", - ".zaz": "application/vnd.zzazz.deck+xml", - ".vxml": "application/voicexml+xml", - ".wif": "application/watcherinfo+xml", - ".wgt": "application/widget", - ".wsdl": "application/wsdl+xml", - ".wspolicy": "application/wspolicy+xml", - ".xav": "application/xcap-att+xml", - ".xca": "application/xcap-caps+xml", - ".xdf": "application/xcap-diff+xml", - ".xel": "application/xcap-el+xml", - ".xer": "application/xcap-error+xml", - ".xns": "application/xcap-ns+xml", - ".xhtml": "application/xhtml+xml", - ".xhtm": "application/xhtml+xml", - ".xht": "application/xhtml+xml", - ".dtd": "application/xml-dtd", - ".xop": "application/xop+xml", - ".xsl": "application/xslt+xml", - ".xslt": "application/xslt+xml", - ".mxml": "application/xv+xml", - ".xhvml": "application/xv+xml", - ".xvml": "application/xv+xml", - ".xvm": "application/xv+xml", - ".yang": "application/yang", - ".yin": "application/yin+xml", - ".zip": "application/zip", - ".726": "audio/32kadpcm", - ".ac3": "audio/ac3", - ".amr": "audio/AMR", - ".awb": "audio/AMR-WB", - ".acn": "audio/asc", - ".aal": "audio/ATRAC-ADVANCED-LOSSLESS", - ".atx": "audio/ATRAC-X", - ".at3": "audio/ATRAC3", - ".aa3": "audio/ATRAC3", - ".omg": "audio/ATRAC3", - ".au": "audio/basic", - ".snd": "audio/basic", - ".dls": "audio/dls", - ".evc": "audio/EVRC", - ".evb": "audio/EVRCB", - ".enw": "audio/EVRCNW", - ".evw": "audio/EVRCWB", - ".lbc": "audio/iLBC", - ".l16": "audio/L16", - ".mxmf": "audio/mobile-xmf", - ".m4a": "audio/mp4", - ".mp3": "audio/mpeg", - ".mpga": "audio/mpeg", - ".mp1": "audio/mpeg", - ".mp2": "audio/mpeg", - ".oga": "audio/ogg", - ".ogg": "audio/ogg", - ".opus": "audio/ogg", - ".spx": "audio/ogg", - ".sid": "audio/prs.sid", - ".psid": "audio/prs.sid", - ".qcp": "audio/qcelp", - ".smv": "audio/SMV", - ".koz": "audio/vnd.audikoz", - ".uva": "audio/vnd.dece.audio", - ".uvva": "audio/vnd.dece.audio", - ".eol": "audio/vnd.digital-winds", - ".mlp": "audio/vnd.dolby.mlp", - ".dts": "audio/vnd.dts", - ".dtshd": "audio/vnd.dts.hd", - ".plj": "audio/vnd.everad.plj", - ".lvp": "audio/vnd.lucent.voice", - ".pya": "audio/vnd.ms-playready.media.pya", - ".vbk": "audio/vnd.nortel.vbk", - ".ecelp4800": "audio/vnd.nuera.ecelp4800", - ".ecelp7470": "audio/vnd.nuera.ecelp7470", - ".ecelp9600": "audio/vnd.nuera.ecelp9600", - ".rip": "audio/vnd.rip", - ".smp3": "audio/vnd.sealedmedia.softseal.mpeg", - ".smp": "audio/vnd.sealedmedia.softseal.mpeg", - ".s1m": "audio/vnd.sealedmedia.softseal.mpeg", - ".ttc": "font/collection", - ".otf": "font/otf", - ".ttf": "font/ttf", - ".woff": "font/woff", - ".woff2": "font/woff2", - ".bmp": "image/bmp", - ".dib": "image/bmp", - ".cgm": "image/cgm", - ".drle": "image/dicom-rle", - ".emf": "image/emf", - ".fits": "image/fits", - ".fit": "image/fits", - ".fts": "image/fits", - ".gif": "image/gif", - ".ief": "image/ief", - ".jls": "image/jls", - ".jp2": "image/jp2", - ".jpg2": "image/jp2", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".jpe": "image/jpeg", - ".jfif": "image/jpeg", - ".jpm": "image/jpm", - ".jpgm": "image/jpm", - ".jpx": "image/jpx", - ".jpf": "image/jpx", - ".ktx": "image/ktx", - ".png": "image/png", - ".btif": "image/prs.btif", - ".btf": "image/prs.btif", - ".pti": "image/prs.pti", - ".svg": "image/svg+xml", - ".svgz": "image/svg+xml", - ".t38": "image/t38", - ".tiff": "image/tiff", - ".tif": "image/tiff", - ".tfx": "image/tiff-fx", - ".psd": "image/vnd.adobe.photoshop", - ".azv": "image/vnd.airzip.accelerator.azv", - ".uvi": "image/vnd.dece.graphic", - ".uvvi": "image/vnd.dece.graphic", - ".uvg": "image/vnd.dece.graphic", - ".uvvg": "image/vnd.dece.graphic", - ".djvu": "image/vnd.djvu", - ".djv": "image/vnd.djvu", - ".dwg": "image/vnd.dwg", - ".dxf": "image/vnd.dxf", - ".fbs": "image/vnd.fastbidsheet", - ".fpx": "image/vnd.fpx", - ".fst": "image/vnd.fst", - ".mmr": "image/vnd.fujixerox.edmics-mmr", - ".rlc": "image/vnd.fujixerox.edmics-rlc", - ".pgb": "image/vnd.globalgraphics.pgb", - ".ico": "image/vnd.microsoft.icon", - ".apng": "image/vnd.mozilla.apng", - ".mdi": "image/vnd.ms-modi", - ".hdr": "image/vnd.radiance", - ".rgbe": "image/vnd.radiance", - ".xyze": "image/vnd.radiance", - ".spng": "image/vnd.sealed.png", - ".spn": "image/vnd.sealed.png", - ".s1n": "image/vnd.sealed.png", - ".sgif": "image/vnd.sealedmedia.softseal.gif", - ".sgi": "image/vnd.sealedmedia.softseal.gif", - ".s1g": "image/vnd.sealedmedia.softseal.gif", - ".sjpg": "image/vnd.sealedmedia.softseal.jpg", - ".sjp": "image/vnd.sealedmedia.softseal.jpg", - ".s1j": "image/vnd.sealedmedia.softseal.jpg", - ".tap": "image/vnd.tencent.tap", - ".vtf": "image/vnd.valve.source.texture", - ".wbmp": "image/vnd.wap.wbmp", - ".xif": "image/vnd.xiff", - ".pcx": "image/vnd.zbrush.pcx", - ".wmf": "image/wmf", - ".u8msg": "message/global", - ".u8dsn": "message/global-delivery-status", - ".u8mdn": "message/global-disposition-notification", - ".u8hdr": "message/global-headers", - ".eml": "message/rfc822", - ".mail": "message/rfc822", - ".art": "message/rfc822", - ".gltf": "model/gltf+json", - ".igs": "model/iges", - ".iges": "model/iges", - ".msh": "model/mesh", - ".mesh": "model/mesh", - ".silo": "model/mesh", - ".dae": "model/vnd.collada+xml", - ".dwf": "model/vnd.dwf", - ".gdl": "model/vnd.gdl", - ".gsm": "model/vnd.gdl", - ".win": "model/vnd.gdl", - ".dor": "model/vnd.gdl", - ".lmp": "model/vnd.gdl", - ".rsm": "model/vnd.gdl", - ".msm": "model/vnd.gdl", - ".ism": "model/vnd.gdl", - ".gtw": "model/vnd.gtw", - ".moml": "model/vnd.moml+xml", - ".mts": "model/vnd.mts", - ".ogex": "model/vnd.opengex", - ".x_b": "model/vnd.parasolid.transmit.binary", - ".xmt_bin": "model/vnd.parasolid.transmit.binary", - ".x_t": "model/vnd.parasolid.transmit.text", - ".xmt_txt": "model/vnd.parasolid.transmit.text", - ".bsp": "model/vnd.valve.source.compiled-map", - ".vtu": "model/vnd.vtu", - ".wrl": "model/vrml", - ".vrml": "model/vrml", - ".x3db": "model/x3d+xml", - ".x3dv": "model/x3d-vrml", - ".x3dvz": "model/x3d-vrml", - ".bmed": "multipart/vnd.bint.med-plus", - ".vpm": "multipart/voice-message", - ".appcache": "text/cache-manifest", - ".manifest": "text/cache-manifest", - ".ics": "text/calendar", - ".ifb": "text/calendar", - ".css": "text/css", - ".csv": "text/csv", - ".csvs": "text/csv-schema", - ".soa": "text/dns", - ".zone": "text/dns", - ".html": "text/html", - ".htm": "text/html", - ".cnd": "text/jcr-cnd", - ".markdown": "text/markdown", - ".md": "text/markdown", - ".miz": "text/mizar", - ".n3": "text/n3", - ".txt": "text/plain", - ".asc": "text/plain", - ".text": "text/plain", - ".pm": "text/plain", - ".el": "text/plain", - ".c": "text/plain", - ".h": "text/plain", - ".cc": "text/plain", - ".hh": "text/plain", - ".cxx": "text/plain", - ".hxx": "text/plain", - ".f90": "text/plain", - ".conf": "text/plain", - ".log": "text/plain", - ".provn": "text/provenance-notation", - ".rst": "text/prs.fallenstein.rst", - ".tag": "text/prs.lines.tag", - ".dsc": "text/prs.lines.tag", - ".rtx": "text/richtext", - ".sgml": "text/sgml", - ".sgm": "text/sgml", - ".tsv": "text/tab-separated-values", - ".t": "text/troff", - ".tr": "text/troff", - ".roff": "text/troff", - ".ttl": "text/turtle", - ".uris": "text/uri-list", - ".uri": "text/uri-list", - ".vcf": "text/vcard", - ".vcard": "text/vcard", - ".a": "text/vnd.a", - ".abc": "text/vnd.abc", - ".ascii": "text/vnd.ascii-art", - ".copyright": "text/vnd.debian.copyright", - ".dms": "text/vnd.DMClientScript", - ".sub": "text/vnd.dvb.subtitle", - ".jtd": "text/vnd.esmertec.theme-descriptor", - ".fly": "text/vnd.fly", - ".flx": "text/vnd.fmi.flexstor", - ".gv": "text/vnd.graphviz", - ".dot": "text/vnd.graphviz", - ".3dml": "text/vnd.in3d.3dml", - ".3dm": "text/vnd.in3d.3dml", - ".spot": "text/vnd.in3d.spot", - ".spo": "text/vnd.in3d.spot", - ".mpf": "text/vnd.ms-mediapackage", - ".ccc": "text/vnd.net2phone.commcenter.command", - ".uric": "text/vnd.si.uricatalogue", - ".jad": "text/vnd.sun.j2me.app-descriptor", - ".ts": "text/vnd.trolltech.linguist", - ".si": "text/vnd.wap.si", - ".sl": "text/vnd.wap.sl", - ".wml": "text/vnd.wap.wml", - ".wmls": "text/vnd.wap.wmlscript", - ".xml": "text/xml", - ".xsd": "text/xml", - ".rng": "text/xml", - ".ent": "text/xml-external-parsed-entity", - ".3gp": "video/3gpp", - ".3gpp": "video/3gpp", - ".3g2": "video/3gpp2", - ".3gpp2": "video/3gpp2", - ".m4s": "video/iso.segment", - ".mj2": "video/mj2", - ".mjp2": "video/mj2", - ".mp4": "video/mp4", - ".mpg4": "video/mp4", - ".m4v": "video/mp4", - ".mpeg": "video/mpeg", - ".mpg": "video/mpeg", - ".mpe": "video/mpeg", - ".m1v": "video/mpeg", - ".m2v": "video/mpeg", - ".ogv": "video/ogg", - ".mov": "video/quicktime", - ".qt": "video/quicktime", - ".uvh": "video/vnd.dece.hd", - ".uvvh": "video/vnd.dece.hd", - ".uvm": "video/vnd.dece.mobile", - ".uvvm": "video/vnd.dece.mobile", - ".uvu": "video/vnd.dece.mp4", - ".uvvu": "video/vnd.dece.mp4", - ".uvp": "video/vnd.dece.pd", - ".uvvp": "video/vnd.dece.pd", - ".uvs": "video/vnd.dece.sd", - ".uvvs": "video/vnd.dece.sd", - ".uvv": "video/vnd.dece.video", - ".uvvv": "video/vnd.dece.video", - ".dvb": "video/vnd.dvb.file", - ".fvt": "video/vnd.fvt", - ".mxu": "video/vnd.mpegurl", - ".m4u": "video/vnd.mpegurl", - ".pyv": "video/vnd.ms-playready.media.pyv", - ".nim": "video/vnd.nokia.interleaved-multimedia", - ".bik": "video/vnd.radgamettools.bink", - ".bk2": "video/vnd.radgamettools.bink", - ".smk": "video/vnd.radgamettools.smacker", - ".smpg": "video/vnd.sealed.mpeg1", - ".s11": "video/vnd.sealed.mpeg1", - ".s14": "video/vnd.sealed.mpeg4", - ".sswf": "video/vnd.sealed.swf", - ".ssw": "video/vnd.sealed.swf", - ".smov": "video/vnd.sealedmedia.softseal.mov", - ".smo": "video/vnd.sealedmedia.softseal.mov", - ".s1q": "video/vnd.sealedmedia.softseal.mov", - ".viv": "video/vnd.vivo", - ".cpt": "application/mac-compactpro", - ".metalink": "application/metalink+xml", - ".owx": "application/owl+xml", - ".rss": "application/rss+xml", - ".apk": "application/vnd.android.package-archive", - ".dd": "application/vnd.oma.dd+xml", - ".dcf": "application/vnd.oma.drm.content", - ".o4a": "application/vnd.oma.drm.dcf", - ".o4v": "application/vnd.oma.drm.dcf", - ".dm": "application/vnd.oma.drm.message", - ".drc": "application/vnd.oma.drm.rights+wbxml", - ".dr": "application/vnd.oma.drm.rights+xml", - ".sxc": "application/vnd.sun.xml.calc", - ".stc": "application/vnd.sun.xml.calc.template", - ".sxd": "application/vnd.sun.xml.draw", - ".std": "application/vnd.sun.xml.draw.template", - ".sxi": "application/vnd.sun.xml.impress", - ".sti": "application/vnd.sun.xml.impress.template", - ".sxm": "application/vnd.sun.xml.math", - ".sxw": "application/vnd.sun.xml.writer", - ".sxg": "application/vnd.sun.xml.writer.global", - ".stw": "application/vnd.sun.xml.writer.template", - ".sis": "application/vnd.symbian.install", - ".mms": "application/vnd.wap.mms-message", - ".anx": "application/x-annodex", - ".bcpio": "application/x-bcpio", - ".torrent": "application/x-bittorrent", - ".bz2": "application/x-bzip2", - ".vcd": "application/x-cdlink", - ".crx": "application/x-chrome-extension", - ".cpio": "application/x-cpio", - ".csh": "application/x-csh", - ".dcr": "application/x-director", - ".dir": "application/x-director", - ".dxr": "application/x-director", - ".dvi": "application/x-dvi", - ".spl": "application/x-futuresplash", - ".gtar": "application/x-gtar", - ".hdf": "application/x-hdf", - ".jar": "application/x-java-archive", - ".jnlp": "application/x-java-jnlp-file", - ".pack": "application/x-java-pack200", - ".kil": "application/x-killustrator", - ".latex": "application/x-latex", - ".nc": "application/x-netcdf", - ".cdf": "application/x-netcdf", - ".pl": "application/x-perl", - ".rpm": "application/x-rpm", - ".sh": "application/x-sh", - ".shar": "application/x-shar", - ".sit": "application/x-stuffit", - ".sv4cpio": "application/x-sv4cpio", - ".sv4crc": "application/x-sv4crc", - ".tar": "application/x-tar", - ".tcl": "application/x-tcl", - ".tex": "application/x-tex", - ".texinfo": "application/x-texinfo", - ".texi": "application/x-texinfo", - ".man": "application/x-troff-man", - ".1": "application/x-troff-man", - ".2": "application/x-troff-man", - ".3": "application/x-troff-man", - ".4": "application/x-troff-man", - ".5": "application/x-troff-man", - ".6": "application/x-troff-man", - ".7": "application/x-troff-man", - ".8": "application/x-troff-man", - ".me": "application/x-troff-me", - ".ms": "application/x-troff-ms", - ".ustar": "application/x-ustar", - ".src": "application/x-wais-source", - ".xpi": "application/x-xpinstall", - ".xspf": "application/x-xspf+xml", - ".xz": "application/x-xz", - ".mid": "audio/midi", - ".midi": "audio/midi", - ".kar": "audio/midi", - ".aif": "audio/x-aiff", - ".aiff": "audio/x-aiff", - ".aifc": "audio/x-aiff", - ".axa": "audio/x-annodex", - ".flac": "audio/x-flac", - ".mka": "audio/x-matroska", - ".mod": "audio/x-mod", - ".ult": "audio/x-mod", - ".uni": "audio/x-mod", - ".m15": "audio/x-mod", - ".mtm": "audio/x-mod", - ".669": "audio/x-mod", - ".med": "audio/x-mod", - ".m3u": "audio/x-mpegurl", - ".wax": "audio/x-ms-wax", - ".wma": "audio/x-ms-wma", - ".ram": "audio/x-pn-realaudio", - ".rm": "audio/x-pn-realaudio", - ".ra": "audio/x-realaudio", - ".s3m": "audio/x-s3m", - ".stm": "audio/x-stm", - ".wav": "audio/x-wav", - ".xyz": "chemical/x-xyz", - ".webp": "image/webp", - ".ras": "image/x-cmu-raster", - ".pnm": "image/x-portable-anymap", - ".pbm": "image/x-portable-bitmap", - ".pgm": "image/x-portable-graymap", - ".ppm": "image/x-portable-pixmap", - ".rgb": "image/x-rgb", - ".tga": "image/x-targa", - ".xbm": "image/x-xbitmap", - ".xpm": "image/x-xpixmap", - ".xwd": "image/x-xwindowdump", - ".sandboxed": "text/html-sandboxed", - ".pod": "text/x-pod", - ".etx": "text/x-setext", - ".webm": "video/webm", - ".axv": "video/x-annodex", - ".flv": "video/x-flv", - ".fxm": "video/x-javafx", - ".mkv": "video/x-matroska", - ".mk3d": "video/x-matroska-3d", - ".asx": "video/x-ms-asf", - ".wm": "video/x-ms-wm", - ".wmv": "video/x-ms-wmv", - ".wmx": "video/x-ms-wmx", - ".wvx": "video/x-ms-wvx", - ".avi": "video/x-msvideo", - ".movie": "video/x-sgi-movie", - ".ice": "x-conference/x-cooltalk", - ".sisx": "x-epoc/x-sisx-app", - } - for ext, name := range mimeTypes { - if err := mime.AddExtensionType(ext, name); err != nil { - panic(err) - } - } -} diff --git a/swarm/api/http/middleware.go b/swarm/api/http/middleware.go deleted file mode 100644 index e6e263f4c0..0000000000 --- a/swarm/api/http/middleware.go +++ /dev/null @@ -1,162 +0,0 @@ -package http - -import ( - "fmt" - "net/http" - "runtime/debug" - "strings" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/sctx" - "github.com/ethereum/go-ethereum/swarm/spancontext" - "github.com/pborman/uuid" -) - -// Adapt chains h (main request handler) main handler to adapters (middleware handlers) -// Please note that the order of execution for `adapters` is FIFO (adapters[0] will be executed first) -func Adapt(h http.Handler, adapters ...Adapter) http.Handler { - for i := range adapters { - adapter := adapters[len(adapters)-1-i] - h = adapter(h) - } - return h -} - -type Adapter func(http.Handler) http.Handler - -func SetRequestID(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = r.WithContext(SetRUID(r.Context(), uuid.New()[:8])) - metrics.GetOrRegisterCounter(fmt.Sprintf("http.request.%s", r.Method), nil).Inc(1) - log.Info("created ruid for request", "ruid", GetRUID(r.Context()), "method", r.Method, "url", r.RequestURI) - - h.ServeHTTP(w, r) - }) -} - -func SetRequestHost(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = r.WithContext(sctx.SetHost(r.Context(), r.Host)) - log.Info("setting request host", "ruid", GetRUID(r.Context()), "host", sctx.GetHost(r.Context())) - - h.ServeHTTP(w, r) - }) -} - -func ParseURI(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - uri, err := api.Parse(strings.TrimLeft(r.URL.Path, "/")) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - respondError(w, r, fmt.Sprintf("invalid URI %q", r.URL.Path), http.StatusBadRequest) - return - } - if uri.Addr != "" && strings.HasPrefix(uri.Addr, "0x") { - uri.Addr = strings.TrimPrefix(uri.Addr, "0x") - - msg := fmt.Sprintf(`The requested hash seems to be prefixed with '0x'. You will be redirected to the correct URL within 5 seconds.
- Please click here if your browser does not redirect you within 5 seconds.`, "/"+uri.String()) - w.WriteHeader(http.StatusNotFound) - w.Write([]byte(msg)) - return - } - - ctx := r.Context() - r = r.WithContext(SetURI(ctx, uri)) - log.Debug("parsed request path", "ruid", GetRUID(r.Context()), "method", r.Method, "uri.Addr", uri.Addr, "uri.Path", uri.Path, "uri.Scheme", uri.Scheme) - - h.ServeHTTP(w, r) - }) -} - -func InitLoggingResponseWriter(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tn := time.Now() - - writer := newLoggingResponseWriter(w) - h.ServeHTTP(writer, r) - - ts := time.Since(tn) - log.Info("request served", "ruid", GetRUID(r.Context()), "code", writer.statusCode, "time", ts) - metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.time", r.Method), nil).Update(ts) - metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.%d.time", r.Method, writer.statusCode), nil).Update(ts) - }) -} - -// InitUploadTag creates a new tag for an upload to the local HTTP proxy -// if a tag is not named using the SwarmTagHeaderName, a fallback name will be used -// when the Content-Length header is set, an ETA on chunking will be available since the -// number of chunks to be split is known in advance (not including enclosing manifest chunks) -// the tag can later be accessed using the appropriate identifier in the request context -func InitUploadTag(h http.Handler, tags *chunk.Tags) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var ( - tagName string - err error - estimatedTotal int64 = 0 - contentType = r.Header.Get("Content-Type") - headerTag = r.Header.Get(SwarmTagHeaderName) - ) - if headerTag != "" { - tagName = headerTag - log.Trace("got tag name from http header", "tagName", tagName) - } else { - tagName = fmt.Sprintf("unnamed_tag_%d", time.Now().Unix()) - } - - if !strings.Contains(contentType, "multipart") && r.ContentLength > 0 { - log.Trace("calculating tag size", "contentType", contentType, "contentLength", r.ContentLength) - uri := GetURI(r.Context()) - if uri != nil { - log.Debug("got uri from context") - if uri.Addr == "encrypt" { - estimatedTotal = calculateNumberOfChunks(r.ContentLength, true) - } else { - estimatedTotal = calculateNumberOfChunks(r.ContentLength, false) - } - } - } - - log.Trace("creating tag", "tagName", tagName, "estimatedTotal", estimatedTotal) - - t, err := tags.New(tagName, estimatedTotal) - if err != nil { - log.Error("error creating tag", "err", err, "tagName", tagName) - } - - log.Trace("setting tag id to context", "uid", t.Uid) - ctx := sctx.SetTag(r.Context(), t.Uid) - - h.ServeHTTP(w, r.WithContext(ctx)) - }) -} - -func InstrumentOpenTracing(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - uri := GetURI(r.Context()) - if uri == nil || r.Method == "" || (uri != nil && uri.Scheme == "") { - h.ServeHTTP(w, r) // soft fail - return - } - spanName := fmt.Sprintf("http.%s.%s", r.Method, uri.Scheme) - ctx, sp := spancontext.StartSpan(r.Context(), spanName) - - defer sp.Finish() - h.ServeHTTP(w, r.WithContext(ctx)) - }) -} - -func RecoverPanic(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - defer func() { - if err := recover(); err != nil { - log.Error("panic recovery!", "stack trace", string(debug.Stack()), "url", r.URL.String(), "headers", r.Header) - } - }() - h.ServeHTTP(w, r) - }) -} diff --git a/swarm/api/http/response.go b/swarm/api/http/response.go deleted file mode 100644 index c851a3992e..0000000000 --- a/swarm/api/http/response.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package http - -import ( - "encoding/json" - "fmt" - "html/template" - "net/http" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/api" -) - -var ( - htmlCounter = metrics.NewRegisteredCounter("api.http.errorpage.html.count", nil) - jsonCounter = metrics.NewRegisteredCounter("api.http.errorpage.json.count", nil) - plaintextCounter = metrics.NewRegisteredCounter("api.http.errorpage.plaintext.count", nil) -) - -type ResponseParams struct { - Msg template.HTML - Code int - Timestamp string - template *template.Template - Details template.HTML -} - -// ShowMultipleChoices is used when a user requests a resource in a manifest which results -// in ambiguous results. It returns a HTML page with clickable links of each of the entry -// in the manifest which fits the request URI ambiguity. -// For example, if the user requests bzz://read and that manifest contains entries -// "readme.md" and "readinglist.txt", a HTML page is returned with this two links. -// This only applies if the manifest has no default entry -func ShowMultipleChoices(w http.ResponseWriter, r *http.Request, list api.ManifestList) { - log.Debug("ShowMultipleChoices", "ruid", GetRUID(r.Context()), "uri", GetURI(r.Context())) - msg := "" - if list.Entries == nil { - respondError(w, r, "Could not resolve", http.StatusInternalServerError) - return - } - requestUri := strings.TrimPrefix(r.RequestURI, "/") - - uri, err := api.Parse(requestUri) - if err != nil { - respondError(w, r, "Bad Request", http.StatusBadRequest) - } - - uri.Scheme = "bzz-list" - msg += fmt.Sprintf("Disambiguation:
Your request may refer to multiple choices.
Click here if your browser does not redirect you within 5 seconds.
", "/"+uri.String()) - respondTemplate(w, r, "error", msg, http.StatusMultipleChoices) -} - -func respondTemplate(w http.ResponseWriter, r *http.Request, templateName, msg string, code int) { - log.Debug("respondTemplate", "ruid", GetRUID(r.Context()), "uri", GetURI(r.Context())) - respond(w, r, &ResponseParams{ - Code: code, - Msg: template.HTML(msg), - Timestamp: time.Now().Format(time.RFC1123), - template: TemplatesMap[templateName], - }) -} - -func respondError(w http.ResponseWriter, r *http.Request, msg string, code int) { - log.Info("respondError", "ruid", GetRUID(r.Context()), "uri", GetURI(r.Context()), "code", code, "msg", msg) - respondTemplate(w, r, "error", msg, code) -} - -func respond(w http.ResponseWriter, r *http.Request, params *ResponseParams) { - w.WriteHeader(params.Code) - - if params.Code >= 400 { - w.Header().Del("Cache-Control") - w.Header().Del("ETag") - } - - acceptHeader := r.Header.Get("Accept") - // this cannot be in a switch since an Accept header can have multiple values: "Accept: */*, text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8" - if strings.Contains(acceptHeader, "application/json") { - if err := respondJSON(w, r, params); err != nil { - respondError(w, r, "Internal server error", http.StatusInternalServerError) - } - } else if strings.Contains(acceptHeader, "text/html") { - respondHTML(w, r, params) - } else { - respondPlaintext(w, r, params) //returns nice errors for curl - } -} - -func respondHTML(w http.ResponseWriter, r *http.Request, params *ResponseParams) { - htmlCounter.Inc(1) - log.Info("respondHTML", "ruid", GetRUID(r.Context()), "code", params.Code) - err := params.template.Execute(w, params) - if err != nil { - log.Error(err.Error()) - } -} - -func respondJSON(w http.ResponseWriter, r *http.Request, params *ResponseParams) error { - jsonCounter.Inc(1) - log.Info("respondJSON", "ruid", GetRUID(r.Context()), "code", params.Code) - w.Header().Set("Content-Type", "application/json") - return json.NewEncoder(w).Encode(params) -} - -func respondPlaintext(w http.ResponseWriter, r *http.Request, params *ResponseParams) error { - plaintextCounter.Inc(1) - log.Info("respondPlaintext", "ruid", GetRUID(r.Context()), "code", params.Code) - w.Header().Set("Content-Type", "text/plain") - strToWrite := "Code: " + fmt.Sprintf("%d", params.Code) + "\n" - strToWrite += "Message: " + string(params.Msg) + "\n" - strToWrite += "Timestamp: " + params.Timestamp + "\n" - _, err := w.Write([]byte(strToWrite)) - return err -} diff --git a/swarm/api/http/response_test.go b/swarm/api/http/response_test.go deleted file mode 100644 index 486c19ab0e..0000000000 --- a/swarm/api/http/response_test.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package http - -import ( - "encoding/json" - "io/ioutil" - "net/http" - "strings" - "testing" - - "golang.org/x/net/html" -) - -func TestError(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - var resp *http.Response - var respbody []byte - - url := srv.URL + "/this_should_fail_as_no_bzz_protocol_present" - resp, err := http.Get(url) - - if err != nil { - t.Fatalf("Request failed: %v", err) - } - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - - if resp.StatusCode != 404 && !strings.Contains(string(respbody), "Invalid URI "/this_should_fail_as_no_bzz_protocol_present": unknown scheme") { - t.Fatalf("Response body does not match, expected: %v, to contain: %v; received code %d, expected code: %d", string(respbody), "Invalid bzz URI: unknown scheme", 400, resp.StatusCode) - } - - _, err = html.Parse(strings.NewReader(string(respbody))) - if err != nil { - t.Fatalf("HTML validation failed for error page returned!") - } -} - -func Test404Page(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - var resp *http.Response - var respbody []byte - - url := srv.URL + "/bzz:/1234567890123456789012345678901234567890123456789012345678901234" - resp, err := http.Get(url) - - if err != nil { - t.Fatalf("Request failed: %v", err) - } - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - - if resp.StatusCode != 404 || !strings.Contains(string(respbody), "404") { - t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode) - } - - _, err = html.Parse(strings.NewReader(string(respbody))) - if err != nil { - t.Fatalf("HTML validation failed for error page returned!") - } -} - -func Test500Page(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - var resp *http.Response - var respbody []byte - - url := srv.URL + "/bzz:/thisShouldFailWith500Code" - resp, err := http.Get(url) - - if err != nil { - t.Fatalf("Request failed: %v", err) - } - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - - if resp.StatusCode != 404 { - t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode) - } - - _, err = html.Parse(strings.NewReader(string(respbody))) - if err != nil { - t.Fatalf("HTML validation failed for error page returned!") - } -} -func Test500PageWith0xHashPrefix(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - var resp *http.Response - var respbody []byte - - url := srv.URL + "/bzz:/0xthisShouldFailWith500CodeAndAHelpfulMessage" - resp, err := http.Get(url) - - if err != nil { - t.Fatalf("Request failed: %v", err) - } - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - - if resp.StatusCode != 404 { - t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode) - } - - if !strings.Contains(string(respbody), "The requested hash seems to be prefixed with") { - t.Fatalf("Did not receive the expected error message") - } - - _, err = html.Parse(strings.NewReader(string(respbody))) - if err != nil { - t.Fatalf("HTML validation failed for error page returned!") - } -} - -func TestJsonResponse(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - var resp *http.Response - var respbody []byte - - url := srv.URL + "/bzz:/thisShouldFailWith500Code/" - req, err := http.NewRequest("GET", url, nil) - if err != nil { - t.Fatalf("Request failed: %v", err) - } - req.Header.Set("Accept", "application/json") - resp, err = http.DefaultClient.Do(req) - if err != nil { - t.Fatalf("Request failed: %v", err) - } - - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - - if resp.StatusCode != 404 { - t.Fatalf("Invalid Status Code received, expected 404, got %d", resp.StatusCode) - } - - if !isJSON(string(respbody)) { - t.Fatalf("Expected response to be JSON, received invalid JSON: %s", string(respbody)) - } - -} - -func isJSON(s string) bool { - var js map[string]interface{} - return json.Unmarshal([]byte(s), &js) == nil -} diff --git a/swarm/api/http/roundtripper.go b/swarm/api/http/roundtripper.go deleted file mode 100644 index be8ea39856..0000000000 --- a/swarm/api/http/roundtripper.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package http - -import ( - "fmt" - "net/http" - - "github.com/ethereum/go-ethereum/swarm/log" -) - -/* -http roundtripper to register for bzz url scheme -see https://github.com/ethereum/go-ethereum/issues/2040 -Usage: - -import ( - "github.com/ethereum/go-ethereum/common/httpclient" - "github.com/ethereum/go-ethereum/swarm/api/http" -) -client := httpclient.New() -// for (private) swarm proxy running locally -client.RegisterScheme("bzz", &http.RoundTripper{Port: port}) -client.RegisterScheme("bzz-immutable", &http.RoundTripper{Port: port}) -client.RegisterScheme("bzz-raw", &http.RoundTripper{Port: port}) - -The port you give the Roundtripper is the port the swarm proxy is listening on. -If Host is left empty, localhost is assumed. - -Using a public gateway, the above few lines gives you the leanest -bzz-scheme aware read-only http client. You really only ever need this -if you need go-native swarm access to bzz addresses. -*/ - -type RoundTripper struct { - Host string - Port string -} - -func (self *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) { - host := self.Host - if len(host) == 0 { - host = "localhost" - } - url := fmt.Sprintf("http://%s:%s/%s:/%s/%s", host, self.Port, req.Proto, req.URL.Host, req.URL.Path) - log.Info(fmt.Sprintf("roundtripper: proxying request '%s' to '%s'", req.RequestURI, url)) - reqProxy, err := http.NewRequest(req.Method, url, req.Body) - if err != nil { - return nil, err - } - return http.DefaultClient.Do(reqProxy) -} diff --git a/swarm/api/http/roundtripper_test.go b/swarm/api/http/roundtripper_test.go deleted file mode 100644 index f99c4f35e0..0000000000 --- a/swarm/api/http/roundtripper_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package http - -import ( - "io/ioutil" - "net" - "net/http" - "net/http/httptest" - "strings" - "testing" - "time" -) - -func TestRoundTripper(t *testing.T) { - serveMux := http.NewServeMux() - serveMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - if r.Method == "GET" { - w.Header().Set("Content-Type", "text/plain") - http.ServeContent(w, r, "", time.Unix(0, 0), strings.NewReader(r.RequestURI)) - } else { - http.Error(w, "Method "+r.Method+" is not supported.", http.StatusMethodNotAllowed) - } - }) - - srv := httptest.NewServer(serveMux) - defer srv.Close() - - host, port, _ := net.SplitHostPort(srv.Listener.Addr().String()) - rt := &RoundTripper{Host: host, Port: port} - trans := &http.Transport{} - trans.RegisterProtocol("bzz", rt) - client := &http.Client{Transport: trans} - resp, err := client.Get("bzz://test.com/path") - if err != nil { - t.Errorf("expected no error, got %v", err) - return - } - - defer func() { - if resp != nil { - resp.Body.Close() - } - }() - - content, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Errorf("expected no error, got %v", err) - return - } - if string(content) != "/HTTP/1.1:/test.com/path" { - t.Errorf("incorrect response from http server: expected '%v', got '%v'", "/HTTP/1.1:/test.com/path", string(content)) - } - -} diff --git a/swarm/api/http/sctx.go b/swarm/api/http/sctx.go deleted file mode 100644 index b8dafab0b7..0000000000 --- a/swarm/api/http/sctx.go +++ /dev/null @@ -1,34 +0,0 @@ -package http - -import ( - "context" - - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/sctx" -) - -type uriKey struct{} - -func GetRUID(ctx context.Context) string { - v, ok := ctx.Value(sctx.HTTPRequestIDKey{}).(string) - if ok { - return v - } - return "xxxxxxxx" -} - -func SetRUID(ctx context.Context, ruid string) context.Context { - return context.WithValue(ctx, sctx.HTTPRequestIDKey{}, ruid) -} - -func GetURI(ctx context.Context) *api.URI { - v, ok := ctx.Value(uriKey{}).(*api.URI) - if ok { - return v - } - return nil -} - -func SetURI(ctx context.Context, uri *api.URI) context.Context { - return context.WithValue(ctx, uriKey{}, uri) -} diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go deleted file mode 100644 index 88f2e4db9c..0000000000 --- a/swarm/api/http/server.go +++ /dev/null @@ -1,937 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/* -A simple http server interface to Swarm -*/ -package http - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "math" - "mime" - "mime/multipart" - "net/http" - "os" - "path" - "strconv" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/sctx" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/rs/cors" -) - -var ( - postRawCount = metrics.NewRegisteredCounter("api.http.post.raw.count", nil) - postRawFail = metrics.NewRegisteredCounter("api.http.post.raw.fail", nil) - postFilesCount = metrics.NewRegisteredCounter("api.http.post.files.count", nil) - postFilesFail = metrics.NewRegisteredCounter("api.http.post.files.fail", nil) - deleteCount = metrics.NewRegisteredCounter("api.http.delete.count", nil) - deleteFail = metrics.NewRegisteredCounter("api.http.delete.fail", nil) - getCount = metrics.NewRegisteredCounter("api.http.get.count", nil) - getFail = metrics.NewRegisteredCounter("api.http.get.fail", nil) - getFileCount = metrics.NewRegisteredCounter("api.http.get.file.count", nil) - getFileNotFound = metrics.NewRegisteredCounter("api.http.get.file.notfound", nil) - getFileFail = metrics.NewRegisteredCounter("api.http.get.file.fail", nil) - getListCount = metrics.NewRegisteredCounter("api.http.get.list.count", nil) - getListFail = metrics.NewRegisteredCounter("api.http.get.list.fail", nil) -) - -const SwarmTagHeaderName = "x-swarm-tag" - -type methodHandler map[string]http.Handler - -func (m methodHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { - v, ok := m[r.Method] - if ok { - v.ServeHTTP(rw, r) - return - } - rw.WriteHeader(http.StatusMethodNotAllowed) -} - -func NewServer(api *api.API, corsString string) *Server { - var allowedOrigins []string - for _, domain := range strings.Split(corsString, ",") { - allowedOrigins = append(allowedOrigins, strings.TrimSpace(domain)) - } - c := cors.New(cors.Options{ - AllowedOrigins: allowedOrigins, - AllowedMethods: []string{http.MethodPost, http.MethodGet, http.MethodDelete, http.MethodPatch, http.MethodPut}, - MaxAge: 600, - AllowedHeaders: []string{"*"}, - }) - - server := &Server{api: api} - - defaultMiddlewares := []Adapter{ - RecoverPanic, - SetRequestID, - SetRequestHost, - InitLoggingResponseWriter, - ParseURI, - InstrumentOpenTracing, - } - - tagAdapter := Adapter(func(h http.Handler) http.Handler { - return InitUploadTag(h, api.Tags) - }) - - defaultPostMiddlewares := append(defaultMiddlewares, tagAdapter) - - mux := http.NewServeMux() - mux.Handle("/bzz:/", methodHandler{ - "GET": Adapt( - http.HandlerFunc(server.HandleBzzGet), - defaultMiddlewares..., - ), - "POST": Adapt( - http.HandlerFunc(server.HandlePostFiles), - defaultPostMiddlewares..., - ), - "DELETE": Adapt( - http.HandlerFunc(server.HandleDelete), - defaultMiddlewares..., - ), - }) - mux.Handle("/bzz-raw:/", methodHandler{ - "GET": Adapt( - http.HandlerFunc(server.HandleGet), - defaultMiddlewares..., - ), - "POST": Adapt( - http.HandlerFunc(server.HandlePostRaw), - defaultPostMiddlewares..., - ), - }) - mux.Handle("/bzz-immutable:/", methodHandler{ - "GET": Adapt( - http.HandlerFunc(server.HandleBzzGet), - defaultMiddlewares..., - ), - }) - mux.Handle("/bzz-hash:/", methodHandler{ - "GET": Adapt( - http.HandlerFunc(server.HandleGet), - defaultMiddlewares..., - ), - }) - mux.Handle("/bzz-list:/", methodHandler{ - "GET": Adapt( - http.HandlerFunc(server.HandleGetList), - defaultMiddlewares..., - ), - }) - mux.Handle("/bzz-feed:/", methodHandler{ - "GET": Adapt( - http.HandlerFunc(server.HandleGetFeed), - defaultMiddlewares..., - ), - "POST": Adapt( - http.HandlerFunc(server.HandlePostFeed), - defaultMiddlewares..., - ), - }) - - mux.Handle("/", methodHandler{ - "GET": Adapt( - http.HandlerFunc(server.HandleRootPaths), - SetRequestID, - InitLoggingResponseWriter, - ), - }) - server.Handler = c.Handler(mux) - - return server -} - -func (s *Server) ListenAndServe(addr string) error { - s.listenAddr = addr - return http.ListenAndServe(addr, s) -} - -// browser API for registering bzz url scheme handlers: -// https://developer.mozilla.org/en/docs/Web-based_protocol_handlers -// electron (chromium) api for registering bzz url scheme handlers: -// https://github.com/atom/electron/blob/master/docs/api/protocol.md -type Server struct { - http.Handler - api *api.API - listenAddr string -} - -func (s *Server) HandleBzzGet(w http.ResponseWriter, r *http.Request) { - log.Debug("handleBzzGet", "ruid", GetRUID(r.Context()), "uri", r.RequestURI) - if r.Header.Get("Accept") == "application/x-tar" { - uri := GetURI(r.Context()) - _, credentials, _ := r.BasicAuth() - reader, err := s.api.GetDirectoryTar(r.Context(), s.api.Decryptor(r.Context(), credentials), uri) - if err != nil { - if isDecryptError(err) { - w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", uri.Address().String())) - respondError(w, r, err.Error(), http.StatusUnauthorized) - return - } - respondError(w, r, fmt.Sprintf("Had an error building the tarball: %v", err), http.StatusInternalServerError) - return - } - defer reader.Close() - - w.Header().Set("Content-Type", "application/x-tar") - - fileName := uri.Addr - if found := path.Base(uri.Path); found != "" && found != "." && found != "/" { - fileName = found - } - w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s.tar\"", fileName)) - - w.WriteHeader(http.StatusOK) - io.Copy(w, reader) - return - } - - s.HandleGetFile(w, r) -} - -func (s *Server) HandleRootPaths(w http.ResponseWriter, r *http.Request) { - switch r.RequestURI { - case "/": - respondTemplate(w, r, "landing-page", "Swarm: Please request a valid ENS or swarm hash with the appropriate bzz scheme", 200) - return - case "/robots.txt": - w.Header().Set("Last-Modified", time.Now().Format(http.TimeFormat)) - fmt.Fprintf(w, "User-agent: *\nDisallow: /") - case "/favicon.ico": - w.WriteHeader(http.StatusOK) - w.Write(faviconBytes) - default: - respondError(w, r, "Not Found", http.StatusNotFound) - } -} - -// HandlePostRaw handles a POST request to a raw bzz-raw:/ URI, stores the request -// body in swarm and returns the resulting storage address as a text/plain response -func (s *Server) HandlePostRaw(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - log.Debug("handle.post.raw", "ruid", ruid) - - tagUid := sctx.GetTag(r.Context()) - tag, err := s.api.Tags.Get(tagUid) - if err != nil { - log.Error("handle post raw got an error retrieving tag for DoneSplit", "tagUid", tagUid, "err", err) - } - - postRawCount.Inc(1) - - toEncrypt := false - uri := GetURI(r.Context()) - if uri.Addr == "encrypt" { - toEncrypt = true - } - - if uri.Path != "" { - postRawFail.Inc(1) - respondError(w, r, "raw POST request cannot contain a path", http.StatusBadRequest) - return - } - - if uri.Addr != "" && uri.Addr != "encrypt" { - postRawFail.Inc(1) - respondError(w, r, "raw POST request addr can only be empty or \"encrypt\"", http.StatusBadRequest) - return - } - - if r.Header.Get("Content-Length") == "" { - postRawFail.Inc(1) - respondError(w, r, "missing Content-Length header in request", http.StatusBadRequest) - return - } - - addr, wait, err := s.api.Store(r.Context(), r.Body, r.ContentLength, toEncrypt) - if err != nil { - postRawFail.Inc(1) - respondError(w, r, err.Error(), http.StatusInternalServerError) - return - } - - wait(r.Context()) - tag.DoneSplit(addr) - - log.Debug("stored content", "ruid", ruid, "key", addr) - - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - fmt.Fprint(w, addr) -} - -// HandlePostFiles handles a POST request to -// bzz:// which contains either a single file or multiple files -// (either a tar archive or multipart form), adds those files either to an -// existing manifest or to a new manifest under and returns the -// resulting manifest hash as a text/plain response -func (s *Server) HandlePostFiles(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - log.Debug("handle.post.files", "ruid", ruid) - postFilesCount.Inc(1) - - contentType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")) - if err != nil { - postFilesFail.Inc(1) - respondError(w, r, err.Error(), http.StatusBadRequest) - return - } - - toEncrypt := false - uri := GetURI(r.Context()) - if uri.Addr == "encrypt" { - toEncrypt = true - } - - var addr storage.Address - if uri.Addr != "" && uri.Addr != "encrypt" { - addr, err = s.api.Resolve(r.Context(), uri.Addr) - if err != nil { - postFilesFail.Inc(1) - respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusInternalServerError) - return - } - log.Debug("resolved key", "ruid", ruid, "key", addr) - } else { - addr, err = s.api.NewManifest(r.Context(), toEncrypt) - if err != nil { - postFilesFail.Inc(1) - respondError(w, r, err.Error(), http.StatusInternalServerError) - return - } - log.Debug("new manifest", "ruid", ruid, "key", addr) - } - newAddr, err := s.api.UpdateManifest(r.Context(), addr, func(mw *api.ManifestWriter) error { - switch contentType { - case "application/x-tar": - _, err := s.handleTarUpload(r, mw) - if err != nil { - respondError(w, r, fmt.Sprintf("error uploading tarball: %v", err), http.StatusInternalServerError) - return err - } - return nil - case "multipart/form-data": - return s.handleMultipartUpload(r, params["boundary"], mw) - - default: - return s.handleDirectUpload(r, mw) - } - }) - if err != nil { - postFilesFail.Inc(1) - respondError(w, r, fmt.Sprintf("cannot create manifest: %s", err), http.StatusInternalServerError) - return - } - - tagUid := sctx.GetTag(r.Context()) - tag, err := s.api.Tags.Get(tagUid) - if err != nil { - log.Error("got an error retrieving tag for DoneSplit", "tagUid", tagUid, "err", err) - } - - log.Debug("done splitting, setting tag total", "SPLIT", tag.Get(chunk.StateSplit), "TOTAL", tag.Total()) - tag.DoneSplit(newAddr) - - log.Debug("stored content", "ruid", ruid, "key", newAddr) - - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - fmt.Fprint(w, newAddr) -} - -func (s *Server) handleTarUpload(r *http.Request, mw *api.ManifestWriter) (storage.Address, error) { - log.Debug("handle.tar.upload", "ruid", GetRUID(r.Context()), "tag", sctx.GetTag(r.Context())) - - defaultPath := r.URL.Query().Get("defaultpath") - - key, err := s.api.UploadTar(r.Context(), r.Body, GetURI(r.Context()).Path, defaultPath, mw) - if err != nil { - return nil, err - } - return key, nil -} - -func (s *Server) handleMultipartUpload(r *http.Request, boundary string, mw *api.ManifestWriter) error { - ruid := GetRUID(r.Context()) - log.Debug("handle.multipart.upload", "ruid", ruid) - mr := multipart.NewReader(r.Body, boundary) - for { - part, err := mr.NextPart() - if err == io.EOF { - return nil - } else if err != nil { - return fmt.Errorf("error reading multipart form: %s", err) - } - - var size int64 - var reader io.Reader - if contentLength := part.Header.Get("Content-Length"); contentLength != "" { - size, err = strconv.ParseInt(contentLength, 10, 64) - if err != nil { - return fmt.Errorf("error parsing multipart content length: %s", err) - } - reader = part - } else { - // copy the part to a tmp file to get its size - tmp, err := ioutil.TempFile("", "swarm-multipart") - if err != nil { - return err - } - defer os.Remove(tmp.Name()) - defer tmp.Close() - size, err = io.Copy(tmp, part) - if err != nil { - return fmt.Errorf("error copying multipart content: %s", err) - } - if _, err := tmp.Seek(0, io.SeekStart); err != nil { - return fmt.Errorf("error copying multipart content: %s", err) - } - reader = tmp - } - - // add the entry under the path from the request - name := part.FileName() - if name == "" { - name = part.FormName() - } - uri := GetURI(r.Context()) - path := path.Join(uri.Path, name) - entry := &api.ManifestEntry{ - Path: path, - ContentType: part.Header.Get("Content-Type"), - Size: size, - } - log.Debug("adding path to new manifest", "ruid", ruid, "bytes", entry.Size, "path", entry.Path) - contentKey, err := mw.AddEntry(r.Context(), reader, entry) - if err != nil { - return fmt.Errorf("error adding manifest entry from multipart form: %s", err) - } - log.Debug("stored content", "ruid", ruid, "key", contentKey) - } -} - -func (s *Server) handleDirectUpload(r *http.Request, mw *api.ManifestWriter) error { - ruid := GetRUID(r.Context()) - log.Debug("handle.direct.upload", "ruid", ruid) - key, err := mw.AddEntry(r.Context(), r.Body, &api.ManifestEntry{ - Path: GetURI(r.Context()).Path, - ContentType: r.Header.Get("Content-Type"), - Mode: 0644, - Size: r.ContentLength, - }) - if err != nil { - return err - } - log.Debug("stored content", "ruid", ruid, "key", key) - return nil -} - -// HandleDelete handles a DELETE request to bzz://, removes -// from and returns the resulting manifest hash as a -// text/plain response -func (s *Server) HandleDelete(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - uri := GetURI(r.Context()) - log.Debug("handle.delete", "ruid", ruid) - deleteCount.Inc(1) - newKey, err := s.api.Delete(r.Context(), uri.Addr, uri.Path) - if err != nil { - deleteFail.Inc(1) - respondError(w, r, fmt.Sprintf("could not delete from manifest: %v", err), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - fmt.Fprint(w, newKey) -} - -// Handles feed manifest creation and feed updates -// The POST request admits a JSON structure as defined in the feeds package: `feed.updateRequestJSON` -// The requests can be to a) create a feed manifest, b) update a feed or c) both a+b: create a feed manifest and publish a first update -func (s *Server) HandlePostFeed(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - uri := GetURI(r.Context()) - log.Debug("handle.post.feed", "ruid", ruid) - var err error - - // Creation and update must send feed.updateRequestJSON JSON structure - body, err := ioutil.ReadAll(r.Body) - if err != nil { - respondError(w, r, err.Error(), http.StatusInternalServerError) - return - } - - fd, err := s.api.ResolveFeed(r.Context(), uri, r.URL.Query()) - if err != nil { // couldn't parse query string or retrieve manifest - getFail.Inc(1) - httpStatus := http.StatusBadRequest - if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI { - httpStatus = http.StatusNotFound - } - respondError(w, r, fmt.Sprintf("cannot retrieve feed from manifest: %s", err), httpStatus) - return - } - - var updateRequest feed.Request - updateRequest.Feed = *fd - query := r.URL.Query() - - if err := updateRequest.FromValues(query, body); err != nil { // decodes request from query parameters - respondError(w, r, err.Error(), http.StatusBadRequest) - return - } - - switch { - case updateRequest.IsUpdate(): - // Verify that the signature is intact and that the signer is authorized - // to update this feed - // Check this early, to avoid creating a feed and then not being able to set its first update. - if err = updateRequest.Verify(); err != nil { - respondError(w, r, err.Error(), http.StatusForbidden) - return - } - _, err = s.api.FeedsUpdate(r.Context(), &updateRequest) - if err != nil { - respondError(w, r, err.Error(), http.StatusInternalServerError) - return - } - fallthrough - case query.Get("manifest") == "1": - // we create a manifest so we can retrieve feed updates with bzz:// later - // this manifest has a special "feed type" manifest, and saves the - // feed identification used to retrieve feed updates later - m, err := s.api.NewFeedManifest(r.Context(), &updateRequest.Feed) - if err != nil { - respondError(w, r, fmt.Sprintf("failed to create feed manifest: %v", err), http.StatusInternalServerError) - return - } - // the key to the manifest will be passed back to the client - // the client can access the feed directly through its Feed member - // the manifest key can be set as content in the resolver of the ENS name - outdata, err := json.Marshal(m) - if err != nil { - respondError(w, r, fmt.Sprintf("failed to create json response: %s", err), http.StatusInternalServerError) - return - } - fmt.Fprint(w, string(outdata)) - - w.Header().Add("Content-type", "application/json") - default: - respondError(w, r, "Missing signature in feed update request", http.StatusBadRequest) - } -} - -// HandleGetFeed retrieves Swarm feeds updates: -// bzz-feed:// - get latest feed update, given a manifest address -// - or - -// specify user + topic (optional), subtopic name (optional) directly, without manifest: -// bzz-feed://?user=0x...&topic=0x...&name=subtopic name -// topic defaults to 0x000... if not specified. -// name defaults to empty string if not specified. -// thus, empty name and topic refers to the user's default feed. -// -// Optional parameters: -// time=xx - get the latest update before time (in epoch seconds) -// hint.time=xx - hint the lookup algorithm looking for updates at around that time -// hint.level=xx - hint the lookup algorithm looking for updates at around this frequency level -// meta=1 - get feed metadata and status information instead of performing a feed query -// NOTE: meta=1 will be deprecated in the near future -func (s *Server) HandleGetFeed(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - uri := GetURI(r.Context()) - log.Debug("handle.get.feed", "ruid", ruid) - var err error - - fd, err := s.api.ResolveFeed(r.Context(), uri, r.URL.Query()) - if err != nil { // couldn't parse query string or retrieve manifest - getFail.Inc(1) - httpStatus := http.StatusBadRequest - if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI { - httpStatus = http.StatusNotFound - } - respondError(w, r, fmt.Sprintf("cannot retrieve feed information from manifest: %s", err), httpStatus) - return - } - - // determine if the query specifies period and version or it is a metadata query - if r.URL.Query().Get("meta") == "1" { - unsignedUpdateRequest, err := s.api.FeedsNewRequest(r.Context(), fd) - if err != nil { - getFail.Inc(1) - respondError(w, r, fmt.Sprintf("cannot retrieve feed metadata for feed=%s: %s", fd.Hex(), err), http.StatusNotFound) - return - } - rawResponse, err := unsignedUpdateRequest.MarshalJSON() - if err != nil { - respondError(w, r, fmt.Sprintf("cannot encode unsigned feed update request: %v", err), http.StatusInternalServerError) - return - } - w.Header().Add("Content-type", "application/json") - w.WriteHeader(http.StatusOK) - fmt.Fprint(w, string(rawResponse)) - return - } - - lookupParams := &feed.Query{Feed: *fd} - if err = lookupParams.FromValues(r.URL.Query()); err != nil { // parse period, version - respondError(w, r, fmt.Sprintf("invalid feed update request:%s", err), http.StatusBadRequest) - return - } - - data, err := s.api.FeedsLookup(r.Context(), lookupParams) - - // any error from the switch statement will end up here - if err != nil { - code, err2 := s.translateFeedError(w, r, "feed lookup fail", err) - respondError(w, r, err2.Error(), code) - return - } - - // All ok, serve the retrieved update - log.Debug("Found update", "feed", fd.Hex(), "ruid", ruid) - w.Header().Set("Content-Type", api.MimeOctetStream) - http.ServeContent(w, r, "", time.Now(), bytes.NewReader(data)) -} - -func (s *Server) translateFeedError(w http.ResponseWriter, r *http.Request, supErr string, err error) (int, error) { - code := 0 - defaultErr := fmt.Errorf("%s: %v", supErr, err) - rsrcErr, ok := err.(*feed.Error) - if !ok && rsrcErr != nil { - code = rsrcErr.Code() - } - switch code { - case storage.ErrInvalidValue: - return http.StatusBadRequest, defaultErr - case storage.ErrNotFound, storage.ErrNotSynced, storage.ErrNothingToReturn, storage.ErrInit: - return http.StatusNotFound, defaultErr - case storage.ErrUnauthorized, storage.ErrInvalidSignature: - return http.StatusUnauthorized, defaultErr - case storage.ErrDataOverflow: - return http.StatusRequestEntityTooLarge, defaultErr - } - - return http.StatusInternalServerError, defaultErr -} - -// HandleGet handles a GET request to -// - bzz-raw:// and responds with the raw content stored at the -// given storage key -// - bzz-hash:// and responds with the hash of the content stored -// at the given storage key as a text/plain response -func (s *Server) HandleGet(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - uri := GetURI(r.Context()) - log.Debug("handle.get", "ruid", ruid, "uri", uri) - getCount.Inc(1) - _, pass, _ := r.BasicAuth() - - addr, err := s.api.ResolveURI(r.Context(), uri, pass) - if err != nil { - getFail.Inc(1) - respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusNotFound) - return - } - w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz:///path, so we are sure it is immutable. - - log.Debug("handle.get: resolved", "ruid", ruid, "key", addr) - - // if path is set, interpret as a manifest and return the - // raw entry at the given path - etag := common.Bytes2Hex(addr) - noneMatchEtag := r.Header.Get("If-None-Match") - w.Header().Set("ETag", fmt.Sprintf("%q", etag)) // set etag to manifest key or raw entry key. - if noneMatchEtag != "" { - if bytes.Equal(storage.Address(common.Hex2Bytes(noneMatchEtag)), addr) { - w.WriteHeader(http.StatusNotModified) - return - } - } - - switch { - case uri.Raw(): - // check the root chunk exists by retrieving the file's size - reader, isEncrypted := s.api.Retrieve(r.Context(), addr) - if _, err := reader.Size(r.Context(), nil); err != nil { - getFail.Inc(1) - respondError(w, r, fmt.Sprintf("root chunk not found %s: %s", addr, err), http.StatusNotFound) - return - } - - w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted)) - - // allow the request to overwrite the content type using a query - // parameter - if typ := r.URL.Query().Get("content_type"); typ != "" { - w.Header().Set("Content-Type", typ) - } - http.ServeContent(w, r, "", time.Now(), reader) - case uri.Hash(): - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - fmt.Fprint(w, addr) - } - -} - -// HandleGetList handles a GET request to bzz-list:// and returns -// a list of all files contained in under grouped into -// common prefixes using "/" as a delimiter -func (s *Server) HandleGetList(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - uri := GetURI(r.Context()) - _, credentials, _ := r.BasicAuth() - log.Debug("handle.get.list", "ruid", ruid, "uri", uri) - getListCount.Inc(1) - - // ensure the root path has a trailing slash so that relative URLs work - if uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, r, r.URL.Path+"/", http.StatusMovedPermanently) - return - } - - addr, err := s.api.Resolve(r.Context(), uri.Addr) - if err != nil { - getListFail.Inc(1) - respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusNotFound) - return - } - log.Debug("handle.get.list: resolved", "ruid", ruid, "key", addr) - - list, err := s.api.GetManifestList(r.Context(), s.api.Decryptor(r.Context(), credentials), addr, uri.Path) - if err != nil { - getListFail.Inc(1) - if isDecryptError(err) { - w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", addr.String())) - respondError(w, r, err.Error(), http.StatusUnauthorized) - return - } - respondError(w, r, err.Error(), http.StatusInternalServerError) - return - } - - // if the client wants HTML (e.g. a browser) then render the list as a - // HTML index with relative URLs - if strings.Contains(r.Header.Get("Accept"), "text/html") { - w.Header().Set("Content-Type", "text/html") - err := TemplatesMap["bzz-list"].Execute(w, &htmlListData{ - URI: &api.URI{ - Scheme: "bzz", - Addr: uri.Addr, - Path: uri.Path, - }, - List: &list, - }) - if err != nil { - getListFail.Inc(1) - log.Error(fmt.Sprintf("error rendering list HTML: %s", err)) - } - return - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(&list) -} - -// HandleGetFile handles a GET request to bzz:/// and responds -// with the content of the file at from the given -func (s *Server) HandleGetFile(w http.ResponseWriter, r *http.Request) { - ruid := GetRUID(r.Context()) - uri := GetURI(r.Context()) - _, credentials, _ := r.BasicAuth() - log.Debug("handle.get.file", "ruid", ruid, "uri", r.RequestURI) - getFileCount.Inc(1) - - // ensure the root path has a trailing slash so that relative URLs work - if uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, r, r.URL.Path+"/", http.StatusMovedPermanently) - return - } - var err error - manifestAddr := uri.Address() - - if manifestAddr == nil { - manifestAddr, err = s.api.Resolve(r.Context(), uri.Addr) - if err != nil { - getFileFail.Inc(1) - respondError(w, r, fmt.Sprintf("cannot resolve %s: %s", uri.Addr, err), http.StatusNotFound) - return - } - } else { - w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz:///path, so we are sure it is immutable. - } - - log.Debug("handle.get.file: resolved", "ruid", ruid, "key", manifestAddr) - - reader, contentType, status, contentKey, err := s.api.Get(r.Context(), s.api.Decryptor(r.Context(), credentials), manifestAddr, uri.Path) - - etag := common.Bytes2Hex(contentKey) - noneMatchEtag := r.Header.Get("If-None-Match") - w.Header().Set("ETag", fmt.Sprintf("%q", etag)) // set etag to actual content key. - if noneMatchEtag != "" { - if bytes.Equal(storage.Address(common.Hex2Bytes(noneMatchEtag)), contentKey) { - w.WriteHeader(http.StatusNotModified) - return - } - } - - if err != nil { - if isDecryptError(err) { - w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", manifestAddr)) - respondError(w, r, err.Error(), http.StatusUnauthorized) - return - } - - switch status { - case http.StatusNotFound: - getFileNotFound.Inc(1) - respondError(w, r, err.Error(), http.StatusNotFound) - default: - getFileFail.Inc(1) - respondError(w, r, err.Error(), http.StatusInternalServerError) - } - return - } - - //the request results in ambiguous files - //e.g. /read with readme.md and readinglist.txt available in manifest - if status == http.StatusMultipleChoices { - list, err := s.api.GetManifestList(r.Context(), s.api.Decryptor(r.Context(), credentials), manifestAddr, uri.Path) - if err != nil { - getFileFail.Inc(1) - if isDecryptError(err) { - w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", manifestAddr)) - respondError(w, r, err.Error(), http.StatusUnauthorized) - return - } - respondError(w, r, err.Error(), http.StatusInternalServerError) - return - } - - log.Debug(fmt.Sprintf("Multiple choices! --> %v", list), "ruid", ruid) - //show a nice page links to available entries - ShowMultipleChoices(w, r, list) - return - } - - // check the root chunk exists by retrieving the file's size - if _, err := reader.Size(r.Context(), nil); err != nil { - getFileNotFound.Inc(1) - respondError(w, r, fmt.Sprintf("file not found %s: %s", uri, err), http.StatusNotFound) - return - } - - if contentType != "" { - w.Header().Set("Content-Type", contentType) - } - - fileName := uri.Addr - if found := path.Base(uri.Path); found != "" && found != "." && found != "/" { - fileName = found - } - w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", fileName)) - - http.ServeContent(w, r, fileName, time.Now(), newBufferedReadSeeker(reader, getFileBufferSize)) -} - -// calculateNumberOfChunks calculates the number of chunks in an arbitrary content length -func calculateNumberOfChunks(contentLength int64, isEncrypted bool) int64 { - if contentLength < 4096 { - return 1 - } - branchingFactor := 128 - if isEncrypted { - branchingFactor = 64 - } - - dataChunks := math.Ceil(float64(contentLength) / float64(4096)) - totalChunks := dataChunks - intermediate := dataChunks / float64(branchingFactor) - - for intermediate > 1 { - totalChunks += math.Ceil(intermediate) - intermediate = intermediate / float64(branchingFactor) - } - - return int64(totalChunks) + 1 -} - -// The size of buffer used for bufio.Reader on LazyChunkReader passed to -// http.ServeContent in HandleGetFile. -// Warning: This value influences the number of chunk requests and chunker join goroutines -// per file request. -// Recommended value is 4 times the io.Copy default buffer value which is 32kB. -const getFileBufferSize = 4 * 32 * 1024 - -// bufferedReadSeeker wraps bufio.Reader to expose Seek method -// from the provied io.ReadSeeker in newBufferedReadSeeker. -type bufferedReadSeeker struct { - r io.Reader - s io.Seeker -} - -// newBufferedReadSeeker creates a new instance of bufferedReadSeeker, -// out of io.ReadSeeker. Argument `size` is the size of the read buffer. -func newBufferedReadSeeker(readSeeker io.ReadSeeker, size int) bufferedReadSeeker { - return bufferedReadSeeker{ - r: bufio.NewReaderSize(readSeeker, size), - s: readSeeker, - } -} - -func (b bufferedReadSeeker) Read(p []byte) (n int, err error) { - return b.r.Read(p) -} - -func (b bufferedReadSeeker) Seek(offset int64, whence int) (int64, error) { - return b.s.Seek(offset, whence) -} - -type loggingResponseWriter struct { - http.ResponseWriter - statusCode int -} - -func newLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter { - return &loggingResponseWriter{w, http.StatusOK} -} - -func (lrw *loggingResponseWriter) WriteHeader(code int) { - lrw.statusCode = code - lrw.ResponseWriter.WriteHeader(code) -} - -func isDecryptError(err error) bool { - return strings.Contains(err.Error(), api.ErrDecrypt.Error()) -} diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go deleted file mode 100644 index 9df820ce4b..0000000000 --- a/swarm/api/http/server_test.go +++ /dev/null @@ -1,1409 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package http - -import ( - "archive/tar" - "bytes" - "context" - "encoding/json" - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "math/big" - "mime/multipart" - "net/http" - "net/url" - "os" - "path" - "strconv" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -func init() { - loglevel := flag.Int("loglevel", 2, "loglevel") - flag.Parse() - log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) -} - -func serverFunc(api *api.API) TestServer { - return NewServer(api, "") -} - -func newTestSigner() (*feed.GenericSigner, error) { - privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") - if err != nil { - return nil, err - } - return feed.NewGenericSigner(privKey), nil -} - -// Test the transparent resolving of feed updates with bzz:// scheme -// -// First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update. -// This effectively uses a feed to store a pointer to content rather than the content itself -// Retrieving the update with the Swarm hash should return the manifest pointing directly to the data -// and raw retrieve of that hash should return the data -func TestBzzWithFeed(t *testing.T) { - - signer, _ := newTestSigner() - - // Initialize Swarm test server - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - // put together some data for our test: - dataBytes := []byte(` - // - // Create some data our manifest will point to. Data that could be very big and wouldn't fit in a feed update. - // So what we are going to do is upload it to Swarm bzz:// and obtain a **manifest hash** pointing to it: - // - // MANIFEST HASH --> DATA - // - // Then, we store that **manifest hash** into a Swarm Feed update. Once we have done this, - // we can use the **feed manifest hash** in bzz:// instead, this way: bzz://feed-manifest-hash. - // - // FEED MANIFEST HASH --> MANIFEST HASH --> DATA - // - // Given that we can update the feed at any time with a new **manifest hash** but the **feed manifest hash** - // stays constant, we have effectively created a fixed address to changing content. (Applause) - // - // FEED MANIFEST HASH (the same) --> MANIFEST HASH(2) --> DATA(2) ... - // - `) - - // POST data to bzz and get back a content-addressed **manifest hash** pointing to it. - resp, err := http.Post(fmt.Sprintf("%s/bzz:/", srv.URL), "text/plain", bytes.NewReader([]byte(dataBytes))) - if err != nil { - t.Fatal(err) - } - - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - manifestAddressHex, err := ioutil.ReadAll(resp.Body) - - if err != nil { - t.Fatal(err) - } - - manifestAddress := common.FromHex(string(manifestAddressHex)) - - log.Info("added data", "manifest", string(manifestAddressHex)) - - // At this point we have uploaded the data and have a manifest pointing to it - // Now store that manifest address in a feed update. - // We also want a feed manifest, so we can use it to refer to the feed. - - // First, create a topic for our feed: - topic, _ := feed.NewTopic("interesting topic indeed", nil) - - // Create a feed update request: - updateRequest := feed.NewFirstRequest(topic) - - // Store the **manifest address** as data into the feed update. - updateRequest.SetData(manifestAddress) - - // Sign the update - if err := updateRequest.Sign(signer); err != nil { - t.Fatal(err) - } - log.Info("added data", "data", common.ToHex(manifestAddress)) - - // Build the feed update http request: - feedUpdateURL, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) - if err != nil { - t.Fatal(err) - } - query := feedUpdateURL.Query() - body := updateRequest.AppendValues(query) // this adds all query parameters and returns the data to be posted - query.Set("manifest", "1") // indicate we want a feed manifest back - feedUpdateURL.RawQuery = query.Encode() - - // submit the feed update request to Swarm - resp, err = http.Post(feedUpdateURL.String(), "application/octet-stream", bytes.NewReader(body)) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - - feedManifestAddressHex, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - feedManifestAddress := &storage.Address{} - err = json.Unmarshal(feedManifestAddressHex, feedManifestAddress) - if err != nil { - t.Fatalf("data %s could not be unmarshaled: %v", feedManifestAddressHex, err) - } - - correctManifestAddrHex := "747c402e5b9dc715a25a4393147512167bab018a007fad7cdcd9adc7fce1ced2" - if feedManifestAddress.Hex() != correctManifestAddrHex { - t.Fatalf("Response feed manifest address mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestAddress.Hex()) - } - - // get bzz manifest transparent feed update resolve - getBzzURL := fmt.Sprintf("%s/bzz:/%s", srv.URL, feedManifestAddress) - resp, err = http.Get(getBzzURL) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - retrievedData, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(retrievedData, []byte(dataBytes)) { - t.Fatalf("retrieved data mismatch, expected %x, got %x", dataBytes, retrievedData) - } -} - -// Test Swarm feeds using the raw update methods -func TestBzzFeed(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - signer, _ := newTestSigner() - - defer srv.Close() - - // data of update 1 - update1Data := testutil.RandomBytes(1, 666) - update1Timestamp := srv.CurrentTime - //data for update 2 - update2Data := []byte("foo") - - topic, _ := feed.NewTopic("foo.eth", nil) - updateRequest := feed.NewFirstRequest(topic) - updateRequest.SetData(update1Data) - - if err := updateRequest.Sign(signer); err != nil { - t.Fatal(err) - } - - // creates feed and sets update 1 - testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) - if err != nil { - t.Fatal(err) - } - urlQuery := testUrl.Query() - body := updateRequest.AppendValues(urlQuery) // this adds all query parameters - urlQuery.Set("manifest", "1") // indicate we want a manifest back - testUrl.RawQuery = urlQuery.Encode() - - resp, err := http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - rsrcResp := &storage.Address{} - err = json.Unmarshal(b, rsrcResp) - if err != nil { - t.Fatalf("data %s could not be unmarshaled: %v", b, err) - } - - correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" - if rsrcResp.Hex() != correctManifestAddrHex { - t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex()) - } - - // get the manifest - testRawUrl := fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, rsrcResp) - resp, err = http.Get(testRawUrl) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - b, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - manifest := &api.Manifest{} - err = json.Unmarshal(b, manifest) - if err != nil { - t.Fatal(err) - } - if len(manifest.Entries) != 1 { - t.Fatalf("Manifest has %d entries", len(manifest.Entries)) - } - correctFeedHex := "0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d" - if manifest.Entries[0].Feed.Hex() != correctFeedHex { - t.Fatalf("Expected manifest Feed '%s', got '%s'", correctFeedHex, manifest.Entries[0].Feed.Hex()) - } - - // take the chance to have bzz: crash on resolving a feed update that does not contain - // a swarm hash: - testBzzUrl := fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp) - resp, err = http.Get(testBzzUrl) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode == http.StatusOK { - t.Fatal("Expected error status since feed update does not contain a Swarm hash. Received 200 OK") - } - _, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - - // get non-existent name, should fail - testBzzResUrl := fmt.Sprintf("%s/bzz-feed:/bar", srv.URL) - resp, err = http.Get(testBzzResUrl) - if err != nil { - t.Fatal(err) - } - - if resp.StatusCode != http.StatusNotFound { - t.Fatalf("Expected get non-existent feed manifest to fail with StatusNotFound (404), got %d", resp.StatusCode) - } - - resp.Body.Close() - - // get latest update through bzz-feed directly - log.Info("get update latest = 1.1", "addr", correctManifestAddrHex) - testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s", srv.URL, correctManifestAddrHex) - resp, err = http.Get(testBzzResUrl) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - b, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(update1Data, b) { - t.Fatalf("Expected body '%x', got '%x'", update1Data, b) - } - - // update 2 - // Move the clock ahead 1 second - srv.CurrentTime++ - log.Info("update 2") - - // 1.- get metadata about this feed - testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s/", srv.URL, correctManifestAddrHex) - resp, err = http.Get(testBzzResUrl + "?meta=1") - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("Get feed metadata returned %s", resp.Status) - } - b, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - updateRequest = &feed.Request{} - if err = updateRequest.UnmarshalJSON(b); err != nil { - t.Fatalf("Error decoding feed metadata: %s", err) - } - updateRequest.SetData(update2Data) - if err = updateRequest.Sign(signer); err != nil { - t.Fatal(err) - } - testUrl, err = url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) - if err != nil { - t.Fatal(err) - } - urlQuery = testUrl.Query() - body = updateRequest.AppendValues(urlQuery) // this adds all query parameters - goodQueryParameters := urlQuery.Encode() // save the query parameters for a second attempt - - // create bad query parameters in which the signature is missing - urlQuery.Del("signature") - testUrl.RawQuery = urlQuery.Encode() - - // 1st attempt with bad query parameters in which the signature is missing - resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - expectedCode := http.StatusBadRequest - if resp.StatusCode != expectedCode { - t.Fatalf("Update returned %s. Expected %d", resp.Status, expectedCode) - } - - // 2nd attempt with bad query parameters in which the signature is of incorrect length - urlQuery.Set("signature", "0xabcd") // should be 130 hex chars - resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - expectedCode = http.StatusBadRequest - if resp.StatusCode != expectedCode { - t.Fatalf("Update returned %s. Expected %d", resp.Status, expectedCode) - } - - // 3rd attempt, with good query parameters: - testUrl.RawQuery = goodQueryParameters - resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body)) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - expectedCode = http.StatusOK - if resp.StatusCode != expectedCode { - t.Fatalf("Update returned %s. Expected %d", resp.Status, expectedCode) - } - - // get latest update through bzz-feed directly - log.Info("get update 1.2") - testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s", srv.URL, correctManifestAddrHex) - resp, err = http.Get(testBzzResUrl) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - b, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(update2Data, b) { - t.Fatalf("Expected body '%x', got '%x'", update2Data, b) - } - - // test manifest-less queries - log.Info("get first update in update1Timestamp via direct query") - query := feed.NewQuery(&updateRequest.Feed, update1Timestamp, lookup.NoClue) - - urlq, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) - if err != nil { - t.Fatal(err) - } - - values := urlq.Query() - query.AppendValues(values) // this adds feed query parameters - urlq.RawQuery = values.Encode() - resp, err = http.Get(urlq.String()) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - b, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(update1Data, b) { - t.Fatalf("Expected body '%x', got '%x'", update1Data, b) - } - -} - -func TestBzzGetPath(t *testing.T) { - testBzzGetPath(false, t) - testBzzGetPath(true, t) -} - -func testBzzGetPath(encrypted bool, t *testing.T) { - var err error - - testmanifest := []string{ - `{"entries":[{"path":"b","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"c","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0}]}`, - `{"entries":[{"path":"a","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"b/","hash":"","contentType":"application/bzz-manifest+json","status":0}]}`, - `{"entries":[{"path":"a/","hash":"","contentType":"application/bzz-manifest+json","status":0}]}`, - } - - testrequests := make(map[string]int) - testrequests["/"] = 2 - testrequests["/a/"] = 1 - testrequests["/a/b/"] = 0 - testrequests["/x"] = 0 - testrequests[""] = 0 - - expectedfailrequests := []string{"", "/x"} - - reader := [3]*bytes.Reader{} - - addr := [3]storage.Address{} - - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - for i, mf := range testmanifest { - reader[i] = bytes.NewReader([]byte(mf)) - var wait func(context.Context) error - ctx := context.TODO() - addr[i], wait, err = srv.FileStore.Store(ctx, reader[i], int64(len(mf)), encrypted) - if err != nil { - t.Fatal(err) - } - for j := i + 1; j < len(testmanifest); j++ { - testmanifest[j] = strings.Replace(testmanifest[j], fmt.Sprintf("", i), addr[i].Hex(), -1) - } - err = wait(ctx) - if err != nil { - t.Fatal(err) - } - } - - rootRef := addr[2].Hex() - - _, err = http.Get(srv.URL + "/bzz-raw:/" + rootRef + "/a") - if err != nil { - t.Fatalf("Failed to connect to proxy: %v", err) - } - - for k, v := range testrequests { - var resp *http.Response - var respbody []byte - - url := srv.URL + "/bzz-raw:/" - if k != "" { - url += rootRef + "/" + k[1:] + "?content_type=text/plain" - } - resp, err = http.Get(url) - if err != nil { - t.Fatalf("Request failed: %v", err) - } - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("Error while reading response body: %v", err) - } - - if string(respbody) != testmanifest[v] { - isexpectedfailrequest := false - - for _, r := range expectedfailrequests { - if k == r { - isexpectedfailrequest = true - } - } - if !isexpectedfailrequest { - t.Fatalf("Response body does not match, expected: %v, got %v", testmanifest[v], string(respbody)) - } - } - } - - for k, v := range testrequests { - var resp *http.Response - var respbody []byte - - url := srv.URL + "/bzz-hash:/" - if k != "" { - url += rootRef + "/" + k[1:] - } - resp, err = http.Get(url) - if err != nil { - t.Fatalf("Request failed: %v", err) - } - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("Read request body: %v", err) - } - - if string(respbody) != addr[v].Hex() { - isexpectedfailrequest := false - - for _, r := range expectedfailrequests { - if k == r { - isexpectedfailrequest = true - } - } - if !isexpectedfailrequest { - t.Fatalf("Response body does not match, expected: %v, got %v", addr[v], string(respbody)) - } - } - } - - ref := addr[2].Hex() - - for _, c := range []struct { - path string - json string - pageFragments []string - }{ - { - path: "/", - json: `{"common_prefixes":["a/"]}`, - pageFragments: []string{ - fmt.Sprintf("Swarm index of bzz:/%s/", ref), - `a/`, - }, - }, - { - path: "/a/", - json: `{"common_prefixes":["a/b/"],"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/a","mod_time":"0001-01-01T00:00:00Z"}]}`, - pageFragments: []string{ - fmt.Sprintf("Swarm index of bzz:/%s/a/", ref), - `b/`, - fmt.Sprintf(`a`, ref), - }, - }, - { - path: "/a/b/", - json: `{"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/b","mod_time":"0001-01-01T00:00:00Z"},{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/c","mod_time":"0001-01-01T00:00:00Z"}]}`, - pageFragments: []string{ - fmt.Sprintf("Swarm index of bzz:/%s/a/b/", ref), - fmt.Sprintf(`b`, ref), - fmt.Sprintf(`c`, ref), - }, - }, - { - path: "/x", - }, - { - path: "", - }, - } { - k := c.path - url := srv.URL + "/bzz-list:/" - if k != "" { - url += rootRef + "/" + k[1:] - } - t.Run("json list "+c.path, func(t *testing.T) { - resp, err := http.Get(url) - if err != nil { - t.Fatalf("HTTP request: %v", err) - } - defer resp.Body.Close() - respbody, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("Read response body: %v", err) - } - - body := strings.TrimSpace(string(respbody)) - if body != c.json { - isexpectedfailrequest := false - - for _, r := range expectedfailrequests { - if k == r { - isexpectedfailrequest = true - } - } - if !isexpectedfailrequest { - t.Errorf("Response list body %q does not match, expected: %v, got %v", k, c.json, body) - } - } - }) - t.Run("html list "+c.path, func(t *testing.T) { - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - t.Fatalf("New request: %v", err) - } - req.Header.Set("Accept", "text/html") - resp, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatalf("HTTP request: %v", err) - } - defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("Read response body: %v", err) - } - - body := string(b) - - for _, f := range c.pageFragments { - if !strings.Contains(body, f) { - isexpectedfailrequest := false - - for _, r := range expectedfailrequests { - if k == r { - isexpectedfailrequest = true - } - } - if !isexpectedfailrequest { - t.Errorf("Response list body %q does not contain %q: body %q", k, f, body) - } - } - } - }) - } - - nonhashtests := []string{ - srv.URL + "/bzz:/name", - srv.URL + "/bzz-immutable:/nonhash", - srv.URL + "/bzz-raw:/nonhash", - srv.URL + "/bzz-list:/nonhash", - srv.URL + "/bzz-hash:/nonhash", - } - - nonhashresponses := []string{ - `cannot resolve name: no DNS to resolve name: "name"`, - `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, - `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, - `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, - `cannot resolve nonhash: no DNS to resolve name: "nonhash"`, - } - - for i, url := range nonhashtests { - var resp *http.Response - var respbody []byte - - resp, err = http.Get(url) - - if err != nil { - t.Fatalf("Request failed: %v", err) - } - defer resp.Body.Close() - respbody, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("ReadAll failed: %v", err) - } - if !strings.Contains(string(respbody), nonhashresponses[i]) { - t.Fatalf("Non-Hash response body does not match, expected: %v, got: %v", nonhashresponses[i], string(respbody)) - } - } -} - -func TestBzzTar(t *testing.T) { - testBzzTar(false, t) - testBzzTar(true, t) -} - -func testBzzTar(encrypted bool, t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - fileNames := []string{"tmp1.txt", "tmp2.lock", "tmp3.rtf"} - fileContents := []string{"tmp1textfilevalue", "tmp2lockfilelocked", "tmp3isjustaplaintextfile"} - - buf := &bytes.Buffer{} - tw := tar.NewWriter(buf) - defer tw.Close() - - for i, v := range fileNames { - size := int64(len(fileContents[i])) - hdr := &tar.Header{ - Name: v, - Mode: 0644, - Size: size, - ModTime: time.Now(), - Xattrs: map[string]string{ - "user.swarm.content-type": "text/plain", - }, - } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } - - // copy the file into the tar stream - n, err := io.Copy(tw, bytes.NewBufferString(fileContents[i])) - if err != nil { - t.Fatal(err) - } else if n != size { - t.Fatal("size mismatch") - } - } - - //post tar stream - url := srv.URL + "/bzz:/" - if encrypted { - url = url + "encrypt" - } - req, err := http.NewRequest("POST", url, buf) - if err != nil { - t.Fatal(err) - } - req.Header.Add("Content-Type", "application/x-tar") - req.Header.Add(SwarmTagHeaderName, "test-upload") - client := &http.Client{} - resp2, err := client.Do(req) - if err != nil { - t.Fatal(err) - } - if resp2.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp2.Status) - } - - // check that the tag was written correctly - tag := srv.Tags.All()[0] - testutil.CheckTag(t, tag, 4, 4, 0, 4) - - swarmHash, err := ioutil.ReadAll(resp2.Body) - resp2.Body.Close() - if err != nil { - t.Fatal(err) - } - - // now do a GET to get a tarball back - req, err = http.NewRequest("GET", fmt.Sprintf(srv.URL+"/bzz:/%s", string(swarmHash)), nil) - if err != nil { - t.Fatal(err) - } - req.Header.Add("Accept", "application/x-tar") - resp2, err = client.Do(req) - if err != nil { - t.Fatal(err) - } - defer resp2.Body.Close() - - if h := resp2.Header.Get("Content-Type"); h != "application/x-tar" { - t.Fatalf("Content-Type header expected: application/x-tar, got: %s", h) - } - - expectedFileName := string(swarmHash) + ".tar" - expectedContentDisposition := fmt.Sprintf("inline; filename=\"%s\"", expectedFileName) - if h := resp2.Header.Get("Content-Disposition"); h != expectedContentDisposition { - t.Fatalf("Content-Disposition header expected: %s, got: %s", expectedContentDisposition, h) - } - - file, err := ioutil.TempFile("", "swarm-downloaded-tarball") - if err != nil { - t.Fatal(err) - } - defer os.Remove(file.Name()) - _, err = io.Copy(file, resp2.Body) - if err != nil { - t.Fatalf("error getting tarball: %v", err) - } - file.Sync() - file.Close() - - tarFileHandle, err := os.Open(file.Name()) - if err != nil { - t.Fatal(err) - } - tr := tar.NewReader(tarFileHandle) - - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } else if err != nil { - t.Fatalf("error reading tar stream: %s", err) - } - bb := make([]byte, hdr.Size) - _, err = tr.Read(bb) - if err != nil && err != io.EOF { - t.Fatal(err) - } - passed := false - for i, v := range fileNames { - if v == hdr.Name { - if string(bb) == fileContents[i] { - passed = true - break - } - } - } - if !passed { - t.Fatalf("file %s did not pass content assertion", hdr.Name) - } - } - - // now check the tags endpoint -} - -// TestBzzCorrectTagEstimate checks that the HTTP middleware sets the total number of chunks -// in the tag according to an estimate from the HTTP request Content-Length header divided -// by chunk size (4096). It is needed to be checked BEFORE chunking is done, therefore -// concurrency was introduced to slow down the HTTP request -func TestBzzCorrectTagEstimate(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - for _, v := range []struct { - toEncrypt bool - expChunks int64 - }{ - {toEncrypt: false, expChunks: 248}, - {toEncrypt: true, expChunks: 250}, - } { - pr, pw := io.Pipe() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - addr := "" - if v.toEncrypt { - addr = "encrypt" - } - req, err := http.NewRequest("POST", srv.URL+"/bzz:/"+addr, pr) - if err != nil { - t.Fatal(err) - } - - req = req.WithContext(ctx) - req.ContentLength = 1000000 - req.Header.Add(SwarmTagHeaderName, "1000000") - - go func() { - for { - select { - case <-ctx.Done(): - return - case <-time.After(1 * time.Millisecond): - _, err := pw.Write([]byte{0}) - if err != nil { - t.Error(err) - } - } - } - }() - go func() { - transport := http.DefaultTransport - _, err := transport.RoundTrip(req) - if err != nil { - t.Error(err) - } - }() - done := false - for !done { - switch len(srv.Tags.All()) { - case 0: - <-time.After(10 * time.Millisecond) - case 1: - tag := srv.Tags.All()[0] - testutil.CheckTag(t, tag, 0, 0, 0, v.expChunks) - srv.Tags.Delete(tag.Uid) - done = true - } - } - } -} - -// TestBzzRootRedirect tests that getting the root path of a manifest without -// a trailing slash gets redirected to include the trailing slash so that -// relative URLs work as expected. -func TestBzzRootRedirect(t *testing.T) { - testBzzRootRedirect(false, t) -} -func TestBzzRootRedirectEncrypted(t *testing.T) { - testBzzRootRedirect(true, t) -} - -func testBzzRootRedirect(toEncrypt bool, t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - // create a manifest with some data at the root path - data := []byte("data") - headers := map[string]string{"Content-Type": "text/plain"} - res, hash := httpDo("POST", srv.URL+"/bzz:/", bytes.NewReader(data), headers, false, t) - if res.StatusCode != http.StatusOK { - t.Fatalf("unexpected status code from server %d want %d", res.StatusCode, http.StatusOK) - } - - // define a CheckRedirect hook which ensures there is only a single - // redirect to the correct URL - redirected := false - httpClient := http.Client{ - CheckRedirect: func(req *http.Request, via []*http.Request) error { - if redirected { - return errors.New("too many redirects") - } - redirected = true - expectedPath := "/bzz:/" + hash + "/" - if req.URL.Path != expectedPath { - return fmt.Errorf("expected redirect to %q, got %q", expectedPath, req.URL.Path) - } - return nil - }, - } - - // perform the GET request and assert the response - res, err := httpClient.Get(srv.URL + "/bzz:/" + hash) - if err != nil { - t.Fatal(err) - } - defer res.Body.Close() - if !redirected { - t.Fatal("expected GET /bzz:/ to redirect to /bzz:// but it didn't") - } - gotData, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(gotData, data) { - t.Fatalf("expected response to equal %q, got %q", data, gotData) - } -} - -func TestMethodsNotAllowed(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - databytes := "bar" - for _, c := range []struct { - url string - code int - }{ - { - url: fmt.Sprintf("%s/bzz-list:/", srv.URL), - code: http.StatusMethodNotAllowed, - }, { - url: fmt.Sprintf("%s/bzz-hash:/", srv.URL), - code: http.StatusMethodNotAllowed, - }, - { - url: fmt.Sprintf("%s/bzz-immutable:/", srv.URL), - code: http.StatusMethodNotAllowed, - }, - } { - res, _ := http.Post(c.url, "text/plain", bytes.NewReader([]byte(databytes))) - if res.StatusCode != c.code { - t.Fatalf("should have failed. requested url: %s, expected code %d, got %d", c.url, c.code, res.StatusCode) - } - } - -} - -func httpDo(httpMethod string, url string, reqBody io.Reader, headers map[string]string, verbose bool, t *testing.T) (*http.Response, string) { - // Build the Request - req, err := http.NewRequest(httpMethod, url, reqBody) - if err != nil { - t.Fatal(err) - } - for key, value := range headers { - req.Header.Set(key, value) - } - if verbose { - t.Log(req.Method, req.URL, req.Header, req.Body) - } - - // Send Request out - httpClient := &http.Client{} - res, err := httpClient.Do(req) - if err != nil { - t.Fatal(err) - } - - // Read the HTTP Body - buffer, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatal(err) - } - defer res.Body.Close() - body := string(buffer) - - return res, body -} - -func TestGet(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - for _, testCase := range []struct { - uri string - method string - headers map[string]string - expectedStatusCode int - assertResponseBody string - verbose bool - }{ - { - uri: fmt.Sprintf("%s/", srv.URL), - method: "GET", - headers: map[string]string{"Accept": "text/html"}, - expectedStatusCode: http.StatusOK, - assertResponseBody: "Swarm provides censorship resistant storage and communication infrastructure for a sovereign digital society", - verbose: false, - }, - { - uri: fmt.Sprintf("%s/", srv.URL), - method: "GET", - headers: map[string]string{"Accept": "application/json"}, - expectedStatusCode: http.StatusOK, - assertResponseBody: "Swarm: Please request a valid ENS or swarm hash with the appropriate bzz scheme", - verbose: false, - }, - { - uri: fmt.Sprintf("%s/robots.txt", srv.URL), - method: "GET", - headers: map[string]string{"Accept": "text/html"}, - expectedStatusCode: http.StatusOK, - assertResponseBody: "User-agent: *\nDisallow: /", - verbose: false, - }, - { - uri: fmt.Sprintf("%s/nonexistent_path", srv.URL), - method: "GET", - headers: map[string]string{}, - expectedStatusCode: http.StatusNotFound, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz:asdf/", srv.URL), - method: "GET", - headers: map[string]string{}, - expectedStatusCode: http.StatusNotFound, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/tbz2/", srv.URL), - method: "GET", - headers: map[string]string{}, - expectedStatusCode: http.StatusNotFound, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz-rack:/", srv.URL), - method: "GET", - headers: map[string]string{}, - expectedStatusCode: http.StatusNotFound, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz-ls", srv.URL), - method: "GET", - headers: map[string]string{}, - expectedStatusCode: http.StatusNotFound, - verbose: false, - }} { - t.Run("GET "+testCase.uri, func(t *testing.T) { - res, body := httpDo(testCase.method, testCase.uri, nil, testCase.headers, testCase.verbose, t) - if res.StatusCode != testCase.expectedStatusCode { - t.Fatalf("expected status code %d but got %d", testCase.expectedStatusCode, res.StatusCode) - } - if testCase.assertResponseBody != "" && !strings.Contains(body, testCase.assertResponseBody) { - t.Fatalf("expected response to be: %s but got: %s", testCase.assertResponseBody, body) - } - }) - } -} - -func TestModify(t *testing.T) { - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - headers := map[string]string{"Content-Type": "text/plain"} - res, hash := httpDo("POST", srv.URL+"/bzz:/", bytes.NewReader([]byte("data")), headers, false, t) - if res.StatusCode != http.StatusOK { - t.Fatalf("unexpected status code from server %d want %d", res.StatusCode, http.StatusOK) - } - - for _, testCase := range []struct { - uri string - method string - headers map[string]string - requestBody []byte - expectedStatusCode int - assertResponseBody string - assertResponseHeaders map[string]string - verbose bool - }{ - { - uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash), - method: "DELETE", - headers: map[string]string{}, - expectedStatusCode: http.StatusOK, - assertResponseBody: "8b634aea26eec353ac0ecbec20c94f44d6f8d11f38d4578a4c207a84c74ef731", - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash), - method: "PUT", - headers: map[string]string{}, - expectedStatusCode: http.StatusMethodNotAllowed, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, hash), - method: "PUT", - headers: map[string]string{}, - expectedStatusCode: http.StatusMethodNotAllowed, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash), - method: "PATCH", - headers: map[string]string{}, - expectedStatusCode: http.StatusMethodNotAllowed, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz-raw:/", srv.URL), - method: "POST", - headers: map[string]string{}, - requestBody: []byte("POSTdata"), - expectedStatusCode: http.StatusOK, - assertResponseHeaders: map[string]string{"Content-Length": "64"}, - verbose: false, - }, - { - uri: fmt.Sprintf("%s/bzz-raw:/encrypt", srv.URL), - method: "POST", - headers: map[string]string{}, - requestBody: []byte("POSTdata"), - expectedStatusCode: http.StatusOK, - assertResponseHeaders: map[string]string{"Content-Length": "128"}, - verbose: false, - }, - } { - t.Run(testCase.method+" "+testCase.uri, func(t *testing.T) { - reqBody := bytes.NewReader(testCase.requestBody) - res, body := httpDo(testCase.method, testCase.uri, reqBody, testCase.headers, testCase.verbose, t) - - if res.StatusCode != testCase.expectedStatusCode { - t.Fatalf("expected status code %d but got %d, %s", testCase.expectedStatusCode, res.StatusCode, body) - } - if testCase.assertResponseBody != "" && !strings.Contains(body, testCase.assertResponseBody) { - t.Log(body) - t.Fatalf("expected response %s but got %s", testCase.assertResponseBody, body) - } - for key, value := range testCase.assertResponseHeaders { - if res.Header.Get(key) != value { - t.Logf("expected %s=%s in HTTP response header but got %s", key, value, res.Header.Get(key)) - } - } - }) - } -} - -func TestMultiPartUpload(t *testing.T) { - // POST /bzz:/ Content-Type: multipart/form-data - verbose := false - // Setup Swarm - srv := NewTestSwarmServer(t, serverFunc, nil) - defer srv.Close() - - url := fmt.Sprintf("%s/bzz:/", srv.URL) - - buf := new(bytes.Buffer) - form := multipart.NewWriter(buf) - form.WriteField("name", "John Doe") - file1, _ := form.CreateFormFile("cv", "cv.txt") - file1.Write([]byte("John Doe's Credentials")) - file2, _ := form.CreateFormFile("profile_picture", "profile.jpg") - file2.Write([]byte("imaginethisisjpegdata")) - form.Close() - - headers := map[string]string{ - "Content-Type": form.FormDataContentType(), - "Content-Length": strconv.Itoa(buf.Len()), - } - res, body := httpDo("POST", url, buf, headers, verbose, t) - - if res.StatusCode != http.StatusOK { - t.Fatalf("expected POST multipart/form-data to return 200, but it returned %d", res.StatusCode) - } - if len(body) != 64 { - t.Fatalf("expected POST multipart/form-data to return a 64 char manifest but the answer was %d chars long", len(body)) - } -} - -// TestBzzGetFileWithResolver tests fetching a file using a mocked ENS resolver -func TestBzzGetFileWithResolver(t *testing.T) { - resolver := newTestResolveValidator("") - srv := NewTestSwarmServer(t, serverFunc, resolver) - defer srv.Close() - fileNames := []string{"dir1/tmp1.txt", "dir2/tmp2.lock", "dir3/tmp3.rtf"} - fileContents := []string{"tmp1textfilevalue", "tmp2lockfilelocked", "tmp3isjustaplaintextfile"} - - buf := &bytes.Buffer{} - tw := tar.NewWriter(buf) - - for i, v := range fileNames { - size := len(fileContents[i]) - hdr := &tar.Header{ - Name: v, - Mode: 0644, - Size: int64(size), - ModTime: time.Now(), - Xattrs: map[string]string{ - "user.swarm.content-type": "text/plain", - }, - } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } - - // copy the file into the tar stream - n, err := io.WriteString(tw, fileContents[i]) - if err != nil { - t.Fatal(err) - } else if n != size { - t.Fatal("size mismatch") - } - } - - if err := tw.Close(); err != nil { - t.Fatal(err) - } - - //post tar stream - url := srv.URL + "/bzz:/" - - req, err := http.NewRequest("POST", url, buf) - if err != nil { - t.Fatal(err) - } - req.Header.Add("Content-Type", "application/x-tar") - client := &http.Client{} - serverResponse, err := client.Do(req) - if err != nil { - t.Fatal(err) - } - if serverResponse.StatusCode != http.StatusOK { - t.Fatalf("err %s", serverResponse.Status) - } - swarmHash, err := ioutil.ReadAll(serverResponse.Body) - serverResponse.Body.Close() - if err != nil { - t.Fatal(err) - } - // set the resolved hash to be the swarm hash of what we've just uploaded - hash := common.HexToHash(string(swarmHash)) - resolver.hash = &hash - for _, v := range []struct { - addr string - path string - expectedStatusCode int - expectedContentType string - expectedFileName string - }{ - { - addr: string(swarmHash), - path: fileNames[0], - expectedStatusCode: http.StatusOK, - expectedContentType: "text/plain", - expectedFileName: path.Base(fileNames[0]), - }, - { - addr: "somebogusensname", - path: fileNames[0], - expectedStatusCode: http.StatusOK, - expectedContentType: "text/plain", - expectedFileName: path.Base(fileNames[0]), - }, - } { - req, err := http.NewRequest("GET", fmt.Sprintf(srv.URL+"/bzz:/%s/%s", v.addr, v.path), nil) - if err != nil { - t.Fatal(err) - } - serverResponse, err := client.Do(req) - if err != nil { - t.Fatal(err) - } - defer serverResponse.Body.Close() - if serverResponse.StatusCode != v.expectedStatusCode { - t.Fatalf("expected %d, got %d", v.expectedStatusCode, serverResponse.StatusCode) - } - - if h := serverResponse.Header.Get("Content-Type"); h != v.expectedContentType { - t.Fatalf("Content-Type header expected: %s, got %s", v.expectedContentType, h) - } - - expectedContentDisposition := fmt.Sprintf("inline; filename=\"%s\"", v.expectedFileName) - if h := serverResponse.Header.Get("Content-Disposition"); h != expectedContentDisposition { - t.Fatalf("Content-Disposition header expected: %s, got: %s", expectedContentDisposition, h) - } - - } -} - -// TestCalculateNumberOfChunks is a unit test for the chunk-number-according-to-content-length -// calculation -func TestCalculateNumberOfChunks(t *testing.T) { - - //test cases: - for _, tc := range []struct{ len, chunks int64 }{ - {len: 1000, chunks: 1}, - {len: 5000, chunks: 3}, - {len: 10000, chunks: 4}, - {len: 100000, chunks: 26}, - {len: 1000000, chunks: 248}, - {len: 325839339210, chunks: 79550620 + 621490 + 4856 + 38 + 1}, - } { - res := calculateNumberOfChunks(tc.len, false) - if res != tc.chunks { - t.Fatalf("expected result for %d bytes to be %d got %d", tc.len, tc.chunks, res) - } - } -} - -// TestCalculateNumberOfChunksEncrypted is a unit test for the chunk-number-according-to-content-length -// calculation with encryption (branching factor=64) -func TestCalculateNumberOfChunksEncrypted(t *testing.T) { - - //test cases: - for _, tc := range []struct{ len, chunks int64 }{ - {len: 1000, chunks: 1}, - {len: 5000, chunks: 3}, - {len: 10000, chunks: 4}, - {len: 100000, chunks: 26}, - {len: 1000000, chunks: 245 + 4 + 1}, - {len: 325839339210, chunks: 79550620 + 1242979 + 19422 + 304 + 5 + 1}, - } { - res := calculateNumberOfChunks(tc.len, true) - if res != tc.chunks { - t.Fatalf("expected result for %d bytes to be %d got %d", tc.len, tc.chunks, res) - } - } -} - -// testResolver implements the Resolver interface and either returns the given -// hash if it is set, or returns a "name not found" error -type testResolveValidator struct { - hash *common.Hash -} - -func newTestResolveValidator(addr string) *testResolveValidator { - r := &testResolveValidator{} - if addr != "" { - hash := common.HexToHash(addr) - r.hash = &hash - } - return r -} - -func (t *testResolveValidator) Resolve(addr string) (common.Hash, error) { - if t.hash == nil { - return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr) - } - return *t.hash, nil -} - -func (t *testResolveValidator) Owner(node [32]byte) (addr common.Address, err error) { - return -} - -func (t *testResolveValidator) HeaderByNumber(context.Context, *big.Int) (header *types.Header, err error) { - return -} diff --git a/swarm/api/http/templates.go b/swarm/api/http/templates.go deleted file mode 100644 index 19c4040ca5..0000000000 --- a/swarm/api/http/templates.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package http - -import ( - "encoding/hex" - "fmt" - "html/template" - "path" - - "github.com/ethereum/go-ethereum/swarm/api" -) - -type htmlListData struct { - URI *api.URI - List *api.ManifestList -} - -var TemplatesMap = make(map[string]*template.Template) -var faviconBytes []byte - -func init() { - for _, v := range []struct { - templateName string - partial string - funcs template.FuncMap - }{ - { - templateName: "error", - partial: errorResponse, - }, - { - templateName: "bzz-list", - partial: bzzList, - funcs: template.FuncMap{ - "basename": path.Base, - "leaflink": leafLink, - }, - }, - { - templateName: "landing-page", - partial: landing, - }, - } { - TemplatesMap[v.templateName] = template.Must(template.New(v.templateName).Funcs(v.funcs).Parse(baseTemplate + css + v.partial + logo)) - } - - bytes, err := hex.DecodeString(favicon) - if err != nil { - panic(err) - } - faviconBytes = bytes -} - -func leafLink(URI api.URI, manifestEntry api.ManifestEntry) string { - return fmt.Sprintf("/bzz:/%s/%s", URI.Addr, manifestEntry.Path) -} - -const bzzList = `{{ define "content" }} -

Swarm index of {{ .URI }}

-
- - - - - - - - - - - {{ range .List.CommonPrefixes }} - - - - - - {{ end }} - {{ range .List.Entries }} - - - - - - {{ end }} -
PathTypeSize
- {{ basename . }}/ - DIR-
- {{ basename .Path }} - {{ .ContentType }}{{ .Size }}
-
- - {{ end }}` - -const errorResponse = `{{ define "content" }} -
- - -
-

{{.Msg}}

-
- -
-
Error code: {{.Code}}
-
- - -
-{{ end }}` - -const landing = `{{ define "content" }} - - - -
- - - - - -
- -{{ end }}` - -const baseTemplate = ` - - - - - - - - - {{ template "content" . }} - - -` - -const css = `{{ define "css" }} -html { - font-size: 18px; - font-size: 1.13rem; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - font-family: Helvetica, Arial, sans-serif; -} - -body { - background: #f6f6f6; - color: #333; -} - -a, a:visited, a:active { - color: darkorange; -} - -a.normal-link, a.normal-link:active { color: #0000EE; } -a.normal-link:visited { color: #551A8B; } - -table { - border-collapse: separate; -} - -td { - padding: 3px 10px; -} - - -.container { - max-width: 600px; - margin: 40px auto 40px; - text-align: center; -} - -.separate-block { - margin: 40px 0; - word-wrap: break-word; -} - -.footer { - font-size: 12px; - font-size: 0.75rem; - text-align: center; -} - -.orange { - color: #ffa500; -} - -.top-space { - margin-top: 20px; - margin-bottom: 20px; -} - -/* SVG Logos, editable */ - -.searchbar { - padding: 20px 20px 0; -} - -.logo { - margin: 100px 80px 0; -} - -.logo a img { - max-width: 140px; -} - -/* Tablet < 600p*/ - -@media only screen and (max-width: 600px) {} - -/* Mobile phone < 360p*/ - -@media only screen and (max-width: 360px) { - h1 { - font-size: 20px; - font-size: 1.5rem; - } - h2 { - font-size: 0.88rem; - margin: 0; - } - .logo { - margin: 50px 40px 0; - } - .footer { - font-size: 0.63rem; - text-align: center; - } -} - -input[type=text] { - width: 100%; - box-sizing: border-box; - border: 2px solid #777; - border-radius: 2px; - font-size: 16px; - padding: 12px 20px 12px 20px; - transition: border 250ms ease-in-out; -} - -input[type=text]:focus { - border: 2px solid #ffce73; -} - -.button { - background-color: #ffa500; - margin: 20px 0; - border: none; - border-radius: 2px; - color: #222; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; -} -{{ end }}` - -const logo = `{{ define "logo" }} - -{{ end }}` - -const favicon = `000001000400101000000000200068040000460000002020000000002000a8100000ae0400003030000000002000a825000056150000404000000000200028420000fe3a000028000000100000002000000001002000000000004004000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e0362626263545454c548484849ffffff01ffffff01ffffff01ffffff01646464375b5b5bbf4545457758585809ffffff01ffffff01ffffff0164646443626262cf626262ff535353ff454545ff454545b74949492b6868681d626262a5626262fd5c5c5cff464646ff454545dd47474755ffffff01ffffff013f3f3feb565656ff636363ff535353ff464646ff3f3f3fff373737ab393939894d4d4dff626262ff5c5c5cff464646ff424242ff3a3a3af7ffffff01ffffff01383838e9353535ff424242ff474747ff383838ff353535ff363636ab35353587363636ff3a3a3aff4a4a4aff3b3b3bff353535ff363636f5ffffff01ffffff01383838e9303030ff181818ff131313ff232323ff343434ff363636ab35353587343434ff202020ff101010ff1d1d1dff303030ff373737f5ffffff01ffffff01232323c50c0c0cff0d0d0dff131313ff171717ff171717ff2929298b2727276b0f0f0ffd0d0d0dff101010ff171717ff161616ff232323d9ffffff01ffffff014d4d4d030f0f0f650c0c0ce7131313ff161616d51d1d1d4b63636363464646691717173b0d0d0dc50f0f0fff161616ef171717752e2e2e07ffffff01ffffff01ffffff01ffffff011d1d1d0f1515155360606045626262cf636363ff464646ff454545d3484848491414144d24242417ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013c3c3c374f4f4fff636363ff636363ff464646ff464646ff3f3f3fff3c3c3c41ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636363d353535ff3c3c3cff575757ff363636ff181818ff282828ff37373747ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636363d363636ff303030ff181818ff292929ff131313ef17171771696969136565653bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01323232371e1e1eff0d0d0dff0c0c0cff363636ff363636a3ffffff0185858515606060ff4747476bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01111111450d0d0dd10c0c0cff1b1b1bff2a2a2a993e3e3e0b30303085292929ff37373787ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636030e0e0e671616166b45454505323232432e2e2ed9151515c31d1d1d2dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014e4e4e05ffffff01ffffff01ffffff01ffffff010000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff28000000200000004000000001002000000000008010000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017272721b646464a54646466f72727205ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0168686845575757b74f4f4f39ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e0b6262627d616161f3636363ff424242ff444444d74f4f4f49ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016c6c6c27636363b5616161ff555555ff434343ff464646a35858581dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016666665d616161e3626262ff636363ff636363ff444444ff464646ff434343ff454545b95252522bffffff01ffffff01ffffff01ffffff016c6c6c1363636393616161fb636363ff636363ff555555ff464646ff464646ff444444f5464646836666660bffffff01ffffff01ffffff01ffffff01ffffff016a6a6a3f626262c9616161ff636363ff636363ff636363ff636363ff444444ff464646ff464646ff464646ff434343fb48484897545454135b5b5b036868686f616161ef626262ff636363ff636363ff636363ff555555ff464646ff464646ff464646ff454545ff444444e54a4a4a5fffffff01ffffff01ffffff01ffffff013b3b3bd7505050ff646464ff636363ff636363ff636363ff636363ff444444ff464646ff464646ff464646ff454545ff3a3a3aff33333357313131113c3c3cff5a5a5aff646464ff636363ff636363ff636363ff555555ff464646ff464646ff464646ff464646ff424242ff383838f1ffffff01ffffff01ffffff01ffffff013a3a3ad5353535ff3a3a3aff575757ff646464ff626262ff636363ff444444ff464646ff464646ff3d3d3dff353535ff363636ff3636365535353511363636ff343434ff434343ff606060ff636363ff636363ff555555ff464646ff464646ff444444ff393939ff353535ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff343434ff3f3f3fff5d5d5dff646464ff444444ff404040ff363636ff353535ff363636ff363636ff3636365535353511363636ff363636ff363636ff343434ff4a4a4aff636363ff555555ff454545ff3c3c3cff353535ff363636ff363636ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff363636ff363636ff353535ff3f3f3fff363636ff353535ff363636ff363636ff363636ff363636ff3636365535353511363636ff363636ff363636ff363636ff353535ff383838ff3a3a3aff373737ff353535ff363636ff363636ff363636ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff363636ff323232ff181818ff0e0e0eff171717ff282828ff373737ff363636ff363636ff363636ff3636365535353511363636ff363636ff353535ff373737ff292929ff0f0f0fff111111ff1b1b1bff2f2f2fff373737ff363636ff363636ff373737edffffff01ffffff01ffffff01ffffff013a3a3ad5363636ff363636ff1e1e1eff0b0b0bff0d0d0dff0f0f0fff171717ff161616ff191919ff2c2c2cff373737ff363636ff3636365535353511363636ff373737ff2f2f2fff141414ff0b0b0bff0d0d0dff131313ff171717ff151515ff1f1f1fff333333ff363636ff373737edffffff01ffffff01ffffff01ffffff013b3b3bd5252525ff0d0d0dff0c0c0cff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff151515ff1c1c1cff313131ff3535355734343411333333ff1a1a1aff0b0b0bff0d0d0dff0d0d0dff0d0d0dff131313ff171717ff171717ff171717ff161616ff242424ff373737efffffff01ffffff01ffffff01ffffff012020205d0b0b0be50b0b0bff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff131313ff161616b73333331f3b3b3b05111111970a0a0afb0d0d0dff0d0d0dff0d0d0dff0d0d0dff131313ff171717ff171717ff171717ff161616ff141414f51c1c1c7fffffff01ffffff01ffffff01ffffff01ffffff014d4d4d0b1212127f0a0a0af50d0d0dff0d0d0dff0f0f0fff171717ff171717ff151515ff151515d522222249ffffff017373731b51515121ffffff011d1d1d2b101010b50a0a0aff0d0d0dff0d0d0dff131313ff171717ff171717ff131313ff181818a12e2e2e1dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012c2c2c1b0f0f0fa10a0a0afd0f0f0fff161616ff141414e91b1b1b69656565057878780b6363637b626262f3464646f7454545896969690fffffff011c1c1c470c0c0cd30b0b0bff131313ff141414ff151515c32a2a2a37ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff011d1d1d35111111bd1a1a1a8d2f2f2f11ffffff0166666659616161e1626262ff646464ff474747ff454545ff444444e9494949677b7b7b054040400517171769131313cd24242455ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0169696939626262c7616161ff636363ff636363ff646464ff474747ff464646ff464646ff444444ff454545d14e4e4e45ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01424242615e5e5eff636363ff636363ff636363ff636363ff646464ff474747ff464646ff464646ff464646ff464646ff434343ff3f3f3f77ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679343434ff494949ff636363ff636363ff636363ff646464ff474747ff464646ff464646ff474747ff3d3d3dff353535ff3a3a3a8dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff353535ff363636ff505050ff646464ff636363ff474747ff484848ff2f2f2fff1c1c1cff323232ff363636ff3a3a3a8dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff363636ff363636ff353535ff3a3a3aff5a5a5aff393939ff0f0f0fff040404ff111111ff151515ff232323ff3535358fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff363636ff363636ff363636ff323232ff171717ff2a2a2aff0c0c0cff030303ff111111ff141414fb171717992e2e2e17a3a3a305ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679363636ff363636ff363636ff1f1f1fff0b0b0bff0d0d0dff363636ff383838ff242424ff121212bf2a2a2a2dffffff01ffffff018484842b636363bf6d6d6d2fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0136363679373737ff252525ff0d0d0dff0c0c0cff0d0d0dff0d0d0dff373737ff363636ff353535ff39393949ffffff01ffffff01ffffff0186868629646464ff656565fb6464649b55555505ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012e2e2e650e0e0eff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0c0c0cff353535ff363636ff353535ff37373749ffffff01ffffff01ffffff0185858529656565ff525252ff353535ff4b4b4b0fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff011c1c1c430d0d0dcf0b0b0bff0d0d0dff0d0d0dff0d0d0dff171717ff282828ff363636ff37373749ffffff01ffffff01ffffff0144444459363636ff353535ff353535ff4e4e4e0fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0162626203161616630b0b0be70c0c0cff0d0d0dff171717ff161616ff171717ed3737372fffffff013e3e3e2b303030b72a2a2aff151515ff262626ff363636ff4b4b4b0fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636360d101010850a0a0af7141414f91717178f45454511ffffff014c4c4c252c2c2cdb303030ff2d2d2dff151515ff131313ff1b1b1bad5a5a5a07ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012b2b2b2121212127ffffff01ffffff01ffffff01ffffff0161616109313131752b2b2bf1131313cd26262641ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014e4e4e1359595903ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000300000006000000001002000000000008025000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0173737357545454997c7c7c11ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767663515151916c6c6c0dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017676762d636363bb636363ff4d4d4dff434343eb4f4f4f6d7f7f7f05ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767635616161c3626262ff494949ff424242e94f4f4f6392929203ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e19626262955f5f5ffd626262ff666666ff4f4f4fff464646ff424242ff434343d75a5a5a49ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017777771d6464649f5f5f5fff636363ff656565ff4b4b4bff464646ff424242ff444444d158585841ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018585850966666677606060ef626262ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff414141ff464646b75d5d5d2dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018989890d6868687f5f5f5ff5626262ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff404040ff484848b160606027ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016a6a6a55626262df606060ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff454545ff424242fd484848956a6a6a17ffffff01ffffff01ffffff01ffffff01ffffff016969695f606060e3606060ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff454545ff414141f94a4a4a8d65656513ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff016e6e6e3b656565c15f5f5fff636363ff636363ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff464646ff464646ff444444ff424242ed52525277ffffff01ffffff016c6c6c37676767c95f5f5fff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff464646ff464646ff434343ff444444e94d4d4d6dffffff01ffffff01ffffff01ffffff01ffffff01ffffff013c3c3cc5454545ff646464ff646464ff636363ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff464646ff464646ff474747ff424242ff333333fb34343409ffffff0131313199494949ff656565ff646464ff636363ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff464646ff464646ff474747ff414141ff373737ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf333333ff343434ff4f4f4fff666666ff636363ff636363ff636363ff636363ff666666ff4f4f4fff464646ff464646ff464646ff464646ff474747ff444444ff383838ff343434ff363636f737373707ffffff0135353597343434ff343434ff525252ff666666ff636363ff636363ff636363ff636363ff656565ff4b4b4bff464646ff464646ff464646ff464646ff474747ff444444ff383838ff343434ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff333333ff383838ff585858ff676767ff636363ff636363ff666666ff4f4f4fff464646ff464646ff474747ff464646ff3b3b3bff343434ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff333333ff383838ff5a5a5aff666666ff636363ff636363ff656565ff4b4b4bff464646ff464646ff474747ff454545ff3a3a3aff343434ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff323232ff3d3d3dff5d5d5dff666666ff666666ff4f4f4fff464646ff474747ff3e3e3eff353535ff353535ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff313131ff3f3f3fff5f5f5fff666666ff656565ff4b4b4bff464646ff474747ff3d3d3dff353535ff353535ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff363636ff353535ff323232ff444444ff676767ff525252ff404040ff363636ff353535ff363636ff363636ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff363636ff353535ff323232ff464646ff676767ff4e4e4eff404040ff363636ff353535ff363636ff363636ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff363636ff363636ff353535ff383838ff2d2d2dff2b2b2bff373737ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff363636ff363636ff363636ff383838ff2c2c2cff2a2a2aff373737ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff363636ff353535ff383838ff343434ff171717ff090909ff151515ff171717ff2d2d2dff383838ff363636ff363636ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff363636ff353535ff383838ff333333ff151515ff090909ff151515ff181818ff2f2f2fff383838ff363636ff363636ff363636ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff363636ff373737ff373737ff1f1f1fff090909ff0c0c0cff0c0c0cff171717ff171717ff141414ff1b1b1bff323232ff383838ff363636ff363636ff363636ff363636f737373707ffffff0135353597363636ff363636ff363636ff373737ff373737ff1d1d1dff0a0a0aff0c0c0cff0c0c0cff171717ff171717ff141414ff1c1c1cff333333ff383838ff353535ff363636ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf343434ff363636ff393939ff272727ff0c0c0cff0b0b0bff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff161616ff141414ff202020ff353535ff373737ff363636ff363636f737373707ffffff0135353597363636ff363636ff383838ff252525ff0b0b0bff0b0b0bff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff161616ff141414ff222222ff363636ff373737ff363636ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040bf383838ff2d2d2dff101010ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff161616ff141414ff262626ff373737ff373737f737373707ffffff0136363697393939ff2b2b2bff0f0f0fff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff161616ff151515ff272727ff383838ff393939e3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013a3a3abd131313ff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff171717ff262626fb38383807ffffff012a2a2a97121212ff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff161616ff2a2a2ae7ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015f5f5f0b1616167b090909ef0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff171717ff0f0f0fff181818b74040402dffffff01ffffff014646461118181883080808f30b0b0bff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff171717ff161616ff101010ff181818b141414127ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014d4d4d171212129b090909fd0c0c0cff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff111111ff141414d335353547ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013838381d131313a5060606ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff171717ff171717ff111111ff181818cd2e2e2e3dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01333333310f0f0fbb070707ff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff141414ff121212e72424246d86868603ffffff01ffffff017373732b656565b9464646c95e5e5e3bffffff01ffffff01ffffff01323232370e0e0ec3080808ff0d0d0dff0d0d0dff0c0c0cff171717ff171717ff171717ff121212ff161616e525252563ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012525254d0e0e0ed9090909ff0c0c0cff171717ff151515ff121212f91d1d1d894d4d4d13ffffff01ffffff0178787815656565935f5f5ffb646464ff484848ff404040ff454545a96a6a6a1fffffff01ffffff01ffffff011b1b1b570e0e0edf080808ff0d0d0dff171717ff151515ff0f0f0ff3212121815656560dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01636363071a1a1a710a0a0aed0f0f0fff1b1b1bad2f2f2f23ffffff01ffffff018d8d8d0566666675616161eb616161ff636363ff646464ff484848ff464646ff454545ff424242f54c4c4c856262620fffffff01ffffff014040400b21212179080808f10f0f0fff1b1b1ba15757571dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014141411740404037ffffff01ffffff01ffffff016a6a6a4d616161db606060ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff434343ff434343e751515167ffffff01ffffff01ffffff014646461d30303033ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767631616161c35f5f5fff636363ff636363ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff464646ff464646ff424242ff454545d158585841ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015252527f636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff434343ff454545a1ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01313131b53b3b3bff5b5b5bff676767ff636363ff636363ff636363ff636363ff636363ff646464ff484848ff464646ff464646ff464646ff464646ff464646ff474747ff444444ff393939ff383838d3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff323232ff404040ff616161ff656565ff626262ff636363ff636363ff646464ff484848ff464646ff464646ff454545ff494949ff474747ff3b3b3bff343434ff353535ff3a3a3ad3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff353535ff323232ff484848ff656565ff646464ff636363ff646464ff484848ff464646ff474747ff494949ff242424ff282828ff383838ff363636ff363636ff3a3a3ad3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff343434ff343434ff515151ff666666ff656565ff484848ff4b4b4bff323232ff070707ff040404ff151515ff181818ff2f2f2fff383838ff3a3a3ad3ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff363636ff363636ff333333ff383838ff5f5f5fff3c3c3cff0f0f0fff020202ff050505ff050505ff171717ff171717ff141414ff1c1c1cff323232d7ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff363636ff353535ff383838ff343434ff161616ff2a2a2aff0c0c0cff020202ff050505ff050505ff171717ff171717ff101010ff161616bf2e2e2e35ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff363636ff373737ff383838ff1f1f1fff0a0a0aff0c0c0cff373737ff3a3a3aff262626ff060606ff040404ff121212ff151515dd30303051ffffff01ffffff01ffffff018787872d6b6b6b47ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff363636ff363636ff393939ff272727ff0d0d0dff0b0b0bff0d0d0dff0d0d0dff373737ff363636ff373737ff383838ff1c1c1cf92020207568686807ffffff01ffffff01ffffff01ffffff018686863d5f5f5fff676767af77777721ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01363636b3363636ff393939ff2e2e2eff101010ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff373737ff363636ff363636ff353535ff373737ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff018686863d626262ff666666ff646464f76969698d9494940fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01383838b5333333ff161616ff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff373737ff363636ff363636ff363636ff353535ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff018686863d626262ff676767ff6b6b6bff555555ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0125252589030303ff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff333333ff383838ff353535ff363636ff353535ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff018585853d666666ff5f5f5fff3c3c3cff313131ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012d2d2d3f0e0e0ecb080808ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff141414ff222222ff363636ff373737ff353535ebffffff01ffffff01ffffff01ffffff01ffffff01ffffff0177777741414141ff313131ff363636ff353535ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff011e1e1e5f0a0a0ae50a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff171717ff161616ff151515ff282828ff353535f3ffffff01ffffff01ffffff01ffffff016e6e6e0b37373781242424f1191919ff333333ff383838ff343434ff3a3a3a93ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015a5a5a0d1919197f0a0a0af30b0b0bff0d0d0dff0d0d0dff171717ff171717ff161616ff0f0f0ffb24242489ffffff01ffffff01ffffff013e3e3e5d2d2d2de52e2e2eff2b2b2bff151515ff141414ff212121ff363636ff3b3b3b95ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636361b111111a3080808ff0c0c0cff181818ff0f0f0fff171717b545454525ffffff01ffffff017f7f7f05363636c7282828ff313131ff313131ff2b2b2bff151515ff171717ff161616ff0c0c0cfb3434346bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01303030350f0f0fc7121212d337373741ffffff01ffffff01ffffff01ffffff01ffffff016b6b6b0b3a3a3a7d2c2c2cf12f2f2fff2b2b2bff151515ff101010ff171717bb4646462dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01515151193535359b242424ff131313d72828284bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014e4e4e2b59595905ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff000000000000ffff28000000400000008000000001002000000000000042000000000000000000000000000000000000ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0176767635666666914e4e4e457c7c7c09ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018080801569696989545454696c6c6c0bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018484840d70707061616161d5606060fb3d3d3ddf4e4e4e9172727213ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017070704d626262b35f5f5ffb464646f1454545a16a6a6a33ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017676760f67676753646464cf5e5e5eff656565ff626262ff414141ff404040ff444444e54b4b4b7b69696919ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01979797036c6c6c45676767a95d5d5dff616161ff626262ff484848ff424242ff3e3e3efd4e4e4e8958585831ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017e7e7e2b616161a75f5f5fef616161ff636363ff656565ff626262ff424242ff464646ff444444ff414141fd434343b961616153ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017777771969696981606060e7606060ff636363ff636363ff626262ff484848ff464646ff454545ff424242fd414141d95656566569696911ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01858585056e6e6e29656565995f5f5ff1616161ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff444444ff3f3f3fff484848af5353534b86868607ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01797979216a6a6a6f616161ed5e5e5eff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff3e3e3eff474747d75151515762626213ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01838383036f6f6f755f5f5fd3606060ff626262ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff454545ff434343ff404040e94e4e4e8d5f5f5f1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff018f8f8f056b6b6b45616161c95f5f5ff7616161ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff444444ff424242f1434343b16666662dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017070700f6969695f626262d35e5e5eff626262ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff404040ff444444f14d4d4d776a6a6a23ffffff01ffffff01ffffff01ffffff017b7b7b096c6c6c39636363c15f5f5ffb626262ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff434343ff414141f54a4a4aa35b5b5b2d70707007ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0171717143676767a7616161f3616161ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff414141f7474747cd54545447ffffff01ffffff015b5b5b096b6b6b99646464e1606060ff626262ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff424242ff414141d552525277ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01404040b33b3b3bff5c5c5cff656565ff646464ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff474747ff454545ff3a3a3aff313131ad34343407ffffff012e2e2e25383838ff535353ff656565ff656565ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff474747ff464646ff3b3b3bff3a3a3ae9ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9313131ff363636ff484848ff636363ff676767ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff404040ff363636ff343434ff353535a537373705ffffff0135353521333333ff333333ff434343ff5c5c5cff686868ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff484848ff414141ff393939ff313131ff3c3c3cdbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff323232ff353535ff4b4b4bff636363ff656565ff636363ff626262ff636363ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff464646ff474747ff464646ff414141ff363636ff343434ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff333333ff313131ff484848ff5e5e5eff666666ff646464ff626262ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff464646ff464646ff474747ff424242ff3a3a3aff343434ff353535ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff343434ff333333ff3d3d3dff555555ff686868ff656565ff626262ff636363ff656565ff626262ff424242ff464646ff464646ff464646ff484848ff444444ff393939ff353535ff353535ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff353535ff323232ff363636ff515151ff646464ff656565ff636363ff636363ff636363ff626262ff484848ff464646ff464646ff464646ff484848ff454545ff3d3d3dff353535ff343434ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff343434ff303030ff3f3f3fff575757ff666666ff656565ff646464ff626262ff424242ff464646ff474747ff454545ff3a3a3aff343434ff353535ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff303030ff373737ff535353ff636363ff656565ff636363ff626262ff484848ff464646ff474747ff454545ff3e3e3eff353535ff343434ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff333333ff484848ff606060ff696969ff626262ff434343ff474747ff3e3e3eff363636ff353535ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff353535ff343434ff333333ff3e3e3eff5d5d5dff686868ff626262ff484848ff474747ff424242ff373737ff353535ff353535ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff323232ff323232ff505050ff616161ff3d3d3dff373737ff343434ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff343434ff313131ff434343ff606060ff464646ff383838ff343434ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff3a3a3aff2b2b2bff1e1e1eff2d2d2dff383838ff373737ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff393939ff323232ff1c1c1cff262626ff373737ff383838ff353535ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff363636ff353535ff373737ff383838ff303030ff191919ff080808ff101010ff141414ff1a1a1aff303030ff383838ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff363636ff353535ff363636ff383838ff363636ff1d1d1dff0b0b0bff0c0c0cff141414ff181818ff292929ff373737ff373737ff363636ff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff363636ff353535ff393939ff363636ff222222ff0c0c0cff0a0a0aff0c0c0cff121212ff171717ff151515ff161616ff212121ff353535ff393939ff363636ff363636ff363636ff363636ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff363636ff363636ff353535ff383838ff3a3a3aff262626ff121212ff0a0a0aff0c0c0cff0f0f0fff171717ff151515ff151515ff1e1e1eff2f2f2fff3a3a3aff363636ff363636ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff363636ff363636ff363636ff383838ff363636ff262626ff0d0d0dff090909ff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff141414ff151515ff232323ff353535ff383838ff363636ff353535ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff353535ff383838ff383838ff292929ff131313ff080808ff0c0c0cff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff151515ff131313ff202020ff313131ff383838ff363636ff363636ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9343434ff353535ff363636ff3a3a3aff2e2e2eff131313ff0a0a0aff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff161616ff141414ff1a1a1aff2a2a2aff393939ff373737ff363636ff363636ff363636a537373705ffffff0135353521363636ff363636ff363636ff3a3a3aff313131ff1c1c1cff0a0a0aff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff161616ff151515ff161616ff282828ff363636ff383838ff363636ff333333ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444a9353535ff383838ff313131ff151515ff080808ff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff161616ff131313ff1b1b1bff2d2d2dff373737ff373737ff363636a537373705ffffff0134343421363636ff383838ff333333ff1e1e1eff090909ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff131313ff171717ff2a2a2aff363636ff353535ff3d3d3ddbffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01444444af353535ff1e1e1eff0d0d0dff0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff151515ff222222ff333333ff353535ad30303007ffffff0134343423373737ff282828ff0d0d0dff0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff141414ff1b1b1bff2e2e2eff3e3e3ee1ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013e3e3e6f0f0f0fd5040404ff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff101010ff0e0e0ee72f2f2f7347474703ffffff013b3b3b13141414cd050505f70a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff121212ff0c0c0cf12a2a2aa5ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015f5f5f052020202b1a1a1aa1080808f1070707ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff141414ff0c0c0cff212121af2a2a2a496d6d6d07ffffff01ffffff01ffffff01333333231d1d1d730b0b0beb060606ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff171717ff171717ff151515ff0e0e0eff181818d72626265546464615ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014d4d4d29121212af080808ef0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff171717ff141414ff121212f9141414b93b3b3b4fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0138383819151515890a0a0ae5080808ff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff171717ff161616ff101010fb151515d72c2c2c614444440dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0133333311262626510f0f0fd7050505ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff121212ff171717ff171717ff171717ff171717ff171717ff101010ff141414e7242424733a3a3a19ffffff01ffffff01ffffff01878787097272725f4d4d4d736a6a6a11ffffff01ffffff01ffffff016060600524242445191919ad040404ff0a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff171717ff171717ff171717ff111111ff0e0e0efd242424873232322dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015c5c5c0d2525255f090909d7080808fb0b0b0bff0d0d0dff0c0c0cff121212ff171717ff171717ff161616ff121212ff121212df2121218965656511ffffff01ffffff01ffffff018080800d6767674b646464d1606060ff454545ff464646df4f4f4f6165656517ffffff01ffffff01ffffff01ffffff012d2d2d4b101010b5060606fb0a0a0aff0d0d0dff0d0d0dff0f0f0fff171717ff171717ff161616ff131313ff101010ef2020209d4242422dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012c2c2c2d1f1f1f83080808fb080808ff0d0d0dff121212ff171717ff141414ff0f0f0ff91e1e1eb12c2c2c354d4d4d09ffffff01ffffff01ffffff0178787825646464a75f5f5feb616161ff656565ff4a4a4aff414141ff424242f3414141bd69696937ffffff01ffffff01ffffff01ffffff0142424219171717710d0d0de3060606ff0c0c0cff0f0f0fff171717ff151515ff0d0d0dff171717c3292929575656560dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013737372d1212129d080808ef0d0d0dff121212f5191919bf2e2e2e3d70707003ffffff01ffffff018c8c8c037676762564646497606060ed606060ff636363ff636363ff656565ff4a4a4aff444444ff464646ff444444ff404040f74a4a4aad5555553162626207ffffff01ffffff01ffffff014040401125252589090909dd0a0a0aff121212ff141414c738383869ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015b5b5b0b1f1f1f591d1d1daf292929673f3f3f19ffffff01ffffff01ffffff01ffffff016d6d6d715f5f5fcd606060ff626262ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff454545ff434343ff414141db4f4f4f857b7b7b11ffffff01ffffff01ffffff0153535307222222331d1d1da91b1b1b8d4141412365656503ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff017c7c7c0f6868685d636363cb5e5e5eff626262ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff404040ff454545e14c4c4c6b69696917ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0177777733626262a3606060f3616161ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff424242f9454545b55d5d5d49ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014b4b4b0f5e5e5e85626262ff626262ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff444444ff414141ff454545a16464641dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0132323225333333cf4e4e4eff646464ff666666ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff474747ff404040ff303030e35757573bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd313131ff363636ff515151ff636363ff656565ff636363ff636363ff636363ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff464646ff464646ff464646ff464646ff464646ff414141ff373737ff343434ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff343434ff333333ff3c3c3cff5b5b5bff686868ff636363ff626262ff636363ff636363ff636363ff656565ff4a4a4aff444444ff464646ff464646ff454545ff464646ff4c4c4cff454545ff393939ff353535ff353535ff353535ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff353535ff313131ff3f3f3fff5d5d5dff666666ff646464ff626262ff636363ff656565ff4a4a4aff444444ff454545ff474747ff4a4a4aff404040ff212121ff2f2f2fff373737ff373737ff353535ff363636ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff353535ff333333ff363636ff484848ff646464ff676767ff626262ff656565ff4a4a4aff444444ff4b4b4bff4a4a4aff262626ff0b0b0bff090909ff171717ff252525ff353535ff393939ff363636ff323232e159595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff323232ff363636ff4c4c4cff646464ff676767ff4d4d4dff484848ff2c2c2cff0b0b0bff020202ff040404ff0b0b0bff171717ff141414ff161616ff282828ff353535ff343434e359595939ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff363636ff343434ff323232ff3f3f3fff5f5f5fff3a3a3aff161616ff030303ff030303ff050505ff040404ff0b0b0bff171717ff171717ff161616ff151515ff1a1a1aff242424e55555553bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff353535ff363636ff383838ff2e2e2eff191919ff262626ff111111ff030303ff030303ff050505ff040404ff0b0b0bff171717ff171717ff151515ff111111f9121212cd272727557d7d7d09ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff363636ff363636ff383838ff373737ff242424ff0b0b0bff0a0a0aff393939ff393939ff222222ff080808ff020202ff030303ff0b0b0bff181818ff0f0f0fff151515f32424247935353525ffffff01ffffff01ffffff01a3a3a30fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff363636ff363636ff363636ff383838ff373737ff272727ff0c0c0cff090909ff0c0c0cff0e0e0eff373737ff363636ff3a3a3aff393939ff1e1e1eff080808ff080808ff0f0f0feb232323914040401dffffff01ffffff01ffffff01ffffff01ffffff018282825d626262c36d6d6d4d8d8d8d09ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff363636ff353535ff363636ff3a3a3aff2f2f2fff131313ff0b0b0bff0b0b0bff0d0d0dff0c0c0cff0e0e0eff373737ff363636ff353535ff363636ff393939ff303030ff1c1c1cc92626264d68686807ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01868686515e5e5eff646464e9696969957878781fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723363636cd363636ff373737ff383838ff313131ff161616ff090909ff0b0b0bff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0e0e0eff373737ff363636ff363636ff363636ff353535ff353535ff3c3c3c8fffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0186868651616161ff676767ff646464ff656565f16a6a6a7d7f7f7f25ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0137373723353535cd393939ff373737ff1f1f1fff0d0d0dff0a0a0aff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0e0e0eff373737ff363636ff363636ff363636ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0186868651616161ff676767ff666666ff676767ff686868f9555555cd55555511ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0134343425323232cf212121ff0e0e0eff090909ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0e0e0eff383838ff363636ff363636ff363636ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0186868651616161ff686868ff696969ff5f5f5fff3d3d3dff303030ff4848481dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01474747132323238f020202ff080808ff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0c0c0cff2e2e2eff393939ff363636ff353535ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0185858551666666ff676767ff494949ff353535ff323232ff353535ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0130303045101010af080808f70a0a0aff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0d0d0dff131313ff1c1c1cff303030ff373737ff363636ff353535ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0181818151494949ff363636ff313131ff363636ff353535ff363636ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff0141414113191919690f0f0fdb060606ff0c0c0cff0d0d0dff0d0d0dff0d0d0dff0d0d0dff0c0c0cff0d0d0dff171717ff151515ff161616ff222222ff363636ff383838ff37373791ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff014d4d4d53272727c1242424ff373737ff373737ff353535ff353535ff363636ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01626262091c1c1c830b0b0bd7090909ff0c0c0cff0d0d0dff0d0d0dff0c0c0cff0d0d0dff171717ff171717ff171717ff141414ff151515ff202020ff35353595ffffff01ffffff01ffffff01ffffff017474740540404049343434af2a2a2aff262626ff101010ff191919ff2e2e2eff373737ff363636ff363636ff4e4e4e1bffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015a5a5a073636362d141414a7080808f5080808ff0d0d0dff0c0c0cff0d0d0dff171717ff171717ff171717ff151515ff0e0e0efb1b1b1bbb3d3d3d29ffffff01ffffff01ffffff0151515119393939892a2a2ae92d2d2dff323232ff282828ff141414ff151515ff151515ff1f1f1fff343434ff393939ff4949491dffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff013636362f111111b5070707f30a0a0aff0d0d0dff171717ff141414ff111111f5111111c74343433d70707005ffffff01ffffff017c7c7c034e4e4e632a2a2af7292929ff323232ff313131ff323232ff282828ff141414ff171717ff171717ff151515ff0e0e0efd222222e153535315ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff012d2d2d151f1f1f590e0e0edb040404ff0f0f0fff171717e7262626673f3f3f1dffffff01ffffff01ffffff01ffffff01ffffff01444444293535358b2d2d2deb2b2b2bff313131ff323232ff282828ff141414ff171717ff121212ff0d0d0dff2222229d2626263dbebebe03ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01505050112626266f1d1d1d7f36363617ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01616161213333339d2c2c2ce92f2f2fff282828ff111111ff111111f7191919ab3c3c3c41ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015151510b3b3b3b43383838c51f1f1fff141414d71e1e1e654f4f4f13ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff015858580b4d4d4d4159595909ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff01ffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000` diff --git a/swarm/api/http/test_server.go b/swarm/api/http/test_server.go deleted file mode 100644 index a3be01e992..0000000000 --- a/swarm/api/http/test_server.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package http - -import ( - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "testing" - - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" -) - -type TestServer interface { - ServeHTTP(http.ResponseWriter, *http.Request) -} - -func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, resolver api.Resolver) *TestSwarmServer { - swarmDir, err := ioutil.TempDir("", "swarm-storage-test") - if err != nil { - t.Fatal(err) - } - localStore, err := localstore.New(swarmDir, make([]byte, 32), nil) - if err != nil { - os.RemoveAll(swarmDir) - t.Fatal(err) - } - - tags := chunk.NewTags() - fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams(), tags) - - // Swarm feeds test setup - feedsDir, err := ioutil.TempDir("", "swarm-feeds-test") - if err != nil { - t.Fatal(err) - } - - feeds, err := feed.NewTestHandler(feedsDir, &feed.HandlerParams{}) - if err != nil { - t.Fatal(err) - } - - swarmApi := api.NewAPI(fileStore, resolver, feeds.Handler, nil, tags) - apiServer := httptest.NewServer(serverFunc(swarmApi)) - - tss := &TestSwarmServer{ - Server: apiServer, - FileStore: fileStore, - Tags: tags, - dir: swarmDir, - Hasher: storage.MakeHashFunc(storage.DefaultHash)(), - cleanup: func() { - apiServer.Close() - fileStore.Close() - feeds.Close() - os.RemoveAll(swarmDir) - os.RemoveAll(feedsDir) - }, - CurrentTime: 42, - } - feed.TimestampProvider = tss - return tss -} - -type TestSwarmServer struct { - *httptest.Server - Hasher storage.SwarmHash - FileStore *storage.FileStore - Tags *chunk.Tags - dir string - cleanup func() - CurrentTime uint64 -} - -func (t *TestSwarmServer) Close() { - t.cleanup() -} - -func (t *TestSwarmServer) Now() feed.Timestamp { - return feed.Timestamp{Time: t.CurrentTime} -} diff --git a/swarm/api/inspector.go b/swarm/api/inspector.go deleted file mode 100644 index c4151bf20a..0000000000 --- a/swarm/api/inspector.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -type Inspector struct { - api *API - hive *network.Hive - netStore *storage.NetStore -} - -func NewInspector(api *API, hive *network.Hive, netStore *storage.NetStore) *Inspector { - return &Inspector{api, hive, netStore} -} - -// Hive prints the kademlia table -func (inspector *Inspector) Hive() string { - return inspector.hive.String() -} - -func (inspector *Inspector) ListKnown() []string { - res := []string{} - for _, v := range inspector.hive.Kademlia.ListKnown() { - res = append(res, fmt.Sprintf("%v", v)) - } - return res -} - -func (inspector *Inspector) IsSyncing() bool { - lastReceivedChunksMsg := metrics.GetOrRegisterGauge("network.stream.received_chunks", nil) - - // last received chunks msg time - lrct := time.Unix(0, lastReceivedChunksMsg.Value()) - - // if last received chunks msg time is after now-15sec. (i.e. within the last 15sec.) then we say that the node is still syncing - // technically this is not correct, because this might have been a retrieve request, but for the time being it works for our purposes - // because we know we are not making retrieve requests on the node while checking this - return lrct.After(time.Now().Add(-15 * time.Second)) -} - -// Has checks whether each chunk address is present in the underlying datastore, -// the bool in the returned structs indicates if the underlying datastore has -// the chunk stored with the given address (true), or not (false) -func (inspector *Inspector) Has(chunkAddresses []storage.Address) string { - hostChunks := []string{} - for _, addr := range chunkAddresses { - has, err := inspector.netStore.Has(context.Background(), addr) - if err != nil { - log.Error(err.Error()) - } - if has { - hostChunks = append(hostChunks, "1") - } else { - hostChunks = append(hostChunks, "0") - } - } - - return strings.Join(hostChunks, "") -} diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go deleted file mode 100644 index d753b3f2e6..0000000000 --- a/swarm/api/manifest.go +++ /dev/null @@ -1,584 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "strings" - "time" - - "github.com/ethereum/go-ethereum/swarm/storage/feed" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -const ( - ManifestType = "application/bzz-manifest+json" - FeedContentType = "application/bzz-feed" - - manifestSizeLimit = 5 * 1024 * 1024 -) - -// Manifest represents a swarm manifest -type Manifest struct { - Entries []ManifestEntry `json:"entries,omitempty"` -} - -// ManifestEntry represents an entry in a swarm manifest -type ManifestEntry struct { - Hash string `json:"hash,omitempty"` - Path string `json:"path,omitempty"` - ContentType string `json:"contentType,omitempty"` - Mode int64 `json:"mode,omitempty"` - Size int64 `json:"size,omitempty"` - ModTime time.Time `json:"mod_time,omitempty"` - Status int `json:"status,omitempty"` - Access *AccessEntry `json:"access,omitempty"` - Feed *feed.Feed `json:"feed,omitempty"` -} - -// ManifestList represents the result of listing files in a manifest -type ManifestList struct { - CommonPrefixes []string `json:"common_prefixes,omitempty"` - Entries []*ManifestEntry `json:"entries,omitempty"` -} - -// NewManifest creates and stores a new, empty manifest -func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, error) { - var manifest Manifest - data, err := json.Marshal(&manifest) - if err != nil { - return nil, err - } - addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt) - if err != nil { - return nil, err - } - err = wait(ctx) - return addr, err -} - -// Manifest hack for supporting Swarm feeds from the bzz: scheme -// see swarm/api/api.go:API.Get() for more information -func (a *API) NewFeedManifest(ctx context.Context, feed *feed.Feed) (storage.Address, error) { - var manifest Manifest - entry := ManifestEntry{ - Feed: feed, - ContentType: FeedContentType, - } - manifest.Entries = append(manifest.Entries, entry) - data, err := json.Marshal(&manifest) - if err != nil { - return nil, err - } - addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), false) - if err != nil { - return nil, err - } - err = wait(ctx) - return addr, err -} - -// ManifestWriter is used to add and remove entries from an underlying manifest -type ManifestWriter struct { - api *API - trie *manifestTrie - quitC chan bool -} - -func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC chan bool) (*ManifestWriter, error) { - trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) - if err != nil { - return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) - } - return &ManifestWriter{a, trie, quitC}, nil -} - -// AddEntry stores the given data and adds the resulting address to the manifest -func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (addr storage.Address, err error) { - entry := newManifestTrieEntry(e, nil) - if data != nil { - var wait func(context.Context) error - addr, wait, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted) - if err != nil { - return nil, err - } - err = wait(ctx) - if err != nil { - return nil, err - } - entry.Hash = addr.Hex() - } - if entry.Hash == "" { - return addr, errors.New("missing entry hash") - } - m.trie.addEntry(entry, m.quitC) - return addr, nil -} - -// RemoveEntry removes the given path from the manifest -func (m *ManifestWriter) RemoveEntry(path string) error { - m.trie.deleteEntry(path, m.quitC) - return nil -} - -// Store stores the manifest, returning the resulting storage address -func (m *ManifestWriter) Store() (storage.Address, error) { - return m.trie.ref, m.trie.recalcAndStore() -} - -// ManifestWalker is used to recursively walk the entries in the manifest and -// all of its submanifests -type ManifestWalker struct { - api *API - trie *manifestTrie - quitC chan bool -} - -func (a *API) NewManifestWalker(ctx context.Context, addr storage.Address, decrypt DecryptFunc, quitC chan bool) (*ManifestWalker, error) { - trie, err := loadManifest(ctx, a.fileStore, addr, quitC, decrypt) - if err != nil { - return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) - } - return &ManifestWalker{a, trie, quitC}, nil -} - -// ErrSkipManifest is used as a return value from WalkFn to indicate that the -// manifest should be skipped -var ErrSkipManifest = errors.New("skip this manifest") - -// WalkFn is the type of function called for each entry visited by a recursive -// manifest walk -type WalkFn func(entry *ManifestEntry) error - -// Walk recursively walks the manifest calling walkFn for each entry in the -// manifest, including submanifests -func (m *ManifestWalker) Walk(walkFn WalkFn) error { - return m.walk(m.trie, "", walkFn) -} - -func (m *ManifestWalker) walk(trie *manifestTrie, prefix string, walkFn WalkFn) error { - for _, entry := range &trie.entries { - if entry == nil { - continue - } - entry.Path = prefix + entry.Path - err := walkFn(&entry.ManifestEntry) - if err != nil { - if entry.ContentType == ManifestType && err == ErrSkipManifest { - continue - } - return err - } - if entry.ContentType != ManifestType { - continue - } - if err := trie.loadSubTrie(entry, nil); err != nil { - return err - } - if err := m.walk(entry.subtrie, entry.Path, walkFn); err != nil { - return err - } - } - return nil -} - -type manifestTrie struct { - fileStore *storage.FileStore - entries [257]*manifestTrieEntry // indexed by first character of basePath, entries[256] is the empty basePath entry - ref storage.Address // if ref != nil, it is stored - encrypted bool - decrypt DecryptFunc -} - -func newManifestTrieEntry(entry *ManifestEntry, subtrie *manifestTrie) *manifestTrieEntry { - return &manifestTrieEntry{ - ManifestEntry: *entry, - subtrie: subtrie, - } -} - -type manifestTrieEntry struct { - ManifestEntry - - subtrie *manifestTrie -} - -func loadManifest(ctx context.Context, fileStore *storage.FileStore, addr storage.Address, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand - log.Trace("manifest lookup", "addr", addr) - // retrieve manifest via FileStore - manifestReader, isEncrypted := fileStore.Retrieve(ctx, addr) - log.Trace("reader retrieved", "addr", addr) - return readManifest(manifestReader, addr, fileStore, isEncrypted, quitC, decrypt) -} - -func readManifest(mr storage.LazySectionReader, addr storage.Address, fileStore *storage.FileStore, isEncrypted bool, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand - // TODO check size for oversized manifests - size, err := mr.Size(mr.Context(), quitC) - if err != nil { // size == 0 - // can't determine size means we don't have the root chunk - log.Trace("manifest not found", "addr", addr) - err = fmt.Errorf("Manifest not Found") - return - } - if size > manifestSizeLimit { - log.Warn("manifest exceeds size limit", "addr", addr, "size", size, "limit", manifestSizeLimit) - err = fmt.Errorf("Manifest size of %v bytes exceeds the %v byte limit", size, manifestSizeLimit) - return - } - manifestData := make([]byte, size) - read, err := mr.Read(manifestData) - if int64(read) < size { - log.Trace("manifest not found", "addr", addr) - if err == nil { - err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size) - } - return - } - - log.Debug("manifest retrieved", "addr", addr) - var man struct { - Entries []*manifestTrieEntry `json:"entries"` - } - err = json.Unmarshal(manifestData, &man) - if err != nil { - err = fmt.Errorf("Manifest %v is malformed: %v", addr.Log(), err) - log.Trace("malformed manifest", "addr", addr) - return - } - - log.Trace("manifest entries", "addr", addr, "len", len(man.Entries)) - - trie = &manifestTrie{ - fileStore: fileStore, - encrypted: isEncrypted, - decrypt: decrypt, - } - for _, entry := range man.Entries { - err = trie.addEntry(entry, quitC) - if err != nil { - return - } - } - return -} - -func (mt *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) error { - mt.ref = nil // trie modified, hash needs to be re-calculated on demand - - if entry.ManifestEntry.Access != nil { - if mt.decrypt == nil { - return errors.New("dont have decryptor") - } - - err := mt.decrypt(&entry.ManifestEntry) - if err != nil { - return err - } - } - - if len(entry.Path) == 0 { - mt.entries[256] = entry - return nil - } - - b := entry.Path[0] - oldentry := mt.entries[b] - if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) { - mt.entries[b] = entry - return nil - } - - cpl := 0 - for (len(entry.Path) > cpl) && (len(oldentry.Path) > cpl) && (entry.Path[cpl] == oldentry.Path[cpl]) { - cpl++ - } - - if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) { - if mt.loadSubTrie(oldentry, quitC) != nil { - return nil - } - entry.Path = entry.Path[cpl:] - oldentry.subtrie.addEntry(entry, quitC) - oldentry.Hash = "" - return nil - } - - commonPrefix := entry.Path[:cpl] - - subtrie := &manifestTrie{ - fileStore: mt.fileStore, - encrypted: mt.encrypted, - } - entry.Path = entry.Path[cpl:] - oldentry.Path = oldentry.Path[cpl:] - subtrie.addEntry(entry, quitC) - subtrie.addEntry(oldentry, quitC) - - mt.entries[b] = newManifestTrieEntry(&ManifestEntry{ - Path: commonPrefix, - ContentType: ManifestType, - }, subtrie) - return nil -} - -func (mt *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) { - for _, e := range &mt.entries { - if e != nil { - cnt++ - entry = e - } - } - return -} - -func (mt *manifestTrie) deleteEntry(path string, quitC chan bool) { - mt.ref = nil // trie modified, hash needs to be re-calculated on demand - - if len(path) == 0 { - mt.entries[256] = nil - return - } - - b := path[0] - entry := mt.entries[b] - if entry == nil { - return - } - if entry.Path == path { - mt.entries[b] = nil - return - } - - epl := len(entry.Path) - if (entry.ContentType == ManifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) { - if mt.loadSubTrie(entry, quitC) != nil { - return - } - entry.subtrie.deleteEntry(path[epl:], quitC) - entry.Hash = "" - // remove subtree if it has less than 2 elements - cnt, lastentry := entry.subtrie.getCountLast() - if cnt < 2 { - if lastentry != nil { - lastentry.Path = entry.Path + lastentry.Path - } - mt.entries[b] = lastentry - } - } -} - -func (mt *manifestTrie) recalcAndStore() error { - if mt.ref != nil { - return nil - } - - var buffer bytes.Buffer - buffer.WriteString(`{"entries":[`) - - list := &Manifest{} - for _, entry := range &mt.entries { - if entry != nil { - if entry.Hash == "" { // TODO: paralellize - err := entry.subtrie.recalcAndStore() - if err != nil { - return err - } - entry.Hash = entry.subtrie.ref.Hex() - } - list.Entries = append(list.Entries, entry.ManifestEntry) - } - - } - - manifest, err := json.Marshal(list) - if err != nil { - return err - } - - sr := bytes.NewReader(manifest) - ctx := context.TODO() - addr, wait, err2 := mt.fileStore.Store(ctx, sr, int64(len(manifest)), mt.encrypted) - if err2 != nil { - return err2 - } - err2 = wait(ctx) - mt.ref = addr - return err2 -} - -func (mt *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) { - if entry.ManifestEntry.Access != nil { - if mt.decrypt == nil { - return errors.New("dont have decryptor") - } - - err := mt.decrypt(&entry.ManifestEntry) - if err != nil { - return err - } - } - - if entry.subtrie == nil { - hash := common.Hex2Bytes(entry.Hash) - entry.subtrie, err = loadManifest(context.TODO(), mt.fileStore, hash, quitC, mt.decrypt) - entry.Hash = "" // might not match, should be recalculated - } - return -} - -func (mt *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error { - plen := len(prefix) - var start, stop int - if plen == 0 { - start = 0 - stop = 256 - } else { - start = int(prefix[0]) - stop = start - } - - for i := start; i <= stop; i++ { - select { - case <-quitC: - return fmt.Errorf("aborted") - default: - } - entry := mt.entries[i] - if entry != nil { - epl := len(entry.Path) - if entry.ContentType == ManifestType { - l := plen - if epl < l { - l = epl - } - if prefix[:l] == entry.Path[:l] { - err := mt.loadSubTrie(entry, quitC) - if err != nil { - return err - } - err = entry.subtrie.listWithPrefixInt(prefix[l:], rp+entry.Path[l:], quitC, cb) - if err != nil { - return err - } - } - } else { - if (epl >= plen) && (prefix == entry.Path[:plen]) { - cb(entry, rp+entry.Path[plen:]) - } - } - } - } - return nil -} - -func (mt *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) { - return mt.listWithPrefixInt(prefix, "", quitC, cb) -} - -func (mt *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) { - log.Trace(fmt.Sprintf("findPrefixOf(%s)", path)) - - if len(path) == 0 { - return mt.entries[256], 0 - } - - //see if first char is in manifest entries - b := path[0] - entry = mt.entries[b] - if entry == nil { - return mt.entries[256], 0 - } - - epl := len(entry.Path) - log.Trace(fmt.Sprintf("path = %v entry.Path = %v epl = %v", path, entry.Path, epl)) - if len(path) <= epl { - if entry.Path[:len(path)] == path { - if entry.ContentType == ManifestType { - err := mt.loadSubTrie(entry, quitC) - if err == nil && entry.subtrie != nil { - subentries := entry.subtrie.entries - for i := 0; i < len(subentries); i++ { - sub := subentries[i] - if sub != nil && sub.Path == "" { - return sub, len(path) - } - } - } - entry.Status = http.StatusMultipleChoices - } - pos = len(path) - return - } - return nil, 0 - } - if path[:epl] == entry.Path { - log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType)) - //the subentry is a manifest, load subtrie - if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) { - err := mt.loadSubTrie(entry, quitC) - if err != nil { - return nil, 0 - } - sub, pos := entry.subtrie.findPrefixOf(path[epl:], quitC) - if sub != nil { - entry = sub - pos += epl - return sub, pos - } else if path == entry.Path { - entry.Status = http.StatusMultipleChoices - } - - } else { - //entry is not a manifest, return it - if path != entry.Path { - return nil, 0 - } - } - } - return nil, 0 -} - -// file system manifest always contains regularized paths -// no leading or trailing slashes, only single slashes inside -func RegularSlashes(path string) (res string) { - for i := 0; i < len(path); i++ { - if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) { - res = res + path[i:i+1] - } - } - if (len(res) > 0) && (res[len(res)-1] == '/') { - res = res[:len(res)-1] - } - return -} - -func (mt *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) { - path := RegularSlashes(spath) - var pos int - quitC := make(chan bool) - entry, pos = mt.findPrefixOf(path, quitC) - return entry, path[:pos] -} diff --git a/swarm/api/manifest_test.go b/swarm/api/manifest_test.go deleted file mode 100644 index c193ebcb4d..0000000000 --- a/swarm/api/manifest_test.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -func manifest(paths ...string) (manifestReader storage.LazySectionReader) { - var entries []string - for _, path := range paths { - entry := fmt.Sprintf(`{"path":"%s"}`, path) - entries = append(entries, entry) - } - manifest := fmt.Sprintf(`{"entries":[%s]}`, strings.Join(entries, ",")) - return &storage.LazyTestSectionReader{ - SectionReader: io.NewSectionReader(strings.NewReader(manifest), 0, int64(len(manifest))), - } -} - -func testGetEntry(t *testing.T, path, match string, multiple bool, paths ...string) *manifestTrie { - quitC := make(chan bool) - fileStore := storage.NewFileStore(nil, storage.NewFileStoreParams(), chunk.NewTags()) - ref := make([]byte, fileStore.HashSize()) - trie, err := readManifest(manifest(paths...), ref, fileStore, false, quitC, NOOPDecrypt) - if err != nil { - t.Errorf("unexpected error making manifest: %v", err) - } - checkEntry(t, path, match, multiple, trie) - return trie -} - -func checkEntry(t *testing.T, path, match string, multiple bool, trie *manifestTrie) { - entry, fullpath := trie.getEntry(path) - if match == "-" && entry != nil { - t.Errorf("expected no match for '%s', got '%s'", path, fullpath) - } else if entry == nil { - if match != "-" { - t.Errorf("expected entry '%s' to match '%s', got no match", match, path) - } - } else if fullpath != match { - t.Errorf("incorrect entry retrieved for '%s'. expected path '%v', got '%s'", path, match, fullpath) - } - - if multiple && entry.Status != http.StatusMultipleChoices { - t.Errorf("Expected %d Multiple Choices Status for path %s, match %s, got %d", http.StatusMultipleChoices, path, match, entry.Status) - } else if !multiple && entry != nil && entry.Status == http.StatusMultipleChoices { - t.Errorf("Were not expecting %d Multiple Choices Status for path %s, match %s, but got it", http.StatusMultipleChoices, path, match) - } -} - -func TestGetEntry(t *testing.T) { - // file system manifest always contains regularized paths - testGetEntry(t, "a", "a", false, "a") - testGetEntry(t, "b", "-", false, "a") - testGetEntry(t, "/a//", "a", false, "a") - // fallback - testGetEntry(t, "/a", "", false, "") - testGetEntry(t, "/a/b", "a/b", false, "a/b") - // longest/deepest math - testGetEntry(t, "read", "read", true, "readme.md", "readit.md") - testGetEntry(t, "rf", "-", false, "readme.md", "readit.md") - testGetEntry(t, "readme", "readme", false, "readme.md") - testGetEntry(t, "readme", "-", false, "readit.md") - testGetEntry(t, "readme.md", "readme.md", false, "readme.md") - testGetEntry(t, "readme.md", "-", false, "readit.md") - testGetEntry(t, "readmeAmd", "-", false, "readit.md") - testGetEntry(t, "readme.mdffff", "-", false, "readme.md") - testGetEntry(t, "ab", "ab", true, "ab/cefg", "ab/cedh", "ab/kkkkkk") - testGetEntry(t, "ab/ce", "ab/ce", true, "ab/cefg", "ab/cedh", "ab/ceuuuuuuuuuu") - testGetEntry(t, "abc", "abc", true, "abcd", "abczzzzef", "abc/def", "abc/e/g") - testGetEntry(t, "a/b", "a/b", true, "a", "a/bc", "a/ba", "a/b/c") - testGetEntry(t, "a/b", "a/b", false, "a", "a/b", "a/bb", "a/b/c") - testGetEntry(t, "//a//b//", "a/b", false, "a", "a/b", "a/bb", "a/b/c") -} - -func TestExactMatch(t *testing.T) { - quitC := make(chan bool) - mf := manifest("shouldBeExactMatch.css", "shouldBeExactMatch.css.map") - fileStore := storage.NewFileStore(nil, storage.NewFileStoreParams(), chunk.NewTags()) - ref := make([]byte, fileStore.HashSize()) - trie, err := readManifest(mf, ref, fileStore, false, quitC, nil) - if err != nil { - t.Errorf("unexpected error making manifest: %v", err) - } - entry, _ := trie.getEntry("shouldBeExactMatch.css") - if entry.Path != "" { - t.Errorf("Expected entry to match %s, got: %s", "shouldBeExactMatch.css", entry.Path) - } - if entry.Status == http.StatusMultipleChoices { - t.Errorf("Got status %d, which is unexepcted", http.StatusMultipleChoices) - } -} - -func TestDeleteEntry(t *testing.T) { - -} - -// TestAddFileWithManifestPath tests that adding an entry at a path which -// already exists as a manifest just adds the entry to the manifest rather -// than replacing the manifest with the entry -func TestAddFileWithManifestPath(t *testing.T) { - // create a manifest containing "ab" and "ac" - manifest, _ := json.Marshal(&Manifest{ - Entries: []ManifestEntry{ - {Path: "ab", Hash: "ab"}, - {Path: "ac", Hash: "ac"}, - }, - }) - reader := &storage.LazyTestSectionReader{ - SectionReader: io.NewSectionReader(bytes.NewReader(manifest), 0, int64(len(manifest))), - } - fileStore := storage.NewFileStore(nil, storage.NewFileStoreParams(), chunk.NewTags()) - ref := make([]byte, fileStore.HashSize()) - trie, err := readManifest(reader, ref, fileStore, false, nil, NOOPDecrypt) - if err != nil { - t.Fatal(err) - } - checkEntry(t, "ab", "ab", false, trie) - checkEntry(t, "ac", "ac", false, trie) - - // now add path "a" and check we can still get "ab" and "ac" - entry := &manifestTrieEntry{} - entry.Path = "a" - entry.Hash = "a" - trie.addEntry(entry, nil) - checkEntry(t, "ab", "ab", false, trie) - checkEntry(t, "ac", "ac", false, trie) - checkEntry(t, "a", "a", false, trie) -} - -// TestReadManifestOverSizeLimit creates a manifest reader with data longer then -// manifestSizeLimit and checks if readManifest function will return the exact error -// message. -// The manifest data is not in json-encoded format, preventing possbile -// successful parsing attempts if limit check fails. -func TestReadManifestOverSizeLimit(t *testing.T) { - manifest := make([]byte, manifestSizeLimit+1) - reader := &storage.LazyTestSectionReader{ - SectionReader: io.NewSectionReader(bytes.NewReader(manifest), 0, int64(len(manifest))), - } - _, err := readManifest(reader, storage.Address{}, nil, false, nil, NOOPDecrypt) - if err == nil { - t.Fatal("got no error from readManifest") - } - // Error message is part of the http response body - // which justifies exact string validation. - got := err.Error() - want := fmt.Sprintf("Manifest size of %v bytes exceeds the %v byte limit", len(manifest), manifestSizeLimit) - if got != want { - t.Fatalf("got error mesage %q, expected %q", got, want) - } -} diff --git a/swarm/api/testdata/test0/img/logo.png b/swarm/api/testdata/test0/img/logo.png deleted file mode 100644 index 9557f960535d520687f69a9a65b35e3637828dd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4119 zcmZ`+do)z*`yVr7W-!bM$ECrRODHiUOk&0v43%))b0kSoRD+_zm{E-!?8dzgxlAOC z&~1>S=`=36*Bs?i8XdQDL`4YSP3yPT`F+>={;}7ypXYs^&-?j2`+fIXPqM3vqpY-= zGz%m}*Bp7T7 z3NglEuxJw)Y%&lABjv(i%BO#?ce92T;6ZyGsj#&x=^alX4;|&S-yS_Gr7VNSB^kxG z!eBT}Co07w=FQ(jds2?HDxuyj%C}%UP=8=8eWdI3Rdn~_rjAn{G`DV1*?KvJb;ebn zXnC5IajD2Ou_o9AGgx?BK0m6ofNPeR;X*~rD3kD)B@EoXg^IkEi9!|-i< z7gerDG>{aTZz{Z}!3_kt$??eE$AMsGay-^3c~siYL?i_z5|RRV3dp=a8Bn5qv4{n>N7I3<zM z#CMSm4#M>w1ILqxF}><$v}x)olvTqqP?$W7?Nv9WiK(X~iZZ7%$!8V3K^vA}|Ce2O zJH87hxMYwrE+%P#d1y?&e;I;ac9AR;lT^V!s1~pZGnxQ0MVu)Q@~$@JBpUA*iM&`A zzBPIaaIQ@=$${4g3*8%KwhrhVWrp9xcYz0&1d{c|Bq>l8kGb@WuSot!Q4y2aUM<({HY`yy7$xIw!XByjybJspslHnnfs|!hi)vWg6?bCh z{2k?Ly*>etBGs*g+mW{?5wmI z>B~EU$om6rpn|mSc}zb2YkaDVz`SRL>^er;0dC8JBVUb)Zj+s}P{_Vpn{Sg#%gHD# z{Kj|_z^1Fq3qvyHkOz3$@VtsBAcn4vqm{ce3tOYDfsA_q0%hfIVQ7TO_J08%%^Al7 zG`hNs(Ek>S!kMB$h#E*op0-3@AWYQ+<5B#KQ7DX71csC4kW4L+8>2%>4v*!hNpL-U z$apac1xjf^pO>LSQlTyFwdiG$bw~u-TzhpNt3yc-6sP;?pbeCEfc^XewP1^8RIhC~ zxcQQ-&KcfT)PVj)AT)9hQHa%|z41RFLoYL7>b(5Q1p<@hu)VgPP@;m)QC=BxK)(`@ zirk|s#2V3B{10I0WuKVb_ODR@m@J3uwcP`5c1@p2SYE1#kmDC%kvn_VR)<8zpX&~N zH)Q!AK*4jz6Bc=*sbrV3zC}Jm!N5fZxufUGlZmey6jHu%6H>wUHfeDc-V$k z_IWPHmEW{S3!h6}TTMT-aJ~yl%ONk?*rjsG32JL!mo;e%w3&R60=?q6_R27(xq*zlTnllE`0>csGNF;PiKI<$XYJ>|hIT2K(@6)Y(V|Hv)#dmTW z%;_Io(C;%9)8tYK4goGO8A%x=XKQf?7=iwX@n?AG{-`n?G=eBxpz$?i#D+8uf_d++ zhBhfKHbYzpR4q2OVS?54S`#ULbB~4SU{(Fr_Y}3yE2hfe8|uRTIXob{sG%)7#N8Xk z(7_?xZ_XIvKvN&i6?pl}1<#*=zCb4pIj-JF3W1#co@1>~JKA)p8*Swr^;8Fkb-y;# z9JyjIre4`U_YQcm81JIa#pa3S$!T+OPK01J)7BD(b^C%uIC!*MCtZ>b&M0S63V2m= z8RA*;{M??CJTxi~s?7y#$Cj;r1x-(LUP#8aE$I4!PVaQmW#_;d#2vt*D8pI;Iup-x zv?BND2t&T@ug=k2KO+@JPN3$<*E!@wqp!kCu>DjdGIqtd{>V%jZXmJo{FB#Fl+l&p ztCDk52j@n9wu!%i6HaN?ek)ylAFcsZ49izG`hbZIkfETcK@%;zJIqoWNortK=0f;_|9Lc&2R;Xnr(bTYdGZ;Nu#2 z%Wpc!Gwl-)Z9eMdwi0yvtAA>Qwr5&5aNm4%%(vTOu!TA8;QX>pKdS_`8t%DpvkB8k z+;;kQj{*-tz>$TQKC_mL+2Lc-?rY=M62|lc zPY8l>st&`>r0U0`ZywSW3(ZHH)g~`e438ZGA>h~SiQ$yA#{=~fdB|!A_ceQnowHpJ zRh}2OvdvM#N4uc+^HBIHH!JTnIM2b_2a&&9Sh_f?EoyUn`ifnyH%tYpx>$VAGL<-`Du)x}rebb6~2?4fcvHwRJcOaOfKK z^Gbu4I_#Uj8|R15IOk&o?dh(qmml*Bvof_{?m;<0l9n2S2Pzcc#27VEEnN|B9`rrj z=Qw%N#%rBZp~F7w*;2`YRIEJ~s&&=YD~Rc1dYtT^yF<8?keWMPq9}(i84xwn6^G4( z=8`SUg%M#pdIPMaN7QOIFTax@fs?6zysVN>Rq}l&pV>(Uk(Sjw(^~2rs3xGa3Hi2c~Plk;DfZr$SE zL_=Ct* z>Z*4O2eK)XqF*n9w?aTzT{YKsb`&|V{{s{I0NZQ2{D-7(C`!t7*?CF9*bDz~KqSlU z#`ZS-ZsX+yMf~t(10pH0pBcNS{wkt)CrhQXDMJNd8L^UX#ObaiE1R)b9E>i2H6bA5 z2Q&(5T{s0i`K%Zbbb&_cy%}?jDISs~es_G!QyDv)CMT&%2x@%yox;^)oLs$rAZBa8Cg6{{YNF8Hj4kqe z%KXioMa^5Mkt59>(2_I*>y%j3>v1p1J9e^Qm8yzDS2J2A1UY!wUO^CCk_}1U1SjUk z>Anp2@u0lH8PFh!y5M}OALo;!!BwDYLqab+6w(HzBvJf+bb$zF|3FdYE`m%5g@Xtk zysg`+Ze57$wcKdkp7oQqj#3ZEZlJg$%WrO=^iw8(Y~%#Kfl>yWS^LP7A%~nIH~$m| z)*#-_JT9B2%t7}|O{(a|_lc=`1WxI6}Qu{cm} z3!nsT#FyQs41V~5q9#5*pSAPh;W5PA_YIo8s92k2=j(6pn!;n}Yn-9hma_<*O`MOr zDt{--S%j^B;aHHhp)E^UxT+=TlrVY=SNp_muRAI1hLLc1gM=01`_5(O7R_69cM%Y4+p<1 z|62XOSv0_LY7O?+U}hm`xC%|rx>5E%QNf3!j*^bhk3t4!YC^O$GO;o;HS-`6NhTH~ qqWLxx6OxI^pkGJk|0@VT6&xB8`@ajS&{6tO0nEwXh03!FWc~*<+c;7H diff --git a/swarm/api/testdata/test0/index.css b/swarm/api/testdata/test0/index.css deleted file mode 100644 index 693b13a37c..0000000000 --- a/swarm/api/testdata/test0/index.css +++ /dev/null @@ -1,9 +0,0 @@ -h1 { - color: black; - font-size: 12px; - background-color: orange; - border: 4px solid black; -} -body { - background-color: orange -} diff --git a/swarm/api/testdata/test0/index.html b/swarm/api/testdata/test0/index.html deleted file mode 100644 index 321e910d7a..0000000000 --- a/swarm/api/testdata/test0/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - -

Swarm Test

- Ethereum logo - - \ No newline at end of file diff --git a/swarm/api/uri.go b/swarm/api/uri.go deleted file mode 100644 index 09cfa45020..0000000000 --- a/swarm/api/uri.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "fmt" - "net/url" - "regexp" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -//matches hex swarm hashes -// TODO: this is bad, it should not be hardcoded how long is a hash -var hashMatcher = regexp.MustCompile("^([0-9A-Fa-f]{64})([0-9A-Fa-f]{64})?$") - -// URI is a reference to content stored in swarm. -type URI struct { - // Scheme has one of the following values: - // - // * bzz - an entry in a swarm manifest - // * bzz-raw - raw swarm content - // * bzz-immutable - immutable URI of an entry in a swarm manifest - // (address is not resolved) - // * bzz-list - list of all files contained in a swarm manifest - // - Scheme string - - // Addr is either a hexadecimal storage address or it an address which - // resolves to a storage address - Addr string - - // addr stores the parsed storage address - addr storage.Address - - // Path is the path to the content within a swarm manifest - Path string -} - -func (u *URI) MarshalJSON() (out []byte, err error) { - return []byte(`"` + u.String() + `"`), nil -} - -func (u *URI) UnmarshalJSON(value []byte) error { - uri, err := Parse(string(value)) - if err != nil { - return err - } - *u = *uri - return nil -} - -// Parse parses rawuri into a URI struct, where rawuri is expected to have one -// of the following formats: -// -// * :/ -// * :/ -// * :// -// * :// -// * :// -// * :/// -// -// with scheme one of bzz, bzz-raw, bzz-immutable, bzz-list or bzz-hash -func Parse(rawuri string) (*URI, error) { - u, err := url.Parse(rawuri) - if err != nil { - return nil, err - } - uri := &URI{Scheme: u.Scheme} - - // check the scheme is valid - switch uri.Scheme { - case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-feed": - default: - return nil, fmt.Errorf("unknown scheme %q", u.Scheme) - } - - // handle URIs like bzz:/// where the addr and path - // have already been split by url.Parse - if u.Host != "" { - uri.Addr = u.Host - uri.Path = strings.TrimLeft(u.Path, "/") - return uri, nil - } - - // URI is like bzz:// so split the addr and path from - // the raw path (which will be //) - parts := strings.SplitN(strings.TrimLeft(u.Path, "/"), "/", 2) - uri.Addr = parts[0] - if len(parts) == 2 { - uri.Path = parts[1] - } - return uri, nil -} -func (u *URI) Feed() bool { - return u.Scheme == "bzz-feed" -} - -func (u *URI) Raw() bool { - return u.Scheme == "bzz-raw" -} - -func (u *URI) Immutable() bool { - return u.Scheme == "bzz-immutable" -} - -func (u *URI) List() bool { - return u.Scheme == "bzz-list" -} - -func (u *URI) Hash() bool { - return u.Scheme == "bzz-hash" -} - -func (u *URI) String() string { - return u.Scheme + ":/" + u.Addr + "/" + u.Path -} - -func (u *URI) Address() storage.Address { - if u.addr != nil { - return u.addr - } - if hashMatcher.MatchString(u.Addr) { - u.addr = common.Hex2Bytes(u.Addr) - return u.addr - } - return nil -} diff --git a/swarm/api/uri_test.go b/swarm/api/uri_test.go deleted file mode 100644 index a03874c433..0000000000 --- a/swarm/api/uri_test.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package api - -import ( - "bytes" - "reflect" - "testing" - - "github.com/ethereum/go-ethereum/swarm/storage" -) - -func TestParseURI(t *testing.T) { - type test struct { - uri string - expectURI *URI - expectErr bool - expectRaw bool - expectImmutable bool - expectList bool - expectHash bool - expectValidKey bool - expectAddr storage.Address - } - tests := []test{ - { - uri: "", - expectErr: true, - }, - { - uri: "foo", - expectErr: true, - }, - { - uri: "bzz", - expectErr: true, - }, - { - uri: "bzz:", - expectURI: &URI{Scheme: "bzz"}, - }, - { - uri: "bzz-immutable:", - expectURI: &URI{Scheme: "bzz-immutable"}, - expectImmutable: true, - }, - { - uri: "bzz-raw:", - expectURI: &URI{Scheme: "bzz-raw"}, - expectRaw: true, - }, - { - uri: "bzz:/", - expectURI: &URI{Scheme: "bzz"}, - }, - { - uri: "bzz:/abc123", - expectURI: &URI{Scheme: "bzz", Addr: "abc123"}, - }, - { - uri: "bzz:/abc123/path/to/entry", - expectURI: &URI{Scheme: "bzz", Addr: "abc123", Path: "path/to/entry"}, - }, - { - uri: "bzz-raw:/", - expectURI: &URI{Scheme: "bzz-raw"}, - expectRaw: true, - }, - { - uri: "bzz-raw:/abc123", - expectURI: &URI{Scheme: "bzz-raw", Addr: "abc123"}, - expectRaw: true, - }, - { - uri: "bzz-raw:/abc123/path/to/entry", - expectURI: &URI{Scheme: "bzz-raw", Addr: "abc123", Path: "path/to/entry"}, - expectRaw: true, - }, - { - uri: "bzz://", - expectURI: &URI{Scheme: "bzz"}, - }, - { - uri: "bzz://abc123", - expectURI: &URI{Scheme: "bzz", Addr: "abc123"}, - }, - { - uri: "bzz://abc123/path/to/entry", - expectURI: &URI{Scheme: "bzz", Addr: "abc123", Path: "path/to/entry"}, - }, - { - uri: "bzz-hash:", - expectURI: &URI{Scheme: "bzz-hash"}, - expectHash: true, - }, - { - uri: "bzz-hash:/", - expectURI: &URI{Scheme: "bzz-hash"}, - expectHash: true, - }, - { - uri: "bzz-list:", - expectURI: &URI{Scheme: "bzz-list"}, - expectList: true, - }, - { - uri: "bzz-list:/", - expectURI: &URI{Scheme: "bzz-list"}, - expectList: true, - }, - { - uri: "bzz-raw://4378d19c26590f1a818ed7d6a62c3809e149b0999cab5ce5f26233b3b423bf8c", - expectURI: &URI{Scheme: "bzz-raw", - Addr: "4378d19c26590f1a818ed7d6a62c3809e149b0999cab5ce5f26233b3b423bf8c", - }, - expectValidKey: true, - expectRaw: true, - expectAddr: storage.Address{67, 120, 209, 156, 38, 89, 15, 26, - 129, 142, 215, 214, 166, 44, 56, 9, - 225, 73, 176, 153, 156, 171, 92, 229, - 242, 98, 51, 179, 180, 35, 191, 140, - }, - }, - } - for _, x := range tests { - actual, err := Parse(x.uri) - if x.expectErr { - if err == nil { - t.Fatalf("expected %s to error", x.uri) - } - continue - } - if err != nil { - t.Fatalf("error parsing %s: %s", x.uri, err) - } - if !reflect.DeepEqual(actual, x.expectURI) { - t.Fatalf("expected %s to return %#v, got %#v", x.uri, x.expectURI, actual) - } - if actual.Raw() != x.expectRaw { - t.Fatalf("expected %s raw to be %t, got %t", x.uri, x.expectRaw, actual.Raw()) - } - if actual.Immutable() != x.expectImmutable { - t.Fatalf("expected %s immutable to be %t, got %t", x.uri, x.expectImmutable, actual.Immutable()) - } - if actual.List() != x.expectList { - t.Fatalf("expected %s list to be %t, got %t", x.uri, x.expectList, actual.List()) - } - if actual.Hash() != x.expectHash { - t.Fatalf("expected %s hash to be %t, got %t", x.uri, x.expectHash, actual.Hash()) - } - if x.expectValidKey { - if actual.Address() == nil { - t.Fatalf("expected %s to return a valid key, got nil", x.uri) - } else { - if !bytes.Equal(x.expectAddr, actual.Address()) { - t.Fatalf("expected %s to be decoded to %v", x.expectURI.Addr, x.expectAddr) - } - } - } - } -} diff --git a/swarm/bmt/bmt.go b/swarm/bmt/bmt.go deleted file mode 100644 index 18eab5a2bc..0000000000 --- a/swarm/bmt/bmt.go +++ /dev/null @@ -1,690 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package bmt provides a binary merkle tree implementation used for swarm chunk hash -package bmt - -import ( - "fmt" - "hash" - "strings" - "sync" - "sync/atomic" -) - -/* -Binary Merkle Tree Hash is a hash function over arbitrary datachunks of limited size. -It is defined as the root hash of the binary merkle tree built over fixed size segments -of the underlying chunk using any base hash function (e.g., keccak 256 SHA3). -Chunks with data shorter than the fixed size are hashed as if they had zero padding. - -BMT hash is used as the chunk hash function in swarm which in turn is the basis for the -128 branching swarm hash http://swarm-guide.readthedocs.io/en/latest/architecture.html#swarm-hash - -The BMT is optimal for providing compact inclusion proofs, i.e. prove that a -segment is a substring of a chunk starting at a particular offset. -The size of the underlying segments is fixed to the size of the base hash (called the resolution -of the BMT hash), Using Keccak256 SHA3 hash is 32 bytes, the EVM word size to optimize for on-chain BMT verification -as well as the hash size optimal for inclusion proofs in the merkle tree of the swarm hash. - -Two implementations are provided: - -* RefHasher is optimized for code simplicity and meant as a reference implementation - that is simple to understand -* Hasher is optimized for speed taking advantage of concurrency with minimalistic - control structure to coordinate the concurrent routines - - BMT Hasher implements the following interfaces - * standard golang hash.Hash - synchronous, reusable - * SwarmHash - SumWithSpan provided - * io.Writer - synchronous left-to-right datawriter - * AsyncWriter - concurrent section writes and asynchronous Sum call -*/ - -const ( - // PoolSize is the maximum number of bmt trees used by the hashers, i.e, - // the maximum number of concurrent BMT hashing operations performed by the same hasher - PoolSize = 8 -) - -// BaseHasherFunc is a hash.Hash constructor function used for the base hash of the BMT. -// implemented by Keccak256 SHA3 sha3.NewLegacyKeccak256 -type BaseHasherFunc func() hash.Hash - -// Hasher a reusable hasher for fixed maximum size chunks representing a BMT -// - implements the hash.Hash interface -// - reuses a pool of trees for amortised memory allocation and resource control -// - supports order-agnostic concurrent segment writes and section (double segment) writes -// as well as sequential read and write -// - the same hasher instance must not be called concurrently on more than one chunk -// - the same hasher instance is synchronously reuseable -// - Sum gives back the tree to the pool and guaranteed to leave -// the tree and itself in a state reusable for hashing a new chunk -// - generates and verifies segment inclusion proofs (TODO:) -type Hasher struct { - pool *TreePool // BMT resource pool - bmt *tree // prebuilt BMT resource for flowcontrol and proofs -} - -// New creates a reusable BMT Hasher that -// pulls a new tree from a resource pool for hashing each chunk -func New(p *TreePool) *Hasher { - return &Hasher{ - pool: p, - } -} - -// TreePool provides a pool of trees used as resources by the BMT Hasher. -// A tree popped from the pool is guaranteed to have a clean state ready -// for hashing a new chunk. -type TreePool struct { - lock sync.Mutex - c chan *tree // the channel to obtain a resource from the pool - hasher BaseHasherFunc // base hasher to use for the BMT levels - SegmentSize int // size of leaf segments, stipulated to be = hash size - SegmentCount int // the number of segments on the base level of the BMT - Capacity int // pool capacity, controls concurrency - Depth int // depth of the bmt trees = int(log2(segmentCount))+1 - Size int // the total length of the data (count * size) - count int // current count of (ever) allocated resources - zerohashes [][]byte // lookup table for predictable padding subtrees for all levels -} - -// NewTreePool creates a tree pool with hasher, segment size, segment count and capacity -// on Hasher.getTree it reuses free trees or creates a new one if capacity is not reached -func NewTreePool(hasher BaseHasherFunc, segmentCount, capacity int) *TreePool { - // initialises the zerohashes lookup table - depth := calculateDepthFor(segmentCount) - segmentSize := hasher().Size() - zerohashes := make([][]byte, depth+1) - zeros := make([]byte, segmentSize) - zerohashes[0] = zeros - h := hasher() - for i := 1; i < depth+1; i++ { - zeros = doSum(h, nil, zeros, zeros) - zerohashes[i] = zeros - } - return &TreePool{ - c: make(chan *tree, capacity), - hasher: hasher, - SegmentSize: segmentSize, - SegmentCount: segmentCount, - Capacity: capacity, - Size: segmentCount * segmentSize, - Depth: depth, - zerohashes: zerohashes, - } -} - -// Drain drains the pool until it has no more than n resources -func (p *TreePool) Drain(n int) { - p.lock.Lock() - defer p.lock.Unlock() - for len(p.c) > n { - <-p.c - p.count-- - } -} - -// Reserve is blocking until it returns an available tree -// it reuses free trees or creates a new one if size is not reached -// TODO: should use a context here -func (p *TreePool) reserve() *tree { - p.lock.Lock() - defer p.lock.Unlock() - var t *tree - if p.count == p.Capacity { - return <-p.c - } - select { - case t = <-p.c: - default: - t = newTree(p.SegmentSize, p.Depth, p.hasher) - p.count++ - } - return t -} - -// release gives back a tree to the pool. -// this tree is guaranteed to be in reusable state -func (p *TreePool) release(t *tree) { - p.c <- t // can never fail ... -} - -// tree is a reusable control structure representing a BMT -// organised in a binary tree -// Hasher uses a TreePool to obtain a tree for each chunk hash -// the tree is 'locked' while not in the pool -type tree struct { - leaves []*node // leaf nodes of the tree, other nodes accessible via parent links - cursor int // index of rightmost currently open segment - offset int // offset (cursor position) within currently open segment - section []byte // the rightmost open section (double segment) - result chan []byte // result channel - span []byte // The span of the data subsumed under the chunk -} - -// node is a reuseable segment hasher representing a node in a BMT -type node struct { - isLeft bool // whether it is left side of the parent double segment - parent *node // pointer to parent node in the BMT - state int32 // atomic increment impl concurrent boolean toggle - left, right []byte // this is where the two children sections are written - hasher hash.Hash // preconstructed hasher on nodes -} - -// newNode constructs a segment hasher node in the BMT (used by newTree) -func newNode(index int, parent *node, hasher hash.Hash) *node { - return &node{ - parent: parent, - isLeft: index%2 == 0, - hasher: hasher, - } -} - -// Draw draws the BMT (badly) -func (t *tree) draw(hash []byte) string { - var left, right []string - var anc []*node - for i, n := range t.leaves { - left = append(left, fmt.Sprintf("%v", hashstr(n.left))) - if i%2 == 0 { - anc = append(anc, n.parent) - } - right = append(right, fmt.Sprintf("%v", hashstr(n.right))) - } - anc = t.leaves - var hashes [][]string - for l := 0; len(anc) > 0; l++ { - var nodes []*node - hash := []string{""} - for i, n := range anc { - hash = append(hash, fmt.Sprintf("%v|%v", hashstr(n.left), hashstr(n.right))) - if i%2 == 0 && n.parent != nil { - nodes = append(nodes, n.parent) - } - } - hash = append(hash, "") - hashes = append(hashes, hash) - anc = nodes - } - hashes = append(hashes, []string{"", fmt.Sprintf("%v", hashstr(hash)), ""}) - total := 60 - del := " " - var rows []string - for i := len(hashes) - 1; i >= 0; i-- { - var textlen int - hash := hashes[i] - for _, s := range hash { - textlen += len(s) - } - if total < textlen { - total = textlen + len(hash) - } - delsize := (total - textlen) / (len(hash) - 1) - if delsize > len(del) { - delsize = len(del) - } - row := fmt.Sprintf("%v: %v", len(hashes)-i-1, strings.Join(hash, del[:delsize])) - rows = append(rows, row) - - } - rows = append(rows, strings.Join(left, " ")) - rows = append(rows, strings.Join(right, " ")) - return strings.Join(rows, "\n") + "\n" -} - -// newTree initialises a tree by building up the nodes of a BMT -// - segment size is stipulated to be the size of the hash -func newTree(segmentSize, depth int, hashfunc func() hash.Hash) *tree { - n := newNode(0, nil, hashfunc()) - prevlevel := []*node{n} - // iterate over levels and creates 2^(depth-level) nodes - // the 0 level is on double segment sections so we start at depth - 2 since - count := 2 - for level := depth - 2; level >= 0; level-- { - nodes := make([]*node, count) - for i := 0; i < count; i++ { - parent := prevlevel[i/2] - var hasher hash.Hash - if level == 0 { - hasher = hashfunc() - } - nodes[i] = newNode(i, parent, hasher) - } - prevlevel = nodes - count *= 2 - } - // the datanode level is the nodes on the last level - return &tree{ - leaves: prevlevel, - result: make(chan []byte), - section: make([]byte, 2*segmentSize), - } -} - -// methods needed to implement hash.Hash - -// Size returns the size -func (h *Hasher) Size() int { - return h.pool.SegmentSize -} - -// BlockSize returns the block size -func (h *Hasher) BlockSize() int { - return 2 * h.pool.SegmentSize -} - -// Sum returns the BMT root hash of the buffer -// using Sum presupposes sequential synchronous writes (io.Writer interface) -// hash.Hash interface Sum method appends the byte slice to the underlying -// data before it calculates and returns the hash of the chunk -// caller must make sure Sum is not called concurrently with Write, writeSection -func (h *Hasher) Sum(b []byte) (s []byte) { - t := h.getTree() - // write the last section with final flag set to true - go h.writeSection(t.cursor, t.section, true, true) - // wait for the result - s = <-t.result - span := t.span - // release the tree resource back to the pool - h.releaseTree() - // b + sha3(span + BMT(pure_chunk)) - if len(span) == 0 { - return append(b, s...) - } - return doSum(h.pool.hasher(), b, span, s) -} - -// methods needed to implement the SwarmHash and the io.Writer interfaces - -// Write calls sequentially add to the buffer to be hashed, -// with every full segment calls writeSection in a go routine -func (h *Hasher) Write(b []byte) (int, error) { - l := len(b) - if l == 0 || l > h.pool.Size { - return 0, nil - } - t := h.getTree() - secsize := 2 * h.pool.SegmentSize - // calculate length of missing bit to complete current open section - smax := secsize - t.offset - // if at the beginning of chunk or middle of the section - if t.offset < secsize { - // fill up current segment from buffer - copy(t.section[t.offset:], b) - // if input buffer consumed and open section not complete, then - // advance offset and return - if smax == 0 { - smax = secsize - } - if l <= smax { - t.offset += l - return l, nil - } - } else { - // if end of a section - if t.cursor == h.pool.SegmentCount*2 { - return 0, nil - } - } - // read full sections and the last possibly partial section from the input buffer - for smax < l { - // section complete; push to tree asynchronously - go h.writeSection(t.cursor, t.section, true, false) - // reset section - t.section = make([]byte, secsize) - // copy from input buffer at smax to right half of section - copy(t.section, b[smax:]) - // advance cursor - t.cursor++ - // smax here represents successive offsets in the input buffer - smax += secsize - } - t.offset = l - smax + secsize - return l, nil -} - -// Reset needs to be called before writing to the hasher -func (h *Hasher) Reset() { - h.releaseTree() -} - -// methods needed to implement the SwarmHash interface - -// ResetWithLength needs to be called before writing to the hasher -// the argument is supposed to be the byte slice binary representation of -// the length of the data subsumed under the hash, i.e., span -func (h *Hasher) ResetWithLength(span []byte) { - h.Reset() - h.getTree().span = span -} - -// releaseTree gives back the Tree to the pool whereby it unlocks -// it resets tree, segment and index -func (h *Hasher) releaseTree() { - t := h.bmt - if t == nil { - return - } - h.bmt = nil - go func() { - t.cursor = 0 - t.offset = 0 - t.span = nil - t.section = make([]byte, h.pool.SegmentSize*2) - select { - case <-t.result: - default: - } - h.pool.release(t) - }() -} - -// NewAsyncWriter extends Hasher with an interface for concurrent segment/section writes -func (h *Hasher) NewAsyncWriter(double bool) *AsyncHasher { - secsize := h.pool.SegmentSize - if double { - secsize *= 2 - } - write := func(i int, section []byte, final bool) { - h.writeSection(i, section, double, final) - } - return &AsyncHasher{ - Hasher: h, - double: double, - secsize: secsize, - write: write, - } -} - -// SectionWriter is an asynchronous segment/section writer interface -type SectionWriter interface { - Reset() // standard init to be called before reuse - Write(index int, data []byte) // write into section of index - Sum(b []byte, length int, span []byte) []byte // returns the hash of the buffer - SectionSize() int // size of the async section unit to use -} - -// AsyncHasher extends BMT Hasher with an asynchronous segment/section writer interface -// AsyncHasher is unsafe and does not check indexes and section data lengths -// it must be used with the right indexes and length and the right number of sections -// -// behaviour is undefined if -// * non-final sections are shorter or longer than secsize -// * if final section does not match length -// * write a section with index that is higher than length/secsize -// * set length in Sum call when length/secsize < maxsec -// -// * if Sum() is not called on a Hasher that is fully written -// a process will block, can be terminated with Reset -// * it will not leak processes if not all sections are written but it blocks -// and keeps the resource which can be released calling Reset() -type AsyncHasher struct { - *Hasher // extends the Hasher - mtx sync.Mutex // to lock the cursor access - double bool // whether to use double segments (call Hasher.writeSection) - secsize int // size of base section (size of hash or double) - write func(i int, section []byte, final bool) -} - -// methods needed to implement AsyncWriter - -// SectionSize returns the size of async section unit to use -func (sw *AsyncHasher) SectionSize() int { - return sw.secsize -} - -// Write writes the i-th section of the BMT base -// this function can and is meant to be called concurrently -// it sets max segment threadsafely -func (sw *AsyncHasher) Write(i int, section []byte) { - sw.mtx.Lock() - defer sw.mtx.Unlock() - t := sw.getTree() - // cursor keeps track of the rightmost section written so far - // if index is lower than cursor then just write non-final section as is - if i < t.cursor { - // if index is not the rightmost, safe to write section - go sw.write(i, section, false) - return - } - // if there is a previous rightmost section safe to write section - if t.offset > 0 { - if i == t.cursor { - // i==cursor implies cursor was set by Hash call so we can write section as final one - // since it can be shorter, first we copy it to the padded buffer - t.section = make([]byte, sw.secsize) - copy(t.section, section) - go sw.write(i, t.section, true) - return - } - // the rightmost section just changed, so we write the previous one as non-final - go sw.write(t.cursor, t.section, false) - } - // set i as the index of the righmost section written so far - // set t.offset to cursor*secsize+1 - t.cursor = i - t.offset = i*sw.secsize + 1 - t.section = make([]byte, sw.secsize) - copy(t.section, section) -} - -// Sum can be called any time once the length and the span is known -// potentially even before all segments have been written -// in such cases Sum will block until all segments are present and -// the hash for the length can be calculated. -// -// b: digest is appended to b -// length: known length of the input (unsafe; undefined if out of range) -// meta: metadata to hash together with BMT root for the final digest -// e.g., span for protection against existential forgery -func (sw *AsyncHasher) Sum(b []byte, length int, meta []byte) (s []byte) { - sw.mtx.Lock() - t := sw.getTree() - if length == 0 { - sw.mtx.Unlock() - s = sw.pool.zerohashes[sw.pool.Depth] - } else { - // for non-zero input the rightmost section is written to the tree asynchronously - // if the actual last section has been written (t.cursor == length/t.secsize) - maxsec := (length - 1) / sw.secsize - if t.offset > 0 { - go sw.write(t.cursor, t.section, maxsec == t.cursor) - } - // set cursor to maxsec so final section is written when it arrives - t.cursor = maxsec - t.offset = length - result := t.result - sw.mtx.Unlock() - // wait for the result or reset - s = <-result - } - // relesase the tree back to the pool - sw.releaseTree() - // if no meta is given just append digest to b - if len(meta) == 0 { - return append(b, s...) - } - // hash together meta and BMT root hash using the pools - return doSum(sw.pool.hasher(), b, meta, s) -} - -// writeSection writes the hash of i-th section into level 1 node of the BMT tree -func (h *Hasher) writeSection(i int, section []byte, double bool, final bool) { - // select the leaf node for the section - var n *node - var isLeft bool - var hasher hash.Hash - var level int - t := h.getTree() - if double { - level++ - n = t.leaves[i] - hasher = n.hasher - isLeft = n.isLeft - n = n.parent - // hash the section - section = doSum(hasher, nil, section) - } else { - n = t.leaves[i/2] - hasher = n.hasher - isLeft = i%2 == 0 - } - // write hash into parent node - if final { - // for the last segment use writeFinalNode - h.writeFinalNode(level, n, hasher, isLeft, section) - } else { - h.writeNode(n, hasher, isLeft, section) - } -} - -// writeNode pushes the data to the node -// if it is the first of 2 sisters written, the routine terminates -// if it is the second, it calculates the hash and writes it -// to the parent node recursively -// since hashing the parent is synchronous the same hasher can be used -func (h *Hasher) writeNode(n *node, bh hash.Hash, isLeft bool, s []byte) { - level := 1 - for { - // at the root of the bmt just write the result to the result channel - if n == nil { - h.getTree().result <- s - return - } - // otherwise assign child hash to left or right segment - if isLeft { - n.left = s - } else { - n.right = s - } - // the child-thread first arriving will terminate - if n.toggle() { - return - } - // the thread coming second now can be sure both left and right children are written - // so it calculates the hash of left|right and pushes it to the parent - s = doSum(bh, nil, n.left, n.right) - isLeft = n.isLeft - n = n.parent - level++ - } -} - -// writeFinalNode is following the path starting from the final datasegment to the -// BMT root via parents -// for unbalanced trees it fills in the missing right sister nodes using -// the pool's lookup table for BMT subtree root hashes for all-zero sections -// otherwise behaves like `writeNode` -func (h *Hasher) writeFinalNode(level int, n *node, bh hash.Hash, isLeft bool, s []byte) { - - for { - // at the root of the bmt just write the result to the result channel - if n == nil { - if s != nil { - h.getTree().result <- s - } - return - } - var noHash bool - if isLeft { - // coming from left sister branch - // when the final section's path is going via left child node - // we include an all-zero subtree hash for the right level and toggle the node. - n.right = h.pool.zerohashes[level] - if s != nil { - n.left = s - // if a left final node carries a hash, it must be the first (and only thread) - // so the toggle is already in passive state no need no call - // yet thread needs to carry on pushing hash to parent - noHash = false - } else { - // if again first thread then propagate nil and calculate no hash - noHash = n.toggle() - } - } else { - // right sister branch - if s != nil { - // if hash was pushed from right child node, write right segment change state - n.right = s - // if toggle is true, we arrived first so no hashing just push nil to parent - noHash = n.toggle() - - } else { - // if s is nil, then thread arrived first at previous node and here there will be two, - // so no need to do anything and keep s = nil for parent - noHash = true - } - } - // the child-thread first arriving will just continue resetting s to nil - // the second thread now can be sure both left and right children are written - // it calculates the hash of left|right and pushes it to the parent - if noHash { - s = nil - } else { - s = doSum(bh, nil, n.left, n.right) - } - // iterate to parent - isLeft = n.isLeft - n = n.parent - level++ - } -} - -// getTree obtains a BMT resource by reserving one from the pool and assigns it to the bmt field -func (h *Hasher) getTree() *tree { - if h.bmt != nil { - return h.bmt - } - t := h.pool.reserve() - h.bmt = t - return t -} - -// atomic bool toggle implementing a concurrent reusable 2-state object -// atomic addint with %2 implements atomic bool toggle -// it returns true if the toggler just put it in the active/waiting state -func (n *node) toggle() bool { - return atomic.AddInt32(&n.state, 1)%2 == 1 -} - -// calculates the hash of the data using hash.Hash -func doSum(h hash.Hash, b []byte, data ...[]byte) []byte { - h.Reset() - for _, v := range data { - h.Write(v) - } - return h.Sum(b) -} - -// hashstr is a pretty printer for bytes used in tree.draw -func hashstr(b []byte) string { - end := len(b) - if end > 4 { - end = 4 - } - return fmt.Sprintf("%x", b[:end]) -} - -// calculateDepthFor calculates the depth (number of levels) in the BMT tree -func calculateDepthFor(n int) (d int) { - c := 2 - for ; c < n; c *= 2 { - d++ - } - return d + 1 -} diff --git a/swarm/bmt/bmt_r.go b/swarm/bmt/bmt_r.go deleted file mode 100644 index 0cb6c146f5..0000000000 --- a/swarm/bmt/bmt_r.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package bmt is a simple nonconcurrent reference implementation for hashsize segment based -// Binary Merkle tree hash on arbitrary but fixed maximum chunksize -// -// This implementation does not take advantage of any paralellisms and uses -// far more memory than necessary, but it is easy to see that it is correct. -// It can be used for generating test cases for optimized implementations. -// There is extra check on reference hasher correctness in bmt_test.go -// * TestRefHasher -// * testBMTHasherCorrectness function -package bmt - -import ( - "hash" -) - -// RefHasher is the non-optimized easy-to-read reference implementation of BMT -type RefHasher struct { - maxDataLength int // c * hashSize, where c = 2 ^ ceil(log2(count)), where count = ceil(length / hashSize) - sectionLength int // 2 * hashSize - hasher hash.Hash // base hash func (Keccak256 SHA3) -} - -// NewRefHasher returns a new RefHasher -func NewRefHasher(hasher BaseHasherFunc, count int) *RefHasher { - h := hasher() - hashsize := h.Size() - c := 2 - for ; c < count; c *= 2 { - } - return &RefHasher{ - sectionLength: 2 * hashsize, - maxDataLength: c * hashsize, - hasher: h, - } -} - -// Hash returns the BMT hash of the byte slice -// implements the SwarmHash interface -func (rh *RefHasher) Hash(data []byte) []byte { - // if data is shorter than the base length (maxDataLength), we provide padding with zeros - d := make([]byte, rh.maxDataLength) - length := len(data) - if length > rh.maxDataLength { - length = rh.maxDataLength - } - copy(d, data[:length]) - return rh.hash(d, rh.maxDataLength) -} - -// data has length maxDataLength = segmentSize * 2^k -// hash calls itself recursively on both halves of the given slice -// concatenates the results, and returns the hash of that -// if the length of d is 2 * segmentSize then just returns the hash of that section -func (rh *RefHasher) hash(data []byte, length int) []byte { - var section []byte - if length == rh.sectionLength { - // section contains two data segments (d) - section = data - } else { - // section contains hashes of left and right BMT subtreea - // to be calculated by calling hash recursively on left and right half of d - length /= 2 - section = append(rh.hash(data[:length], length), rh.hash(data[length:], length)...) - } - rh.hasher.Reset() - rh.hasher.Write(section) - return rh.hasher.Sum(nil) -} diff --git a/swarm/bmt/bmt_test.go b/swarm/bmt/bmt_test.go deleted file mode 100644 index ab712d08c2..0000000000 --- a/swarm/bmt/bmt_test.go +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package bmt - -import ( - "bytes" - "encoding/binary" - "fmt" - "math/rand" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/testutil" - "golang.org/x/crypto/sha3" -) - -// the actual data length generated (could be longer than max datalength of the BMT) -const BufferSize = 4128 - -const ( - // segmentCount is the maximum number of segments of the underlying chunk - // Should be equal to max-chunk-data-size / hash-size - // Currently set to 128 == 4096 (default chunk size) / 32 (sha3.keccak256 size) - segmentCount = 128 -) - -var counts = []int{1, 2, 3, 4, 5, 8, 9, 15, 16, 17, 32, 37, 42, 53, 63, 64, 65, 111, 127, 128} - -// calculates the Keccak256 SHA3 hash of the data -func sha3hash(data ...[]byte) []byte { - h := sha3.NewLegacyKeccak256() - return doSum(h, nil, data...) -} - -// TestRefHasher tests that the RefHasher computes the expected BMT hash for -// some small data lengths -func TestRefHasher(t *testing.T) { - // the test struct is used to specify the expected BMT hash for - // segment counts between from and to and lengths from 1 to datalength - type test struct { - from int - to int - expected func([]byte) []byte - } - - var tests []*test - // all lengths in [0,64] should be: - // - // sha3hash(data) - // - tests = append(tests, &test{ - from: 1, - to: 2, - expected: func(d []byte) []byte { - data := make([]byte, 64) - copy(data, d) - return sha3hash(data) - }, - }) - - // all lengths in [3,4] should be: - // - // sha3hash( - // sha3hash(data[:64]) - // sha3hash(data[64:]) - // ) - // - tests = append(tests, &test{ - from: 3, - to: 4, - expected: func(d []byte) []byte { - data := make([]byte, 128) - copy(data, d) - return sha3hash(sha3hash(data[:64]), sha3hash(data[64:])) - }, - }) - - // all segmentCounts in [5,8] should be: - // - // sha3hash( - // sha3hash( - // sha3hash(data[:64]) - // sha3hash(data[64:128]) - // ) - // sha3hash( - // sha3hash(data[128:192]) - // sha3hash(data[192:]) - // ) - // ) - // - tests = append(tests, &test{ - from: 5, - to: 8, - expected: func(d []byte) []byte { - data := make([]byte, 256) - copy(data, d) - return sha3hash(sha3hash(sha3hash(data[:64]), sha3hash(data[64:128])), sha3hash(sha3hash(data[128:192]), sha3hash(data[192:]))) - }, - }) - - // run the tests - for i, x := range tests { - for segmentCount := x.from; segmentCount <= x.to; segmentCount++ { - for length := 1; length <= segmentCount*32; length++ { - t.Run(fmt.Sprintf("%d_segments_%d_bytes", segmentCount, length), func(t *testing.T) { - data := testutil.RandomBytes(i, length) - expected := x.expected(data) - actual := NewRefHasher(sha3.NewLegacyKeccak256, segmentCount).Hash(data) - if !bytes.Equal(actual, expected) { - t.Fatalf("expected %x, got %x", expected, actual) - } - }) - } - } - } -} - -// tests if hasher responds with correct hash comparing the reference implementation return value -func TestHasherEmptyData(t *testing.T) { - hasher := sha3.NewLegacyKeccak256 - var data []byte - for _, count := range counts { - t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { - pool := NewTreePool(hasher, count, PoolSize) - defer pool.Drain(0) - bmt := New(pool) - rbmt := NewRefHasher(hasher, count) - refHash := rbmt.Hash(data) - expHash := syncHash(bmt, nil, data) - if !bytes.Equal(expHash, refHash) { - t.Fatalf("hash mismatch with reference. expected %x, got %x", refHash, expHash) - } - }) - } -} - -// tests sequential write with entire max size written in one go -func TestSyncHasherCorrectness(t *testing.T) { - data := testutil.RandomBytes(1, BufferSize) - hasher := sha3.NewLegacyKeccak256 - size := hasher().Size() - - var err error - for _, count := range counts { - t.Run(fmt.Sprintf("segments_%v", count), func(t *testing.T) { - max := count * size - var incr int - capacity := 1 - pool := NewTreePool(hasher, count, capacity) - defer pool.Drain(0) - for n := 0; n <= max; n += incr { - incr = 1 + rand.Intn(5) - bmt := New(pool) - err = testHasherCorrectness(bmt, hasher, data, n, count) - if err != nil { - t.Fatal(err) - } - } - }) - } -} - -// tests order-neutral concurrent writes with entire max size written in one go -func TestAsyncCorrectness(t *testing.T) { - data := testutil.RandomBytes(1, BufferSize) - hasher := sha3.NewLegacyKeccak256 - size := hasher().Size() - whs := []whenHash{first, last, random} - - for _, double := range []bool{false, true} { - for _, wh := range whs { - for _, count := range counts { - t.Run(fmt.Sprintf("double_%v_hash_when_%v_segments_%v", double, wh, count), func(t *testing.T) { - max := count * size - var incr int - capacity := 1 - pool := NewTreePool(hasher, count, capacity) - defer pool.Drain(0) - for n := 1; n <= max; n += incr { - incr = 1 + rand.Intn(5) - bmt := New(pool) - d := data[:n] - rbmt := NewRefHasher(hasher, count) - exp := rbmt.Hash(d) - got := syncHash(bmt, nil, d) - if !bytes.Equal(got, exp) { - t.Fatalf("wrong sync hash for datalength %v: expected %x (ref), got %x", n, exp, got) - } - sw := bmt.NewAsyncWriter(double) - got = asyncHashRandom(sw, nil, d, wh) - if !bytes.Equal(got, exp) { - t.Fatalf("wrong async hash for datalength %v: expected %x, got %x", n, exp, got) - } - } - }) - } - } - } -} - -// Tests that the BMT hasher can be synchronously reused with poolsizes 1 and PoolSize -func TestHasherReuse(t *testing.T) { - t.Run(fmt.Sprintf("poolsize_%d", 1), func(t *testing.T) { - testHasherReuse(1, t) - }) - t.Run(fmt.Sprintf("poolsize_%d", PoolSize), func(t *testing.T) { - testHasherReuse(PoolSize, t) - }) -} - -// tests if bmt reuse is not corrupting result -func testHasherReuse(poolsize int, t *testing.T) { - hasher := sha3.NewLegacyKeccak256 - pool := NewTreePool(hasher, segmentCount, poolsize) - defer pool.Drain(0) - bmt := New(pool) - - for i := 0; i < 100; i++ { - data := testutil.RandomBytes(1, BufferSize) - n := rand.Intn(bmt.Size()) - err := testHasherCorrectness(bmt, hasher, data, n, segmentCount) - if err != nil { - t.Fatal(err) - } - } -} - -// Tests if pool can be cleanly reused even in concurrent use by several hasher -func TestBMTConcurrentUse(t *testing.T) { - hasher := sha3.NewLegacyKeccak256 - pool := NewTreePool(hasher, segmentCount, PoolSize) - defer pool.Drain(0) - cycles := 100 - errc := make(chan error) - - for i := 0; i < cycles; i++ { - go func() { - bmt := New(pool) - data := testutil.RandomBytes(1, BufferSize) - n := rand.Intn(bmt.Size()) - errc <- testHasherCorrectness(bmt, hasher, data, n, 128) - }() - } -LOOP: - for { - select { - case <-time.NewTimer(5 * time.Second).C: - t.Fatal("timed out") - case err := <-errc: - if err != nil { - t.Fatal(err) - } - cycles-- - if cycles == 0 { - break LOOP - } - } - } -} - -// Tests BMT Hasher io.Writer interface is working correctly -// even multiple short random write buffers -func TestBMTWriterBuffers(t *testing.T) { - hasher := sha3.NewLegacyKeccak256 - - for _, count := range counts { - t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { - errc := make(chan error) - pool := NewTreePool(hasher, count, PoolSize) - defer pool.Drain(0) - n := count * 32 - bmt := New(pool) - data := testutil.RandomBytes(1, n) - rbmt := NewRefHasher(hasher, count) - refHash := rbmt.Hash(data) - expHash := syncHash(bmt, nil, data) - if !bytes.Equal(expHash, refHash) { - t.Fatalf("hash mismatch with reference. expected %x, got %x", refHash, expHash) - } - attempts := 10 - f := func() error { - bmt := New(pool) - bmt.Reset() - var buflen int - for offset := 0; offset < n; offset += buflen { - buflen = rand.Intn(n-offset) + 1 - read, err := bmt.Write(data[offset : offset+buflen]) - if err != nil { - return err - } - if read != buflen { - return fmt.Errorf("incorrect read. expected %v bytes, got %v", buflen, read) - } - } - hash := bmt.Sum(nil) - if !bytes.Equal(hash, expHash) { - return fmt.Errorf("hash mismatch. expected %x, got %x", hash, expHash) - } - return nil - } - - for j := 0; j < attempts; j++ { - go func() { - errc <- f() - }() - } - timeout := time.NewTimer(2 * time.Second) - for { - select { - case err := <-errc: - if err != nil { - t.Fatal(err) - } - attempts-- - if attempts == 0 { - return - } - case <-timeout.C: - t.Fatalf("timeout") - } - } - }) - } -} - -// helper function that compares reference and optimised implementations on -// correctness -func testHasherCorrectness(bmt *Hasher, hasher BaseHasherFunc, d []byte, n, count int) (err error) { - span := make([]byte, 8) - if len(d) < n { - n = len(d) - } - binary.BigEndian.PutUint64(span, uint64(n)) - data := d[:n] - rbmt := NewRefHasher(hasher, count) - exp := sha3hash(span, rbmt.Hash(data)) - got := syncHash(bmt, span, data) - if !bytes.Equal(got, exp) { - return fmt.Errorf("wrong hash: expected %x, got %x", exp, got) - } - return err -} - -// -func BenchmarkBMT(t *testing.B) { - for size := 4096; size >= 128; size /= 2 { - t.Run(fmt.Sprintf("%v_size_%v", "SHA3", size), func(t *testing.B) { - benchmarkSHA3(t, size) - }) - t.Run(fmt.Sprintf("%v_size_%v", "Baseline", size), func(t *testing.B) { - benchmarkBMTBaseline(t, size) - }) - t.Run(fmt.Sprintf("%v_size_%v", "REF", size), func(t *testing.B) { - benchmarkRefHasher(t, size) - }) - t.Run(fmt.Sprintf("%v_size_%v", "BMT", size), func(t *testing.B) { - benchmarkBMT(t, size) - }) - } -} - -type whenHash = int - -const ( - first whenHash = iota - last - random -) - -func BenchmarkBMTAsync(t *testing.B) { - whs := []whenHash{first, last, random} - for size := 4096; size >= 128; size /= 2 { - for _, wh := range whs { - for _, double := range []bool{false, true} { - t.Run(fmt.Sprintf("double_%v_hash_when_%v_size_%v", double, wh, size), func(t *testing.B) { - benchmarkBMTAsync(t, size, wh, double) - }) - } - } - } -} - -func BenchmarkPool(t *testing.B) { - caps := []int{1, PoolSize} - for size := 4096; size >= 128; size /= 2 { - for _, c := range caps { - t.Run(fmt.Sprintf("poolsize_%v_size_%v", c, size), func(t *testing.B) { - benchmarkPool(t, c, size) - }) - } - } -} - -// benchmarks simple sha3 hash on chunks -func benchmarkSHA3(t *testing.B, n int) { - data := testutil.RandomBytes(1, n) - hasher := sha3.NewLegacyKeccak256 - h := hasher() - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - doSum(h, nil, data) - } -} - -// benchmarks the minimum hashing time for a balanced (for simplicity) BMT -// by doing count/segmentsize parallel hashings of 2*segmentsize bytes -// doing it on n PoolSize each reusing the base hasher -// the premise is that this is the minimum computation needed for a BMT -// therefore this serves as a theoretical optimum for concurrent implementations -func benchmarkBMTBaseline(t *testing.B, n int) { - hasher := sha3.NewLegacyKeccak256 - hashSize := hasher().Size() - data := testutil.RandomBytes(1, hashSize) - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - count := int32((n-1)/hashSize + 1) - wg := sync.WaitGroup{} - wg.Add(PoolSize) - var i int32 - for j := 0; j < PoolSize; j++ { - go func() { - defer wg.Done() - h := hasher() - for atomic.AddInt32(&i, 1) < count { - doSum(h, nil, data) - } - }() - } - wg.Wait() - } -} - -// benchmarks BMT Hasher -func benchmarkBMT(t *testing.B, n int) { - data := testutil.RandomBytes(1, n) - hasher := sha3.NewLegacyKeccak256 - pool := NewTreePool(hasher, segmentCount, PoolSize) - bmt := New(pool) - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - syncHash(bmt, nil, data) - } -} - -// benchmarks BMT hasher with asynchronous concurrent segment/section writes -func benchmarkBMTAsync(t *testing.B, n int, wh whenHash, double bool) { - data := testutil.RandomBytes(1, n) - hasher := sha3.NewLegacyKeccak256 - pool := NewTreePool(hasher, segmentCount, PoolSize) - bmt := New(pool).NewAsyncWriter(double) - idxs, segments := splitAndShuffle(bmt.SectionSize(), data) - rand.Shuffle(len(idxs), func(i int, j int) { - idxs[i], idxs[j] = idxs[j], idxs[i] - }) - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - asyncHash(bmt, nil, n, wh, idxs, segments) - } -} - -// benchmarks 100 concurrent bmt hashes with pool capacity -func benchmarkPool(t *testing.B, poolsize, n int) { - data := testutil.RandomBytes(1, n) - hasher := sha3.NewLegacyKeccak256 - pool := NewTreePool(hasher, segmentCount, poolsize) - cycles := 100 - - t.ReportAllocs() - t.ResetTimer() - wg := sync.WaitGroup{} - for i := 0; i < t.N; i++ { - wg.Add(cycles) - for j := 0; j < cycles; j++ { - go func() { - defer wg.Done() - bmt := New(pool) - syncHash(bmt, nil, data) - }() - } - wg.Wait() - } -} - -// benchmarks the reference hasher -func benchmarkRefHasher(t *testing.B, n int) { - data := testutil.RandomBytes(1, n) - hasher := sha3.NewLegacyKeccak256 - rbmt := NewRefHasher(hasher, 128) - - t.ReportAllocs() - t.ResetTimer() - for i := 0; i < t.N; i++ { - rbmt.Hash(data) - } -} - -// Hash hashes the data and the span using the bmt hasher -func syncHash(h *Hasher, span, data []byte) []byte { - h.ResetWithLength(span) - h.Write(data) - return h.Sum(nil) -} - -func splitAndShuffle(secsize int, data []byte) (idxs []int, segments [][]byte) { - l := len(data) - n := l / secsize - if l%secsize > 0 { - n++ - } - for i := 0; i < n; i++ { - idxs = append(idxs, i) - end := (i + 1) * secsize - if end > l { - end = l - } - section := data[i*secsize : end] - segments = append(segments, section) - } - rand.Shuffle(n, func(i int, j int) { - idxs[i], idxs[j] = idxs[j], idxs[i] - }) - return idxs, segments -} - -// splits the input data performs a random shuffle to mock async section writes -func asyncHashRandom(bmt SectionWriter, span []byte, data []byte, wh whenHash) (s []byte) { - idxs, segments := splitAndShuffle(bmt.SectionSize(), data) - return asyncHash(bmt, span, len(data), wh, idxs, segments) -} - -// mock for async section writes for BMT SectionWriter -// requires a permutation (a random shuffle) of list of all indexes of segments -// and writes them in order to the appropriate section -// the Sum function is called according to the wh parameter (first, last, random [relative to segment writes]) -func asyncHash(bmt SectionWriter, span []byte, l int, wh whenHash, idxs []int, segments [][]byte) (s []byte) { - bmt.Reset() - if l == 0 { - return bmt.Sum(nil, l, span) - } - c := make(chan []byte, 1) - hashf := func() { - c <- bmt.Sum(nil, l, span) - } - maxsize := len(idxs) - var r int - if wh == random { - r = rand.Intn(maxsize) - } - for i, idx := range idxs { - bmt.Write(idx, segments[idx]) - if (wh == first || wh == random) && i == r { - go hashf() - } - } - if wh == last { - return bmt.Sum(nil, l, span) - } - return <-c -} diff --git a/swarm/chunk/chunk.go b/swarm/chunk/chunk.go deleted file mode 100644 index c44292bb92..0000000000 --- a/swarm/chunk/chunk.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chunk - -import ( - "context" - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" -) - -const ( - DefaultSize = 4096 - MaxPO = 16 - AddressLength = 32 -) - -var ( - ErrChunkNotFound = errors.New("chunk not found") - ErrChunkInvalid = errors.New("invalid chunk") -) - -type Chunk interface { - Address() Address - Data() []byte -} - -type chunk struct { - addr Address - sdata []byte -} - -func NewChunk(addr Address, data []byte) Chunk { - return &chunk{ - addr: addr, - sdata: data, - } -} - -func (c *chunk) Address() Address { - return c.addr -} - -func (c *chunk) Data() []byte { - return c.sdata -} - -func (self *chunk) String() string { - return fmt.Sprintf("Address: %v Chunksize: %v", self.addr.Log(), len(self.sdata)) -} - -type Address []byte - -var ZeroAddr = Address(common.Hash{}.Bytes()) - -func (a Address) Hex() string { - return fmt.Sprintf("%064x", []byte(a[:])) -} - -func (a Address) Log() string { - if len(a[:]) < 8 { - return fmt.Sprintf("%x", []byte(a[:])) - } - return fmt.Sprintf("%016x", []byte(a[:8])) -} - -func (a Address) String() string { - return fmt.Sprintf("%064x", []byte(a)) -} - -func (a Address) MarshalJSON() (out []byte, err error) { - return []byte(`"` + a.String() + `"`), nil -} - -func (a *Address) UnmarshalJSON(value []byte) error { - s := string(value) - *a = make([]byte, 32) - h := common.Hex2Bytes(s[1 : len(s)-1]) - copy(*a, h) - return nil -} - -// Proximity returns the proximity order of the MSB distance between x and y -// -// The distance metric MSB(x, y) of two equal length byte sequences x an y is the -// value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed. -// the binary cast is big endian: most significant bit first (=MSB). -// -// Proximity(x, y) is a discrete logarithmic scaling of the MSB distance. -// It is defined as the reverse rank of the integer part of the base 2 -// logarithm of the distance. -// It is calculated by counting the number of common leading zeros in the (MSB) -// binary representation of the x^y. -// -// (0 farthest, 255 closest, 256 self) -func Proximity(one, other []byte) (ret int) { - b := (MaxPO-1)/8 + 1 - if b > len(one) { - b = len(one) - } - m := 8 - for i := 0; i < b; i++ { - oxo := one[i] ^ other[i] - for j := 0; j < m; j++ { - if (oxo>>uint8(7-j))&0x01 != 0 { - return i*8 + j - } - } - } - return MaxPO -} - -// ModeGet enumerates different Getter modes. -type ModeGet int - -func (m ModeGet) String() string { - switch m { - case ModeGetRequest: - return "Request" - case ModeGetSync: - return "Sync" - case ModeGetLookup: - return "Lookup" - default: - return "Unknown" - } -} - -// Getter modes. -const ( - // ModeGetRequest: when accessed for retrieval - ModeGetRequest ModeGet = iota - // ModeGetSync: when accessed for syncing or proof of custody request - ModeGetSync - // ModeGetLookup: when accessed to lookup a a chunk in feeds or other places - ModeGetLookup -) - -// ModePut enumerates different Putter modes. -type ModePut int - -func (m ModePut) String() string { - switch m { - case ModePutRequest: - return "Request" - case ModePutSync: - return "Sync" - case ModePutUpload: - return "Upload" - default: - return "Unknown" - } -} - -// Putter modes. -const ( - // ModePutRequest: when a chunk is received as a result of retrieve request and delivery - ModePutRequest ModePut = iota - // ModePutSync: when a chunk is received via syncing - ModePutSync - // ModePutUpload: when a chunk is created by local upload - ModePutUpload -) - -// ModeSet enumerates different Setter modes. -type ModeSet int - -func (m ModeSet) String() string { - switch m { - case ModeSetAccess: - return "Access" - case ModeSetSync: - return "Sync" - case ModeSetRemove: - return "Remove" - default: - return "Unknown" - } -} - -// Setter modes. -const ( - // ModeSetAccess: when an update request is received for a chunk or chunk is retrieved for delivery - ModeSetAccess ModeSet = iota - // ModeSetSync: when a chunk is added to a pull sync batch or when a push sync receipt is received - ModeSetSync - // ModeSetRemove: when a chunk is removed - ModeSetRemove -) - -// Descriptor holds information required for Pull syncing. This struct -// is provided by subscribing to pull index. -type Descriptor struct { - Address Address - BinID uint64 -} - -func (d *Descriptor) String() string { - if d == nil { - return "" - } - return fmt.Sprintf("%s bin id %v", d.Address.Hex(), d.BinID) -} - -type Store interface { - Get(ctx context.Context, mode ModeGet, addr Address) (ch Chunk, err error) - Put(ctx context.Context, mode ModePut, ch Chunk) (exists bool, err error) - Has(ctx context.Context, addr Address) (yes bool, err error) - Set(ctx context.Context, mode ModeSet, addr Address) (err error) - LastPullSubscriptionBinID(bin uint8) (id uint64, err error) - SubscribePull(ctx context.Context, bin uint8, since, until uint64) (c <-chan Descriptor, stop func()) - Close() (err error) -} - -// Validator validates a chunk. -type Validator interface { - Validate(ch Chunk) bool -} - -// ValidatorStore encapsulates Store by decorting the Put method -// with validators check. -type ValidatorStore struct { - Store - validators []Validator -} - -// NewValidatorStore returns a new ValidatorStore which uses -// provided validators to validate chunks on Put. -func NewValidatorStore(store Store, validators ...Validator) (s *ValidatorStore) { - return &ValidatorStore{ - Store: store, - validators: validators, - } -} - -// Put overrides Store put method with validators check. If one of the validators -// return true, the chunk is considered valid and Store Put method is called. -// If all validators return false, ErrChunkInvalid is returned. -func (s *ValidatorStore) Put(ctx context.Context, mode ModePut, ch Chunk) (exists bool, err error) { - for _, v := range s.validators { - if v.Validate(ch) { - return s.Store.Put(ctx, mode, ch) - } - } - return false, ErrChunkInvalid -} diff --git a/swarm/chunk/proximity_test.go b/swarm/chunk/proximity_test.go deleted file mode 100644 index 5632114b16..0000000000 --- a/swarm/chunk/proximity_test.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chunk - -import ( - "strconv" - "testing" -) - -// TestProximity validates Proximity function with explicit -// values in a table-driven test. It is highly dependant on -// MaxPO constant and it validates cases up to MaxPO=32. -func TestProximity(t *testing.T) { - // integer from base2 encoded string - bx := func(s string) uint8 { - i, err := strconv.ParseUint(s, 2, 8) - if err != nil { - t.Fatal(err) - } - return uint8(i) - } - // adjust expected bins in respect to MaxPO - limitPO := func(po uint8) uint8 { - if po > MaxPO { - return MaxPO - } - return po - } - base := []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000000")} - for _, tc := range []struct { - addr []byte - po uint8 - }{ - { - addr: base, - po: MaxPO, - }, - { - addr: []byte{bx("10000000"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(0), - }, - { - addr: []byte{bx("01000000"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(1), - }, - { - addr: []byte{bx("00100000"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(2), - }, - { - addr: []byte{bx("00010000"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(3), - }, - { - addr: []byte{bx("00001000"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(4), - }, - { - addr: []byte{bx("00000100"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(5), - }, - { - addr: []byte{bx("00000010"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(6), - }, - { - addr: []byte{bx("00000001"), bx("00000000"), bx("00000000"), bx("00000000")}, - po: limitPO(7), - }, - { - addr: []byte{bx("00000000"), bx("10000000"), bx("00000000"), bx("00000000")}, - po: limitPO(8), - }, - { - addr: []byte{bx("00000000"), bx("01000000"), bx("00000000"), bx("00000000")}, - po: limitPO(9), - }, - { - addr: []byte{bx("00000000"), bx("00100000"), bx("00000000"), bx("00000000")}, - po: limitPO(10), - }, - { - addr: []byte{bx("00000000"), bx("00010000"), bx("00000000"), bx("00000000")}, - po: limitPO(11), - }, - { - addr: []byte{bx("00000000"), bx("00001000"), bx("00000000"), bx("00000000")}, - po: limitPO(12), - }, - { - addr: []byte{bx("00000000"), bx("00000100"), bx("00000000"), bx("00000000")}, - po: limitPO(13), - }, - { - addr: []byte{bx("00000000"), bx("00000010"), bx("00000000"), bx("00000000")}, - po: limitPO(14), - }, - { - addr: []byte{bx("00000000"), bx("00000001"), bx("00000000"), bx("00000000")}, - po: limitPO(15), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("10000000"), bx("00000000")}, - po: limitPO(16), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("01000000"), bx("00000000")}, - po: limitPO(17), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00100000"), bx("00000000")}, - po: limitPO(18), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00010000"), bx("00000000")}, - po: limitPO(19), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00001000"), bx("00000000")}, - po: limitPO(20), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000100"), bx("00000000")}, - po: limitPO(21), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000010"), bx("00000000")}, - po: limitPO(22), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000001"), bx("00000000")}, - po: limitPO(23), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("10000000")}, - po: limitPO(24), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("01000000")}, - po: limitPO(25), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00100000")}, - po: limitPO(26), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00010000")}, - po: limitPO(27), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00001000")}, - po: limitPO(28), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000100")}, - po: limitPO(29), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000010")}, - po: limitPO(30), - }, - { - addr: []byte{bx("00000000"), bx("00000000"), bx("00000000"), bx("00000001")}, - po: limitPO(31), - }, - } { - got := uint8(Proximity(base, tc.addr)) - if got != tc.po { - t.Errorf("got %v bin, want %v", got, tc.po) - } - } -} diff --git a/swarm/chunk/tag.go b/swarm/chunk/tag.go deleted file mode 100644 index ee700d22bf..0000000000 --- a/swarm/chunk/tag.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chunk - -import ( - "encoding/binary" - "errors" - "sync/atomic" - "time" -) - -var ( - errExists = errors.New("already exists") - errNA = errors.New("not available yet") - errNoETA = errors.New("unable to calculate ETA") - errTagNotFound = errors.New("tag not found") -) - -// State is the enum type for chunk states -type State = uint32 - -const ( - StateSplit State = iota // chunk has been processed by filehasher/swarm safe call - StateStored // chunk stored locally - StateSeen // chunk previously seen - StateSent // chunk sent to neighbourhood - StateSynced // proof is received; chunk removed from sync db; chunk is available everywhere -) - -// Tag represents info on the status of new chunks -type Tag struct { - Uid uint32 // a unique identifier for this tag - Name string // a name tag for this tag - Address Address // the associated swarm hash for this tag - total int64 // total chunks belonging to a tag - split int64 // number of chunks already processed by splitter for hashing - seen int64 // number of chunks already seen - stored int64 // number of chunks already stored locally - sent int64 // number of chunks sent for push syncing - synced int64 // number of chunks synced with proof - startedAt time.Time // tag started to calculate ETA -} - -// New creates a new tag, stores it by the name and returns it -// it returns an error if the tag with this name already exists -func NewTag(uid uint32, s string, total int64) *Tag { - t := &Tag{ - Uid: uid, - Name: s, - startedAt: time.Now(), - total: total, - } - return t -} - -// Inc increments the count for a state -func (t *Tag) Inc(state State) { - var v *int64 - switch state { - case StateSplit: - v = &t.split - case StateStored: - v = &t.stored - case StateSeen: - v = &t.seen - case StateSent: - v = &t.sent - case StateSynced: - v = &t.synced - } - atomic.AddInt64(v, 1) -} - -// Get returns the count for a state on a tag -func (t *Tag) Get(state State) int64 { - var v *int64 - switch state { - case StateSplit: - v = &t.split - case StateStored: - v = &t.stored - case StateSeen: - v = &t.seen - case StateSent: - v = &t.sent - case StateSynced: - v = &t.synced - } - return atomic.LoadInt64(v) -} - -// GetTotal returns the total count -func (t *Tag) Total() int64 { - return atomic.LoadInt64(&t.total) -} - -// DoneSplit sets total count to SPLIT count and sets the associated swarm hash for this tag -// is meant to be called when splitter finishes for input streams of unknown size -func (t *Tag) DoneSplit(address Address) int64 { - total := atomic.LoadInt64(&t.split) - atomic.StoreInt64(&t.total, total) - t.Address = address - return total -} - -// Status returns the value of state and the total count -func (t *Tag) Status(state State) (int64, int64, error) { - count, seen, total := t.Get(state), atomic.LoadInt64(&t.seen), atomic.LoadInt64(&t.total) - if total == 0 { - return count, total, errNA - } - switch state { - case StateSplit, StateStored, StateSeen: - return count, total, nil - case StateSent, StateSynced: - stored := atomic.LoadInt64(&t.stored) - if stored < total { - return count, total - seen, errNA - } - return count, total - seen, nil - } - return count, total, errNA -} - -// ETA returns the time of completion estimated based on time passed and rate of completion -func (t *Tag) ETA(state State) (time.Time, error) { - cnt, total, err := t.Status(state) - if err != nil { - return time.Time{}, err - } - if cnt == 0 || total == 0 { - return time.Time{}, errNoETA - } - diff := time.Since(t.startedAt) - dur := time.Duration(total) * diff / time.Duration(cnt) - return t.startedAt.Add(dur), nil -} - -// MarshalBinary marshals the tag into a byte slice -func (tag *Tag) MarshalBinary() (data []byte, err error) { - buffer := make([]byte, 4) - binary.BigEndian.PutUint32(buffer, tag.Uid) - encodeInt64Append(&buffer, tag.total) - encodeInt64Append(&buffer, tag.split) - encodeInt64Append(&buffer, tag.seen) - encodeInt64Append(&buffer, tag.stored) - encodeInt64Append(&buffer, tag.sent) - encodeInt64Append(&buffer, tag.synced) - - intBuffer := make([]byte, 8) - - n := binary.PutVarint(intBuffer, tag.startedAt.Unix()) - buffer = append(buffer, intBuffer[:n]...) - - n = binary.PutVarint(intBuffer, int64(len(tag.Address))) - buffer = append(buffer, intBuffer[:n]...) - - buffer = append(buffer, tag.Address[:]...) - - buffer = append(buffer, []byte(tag.Name)...) - - return buffer, nil -} - -// UnmarshalBinary unmarshals a byte slice into a tag -func (tag *Tag) UnmarshalBinary(buffer []byte) error { - if len(buffer) < 13 { - return errors.New("buffer too short") - } - tag.Uid = binary.BigEndian.Uint32(buffer) - buffer = buffer[4:] - - tag.total = decodeInt64Splice(&buffer) - tag.split = decodeInt64Splice(&buffer) - tag.seen = decodeInt64Splice(&buffer) - tag.stored = decodeInt64Splice(&buffer) - tag.sent = decodeInt64Splice(&buffer) - tag.synced = decodeInt64Splice(&buffer) - - t, n := binary.Varint(buffer) - tag.startedAt = time.Unix(t, 0) - buffer = buffer[n:] - - t, n = binary.Varint(buffer) - buffer = buffer[n:] - if t > 0 { - tag.Address = buffer[:t] - } - tag.Name = string(buffer[t:]) - - return nil -} - -func encodeInt64Append(buffer *[]byte, val int64) { - intBuffer := make([]byte, 8) - n := binary.PutVarint(intBuffer, val) - *buffer = append(*buffer, intBuffer[:n]...) -} - -func decodeInt64Splice(buffer *[]byte) int64 { - val, n := binary.Varint((*buffer)) - *buffer = (*buffer)[n:] - return val -} diff --git a/swarm/chunk/tag_test.go b/swarm/chunk/tag_test.go deleted file mode 100644 index e6acfb185b..0000000000 --- a/swarm/chunk/tag_test.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chunk - -import ( - "bytes" - "sync" - "testing" - "time" -) - -var ( - allStates = []State{StateSplit, StateStored, StateSeen, StateSent, StateSynced} -) - -// TestTagSingleIncrements tests if Inc increments the tag state value -func TestTagSingleIncrements(t *testing.T) { - tg := &Tag{total: 10} - - tc := []struct { - state uint32 - inc int - expcount int64 - exptotal int64 - }{ - {state: StateSplit, inc: 10, expcount: 10, exptotal: 10}, - {state: StateStored, inc: 9, expcount: 9, exptotal: 9}, - {state: StateSeen, inc: 1, expcount: 1, exptotal: 10}, - {state: StateSent, inc: 9, expcount: 9, exptotal: 9}, - {state: StateSynced, inc: 9, expcount: 9, exptotal: 9}, - } - - for _, tc := range tc { - for i := 0; i < tc.inc; i++ { - tg.Inc(tc.state) - } - } - - for _, tc := range tc { - if tg.Get(tc.state) != tc.expcount { - t.Fatalf("not incremented") - } - } -} - -// TestTagStatus is a unit test to cover Tag.Status method functionality -func TestTagStatus(t *testing.T) { - tg := &Tag{total: 10} - tg.Inc(StateSeen) - tg.Inc(StateSent) - tg.Inc(StateSynced) - - for i := 0; i < 10; i++ { - tg.Inc(StateSplit) - tg.Inc(StateStored) - } - for _, v := range []struct { - state State - expVal int64 - expTotal int64 - }{ - {state: StateStored, expVal: 10, expTotal: 10}, - {state: StateSplit, expVal: 10, expTotal: 10}, - {state: StateSeen, expVal: 1, expTotal: 10}, - {state: StateSent, expVal: 1, expTotal: 9}, - {state: StateSynced, expVal: 1, expTotal: 9}, - } { - val, total, err := tg.Status(v.state) - if err != nil { - t.Fatal(err) - } - if val != v.expVal { - t.Fatalf("should be %d, got %d", v.expVal, val) - } - if total != v.expTotal { - t.Fatalf("expected total to be %d, got %d", v.expTotal, total) - } - } -} - -// tests ETA is precise -func TestTagETA(t *testing.T) { - now := time.Now() - maxDiff := 100000 // 100 microsecond - tg := &Tag{total: 10, startedAt: now} - time.Sleep(100 * time.Millisecond) - tg.Inc(StateSplit) - eta, err := tg.ETA(StateSplit) - if err != nil { - t.Fatal(err) - } - diff := time.Until(eta) - 9*time.Since(now) - if int(diff) > maxDiff { - t.Fatalf("ETA is not precise, got diff %v > .1ms", diff) - } -} - -// TestTagConcurrentIncrements tests Inc calls concurrently -func TestTagConcurrentIncrements(t *testing.T) { - tg := &Tag{} - n := 1000 - wg := sync.WaitGroup{} - wg.Add(5 * n) - for _, f := range allStates { - go func(f State) { - for j := 0; j < n; j++ { - go func() { - tg.Inc(f) - wg.Done() - }() - } - }(f) - } - wg.Wait() - for _, f := range allStates { - v := tg.Get(f) - if v != int64(n) { - t.Fatalf("expected state %v to be %v, got %v", f, n, v) - } - } -} - -// TestTagsMultipleConcurrentIncrements tests Inc calls concurrently -func TestTagsMultipleConcurrentIncrementsSyncMap(t *testing.T) { - ts := NewTags() - n := 100 - wg := sync.WaitGroup{} - wg.Add(10 * 5 * n) - for i := 0; i < 10; i++ { - s := string([]byte{uint8(i)}) - tag, err := ts.New(s, int64(n)) - if err != nil { - t.Fatal(err) - } - for _, f := range allStates { - go func(tag *Tag, f State) { - for j := 0; j < n; j++ { - go func() { - tag.Inc(f) - wg.Done() - }() - } - }(tag, f) - } - } - wg.Wait() - i := 0 - ts.Range(func(k, v interface{}) bool { - i++ - uid := k.(uint32) - for _, f := range allStates { - tag, err := ts.Get(uid) - if err != nil { - t.Fatal(err) - } - stateVal := tag.Get(f) - if stateVal != int64(n) { - t.Fatalf("expected tag %v state %v to be %v, got %v", uid, f, n, v) - } - } - return true - - }) - if i != 10 { - t.Fatal("not enough tagz") - } -} - -// TestMarshallingWithAddr tests that marshalling and unmarshalling is done correctly when the -// tag Address (byte slice) contains some arbitrary value -func TestMarshallingWithAddr(t *testing.T) { - tg := NewTag(111, "test/tag", 10) - tg.Address = []byte{0, 1, 2, 3, 4, 5, 6} - - for _, f := range allStates { - tg.Inc(f) - } - - b, err := tg.MarshalBinary() - if err != nil { - t.Fatal(err) - } - - unmarshalledTag := &Tag{} - err = unmarshalledTag.UnmarshalBinary(b) - if err != nil { - t.Fatal(err) - } - - if unmarshalledTag.Uid != tg.Uid { - t.Fatalf("tag uids not equal. want %d got %d", tg.Uid, unmarshalledTag.Uid) - } - - if unmarshalledTag.Name != tg.Name { - t.Fatalf("tag names not equal. want %s got %s", tg.Name, unmarshalledTag.Name) - } - - for _, state := range allStates { - uv, tv := unmarshalledTag.Get(state), tg.Get(state) - if uv != tv { - t.Fatalf("state %d inconsistent. expected %d to equal %d", state, uv, tv) - } - } - - if unmarshalledTag.Total() != tg.Total() { - t.Fatalf("tag names not equal. want %d got %d", tg.Total(), unmarshalledTag.Total()) - } - - if len(unmarshalledTag.Address) != len(tg.Address) { - t.Fatalf("tag addresses length mismatch, want %d, got %d", len(tg.Address), len(unmarshalledTag.Address)) - } - - if !bytes.Equal(unmarshalledTag.Address, tg.Address) { - t.Fatalf("expected tag address to be %v got %v", unmarshalledTag.Address, tg.Address) - } -} - -// TestMarshallingNoAddress tests that marshalling and unmarshalling is done correctly -// when the tag Address (byte slice) is empty in this case -func TestMarshallingNoAddr(t *testing.T) { - tg := NewTag(111, "test/tag", 10) - for _, f := range allStates { - tg.Inc(f) - } - - b, err := tg.MarshalBinary() - if err != nil { - t.Fatal(err) - } - - unmarshalledTag := &Tag{} - err = unmarshalledTag.UnmarshalBinary(b) - if err != nil { - t.Fatal(err) - } - - if unmarshalledTag.Uid != tg.Uid { - t.Fatalf("tag uids not equal. want %d got %d", tg.Uid, unmarshalledTag.Uid) - } - - if unmarshalledTag.Name != tg.Name { - t.Fatalf("tag names not equal. want %s got %s", tg.Name, unmarshalledTag.Name) - } - - for _, state := range allStates { - uv, tv := unmarshalledTag.Get(state), tg.Get(state) - if uv != tv { - t.Fatalf("state %d inconsistent. expected %d to equal %d", state, uv, tv) - } - } - - if unmarshalledTag.Total() != tg.Total() { - t.Fatalf("tag names not equal. want %d got %d", tg.Total(), unmarshalledTag.Total()) - } - - if len(unmarshalledTag.Address) != len(tg.Address) { - t.Fatalf("expected tag addresses to be equal length") - } -} diff --git a/swarm/chunk/tags.go b/swarm/chunk/tags.go deleted file mode 100644 index 435f5d7068..0000000000 --- a/swarm/chunk/tags.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chunk - -import ( - "context" - "errors" - "math/rand" - "sync" - "time" - - "github.com/ethereum/go-ethereum/swarm/sctx" -) - -// Tags hold tag information indexed by a unique random uint32 -type Tags struct { - tags *sync.Map - rng *rand.Rand -} - -// NewTags creates a tags object -func NewTags() *Tags { - return &Tags{ - tags: &sync.Map{}, - rng: rand.New(rand.NewSource(time.Now().Unix())), - } -} - -// New creates a new tag, stores it by the name and returns it -// it returns an error if the tag with this name already exists -func (ts *Tags) New(s string, total int64) (*Tag, error) { - t := &Tag{ - Uid: ts.rng.Uint32(), - Name: s, - startedAt: time.Now(), - total: total, - } - if _, loaded := ts.tags.LoadOrStore(t.Uid, t); loaded { - return nil, errExists - } - return t, nil -} - -// All returns all existing tags in Tags' sync.Map -// Note that tags are returned in no particular order -func (ts *Tags) All() (t []*Tag) { - ts.tags.Range(func(k, v interface{}) bool { - t = append(t, v.(*Tag)) - - return true - }) - - return t -} - -// Get returns the undelying tag for the uid or an error if not found -func (ts *Tags) Get(uid uint32) (*Tag, error) { - t, ok := ts.tags.Load(uid) - if !ok { - return nil, errors.New("tag not found") - } - return t.(*Tag), nil -} - -// GetFromContext gets a tag from the tag uid stored in the context -func (ts *Tags) GetFromContext(ctx context.Context) (*Tag, error) { - uid := sctx.GetTag(ctx) - t, ok := ts.tags.Load(uid) - if !ok { - return nil, errTagNotFound - } - return t.(*Tag), nil -} - -// Range exposes sync.Map's iterator -func (ts *Tags) Range(fn func(k, v interface{}) bool) { - ts.tags.Range(fn) -} - -func (ts *Tags) Delete(k interface{}) { - ts.tags.Delete(k) -} diff --git a/swarm/chunk/tags_test.go b/swarm/chunk/tags_test.go deleted file mode 100644 index f818c4c5ca..0000000000 --- a/swarm/chunk/tags_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chunk - -import "testing" - -func TestAll(t *testing.T) { - ts := NewTags() - - ts.New("1", 1) - ts.New("2", 1) - - all := ts.All() - - if len(all) != 2 { - t.Fatalf("expected length to be 2 got %d", len(all)) - } - - if n := all[0].Total(); n != 1 { - t.Fatalf("expected tag 0 total to be 1 got %d", n) - } - - if n := all[1].Total(); n != 1 { - t.Fatalf("expected tag 1 total to be 1 got %d", n) - } - - ts.New("3", 1) - all = ts.All() - - if len(all) != 3 { - t.Fatalf("expected length to be 3 got %d", len(all)) - } - -} diff --git a/swarm/dev/.dockerignore b/swarm/dev/.dockerignore deleted file mode 100644 index f9e69b37f3..0000000000 --- a/swarm/dev/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -bin/* -cluster/* diff --git a/swarm/dev/.gitignore b/swarm/dev/.gitignore deleted file mode 100644 index f9e69b37f3..0000000000 --- a/swarm/dev/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -bin/* -cluster/* diff --git a/swarm/dev/Dockerfile b/swarm/dev/Dockerfile deleted file mode 100644 index 728bdab1fb..0000000000 --- a/swarm/dev/Dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -FROM ubuntu:xenial - -# install build + test dependencies -RUN apt-get update && \ - apt-get install --yes --no-install-recommends \ - ca-certificates \ - curl \ - fuse \ - g++ \ - gcc \ - git \ - iproute2 \ - iputils-ping \ - less \ - libc6-dev \ - make \ - pkg-config \ - && \ - apt-get clean - -# install Go -ENV GO_VERSION 1.8.1 -RUN curl -fSLo golang.tar.gz "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" && \ - tar -xzf golang.tar.gz -C /usr/local && \ - rm golang.tar.gz -ENV GOPATH /go -ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH - -# install docker CLI -RUN curl -fSLo docker.tar.gz https://get.docker.com/builds/Linux/x86_64/docker-17.04.0-ce.tgz && \ - tar -xzf docker.tar.gz -C /usr/local/bin --strip-components=1 docker/docker && \ - rm docker.tar.gz - -# install jq -RUN curl -fSLo /usr/local/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && \ - chmod +x /usr/local/bin/jq - -# install govendor -RUN go get -u github.com/kardianos/govendor - -# add custom bashrc -ADD bashrc /root/.bashrc diff --git a/swarm/dev/Makefile b/swarm/dev/Makefile deleted file mode 100644 index 365964b7f5..0000000000 --- a/swarm/dev/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -.PHONY: build cluster test - -default: build - -build: - go build -o bin/swarm github.com/ethereum/go-ethereum/cmd/swarm - go build -o bin/geth github.com/ethereum/go-ethereum/cmd/geth - go build -o bin/bootnode github.com/ethereum/go-ethereum/cmd/bootnode - -cluster: build - scripts/boot-cluster.sh - -test: - go test -v github.com/ethereum/go-ethereum/swarm/... diff --git a/swarm/dev/README.md b/swarm/dev/README.md deleted file mode 100644 index 81e3b53585..0000000000 --- a/swarm/dev/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Swarm development environment -============================= - -The Swarm development environment is a Linux bash shell which can be run in a -Docker container and provides a predictable build and test environment. - -### Start the Docker container - -Run the `run.sh` script to build the Docker image and run it, you will then be -at a bash prompt inside the `swarm/dev` directory. - -### Build binaries - -Run `make` to build the `swarm`, `geth` and `bootnode` binaries into the -`swarm/dev/bin` directory. - -### Boot a cluster - -Run `make cluster` to start a 3 node Swarm cluster, or run -`scripts/boot-cluster.sh --size N` to boot a cluster of size N. diff --git a/swarm/dev/bashrc b/swarm/dev/bashrc deleted file mode 100644 index efb504fa36..0000000000 --- a/swarm/dev/bashrc +++ /dev/null @@ -1,21 +0,0 @@ -export ROOT="${GOPATH}/src/github.com/ethereum/go-ethereum" -export PATH="${ROOT}/swarm/dev/bin:${PATH}" - -cd "${ROOT}/swarm/dev" - -cat <&2 <&2 - exit 1 - fi - name="$2" - shift 2 - ;; - -d | --docker-args) - if [[ -z "$2" ]]; then - echo "ERROR: --docker-args flag requires an argument" >&2 - exit 1 - fi - docker_args="$2" - shift 2 - ;; - *) - break - ;; - esac - done - - if [[ $# -ne 0 ]]; then - usage - echo "ERROR: invalid arguments" >&2 - exit 1 - fi -} - -build_image() { - docker build --tag "${name}" "${ROOT}/swarm/dev" -} - -run_image() { - exec docker run \ - --privileged \ - --interactive \ - --tty \ - --rm \ - --hostname "${name}" \ - --name "${name}" \ - --volume "${ROOT}:/go/src/github.com/ethereum/go-ethereum" \ - --volume "/var/run/docker.sock:/var/run/docker.sock" \ - ${docker_args} \ - "${name}" \ - /bin/bash -} - -main "$@" diff --git a/swarm/dev/scripts/boot-cluster.sh b/swarm/dev/scripts/boot-cluster.sh deleted file mode 100755 index 98ae3c8023..0000000000 --- a/swarm/dev/scripts/boot-cluster.sh +++ /dev/null @@ -1,288 +0,0 @@ -#!/bin/bash -# -# A script to boot a dev swarm cluster on a Linux host (typically in a Docker -# container started with swarm/dev/run.sh). -# -# The cluster contains a bootnode, a geth node and multiple swarm nodes, with -# each node having its own data directory in a base directory passed with the -# --dir flag (default is swarm/dev/cluster). -# -# To avoid using different ports for each node and to make networking more -# realistic, each node gets its own network namespace with IPs assigned from -# the 192.168.33.0/24 subnet: -# -# bootnode: 192.168.33.2 -# geth: 192.168.33.3 -# swarm: 192.168.33.10{1,2,...,n} - -set -e - -ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" -source "${ROOT}/swarm/dev/scripts/util.sh" - -# DEFAULT_BASE_DIR is the default base directory to store node data -DEFAULT_BASE_DIR="${ROOT}/swarm/dev/cluster" - -# DEFAULT_CLUSTER_SIZE is the default swarm cluster size -DEFAULT_CLUSTER_SIZE=3 - -# Linux bridge configuration for connecting the node network namespaces -BRIDGE_NAME="swarmbr0" -BRIDGE_IP="192.168.33.1" - -# static bootnode configuration -BOOTNODE_IP="192.168.33.2" -BOOTNODE_PORT="30301" -BOOTNODE_KEY="32078f313bea771848db70745225c52c00981589ad6b5b49163f0f5ee852617d" -BOOTNODE_PUBKEY="760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d" -BOOTNODE_URL="enode://${BOOTNODE_PUBKEY}@${BOOTNODE_IP}:${BOOTNODE_PORT}" - -# static geth configuration -GETH_IP="192.168.33.3" -GETH_RPC_PORT="8545" -GETH_RPC_URL="http://${GETH_IP}:${GETH_RPC_PORT}" - -usage() { - cat >&2 < "${key_file}" - - local args=( - --addr "${BOOTNODE_IP}:${BOOTNODE_PORT}" - --nodekey "${key_file}" - --verbosity "6" - ) - - start_node "bootnode" "${BOOTNODE_IP}" "$(which bootnode)" ${args[@]} -} - -# start_geth_node starts a geth node with --datadir pointing at /geth -# and a single, unlocked account with password "geth" -start_geth_node() { - local dir="${base_dir}/geth" - mkdir -p "${dir}" - - local password="geth" - echo "${password}" > "${dir}/password" - - # create an account if necessary - if [[ ! -e "${dir}/keystore" ]]; then - info "creating geth account" - create_account "${dir}" "${password}" - fi - - # get the account address - local address="$(jq --raw-output '.address' ${dir}/keystore/*)" - if [[ -z "${address}" ]]; then - fail "failed to get geth account address" - fi - - local args=( - --datadir "${dir}" - --networkid "321" - --bootnodes "${BOOTNODE_URL}" - --unlock "${address}" - --password "${dir}/password" - --rpc - --rpcaddr "${GETH_IP}" - --rpcport "${GETH_RPC_PORT}" - --verbosity "6" - ) - - start_node "geth" "${GETH_IP}" "$(which geth)" ${args[@]} -} - -start_swarm_nodes() { - for i in $(seq 1 ${cluster_size}); do - start_swarm_node "${i}" - done -} - -# start_swarm_node starts a swarm node with a name like "swarmNN" (where NN is -# a zero-padded integer like "07"), --datadir pointing at / -# (e.g. /swarm07) and a single account with as the password -start_swarm_node() { - local num=$1 - local name="swarm$(printf '%02d' ${num})" - local ip="192.168.33.1$(printf '%02d' ${num})" - - local dir="${base_dir}/${name}" - mkdir -p "${dir}" - - local password="${name}" - echo "${password}" > "${dir}/password" - - # create an account if necessary - if [[ ! -e "${dir}/keystore" ]]; then - info "creating account for ${name}" - create_account "${dir}" "${password}" - fi - - # get the account address - local address="$(jq --raw-output '.address' ${dir}/keystore/*)" - if [[ -z "${address}" ]]; then - fail "failed to get swarm account address" - fi - - local args=( - --bootnodes "${BOOTNODE_URL}" - --datadir "${dir}" - --identity "${name}" - --ens-api "${GETH_RPC_URL}" - --bzznetworkid "321" - --bzzaccount "${address}" - --password "${dir}/password" - --verbosity "6" - ) - - start_node "${name}" "${ip}" "$(which swarm)" ${args[@]} -} - -# start_node runs the node command as a daemon in a network namespace -start_node() { - local name="$1" - local ip="$2" - local path="$3" - local cmd_args=${@:4} - - info "starting ${name} with IP ${ip}" - - create_node_network "${name}" "${ip}" - - # add a marker to the log file - cat >> "${log_dir}/${name}.log" <>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -Starting ${name} node - $(date) ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - -EOF - - # run the command in the network namespace using start-stop-daemon to - # daemonise the process, sending all output to the log file - local daemon_args=( - --start - --background - --no-close - --make-pidfile - --pidfile "${pid_dir}/${name}.pid" - --exec "${path}" - ) - if ! ip netns exec "${name}" start-stop-daemon ${daemon_args[@]} -- $cmd_args &>> "${log_dir}/${name}.log"; then - fail "could not start ${name}, check ${log_dir}/${name}.log" - fi -} - -# create_node_network creates a network namespace and connects it to the Linux -# bridge using a veth pair -create_node_network() { - local name="$1" - local ip="$2" - - # create the namespace - ip netns add "${name}" - - # create the veth pair - local veth0="veth${name}0" - local veth1="veth${name}1" - ip link add name "${veth0}" type veth peer name "${veth1}" - - # add one end to the bridge - ip link set dev "${veth0}" master "${BRIDGE_NAME}" - ip link set dev "${veth0}" up - - # add the other end to the namespace, rename it eth0 and give it the ip - ip link set dev "${veth1}" netns "${name}" - ip netns exec "${name}" ip link set dev "${veth1}" name "eth0" - ip netns exec "${name}" ip link set dev "eth0" up - ip netns exec "${name}" ip address add "${ip}/24" dev "eth0" -} - -create_account() { - local dir=$1 - local password=$2 - - geth --datadir "${dir}" --password /dev/stdin account new <<< "${password}" -} - -main "$@" diff --git a/swarm/dev/scripts/random-uploads.sh b/swarm/dev/scripts/random-uploads.sh deleted file mode 100755 index 563a51befc..0000000000 --- a/swarm/dev/scripts/random-uploads.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/bash -# -# A script to upload random data to a swarm cluster. -# -# Example: -# -# random-uploads.sh --addr 192.168.33.101:8500 --size 40k --count 1000 - -set -e - -ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" -source "${ROOT}/swarm/dev/scripts/util.sh" - -DEFAULT_ADDR="localhost:8500" -DEFAULT_UPLOAD_SIZE="40k" -DEFAULT_UPLOAD_COUNT="1000" - -usage() { - cat >&2 </dev/null -} - -parse_args() { - while true; do - case "$1" in - -h | --help) - usage - exit 0 - ;; - -a | --addr) - if [[ -z "$2" ]]; then - fail "--addr flag requires an argument" - fi - addr="$2" - shift 2 - ;; - -s | --size) - if [[ -z "$2" ]]; then - fail "--size flag requires an argument" - fi - upload_size="$2" - shift 2 - ;; - -c | --count) - if [[ -z "$2" ]]; then - fail "--count flag requires an argument" - fi - upload_count="$2" - shift 2 - ;; - *) - break - ;; - esac - done - - if [[ $# -ne 0 ]]; then - usage - fail "ERROR: invalid arguments: $@" - fi -} - -main "$@" diff --git a/swarm/dev/scripts/stop-cluster.sh b/swarm/dev/scripts/stop-cluster.sh deleted file mode 100755 index 89cb7b0c9a..0000000000 --- a/swarm/dev/scripts/stop-cluster.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -# -# A script to shutdown a dev swarm cluster. - -set -e - -ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" -source "${ROOT}/swarm/dev/scripts/util.sh" - -DEFAULT_BASE_DIR="${ROOT}/swarm/dev/cluster" - -usage() { - cat >&2 </dev/null; then - ip link delete dev "veth${name}0" - fi -} - -delete_network() { - if ip link show "swarmbr0" &>/dev/null; then - ip link delete dev "swarmbr0" - fi -} - -main "$@" diff --git a/swarm/dev/scripts/util.sh b/swarm/dev/scripts/util.sh deleted file mode 100644 index f17a12e420..0000000000 --- a/swarm/dev/scripts/util.sh +++ /dev/null @@ -1,53 +0,0 @@ -# shared shell functions - -info() { - local msg="$@" - local timestamp="$(date +%H:%M:%S)" - say "===> ${timestamp} ${msg}" "green" -} - -warn() { - local msg="$@" - local timestamp=$(date +%H:%M:%S) - say "===> ${timestamp} WARN: ${msg}" "yellow" >&2 -} - -fail() { - local msg="$@" - say "ERROR: ${msg}" "red" >&2 - exit 1 -} - -# say prints the given message to STDOUT, using the optional color if -# STDOUT is a terminal. -# -# usage: -# -# say "foo" - prints "foo" -# say "bar" "red" - prints "bar" in red -# say "baz" "green" - prints "baz" in green -# say "qux" "red" | tee - prints "qux" with no colour -# -say() { - local msg=$1 - local color=$2 - - if [[ -n "${color}" ]] && [[ -t 1 ]]; then - case "${color}" in - red) - echo -e "\033[1;31m${msg}\033[0m" - ;; - green) - echo -e "\033[1;32m${msg}\033[0m" - ;; - yellow) - echo -e "\033[1;33m${msg}\033[0m" - ;; - *) - echo "${msg}" - ;; - esac - else - echo "${msg}" - fi -} diff --git a/swarm/docker/Dockerfile b/swarm/docker/Dockerfile deleted file mode 100644 index 9450609dd8..0000000000 --- a/swarm/docker/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM golang:1.11-alpine as builder - -ARG VERSION - -RUN apk add --update git gcc g++ linux-headers -RUN mkdir -p $GOPATH/src/github.com/ethereum && \ - cd $GOPATH/src/github.com/ethereum && \ - git clone https://github.com/ethersphere/go-ethereum && \ - cd $GOPATH/src/github.com/ethereum/go-ethereum && \ - git checkout ${VERSION} && \ - go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm && \ - go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm/swarm-smoke && \ - go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm/global-store && \ - go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/geth - - -FROM alpine:3.8 as swarm-smoke -WORKDIR / -COPY --from=builder /go/bin/swarm-smoke / -ADD run-smoke.sh /run-smoke.sh -ENTRYPOINT ["/run-smoke.sh"] - -FROM alpine:3.8 as swarm-global-store -WORKDIR / -COPY --from=builder /go/bin/global-store / -ENTRYPOINT ["/global-store"] - -FROM alpine:3.8 as swarm -WORKDIR / -COPY --from=builder /go/bin/swarm /go/bin/geth / -ADD run.sh /run.sh -ENTRYPOINT ["/run.sh"] diff --git a/swarm/docker/run-smoke.sh b/swarm/docker/run-smoke.sh deleted file mode 100755 index ba57a7ecd6..0000000000 --- a/swarm/docker/run-smoke.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -o errexit -set -o pipefail -set -o nounset - -/swarm-smoke $@ 2>&1 || true diff --git a/swarm/docker/run.sh b/swarm/docker/run.sh deleted file mode 100755 index 3e613b56d9..0000000000 --- a/swarm/docker/run.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -set -o errexit -set -o pipefail -set -o nounset - -PASSWORD=${PASSWORD:-} -DATADIR=${DATADIR:-/root/.ethereum/} - -if [ "$PASSWORD" == "" ]; then echo "Password must be set, in order to use swarm non-interactively." && exit 1; fi - -echo $PASSWORD > /password - -KEYFILE=`find $DATADIR | grep UTC | head -n 1` || true -if [ ! -f "$KEYFILE" ]; then echo "No keyfile found. Generating..." && /geth --datadir $DATADIR --password /password account new; fi -KEYFILE=`find $DATADIR | grep UTC | head -n 1` || true -if [ ! -f "$KEYFILE" ]; then echo "Could not find nor generate a BZZ keyfile." && exit 1; else echo "Found keyfile $KEYFILE"; fi - -VERSION=`/swarm version` -echo "Running Swarm:" -echo $VERSION - -export BZZACCOUNT="`echo -n $KEYFILE | tail -c 40`" || true -if [ "$BZZACCOUNT" == "" ]; then echo "Could not parse BZZACCOUNT from keyfile." && exit 1; fi - -exec /swarm --bzzaccount=$BZZACCOUNT --password /password --datadir $DATADIR $@ 2>&1 diff --git a/swarm/docs/migration-v0.3-to-v0.4.md b/swarm/docs/migration-v0.3-to-v0.4.md deleted file mode 100644 index cebc286c19..0000000000 --- a/swarm/docs/migration-v0.3-to-v0.4.md +++ /dev/null @@ -1,31 +0,0 @@ -Swarm DB migration notes -========================= -Swarm `v0.4` introduces major changes to the existing codebase. Among other things, the storage layer has been rewritten to be more modular and flexible -in a manner that will accomodate for our future needs. Since Swarm at this point does not provide any storage guarantees, we have made the decision to not impose any migrations on our public cluster nor on our users. What this essentially means is that local storage will be purged on `v0.4`. We have nevertheless, provided a procedure below for those of you running private clusters and would like to migrate the data to the new local storage format. - -You are highly encouraged to report to us any bugs or problems caused by running the migration steps below. - -**Note**: we highly recommend you run the commands below with `--verbosity 5` flag and open an issue with the relevant terminal output in case something goes wrong. - -**Important**: since you would be creating an export of your local store, the potential disk usage might peak at `x2-x3` times the normal Swarm data folder size. Please make sure you have enough disk space, backup mediums or other form of local/network attached storage _before_ executing the following steps! - -**Important**: when trying to run Swarm with an old local store format, the Swarm binary will refuse to start showing an error message. - -You will need the following information for the migration procedure: -1. Your `datadir` path. This is indicated with the `--datadir` flag when running Swarm. If you do not specify this flag, the `datadir` will reside by default on `$HOME/.ethereum`. -2. Your chunk directory location. This would normally be located in your `datadir/swarm/bzz-/chunks`. We will refer to this as `chunkDir` below. -3. Your `bzzAddr`. This is _not_ your `--bzzaccount`! You can find your `bzzAddr` when starting Swarm by looking for the following line: -``` -INFO [03-21|17:25:04.791] Swarm network started bzzaddr=ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c -``` - -The migration process is done in the following manner: -1. Try to run the updated Swarm binary, it should complain about the local store format and exit. If it does - execute the following steps: -2. `$ swarm --verbosity 5 db export /.tar ` -3. Move or Remove your existing `chunkDir` -4. Run the new Swarm binary as your would start your Swarm node normally. The binary should now load normally and not complain. This step creates a new empty chunk store. Please shut down the node after it starts correctly. -5. `$ swarm --verbosity 5 db import --legacy /.tar ` -6. Wait patientally for the `Imported X chunks successfully` message. -7. Start your Swarm node as you normally would -8. Have a beer - diff --git a/swarm/fuse/fuse_dir.go b/swarm/fuse/fuse_dir.go deleted file mode 100644 index 7f66451f10..0000000000 --- a/swarm/fuse/fuse_dir.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build linux darwin freebsd - -package fuse - -import ( - "os" - "path/filepath" - "sync" - - "bazil.org/fuse" - "bazil.org/fuse/fs" - "github.com/ethereum/go-ethereum/swarm/log" - "golang.org/x/net/context" -) - -var ( - _ fs.Node = (*SwarmDir)(nil) - _ fs.NodeRequestLookuper = (*SwarmDir)(nil) - _ fs.HandleReadDirAller = (*SwarmDir)(nil) - _ fs.NodeCreater = (*SwarmDir)(nil) - _ fs.NodeRemover = (*SwarmDir)(nil) - _ fs.NodeMkdirer = (*SwarmDir)(nil) -) - -type SwarmDir struct { - inode uint64 - name string - path string - directories []*SwarmDir - files []*SwarmFile - - mountInfo *MountInfo - lock *sync.RWMutex -} - -func NewSwarmDir(fullpath string, minfo *MountInfo) *SwarmDir { - log.Debug("swarmfs", "NewSwarmDir", fullpath) - newdir := &SwarmDir{ - inode: NewInode(), - name: filepath.Base(fullpath), - path: fullpath, - directories: []*SwarmDir{}, - files: []*SwarmFile{}, - mountInfo: minfo, - lock: &sync.RWMutex{}, - } - return newdir -} - -func (sd *SwarmDir) Attr(ctx context.Context, a *fuse.Attr) error { - sd.lock.RLock() - defer sd.lock.RUnlock() - a.Inode = sd.inode - a.Mode = os.ModeDir | 0700 - a.Uid = uint32(os.Getuid()) - a.Gid = uint32(os.Getegid()) - return nil -} - -func (sd *SwarmDir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) { - log.Debug("swarmfs", "Lookup", req.Name) - for _, n := range sd.files { - if n.name == req.Name { - return n, nil - } - } - for _, n := range sd.directories { - if n.name == req.Name { - return n, nil - } - } - return nil, fuse.ENOENT -} - -func (sd *SwarmDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - log.Debug("swarmfs ReadDirAll") - var children []fuse.Dirent - for _, file := range sd.files { - children = append(children, fuse.Dirent{Inode: file.inode, Type: fuse.DT_File, Name: file.name}) - } - for _, dir := range sd.directories { - children = append(children, fuse.Dirent{Inode: dir.inode, Type: fuse.DT_Dir, Name: dir.name}) - } - return children, nil -} - -func (sd *SwarmDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) { - log.Debug("swarmfs Create", "path", sd.path, "req.Name", req.Name) - - newFile := NewSwarmFile(sd.path, req.Name, sd.mountInfo) - newFile.fileSize = 0 // 0 means, file is not in swarm yet and it is just created - - sd.lock.Lock() - defer sd.lock.Unlock() - sd.files = append(sd.files, newFile) - - return newFile, newFile, nil -} - -func (sd *SwarmDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { - log.Debug("swarmfs Remove", "path", sd.path, "req.Name", req.Name) - - if req.Dir && sd.directories != nil { - newDirs := []*SwarmDir{} - for _, dir := range sd.directories { - if dir.name == req.Name { - removeDirectoryFromSwarm(dir) - } else { - newDirs = append(newDirs, dir) - } - } - if len(sd.directories) > len(newDirs) { - sd.lock.Lock() - defer sd.lock.Unlock() - sd.directories = newDirs - } - return nil - } else if !req.Dir && sd.files != nil { - newFiles := []*SwarmFile{} - for _, f := range sd.files { - if f.name == req.Name { - removeFileFromSwarm(f) - } else { - newFiles = append(newFiles, f) - } - } - if len(sd.files) > len(newFiles) { - sd.lock.Lock() - defer sd.lock.Unlock() - sd.files = newFiles - } - return nil - } - return fuse.ENOENT -} - -func (sd *SwarmDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { - log.Debug("swarmfs Mkdir", "path", sd.path, "req.Name", req.Name) - newDir := NewSwarmDir(filepath.Join(sd.path, req.Name), sd.mountInfo) - sd.lock.Lock() - defer sd.lock.Unlock() - sd.directories = append(sd.directories, newDir) - - return newDir, nil -} diff --git a/swarm/fuse/fuse_file.go b/swarm/fuse/fuse_file.go deleted file mode 100644 index ca04f737e2..0000000000 --- a/swarm/fuse/fuse_file.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build linux darwin freebsd - -package fuse - -import ( - "errors" - "io" - "os" - "sync" - - "bazil.org/fuse" - "bazil.org/fuse/fs" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/storage" - "golang.org/x/net/context" -) - -const ( - MaxAppendFileSize = 10485760 // 10Mb -) - -var ( - errInvalidOffset = errors.New("Invalid offset during write") - errFileSizeMaxLimixReached = errors.New("File size exceeded max limit") -) - -var ( - _ fs.Node = (*SwarmFile)(nil) - _ fs.HandleReader = (*SwarmFile)(nil) - _ fs.HandleWriter = (*SwarmFile)(nil) -) - -type SwarmFile struct { - inode uint64 - name string - path string - addr storage.Address - fileSize int64 - reader storage.LazySectionReader - - mountInfo *MountInfo - lock *sync.RWMutex -} - -func NewSwarmFile(path, fname string, minfo *MountInfo) *SwarmFile { - newFile := &SwarmFile{ - inode: NewInode(), - name: fname, - path: path, - addr: nil, - fileSize: -1, // -1 means , file already exists in swarm and you need to just get the size from swarm - reader: nil, - - mountInfo: minfo, - lock: &sync.RWMutex{}, - } - return newFile -} - -func (sf *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error { - log.Debug("swarmfs Attr", "path", sf.path) - sf.lock.Lock() - defer sf.lock.Unlock() - a.Inode = sf.inode - //TODO: need to get permission as argument - a.Mode = 0700 - a.Uid = uint32(os.Getuid()) - a.Gid = uint32(os.Getegid()) - - if sf.fileSize == -1 { - reader, _ := sf.mountInfo.swarmApi.Retrieve(ctx, sf.addr) - quitC := make(chan bool) - size, err := reader.Size(ctx, quitC) - if err != nil { - log.Error("Couldnt get size of file %s : %v", sf.path, err) - return err - } - sf.fileSize = size - log.Trace("swarmfs Attr", "size", size) - close(quitC) - } - a.Size = uint64(sf.fileSize) - return nil -} - -func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - log.Debug("swarmfs Read", "path", sf.path, "req.String", req.String()) - sf.lock.RLock() - defer sf.lock.RUnlock() - if sf.reader == nil { - sf.reader, _ = sf.mountInfo.swarmApi.Retrieve(ctx, sf.addr) - } - buf := make([]byte, req.Size) - n, err := sf.reader.ReadAt(buf, req.Offset) - if err == io.ErrUnexpectedEOF || err == io.EOF { - err = nil - } - resp.Data = buf[:n] - sf.reader = nil - - return err -} - -func (sf *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { - log.Debug("swarmfs Write", "path", sf.path, "req.String", req.String()) - if sf.fileSize == 0 && req.Offset == 0 { - // A new file is created - err := addFileToSwarm(sf, req.Data, len(req.Data)) - if err != nil { - return err - } - resp.Size = len(req.Data) - } else if req.Offset <= sf.fileSize { - totalSize := sf.fileSize + int64(len(req.Data)) - if totalSize > MaxAppendFileSize { - log.Warn("swarmfs Append file size reached (%v) : (%v)", sf.fileSize, len(req.Data)) - return errFileSizeMaxLimixReached - } - - err := appendToExistingFileInSwarm(sf, req.Data, req.Offset, int64(len(req.Data))) - if err != nil { - return err - } - resp.Size = len(req.Data) - } else { - log.Warn("swarmfs Invalid write request size(%v) : off(%v)", sf.fileSize, req.Offset) - return errInvalidOffset - } - return nil -} diff --git a/swarm/fuse/fuse_root.go b/swarm/fuse/fuse_root.go deleted file mode 100644 index b2262d1c5a..0000000000 --- a/swarm/fuse/fuse_root.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build linux darwin freebsd - -package fuse - -import ( - "bazil.org/fuse/fs" -) - -var ( - _ fs.Node = (*SwarmDir)(nil) -) - -type SwarmRoot struct { - root *SwarmDir -} - -func (filesystem *SwarmRoot) Root() (fs.Node, error) { - return filesystem.root, nil -} diff --git a/swarm/fuse/swarmfs.go b/swarm/fuse/swarmfs.go deleted file mode 100644 index db6aefb54c..0000000000 --- a/swarm/fuse/swarmfs.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package fuse - -import ( - "sync" - "time" - - "github.com/ethereum/go-ethereum/swarm/api" -) - -const ( - SwarmFSVersion = "0.1" - mountTimeout = time.Second * 5 - unmountTimeout = time.Second * 10 - maxFUSEMounts = 5 -) - -var ( - swarmfs *SwarmFS // Swarm file system singleton - swarmfsLock sync.Once - - inode uint64 = 1 // global inode - inodeLock sync.RWMutex -) - -type SwarmFS struct { - swarmApi *api.API - activeMounts map[string]*MountInfo - swarmFsLock *sync.RWMutex -} - -func NewSwarmFS(api *api.API) *SwarmFS { - swarmfsLock.Do(func() { - swarmfs = &SwarmFS{ - swarmApi: api, - swarmFsLock: &sync.RWMutex{}, - activeMounts: map[string]*MountInfo{}, - } - }) - return swarmfs - -} - -// Inode numbers need to be unique, they are used for caching inside fuse -func NewInode() uint64 { - inodeLock.Lock() - defer inodeLock.Unlock() - inode += 1 - return inode -} diff --git a/swarm/fuse/swarmfs_fallback.go b/swarm/fuse/swarmfs_fallback.go deleted file mode 100644 index 4864c8689c..0000000000 --- a/swarm/fuse/swarmfs_fallback.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build !linux,!darwin,!freebsd - -package fuse - -import ( - "errors" -) - -var errNoFUSE = errors.New("FUSE is not supported on this platform") - -func isFUSEUnsupportedError(err error) bool { - return err == errNoFUSE -} - -type MountInfo struct { - MountPoint string - StartManifest string - LatestManifest string -} - -func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { - return nil, errNoFUSE -} - -func (self *SwarmFS) Unmount(mountpoint string) (bool, error) { - return false, errNoFUSE -} - -func (self *SwarmFS) Listmounts() ([]*MountInfo, error) { - return nil, errNoFUSE -} - -func (self *SwarmFS) Stop() error { - return nil -} diff --git a/swarm/fuse/swarmfs_test.go b/swarm/fuse/swarmfs_test.go deleted file mode 100644 index 77573f0fc7..0000000000 --- a/swarm/fuse/swarmfs_test.go +++ /dev/null @@ -1,1672 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build linux darwin freebsd - -package fuse - -import ( - "bytes" - "flag" - "fmt" - "io" - "io/ioutil" - "math/rand" - "os" - "path/filepath" - "testing" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/testutil" - colorable "github.com/mattn/go-colorable" -) - -var ( - loglevel = flag.Int("loglevel", 4, "verbosity of logs") - rawlog = flag.Bool("rawlog", false, "turn off terminal formatting in logs") - longrunning = flag.Bool("longrunning", false, "do run long-running tests") -) - -func init() { - flag.Parse() - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(!*rawlog)))) -} - -type fileInfo struct { - perm uint64 - uid int - gid int - contents []byte -} - -//create files from the map of name and content provided and upload them to swarm via api -func createTestFilesAndUploadToSwarm(t *testing.T, api *api.API, files map[string]fileInfo, uploadDir string, toEncrypt bool) string { - - //iterate the map - for fname, finfo := range files { - actualPath := filepath.Join(uploadDir, fname) - filePath := filepath.Dir(actualPath) - - //create directory - err := os.MkdirAll(filePath, 0777) - if err != nil { - t.Fatalf("Error creating directory '%v' : %v", filePath, err) - } - - //create file - fd, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(finfo.perm)) - if err1 != nil { - t.Fatalf("Error creating file %v: %v", actualPath, err1) - } - - //write content to file - _, err = fd.Write(finfo.contents) - if err != nil { - t.Fatalf("Error writing to file '%v' : %v", filePath, err) - } - /* - Note @holisticode: It's not clear why the Chown command was added to the test suite. - Some files are initialized with different permissions in the individual test, - resulting in errors on Chown which were not checked. - After adding the checks tests would fail. - - What's then the reason to have this check in the first place? - Disabling for now - - err = fd.Chown(finfo.uid, finfo.gid) - if err != nil { - t.Fatalf("Error chown file '%v' : %v", filePath, err) - } - */ - err = fd.Chmod(os.FileMode(finfo.perm)) - if err != nil { - t.Fatalf("Error chmod file '%v' : %v", filePath, err) - } - err = fd.Sync() - if err != nil { - t.Fatalf("Error sync file '%v' : %v", filePath, err) - } - err = fd.Close() - if err != nil { - t.Fatalf("Error closing file '%v' : %v", filePath, err) - } - } - - //upload directory to swarm and return hash - bzzhash, err := Upload(uploadDir, "", api, toEncrypt) - if err != nil { - t.Fatalf("Error uploading directory %v: %vm encryption: %v", uploadDir, err, toEncrypt) - } - - return bzzhash -} - -//mount a swarm hash as a directory on files system via FUSE -func mountDir(t *testing.T, api *api.API, files map[string]fileInfo, bzzHash string, mountDir string) *SwarmFS { - swarmfs := NewSwarmFS(api) - _, err := swarmfs.Mount(bzzHash, mountDir) - if isFUSEUnsupportedError(err) { - t.Skip("FUSE not supported:", err) - } else if err != nil { - t.Fatalf("Error mounting hash %v: %v", bzzHash, err) - } - - //check directory is mounted - found := false - mi := swarmfs.Listmounts() - for _, minfo := range mi { - minfo.lock.RLock() - if minfo.MountPoint == mountDir { - if minfo.StartManifest != bzzHash || - minfo.LatestManifest != bzzHash || - minfo.fuseConnection == nil { - minfo.lock.RUnlock() - t.Fatalf("Error mounting: exp(%s): act(%s)", bzzHash, minfo.StartManifest) - } - found = true - } - minfo.lock.RUnlock() - } - - // Test listMounts - if !found { - t.Fatalf("Error getting mounts information for %v: %v", mountDir, err) - } - - // Check if file and their attributes are as expected - compareGeneratedFileWithFileInMount(t, files, mountDir) - - return swarmfs -} - -// Check if file and their attributes are as expected -func compareGeneratedFileWithFileInMount(t *testing.T, files map[string]fileInfo, mountDir string) { - err := filepath.Walk(mountDir, func(path string, f os.FileInfo, err error) error { - if f.IsDir() { - return nil - } - fname := path[len(mountDir)+1:] - if _, ok := files[fname]; !ok { - t.Fatalf(" file %v present in mount dir and is not expected", fname) - } - return nil - }) - if err != nil { - t.Fatalf("Error walking dir %v", mountDir) - } - - for fname, finfo := range files { - destinationFile := filepath.Join(mountDir, fname) - - dfinfo, err := os.Stat(destinationFile) - if err != nil { - t.Fatalf("Destination file %v missing in mount: %v", fname, err) - } - - if int64(len(finfo.contents)) != dfinfo.Size() { - t.Fatalf("file %v Size mismatch source (%v) vs destination(%v)", fname, int64(len(finfo.contents)), dfinfo.Size()) - } - - if dfinfo.Mode().Perm().String() != "-rwx------" { - t.Fatalf("file %v Permission mismatch source (-rwx------) vs destination(%v)", fname, dfinfo.Mode().Perm()) - } - - fileContents, err := ioutil.ReadFile(filepath.Join(mountDir, fname)) - if err != nil { - t.Fatalf("Could not readfile %v : %v", fname, err) - } - if !bytes.Equal(fileContents, finfo.contents) { - t.Fatalf("File %v contents mismatch: %v , %v", fname, fileContents, finfo.contents) - } - // TODO: check uid and gid - } -} - -//check mounted file with provided content -func checkFile(t *testing.T, testMountDir, fname string, contents []byte) { - destinationFile := filepath.Join(testMountDir, fname) - dfinfo, err1 := os.Stat(destinationFile) - if err1 != nil { - t.Fatalf("Could not stat file %v", destinationFile) - } - if dfinfo.Size() != int64(len(contents)) { - t.Fatalf("Mismatch in size actual(%v) vs expected(%v)", dfinfo.Size(), int64(len(contents))) - } - - fd, err2 := os.OpenFile(destinationFile, os.O_RDONLY, os.FileMode(0665)) - if err2 != nil { - t.Fatalf("Could not open file %v", destinationFile) - } - newcontent := make([]byte, len(contents)) - _, err := fd.Read(newcontent) - if err != nil { - t.Fatalf("Could not read from file %v", err) - } - err = fd.Close() - if err != nil { - t.Fatalf("Could not close file %v", err) - } - - if !bytes.Equal(contents, newcontent) { - t.Fatalf("File content mismatch expected (%v): received (%v) ", contents, newcontent) - } -} - -func isDirEmpty(name string) bool { - f, err := os.Open(name) - if err != nil { - return false - } - defer f.Close() - - _, err = f.Readdirnames(1) - - return err == io.EOF -} - -type testAPI struct { - api *api.API -} - -type testData struct { - testDir string - testUploadDir string - testMountDir string - bzzHash string - files map[string]fileInfo - toEncrypt bool - swarmfs *SwarmFS -} - -//create the root dir of a test -func (ta *testAPI) initSubtest(name string) (*testData, error) { - var err error - d := &testData{} - d.testDir, err = ioutil.TempDir(os.TempDir(), name) - if err != nil { - return nil, fmt.Errorf("Couldn't create test dir: %v", err) - } - return d, nil -} - -//upload data and mount directory -func (ta *testAPI) uploadAndMount(dat *testData, t *testing.T) (*testData, error) { - //create upload dir - err := os.MkdirAll(dat.testUploadDir, 0777) - if err != nil { - return nil, fmt.Errorf("Couldn't create upload dir: %v", err) - } - //create mount dir - err = os.MkdirAll(dat.testMountDir, 0777) - if err != nil { - return nil, fmt.Errorf("Couldn't create mount dir: %v", err) - } - //upload the file - dat.bzzHash = createTestFilesAndUploadToSwarm(t, ta.api, dat.files, dat.testUploadDir, dat.toEncrypt) - log.Debug("Created test files and uploaded to Swarm") - //mount the directory - dat.swarmfs = mountDir(t, ta.api, dat.files, dat.bzzHash, dat.testMountDir) - log.Debug("Mounted swarm fs") - return dat, nil -} - -//add a directory to the test directory tree -func addDir(root string, name string) (string, error) { - d := filepath.Join(root, name) - err := os.MkdirAll(d, 0777) - if err != nil { - return "", fmt.Errorf("Couldn't create dir inside test dir: %v", err) - } - return d, nil -} - -func (ta *testAPI) mountListAndUnmountEncrypted(t *testing.T) { - log.Debug("Starting mountListAndUnmountEncrypted test") - ta.mountListAndUnmount(t, true) - log.Debug("Test mountListAndUnmountEncrypted terminated") -} - -func (ta *testAPI) mountListAndUnmountNonEncrypted(t *testing.T) { - log.Debug("Starting mountListAndUnmountNonEncrypted test") - ta.mountListAndUnmount(t, false) - log.Debug("Test mountListAndUnmountNonEncrypted terminated") -} - -//mount a directory unmount and check the directory is empty afterwards -func (ta *testAPI) mountListAndUnmount(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("mountListAndUnmount") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "testUploadDir") - dat.testMountDir = filepath.Join(dat.testDir, "testMountDir") - dat.files = make(map[string]fileInfo) - - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["2.txt"] = fileInfo{0711, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["3.txt"] = fileInfo{0622, 333, 444, testutil.RandomBytes(3, 100)} - dat.files["4.txt"] = fileInfo{0533, 333, 444, testutil.RandomBytes(4, 1024)} - dat.files["5.txt"] = fileInfo{0544, 333, 444, testutil.RandomBytes(5, 10)} - dat.files["6.txt"] = fileInfo{0555, 333, 444, testutil.RandomBytes(6, 10)} - dat.files["7.txt"] = fileInfo{0666, 333, 444, testutil.RandomBytes(7, 10)} - dat.files["8.txt"] = fileInfo{0777, 333, 333, testutil.RandomBytes(8, 10)} - dat.files["11.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(9, 10)} - dat.files["111.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(10, 10)} - dat.files["two/2.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(11, 10)} - dat.files["two/2/2.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(12, 10)} - dat.files["two/2./2.txt"] = fileInfo{0777, 444, 444, testutil.RandomBytes(13, 10)} - dat.files["twice/2.txt"] = fileInfo{0777, 444, 333, testutil.RandomBytes(14, 200)} - dat.files["one/two/three/four/five/six/seven/eight/nine/10.txt"] = fileInfo{0777, 333, 444, testutil.RandomBytes(15, 10240)} - dat.files["one/two/three/four/five/six/six"] = fileInfo{0777, 333, 444, testutil.RandomBytes(16, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - // Check unmount - _, err = dat.swarmfs.Unmount(dat.testMountDir) - if err != nil { - t.Fatalf("could not unmount %v", dat.bzzHash) - } - log.Debug("Unmount successful") - if !isDirEmpty(dat.testMountDir) { - t.Fatalf("unmount didnt work for %v", dat.testMountDir) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) maxMountsEncrypted(t *testing.T) { - log.Debug("Starting maxMountsEncrypted test") - ta.runMaxMounts(t, true) - log.Debug("Test maxMountsEncrypted terminated") -} - -func (ta *testAPI) maxMountsNonEncrypted(t *testing.T) { - log.Debug("Starting maxMountsNonEncrypted test") - ta.runMaxMounts(t, false) - log.Debug("Test maxMountsNonEncrypted terminated") -} - -//mount several different directories until the maximum has been reached -func (ta *testAPI) runMaxMounts(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("runMaxMounts") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "max-upload1") - dat.testMountDir = filepath.Join(dat.testDir, "max-mount1") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - dat.testUploadDir = filepath.Join(dat.testDir, "max-upload2") - dat.testMountDir = filepath.Join(dat.testDir, "max-mount2") - dat.files["2.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - - dat.testUploadDir = filepath.Join(dat.testDir, "max-upload3") - dat.testMountDir = filepath.Join(dat.testDir, "max-mount3") - dat.files["3.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - - dat.testUploadDir = filepath.Join(dat.testDir, "max-upload4") - dat.testMountDir = filepath.Join(dat.testDir, "max-mount4") - dat.files["4.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - - dat.testUploadDir = filepath.Join(dat.testDir, "max-upload5") - dat.testMountDir = filepath.Join(dat.testDir, "max-mount5") - dat.files["5.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - - //now try an additional mount, should fail due to max mounts reached - testUploadDir6 := filepath.Join(dat.testDir, "max-upload6") - err = os.MkdirAll(testUploadDir6, 0777) - if err != nil { - t.Fatalf("Couldn't create upload dir 6: %v", err) - } - dat.files["6.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - testMountDir6 := filepath.Join(dat.testDir, "max-mount6") - err = os.MkdirAll(testMountDir6, 0777) - if err != nil { - t.Fatalf("Couldn't create mount dir 5: %v", err) - } - bzzHash6 := createTestFilesAndUploadToSwarm(t, ta.api, dat.files, testUploadDir6, toEncrypt) - log.Debug("Created test files and uploaded to swarm with uploadDir6") - _, err = dat.swarmfs.Mount(bzzHash6, testMountDir6) - if err == nil { - t.Fatalf("Expected this mount to fail due to exceeding max number of allowed mounts, but succeeded. %v", bzzHash6) - } - log.Debug("Maximum mount reached, additional mount failed. Correct.") -} - -func (ta *testAPI) remountEncrypted(t *testing.T) { - log.Debug("Starting remountEncrypted test") - ta.remount(t, true) - log.Debug("Test remountEncrypted terminated") -} -func (ta *testAPI) remountNonEncrypted(t *testing.T) { - log.Debug("Starting remountNonEncrypted test") - ta.remount(t, false) - log.Debug("Test remountNonEncrypted terminated") -} - -//test remounting same hash second time and different hash in already mounted point -func (ta *testAPI) remount(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("remount") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "remount-upload1") - dat.testMountDir = filepath.Join(dat.testDir, "remount-mount1") - dat.files = make(map[string]fileInfo) - - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // try mounting the same hash second time - testMountDir2, err2 := addDir(dat.testDir, "remount-mount2") - if err2 != nil { - t.Fatalf("Error creating second mount dir: %v", err2) - } - _, err2 = dat.swarmfs.Mount(dat.bzzHash, testMountDir2) - if err2 != nil { - t.Fatalf("Error mounting hash second time on different dir %v", dat.bzzHash) - } - - // mount a different hash in already mounted point - dat.files["2.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - testUploadDir2, err3 := addDir(dat.testDir, "remount-upload2") - if err3 != nil { - t.Fatalf("Error creating second upload dir: %v", err3) - } - bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, dat.files, testUploadDir2, toEncrypt) - _, err = swarmfs.Mount(bzzHash2, dat.testMountDir) - if err == nil { - t.Fatalf("Error mounting hash %v", bzzHash2) - } - log.Debug("Mount on existing mount point failed. Correct.") - - // mount nonexistent hash - failDir, err3 := addDir(dat.testDir, "remount-fail") - if err3 != nil { - t.Fatalf("Error creating remount dir: %v", bzzHash2) - } - failHash := "0xfea11223344" - _, err = swarmfs.Mount(failHash, failDir) - if err == nil { - t.Fatalf("Expected this mount to fail due to non existing hash. But succeeded %v", failHash) - } - log.Debug("Nonexistent hash hasn't been mounted. Correct.") -} - -func (ta *testAPI) unmountEncrypted(t *testing.T) { - log.Debug("Starting unmountEncrypted test") - ta.unmount(t, true) - log.Debug("Test unmountEncrypted terminated") -} - -func (ta *testAPI) unmountNonEncrypted(t *testing.T) { - log.Debug("Starting unmountNonEncrypted test") - ta.unmount(t, false) - log.Debug("Test unmountNonEncrypted terminated") -} - -//mount then unmount and check that it has been unmounted -func (ta *testAPI) unmount(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("unmount") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "ex-upload1") - dat.testMountDir = filepath.Join(dat.testDir, "ex-mount1") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - _, err = dat.swarmfs.Unmount(dat.testMountDir) - if err != nil { - t.Fatalf("could not unmount %v", dat.bzzHash) - } - log.Debug("Unmounted Dir") - - mi := swarmfs.Listmounts() - log.Debug("Going to list mounts") - for _, minfo := range mi { - log.Debug("Mount point in list: ", "point", minfo.MountPoint) - if minfo.MountPoint == dat.testMountDir { - t.Fatalf("mount state not cleaned up in unmount case %v", dat.testMountDir) - } - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) unmountWhenResourceBusyEncrypted(t *testing.T) { - log.Debug("Starting unmountWhenResourceBusyEncrypted test") - ta.unmountWhenResourceBusy(t, true) - log.Debug("Test unmountWhenResourceBusyEncrypted terminated") -} -func (ta *testAPI) unmountWhenResourceBusyNonEncrypted(t *testing.T) { - log.Debug("Starting unmountWhenResourceBusyNonEncrypted test") - ta.unmountWhenResourceBusy(t, false) - log.Debug("Test unmountWhenResourceBusyNonEncrypted terminated") -} - -//unmount while a resource is busy; should fail -func (ta *testAPI) unmountWhenResourceBusy(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("unmountWhenResourceBusy") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "ex-upload1") - dat.testMountDir = filepath.Join(dat.testDir, "ex-mount1") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - //create a file in the mounted directory, then try to unmount - should fail - actualPath := filepath.Join(dat.testMountDir, "2.txt") - //d, err := os.OpenFile(actualPath, os.O_RDWR, os.FileMode(0700)) - d, err := os.Create(actualPath) - if err != nil { - t.Fatalf("Couldn't create new file: %v", err) - } - //we need to manually close the file before mount for this test - //but let's defer too in case of errors - defer d.Close() - _, err = d.Write(testutil.RandomBytes(1, 10)) - if err != nil { - t.Fatalf("Couldn't write to file: %v", err) - } - log.Debug("Bytes written") - - _, err = dat.swarmfs.Unmount(dat.testMountDir) - if err == nil { - t.Fatalf("Expected mount to fail due to resource busy, but it succeeded...") - } - //free resources - err = d.Close() - if err != nil { - t.Fatalf("Couldn't close file! %v", dat.bzzHash) - } - log.Debug("File closed") - - //now unmount after explicitly closed file - _, err = dat.swarmfs.Unmount(dat.testMountDir) - if err != nil { - t.Fatalf("Expected mount to succeed after freeing resource, but it failed: %v", err) - } - //check if the dir is still mounted - mi := dat.swarmfs.Listmounts() - log.Debug("Going to list mounts") - for _, minfo := range mi { - log.Debug("Mount point in list: ", "point", minfo.MountPoint) - if minfo.MountPoint == dat.testMountDir { - t.Fatalf("mount state not cleaned up in unmount case %v", dat.testMountDir) - } - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) seekInMultiChunkFileEncrypted(t *testing.T) { - log.Debug("Starting seekInMultiChunkFileEncrypted test") - ta.seekInMultiChunkFile(t, true) - log.Debug("Test seekInMultiChunkFileEncrypted terminated") -} - -func (ta *testAPI) seekInMultiChunkFileNonEncrypted(t *testing.T) { - log.Debug("Starting seekInMultiChunkFileNonEncrypted test") - ta.seekInMultiChunkFile(t, false) - log.Debug("Test seekInMultiChunkFileNonEncrypted terminated") -} - -//open a file in a mounted dir and go to a certain position -func (ta *testAPI) seekInMultiChunkFile(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("seekInMultiChunkFile") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "seek-upload1") - dat.testMountDir = filepath.Join(dat.testDir, "seek-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10240)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Open the file in the mounted dir and seek the second chunk - actualPath := filepath.Join(dat.testMountDir, "1.txt") - d, err := os.OpenFile(actualPath, os.O_RDONLY, os.FileMode(0700)) - if err != nil { - t.Fatalf("Couldn't open file: %v", err) - } - log.Debug("Opened file") - defer func() { - err := d.Close() - if err != nil { - t.Fatalf("Error closing file! %v", err) - } - }() - - _, err = d.Seek(5000, 0) - if err != nil { - t.Fatalf("Error seeking in file: %v", err) - } - - contents := make([]byte, 1024) - _, err = d.Read(contents) - if err != nil { - t.Fatalf("Error reading file: %v", err) - } - log.Debug("Read contents") - finfo := dat.files["1.txt"] - - if !bytes.Equal(finfo.contents[:6024][5000:], contents) { - t.Fatalf("File seek contents mismatch") - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) createNewFileEncrypted(t *testing.T) { - log.Debug("Starting createNewFileEncrypted test") - ta.createNewFile(t, true) - log.Debug("Test createNewFileEncrypted terminated") -} - -func (ta *testAPI) createNewFileNonEncrypted(t *testing.T) { - log.Debug("Starting createNewFileNonEncrypted test") - ta.createNewFile(t, false) - log.Debug("Test createNewFileNonEncrypted terminated") -} - -//create a new file in a mounted swarm directory, -//unmount the fuse dir and then remount to see if new file is still there -func (ta *testAPI) createNewFile(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("createNewFile") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "create-upload1") - dat.testMountDir = filepath.Join(dat.testDir, "create-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Create a new file in the root dir and check - actualPath := filepath.Join(dat.testMountDir, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not open file %s : %v", actualPath, err1) - } - defer d.Close() - log.Debug("Opened file") - contents := testutil.RandomBytes(1, 11) - log.Debug("content read") - _, err = d.Write(contents) - if err != nil { - t.Fatalf("Couldn't write contents: %v", err) - } - log.Debug("content written") - err = d.Close() - if err != nil { - t.Fatalf("Couldn't close file: %v", err) - } - log.Debug("file closed") - - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("Directory unmounted") - - testMountDir2, err3 := addDir(dat.testDir, "create-mount2") - if err3 != nil { - t.Fatalf("Error creating mount dir2: %v", err3) - } - // mount again and see if things are okay - dat.files["2.txt"] = fileInfo{0700, 333, 444, contents} - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) - log.Debug("Directory mounted again") - - checkFile(t, testMountDir2, "2.txt", contents) - _, err2 = dat.swarmfs.Unmount(testMountDir2) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) createNewFileInsideDirectoryEncrypted(t *testing.T) { - log.Debug("Starting createNewFileInsideDirectoryEncrypted test") - ta.createNewFileInsideDirectory(t, true) - log.Debug("Test createNewFileInsideDirectoryEncrypted terminated") -} - -func (ta *testAPI) createNewFileInsideDirectoryNonEncrypted(t *testing.T) { - log.Debug("Starting createNewFileInsideDirectoryNonEncrypted test") - ta.createNewFileInsideDirectory(t, false) - log.Debug("Test createNewFileInsideDirectoryNonEncrypted terminated") -} - -//create a new file inside a directory inside the mount -func (ta *testAPI) createNewFileInsideDirectory(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("createNewFileInsideDirectory") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "createinsidedir-upload") - dat.testMountDir = filepath.Join(dat.testDir, "createinsidedir-mount") - dat.files = make(map[string]fileInfo) - dat.files["one/1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Create a new file inside a existing dir and check - dirToCreate := filepath.Join(dat.testMountDir, "one") - actualPath := filepath.Join(dirToCreate, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - defer d.Close() - log.Debug("File opened") - contents := testutil.RandomBytes(1, 11) - log.Debug("Content read") - _, err = d.Write(contents) - if err != nil { - t.Fatalf("Error writing random bytes into file %v", err) - } - log.Debug("Content written") - err = d.Close() - if err != nil { - t.Fatalf("Error closing file %v", err) - } - log.Debug("File closed") - - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("Directory unmounted") - - testMountDir2, err3 := addDir(dat.testDir, "createinsidedir-mount2") - if err3 != nil { - t.Fatalf("Error creating mount dir2: %v", err3) - } - // mount again and see if things are okay - dat.files["one/2.txt"] = fileInfo{0700, 333, 444, contents} - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) - log.Debug("Directory mounted again") - - checkFile(t, testMountDir2, "one/2.txt", contents) - _, err = dat.swarmfs.Unmount(testMountDir2) - if err != nil { - t.Fatalf("could not unmount %v", dat.bzzHash) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) createNewFileInsideNewDirectoryEncrypted(t *testing.T) { - log.Debug("Starting createNewFileInsideNewDirectoryEncrypted test") - ta.createNewFileInsideNewDirectory(t, true) - log.Debug("Test createNewFileInsideNewDirectoryEncrypted terminated") -} - -func (ta *testAPI) createNewFileInsideNewDirectoryNonEncrypted(t *testing.T) { - log.Debug("Starting createNewFileInsideNewDirectoryNonEncrypted test") - ta.createNewFileInsideNewDirectory(t, false) - log.Debug("Test createNewFileInsideNewDirectoryNonEncrypted terminated") -} - -//create a new directory in mount and a new file -func (ta *testAPI) createNewFileInsideNewDirectory(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("createNewFileInsideNewDirectory") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "createinsidenewdir-upload") - dat.testMountDir = filepath.Join(dat.testDir, "createinsidenewdir-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Create a new file inside a existing dir and check - dirToCreate, err2 := addDir(dat.testMountDir, "one") - if err2 != nil { - t.Fatalf("Error creating mount dir2: %v", err2) - } - actualPath := filepath.Join(dirToCreate, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - defer d.Close() - log.Debug("File opened") - contents := testutil.RandomBytes(1, 11) - log.Debug("content read") - _, err = d.Write(contents) - if err != nil { - t.Fatalf("Error writing to file: %v", err) - } - log.Debug("content written") - err = d.Close() - if err != nil { - t.Fatalf("Error closing file: %v", err) - } - log.Debug("File closed") - - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("Directory unmounted") - - // mount again and see if things are okay - dat.files["one/2.txt"] = fileInfo{0700, 333, 444, contents} - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, dat.testMountDir) - log.Debug("Directory mounted again") - - checkFile(t, dat.testMountDir, "one/2.txt", contents) - _, err2 = dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) removeExistingFileEncrypted(t *testing.T) { - log.Debug("Starting removeExistingFileEncrypted test") - ta.removeExistingFile(t, true) - log.Debug("Test removeExistingFileEncrypted terminated") -} - -func (ta *testAPI) removeExistingFileNonEncrypted(t *testing.T) { - log.Debug("Starting removeExistingFileNonEncrypted test") - ta.removeExistingFile(t, false) - log.Debug("Test removeExistingFileNonEncrypted terminated") -} - -//remove existing file in mount -func (ta *testAPI) removeExistingFile(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("removeExistingFile") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "remove-upload") - dat.testMountDir = filepath.Join(dat.testDir, "remove-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Remove a file in the root dir and check - actualPath := filepath.Join(dat.testMountDir, "five.txt") - err = os.Remove(actualPath) - if err != nil { - t.Fatalf("Error removing file! %v", err) - } - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("Directory unmounted") - - // mount again and see if things are okay - delete(dat.files, "five.txt") - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, dat.testMountDir) - _, err = os.Stat(actualPath) - if err == nil { - t.Fatal("Expected file to not be present in re-mount after removal, but it is there") - } - _, err2 = dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) removeExistingFileInsideDirEncrypted(t *testing.T) { - log.Debug("Starting removeExistingFileInsideDirEncrypted test") - ta.removeExistingFileInsideDir(t, true) - log.Debug("Test removeExistingFileInsideDirEncrypted terminated") -} - -func (ta *testAPI) removeExistingFileInsideDirNonEncrypted(t *testing.T) { - log.Debug("Starting removeExistingFileInsideDirNonEncrypted test") - ta.removeExistingFileInsideDir(t, false) - log.Debug("Test removeExistingFileInsideDirNonEncrypted terminated") -} - -//remove a file inside a directory inside a mount -func (ta *testAPI) removeExistingFileInsideDir(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("removeExistingFileInsideDir") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "remove-upload") - dat.testMountDir = filepath.Join(dat.testDir, "remove-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["one/five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["one/six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Remove a file in the root dir and check - actualPath := filepath.Join(dat.testMountDir, "one") - actualPath = filepath.Join(actualPath, "five.txt") - err = os.Remove(actualPath) - if err != nil { - t.Fatalf("Error removing file! %v", err) - } - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("Directory unmounted") - - // mount again and see if things are okay - delete(dat.files, "one/five.txt") - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, dat.testMountDir) - _, err = os.Stat(actualPath) - if err == nil { - t.Fatal("Expected file to not be present in re-mount after removal, but it is there") - } - - okPath := filepath.Join(dat.testMountDir, "one") - okPath = filepath.Join(okPath, "six.txt") - _, err = os.Stat(okPath) - if err != nil { - t.Fatal("Expected file to be present in re-mount after removal, but it is not there") - } - _, err2 = dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) removeNewlyAddedFileEncrypted(t *testing.T) { - log.Debug("Starting removeNewlyAddedFileEncrypted test") - ta.removeNewlyAddedFile(t, true) - log.Debug("Test removeNewlyAddedFileEncrypted terminated") -} - -func (ta *testAPI) removeNewlyAddedFileNonEncrypted(t *testing.T) { - log.Debug("Starting removeNewlyAddedFileNonEncrypted test") - ta.removeNewlyAddedFile(t, false) - log.Debug("Test removeNewlyAddedFileNonEncrypted terminated") -} - -//add a file in mount and then remove it; on remount file should not be there -func (ta *testAPI) removeNewlyAddedFile(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("removeNewlyAddedFile") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "removenew-upload") - dat.testMountDir = filepath.Join(dat.testDir, "removenew-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Add a a new file and remove it - dirToCreate := filepath.Join(dat.testMountDir, "one") - err = os.MkdirAll(dirToCreate, os.FileMode(0665)) - if err != nil { - t.Fatalf("Error creating dir in mounted dir: %v", err) - } - actualPath := filepath.Join(dirToCreate, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - defer d.Close() - log.Debug("file opened") - contents := testutil.RandomBytes(1, 11) - log.Debug("content read") - _, err = d.Write(contents) - if err != nil { - t.Fatalf("Error writing random bytes to file: %v", err) - } - log.Debug("content written") - err = d.Close() - if err != nil { - t.Fatalf("Error closing file: %v", err) - } - log.Debug("file closed") - - checkFile(t, dat.testMountDir, "one/2.txt", contents) - log.Debug("file checked") - - err = os.Remove(actualPath) - if err != nil { - t.Fatalf("Error removing file: %v", err) - } - log.Debug("file removed") - - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("Directory unmounted") - - testMountDir2, err3 := addDir(dat.testDir, "removenew-mount2") - if err3 != nil { - t.Fatalf("Error creating mount dir2: %v", err3) - } - // mount again and see if things are okay - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) - log.Debug("Directory mounted again") - - if dat.bzzHash != mi.LatestManifest { - t.Fatalf("same contents different hash orig(%v): new(%v)", dat.bzzHash, mi.LatestManifest) - } - _, err2 = dat.swarmfs.Unmount(testMountDir2) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) addNewFileAndModifyContentsEncrypted(t *testing.T) { - log.Debug("Starting addNewFileAndModifyContentsEncrypted test") - ta.addNewFileAndModifyContents(t, true) - log.Debug("Test addNewFileAndModifyContentsEncrypted terminated") -} - -func (ta *testAPI) addNewFileAndModifyContentsNonEncrypted(t *testing.T) { - log.Debug("Starting addNewFileAndModifyContentsNonEncrypted test") - ta.addNewFileAndModifyContents(t, false) - log.Debug("Test addNewFileAndModifyContentsNonEncrypted terminated") -} - -//add a new file and modify content; remount and check the modified file is intact -func (ta *testAPI) addNewFileAndModifyContents(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("addNewFileAndModifyContents") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "modifyfile-upload") - dat.testMountDir = filepath.Join(dat.testDir, "modifyfile-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - // Create a new file in the root dir - actualPath := filepath.Join(dat.testMountDir, "2.txt") - d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) - if err1 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err1) - } - defer d.Close() - //write some random data into the file - log.Debug("file opened") - line1 := []byte("Line 1") - _, err = rand.Read(line1) - if err != nil { - t.Fatalf("Error writing random bytes to byte array: %v", err) - } - log.Debug("line read") - _, err = d.Write(line1) - if err != nil { - t.Fatalf("Error writing random bytes to file: %v", err) - } - log.Debug("line written") - err = d.Close() - if err != nil { - t.Fatalf("Error closing file: %v", err) - } - log.Debug("file closed") - - //unmount the hash on the mounted dir - mi1, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - log.Debug("Directory unmounted") - - //mount on a different dir to see if modified file is correct - testMountDir2, err3 := addDir(dat.testDir, "modifyfile-mount2") - if err3 != nil { - t.Fatalf("Error creating mount dir2: %v", err3) - } - dat.files["2.txt"] = fileInfo{0700, 333, 444, line1} - _ = mountDir(t, ta.api, dat.files, mi1.LatestManifest, testMountDir2) - log.Debug("Directory mounted again") - - checkFile(t, testMountDir2, "2.txt", line1) - log.Debug("file checked") - - //unmount second dir - mi2, err4 := dat.swarmfs.Unmount(testMountDir2) - if err4 != nil { - t.Fatalf("Could not unmount %v", err4) - } - log.Debug("Directory unmounted again") - - //mount again on original dir and modify the file - //let's clean up the mounted dir first: remove... - err = os.RemoveAll(dat.testMountDir) - if err != nil { - t.Fatalf("Error cleaning up mount dir: %v", err) - } - //...and re-create - err = os.MkdirAll(dat.testMountDir, 0777) - if err != nil { - t.Fatalf("Error re-creating mount dir: %v", err) - } - //now remount - _ = mountDir(t, ta.api, dat.files, mi2.LatestManifest, dat.testMountDir) - log.Debug("Directory mounted yet again") - - //open the file.... - fd, err5 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665)) - if err5 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err5) - } - defer fd.Close() - log.Debug("file opened") - //...and modify something - line2 := []byte("Line 2") - _, err = rand.Read(line2) - if err != nil { - t.Fatalf("Error modifying random bytes to byte array: %v", err) - } - log.Debug("line read") - _, err = fd.Seek(int64(len(line1)), 0) - if err != nil { - t.Fatalf("Error seeking position for modification: %v", err) - } - _, err = fd.Write(line2) - if err != nil { - t.Fatalf("Error modifying file: %v", err) - } - log.Debug("line written") - err = fd.Close() - if err != nil { - t.Fatalf("Error closing modified file; %v", err) - } - log.Debug("file closed") - - //unmount the modified directory - mi3, err6 := dat.swarmfs.Unmount(dat.testMountDir) - if err6 != nil { - t.Fatalf("Could not unmount %v", err6) - } - log.Debug("Directory unmounted yet again") - - //now remount on a different dir and check that the modified file is ok - testMountDir4, err7 := addDir(dat.testDir, "modifyfile-mount4") - if err7 != nil { - t.Fatalf("Could not unmount %v", err7) - } - b := [][]byte{line1, line2} - line1and2 := bytes.Join(b, []byte("")) - dat.files["2.txt"] = fileInfo{0700, 333, 444, line1and2} - _ = mountDir(t, ta.api, dat.files, mi3.LatestManifest, testMountDir4) - log.Debug("Directory mounted final time") - - checkFile(t, testMountDir4, "2.txt", line1and2) - _, err = dat.swarmfs.Unmount(testMountDir4) - if err != nil { - t.Fatalf("Could not unmount %v", err) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) removeEmptyDirEncrypted(t *testing.T) { - log.Debug("Starting removeEmptyDirEncrypted test") - ta.removeEmptyDir(t, true) - log.Debug("Test removeEmptyDirEncrypted terminated") -} - -func (ta *testAPI) removeEmptyDirNonEncrypted(t *testing.T) { - log.Debug("Starting removeEmptyDirNonEncrypted test") - ta.removeEmptyDir(t, false) - log.Debug("Test removeEmptyDirNonEncrypted terminated") -} - -//remove an empty dir inside mount -func (ta *testAPI) removeEmptyDir(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("removeEmptyDir") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "rmdir-upload") - dat.testMountDir = filepath.Join(dat.testDir, "rmdir-mount") - dat.files = make(map[string]fileInfo) - dat.files["1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - _, err2 := addDir(dat.testMountDir, "newdir") - if err2 != nil { - t.Fatalf("Could not unmount %v", err2) - } - mi, err := dat.swarmfs.Unmount(dat.testMountDir) - if err != nil { - t.Fatalf("Could not unmount %v", err) - } - log.Debug("Directory unmounted") - //by just adding an empty dir, the hash doesn't change; test this - if dat.bzzHash != mi.LatestManifest { - t.Fatalf("same contents different hash orig(%v): new(%v)", dat.bzzHash, mi.LatestManifest) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) removeDirWhichHasFilesEncrypted(t *testing.T) { - log.Debug("Starting removeDirWhichHasFilesEncrypted test") - ta.removeDirWhichHasFiles(t, true) - log.Debug("Test removeDirWhichHasFilesEncrypted terminated") -} -func (ta *testAPI) removeDirWhichHasFilesNonEncrypted(t *testing.T) { - log.Debug("Starting removeDirWhichHasFilesNonEncrypted test") - ta.removeDirWhichHasFiles(t, false) - log.Debug("Test removeDirWhichHasFilesNonEncrypted terminated") -} - -//remove a directory with a file; check on remount file isn't there -func (ta *testAPI) removeDirWhichHasFiles(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("removeDirWhichHasFiles") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "rmdir-upload") - dat.testMountDir = filepath.Join(dat.testDir, "rmdir-mount") - dat.files = make(map[string]fileInfo) - dat.files["one/1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["two/five.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["two/six.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - //delete a directory inside the mounted dir with all its files - dirPath := filepath.Join(dat.testMountDir, "two") - err = os.RemoveAll(dirPath) - if err != nil { - t.Fatalf("Error removing directory in mounted dir: %v", err) - } - - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v ", err2) - } - log.Debug("Directory unmounted") - - //we deleted files in the OS, so let's delete them also in the files map - delete(dat.files, "two/five.txt") - delete(dat.files, "two/six.txt") - - // mount again and see if deleted files have been deleted indeed - testMountDir2, err3 := addDir(dat.testDir, "remount-mount2") - if err3 != nil { - t.Fatalf("Could not unmount %v", err3) - } - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) - log.Debug("Directory mounted") - actualPath := filepath.Join(dirPath, "five.txt") - _, err = os.Stat(actualPath) - if err == nil { - t.Fatal("Expected file to not be present in re-mount after removal, but it is there") - } - _, err = os.Stat(dirPath) - if err == nil { - t.Fatal("Expected file to not be present in re-mount after removal, but it is there") - } - _, err = dat.swarmfs.Unmount(testMountDir2) - if err != nil { - t.Fatalf("Could not unmount %v", err) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) removeDirWhichHasSubDirsEncrypted(t *testing.T) { - log.Debug("Starting removeDirWhichHasSubDirsEncrypted test") - ta.removeDirWhichHasSubDirs(t, true) - log.Debug("Test removeDirWhichHasSubDirsEncrypted terminated") -} - -func (ta *testAPI) removeDirWhichHasSubDirsNonEncrypted(t *testing.T) { - log.Debug("Starting removeDirWhichHasSubDirsNonEncrypted test") - ta.removeDirWhichHasSubDirs(t, false) - log.Debug("Test removeDirWhichHasSubDirsNonEncrypted terminated") -} - -//remove a directory with subdirectories inside mount; on remount check they are not there -func (ta *testAPI) removeDirWhichHasSubDirs(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("removeDirWhichHasSubDirs") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "rmsubdir-upload") - dat.testMountDir = filepath.Join(dat.testDir, "rmsubdir-mount") - dat.files = make(map[string]fileInfo) - dat.files["one/1.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(1, 10)} - dat.files["two/three/2.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(2, 10)} - dat.files["two/three/3.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(3, 10)} - dat.files["two/four/5.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(4, 10)} - dat.files["two/four/6.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(5, 10)} - dat.files["two/four/six/7.txt"] = fileInfo{0700, 333, 444, testutil.RandomBytes(6, 10)} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - dirPath := filepath.Join(dat.testMountDir, "two") - err = os.RemoveAll(dirPath) - if err != nil { - t.Fatalf("Error removing directory in mounted dir: %v", err) - } - - //delete a directory inside the mounted dir with all its files - mi, err2 := dat.swarmfs.Unmount(dat.testMountDir) - if err2 != nil { - t.Fatalf("Could not unmount %v ", err2) - } - log.Debug("Directory unmounted") - - //we deleted files in the OS, so let's delete them also in the files map - delete(dat.files, "two/three/2.txt") - delete(dat.files, "two/three/3.txt") - delete(dat.files, "two/four/5.txt") - delete(dat.files, "two/four/6.txt") - delete(dat.files, "two/four/six/7.txt") - - // mount again and see if things are okay - testMountDir2, err3 := addDir(dat.testDir, "remount-mount2") - if err3 != nil { - t.Fatalf("Could not unmount %v", err3) - } - _ = mountDir(t, ta.api, dat.files, mi.LatestManifest, testMountDir2) - log.Debug("Directory mounted again") - actualPath := filepath.Join(dirPath, "three") - actualPath = filepath.Join(actualPath, "2.txt") - _, err = os.Stat(actualPath) - if err == nil { - t.Fatal("Expected file to not be present in re-mount after removal, but it is there") - } - actualPath = filepath.Join(dirPath, "four") - _, err = os.Stat(actualPath) - if err == nil { - t.Fatal("Expected file to not be present in re-mount after removal, but it is there") - } - _, err = os.Stat(dirPath) - if err == nil { - t.Fatal("Expected file to not be present in re-mount after removal, but it is there") - } - _, err = dat.swarmfs.Unmount(testMountDir2) - if err != nil { - t.Fatalf("Could not unmount %v", err) - } - log.Debug("subtest terminated") -} - -func (ta *testAPI) appendFileContentsToEndEncrypted(t *testing.T) { - log.Debug("Starting appendFileContentsToEndEncrypted test") - ta.appendFileContentsToEnd(t, true) - log.Debug("Test appendFileContentsToEndEncrypted terminated") -} - -func (ta *testAPI) appendFileContentsToEndNonEncrypted(t *testing.T) { - log.Debug("Starting appendFileContentsToEndNonEncrypted test") - ta.appendFileContentsToEnd(t, false) - log.Debug("Test appendFileContentsToEndNonEncrypted terminated") -} - -//append contents to the end of a file; remount and check it's intact -func (ta *testAPI) appendFileContentsToEnd(t *testing.T, toEncrypt bool) { - dat, err := ta.initSubtest("appendFileContentsToEnd") - if err != nil { - t.Fatalf("Couldn't initialize subtest dirs: %v", err) - } - defer os.RemoveAll(dat.testDir) - - dat.toEncrypt = toEncrypt - dat.testUploadDir = filepath.Join(dat.testDir, "appendlargefile-upload") - dat.testMountDir = filepath.Join(dat.testDir, "appendlargefile-mount") - dat.files = make(map[string]fileInfo) - - line1 := testutil.RandomBytes(1, 10) - - dat.files["1.txt"] = fileInfo{0700, 333, 444, line1} - - dat, err = ta.uploadAndMount(dat, t) - if err != nil { - t.Fatalf("Error during upload of files to swarm / mount of swarm dir: %v", err) - } - defer dat.swarmfs.Stop() - - actualPath := filepath.Join(dat.testMountDir, "1.txt") - fd, err4 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665)) - if err4 != nil { - t.Fatalf("Could not create file %s : %v", actualPath, err4) - } - defer fd.Close() - log.Debug("file opened") - line2 := testutil.RandomBytes(1, 5) - log.Debug("line read") - _, err = fd.Seek(int64(len(line1)), 0) - if err != nil { - t.Fatalf("Error searching for position to append: %v", err) - } - _, err = fd.Write(line2) - if err != nil { - t.Fatalf("Error appending: %v", err) - } - log.Debug("line written") - err = fd.Close() - if err != nil { - t.Fatalf("Error closing file: %v", err) - } - log.Debug("file closed") - - mi1, err5 := dat.swarmfs.Unmount(dat.testMountDir) - if err5 != nil { - t.Fatalf("Could not unmount %v ", err5) - } - log.Debug("Directory unmounted") - - // mount again and see if appended file is correct - b := [][]byte{line1, line2} - line1and2 := bytes.Join(b, []byte("")) - dat.files["1.txt"] = fileInfo{0700, 333, 444, line1and2} - testMountDir2, err6 := addDir(dat.testDir, "remount-mount2") - if err6 != nil { - t.Fatalf("Could not unmount %v", err6) - } - _ = mountDir(t, ta.api, dat.files, mi1.LatestManifest, testMountDir2) - log.Debug("Directory mounted") - - checkFile(t, testMountDir2, "1.txt", line1and2) - - _, err = dat.swarmfs.Unmount(testMountDir2) - if err != nil { - t.Fatalf("Could not unmount %v", err) - } - log.Debug("subtest terminated") -} - -//run all the tests -func TestFUSE(t *testing.T) { - t.Skip("disable fuse tests until they are stable") - //create a data directory for swarm - datadir, err := ioutil.TempDir("", "fuse") - if err != nil { - t.Fatalf("unable to create temp dir: %v", err) - } - defer os.RemoveAll(datadir) - - fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32), chunk.NewTags()) - if err != nil { - t.Fatal(err) - } - ta := &testAPI{api: api.NewAPI(fileStore, nil, nil, nil, chunk.NewTags())} - - //run a short suite of tests - //approx time: 28s - t.Run("mountListAndUnmountEncrypted", ta.mountListAndUnmountEncrypted) - t.Run("remountEncrypted", ta.remountEncrypted) - t.Run("unmountWhenResourceBusyNonEncrypted", ta.unmountWhenResourceBusyNonEncrypted) - t.Run("removeExistingFileEncrypted", ta.removeExistingFileEncrypted) - t.Run("addNewFileAndModifyContentsNonEncrypted", ta.addNewFileAndModifyContentsNonEncrypted) - t.Run("removeDirWhichHasFilesNonEncrypted", ta.removeDirWhichHasFilesNonEncrypted) - t.Run("appendFileContentsToEndEncrypted", ta.appendFileContentsToEndEncrypted) - - //provide longrunning flag to execute all tests - //approx time with longrunning: 140s - if *longrunning { - t.Run("mountListAndUnmountNonEncrypted", ta.mountListAndUnmountNonEncrypted) - t.Run("maxMountsEncrypted", ta.maxMountsEncrypted) - t.Run("maxMountsNonEncrypted", ta.maxMountsNonEncrypted) - t.Run("remountNonEncrypted", ta.remountNonEncrypted) - t.Run("unmountEncrypted", ta.unmountEncrypted) - t.Run("unmountNonEncrypted", ta.unmountNonEncrypted) - t.Run("unmountWhenResourceBusyEncrypted", ta.unmountWhenResourceBusyEncrypted) - t.Run("unmountWhenResourceBusyNonEncrypted", ta.unmountWhenResourceBusyNonEncrypted) - t.Run("seekInMultiChunkFileEncrypted", ta.seekInMultiChunkFileEncrypted) - t.Run("seekInMultiChunkFileNonEncrypted", ta.seekInMultiChunkFileNonEncrypted) - t.Run("createNewFileEncrypted", ta.createNewFileEncrypted) - t.Run("createNewFileNonEncrypted", ta.createNewFileNonEncrypted) - t.Run("createNewFileInsideDirectoryEncrypted", ta.createNewFileInsideDirectoryEncrypted) - t.Run("createNewFileInsideDirectoryNonEncrypted", ta.createNewFileInsideDirectoryNonEncrypted) - t.Run("createNewFileInsideNewDirectoryEncrypted", ta.createNewFileInsideNewDirectoryEncrypted) - t.Run("createNewFileInsideNewDirectoryNonEncrypted", ta.createNewFileInsideNewDirectoryNonEncrypted) - t.Run("removeExistingFileNonEncrypted", ta.removeExistingFileNonEncrypted) - t.Run("removeExistingFileInsideDirEncrypted", ta.removeExistingFileInsideDirEncrypted) - t.Run("removeExistingFileInsideDirNonEncrypted", ta.removeExistingFileInsideDirNonEncrypted) - t.Run("removeNewlyAddedFileEncrypted", ta.removeNewlyAddedFileEncrypted) - t.Run("removeNewlyAddedFileNonEncrypted", ta.removeNewlyAddedFileNonEncrypted) - t.Run("addNewFileAndModifyContentsEncrypted", ta.addNewFileAndModifyContentsEncrypted) - t.Run("removeEmptyDirEncrypted", ta.removeEmptyDirEncrypted) - t.Run("removeEmptyDirNonEncrypted", ta.removeEmptyDirNonEncrypted) - t.Run("removeDirWhichHasFilesEncrypted", ta.removeDirWhichHasFilesEncrypted) - t.Run("removeDirWhichHasSubDirsEncrypted", ta.removeDirWhichHasSubDirsEncrypted) - t.Run("removeDirWhichHasSubDirsNonEncrypted", ta.removeDirWhichHasSubDirsNonEncrypted) - t.Run("appendFileContentsToEndNonEncrypted", ta.appendFileContentsToEndNonEncrypted) - } -} - -func Upload(uploadDir, index string, a *api.API, toEncrypt bool) (hash string, err error) { - fs := api.NewFileSystem(a) - hash, err = fs.Upload(uploadDir, index, toEncrypt) - return hash, err -} diff --git a/swarm/fuse/swarmfs_unix.go b/swarm/fuse/swarmfs_unix.go deleted file mode 100644 index 54b879a4da..0000000000 --- a/swarm/fuse/swarmfs_unix.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build linux darwin freebsd - -package fuse - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "bazil.org/fuse" - "bazil.org/fuse/fs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/log" -) - -var ( - errEmptyMountPoint = errors.New("need non-empty mount point") - errNoRelativeMountPoint = errors.New("invalid path for mount point (need absolute path)") - errMaxMountCount = errors.New("max FUSE mount count reached") - errMountTimeout = errors.New("mount timeout") - errAlreadyMounted = errors.New("mount point is already serving") -) - -func isFUSEUnsupportedError(err error) bool { - if perr, ok := err.(*os.PathError); ok { - return perr.Op == "open" && perr.Path == "/dev/fuse" - } - return err == fuse.ErrOSXFUSENotFound -} - -// MountInfo contains information about every active mount -type MountInfo struct { - MountPoint string - StartManifest string - LatestManifest string - rootDir *SwarmDir - fuseConnection *fuse.Conn - swarmApi *api.API - lock *sync.RWMutex - serveClose chan struct{} -} - -func NewMountInfo(mhash, mpoint string, sapi *api.API) *MountInfo { - log.Debug("swarmfs NewMountInfo", "hash", mhash, "mount point", mpoint) - newMountInfo := &MountInfo{ - MountPoint: mpoint, - StartManifest: mhash, - LatestManifest: mhash, - rootDir: nil, - fuseConnection: nil, - swarmApi: sapi, - lock: &sync.RWMutex{}, - serveClose: make(chan struct{}), - } - return newMountInfo -} - -func (swarmfs *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { - log.Info("swarmfs", "mounting hash", mhash, "mount point", mountpoint) - if mountpoint == "" { - return nil, errEmptyMountPoint - } - if !strings.HasPrefix(mountpoint, "/") { - return nil, errNoRelativeMountPoint - } - cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint)) - if err != nil { - return nil, err - } - log.Trace("swarmfs mount", "cleanedMountPoint", cleanedMountPoint) - - swarmfs.swarmFsLock.Lock() - defer swarmfs.swarmFsLock.Unlock() - - noOfActiveMounts := len(swarmfs.activeMounts) - log.Debug("swarmfs mount", "# active mounts", noOfActiveMounts) - if noOfActiveMounts >= maxFUSEMounts { - return nil, errMaxMountCount - } - - if _, ok := swarmfs.activeMounts[cleanedMountPoint]; ok { - return nil, errAlreadyMounted - } - - log.Trace("swarmfs mount: getting manifest tree") - _, manifestEntryMap, err := swarmfs.swarmApi.BuildDirectoryTree(context.TODO(), mhash, true) - if err != nil { - return nil, err - } - - log.Trace("swarmfs mount: building mount info") - mi := NewMountInfo(mhash, cleanedMountPoint, swarmfs.swarmApi) - - dirTree := map[string]*SwarmDir{} - rootDir := NewSwarmDir("/", mi) - log.Trace("swarmfs mount", "rootDir", rootDir) - mi.rootDir = rootDir - - log.Trace("swarmfs mount: traversing manifest map") - for suffix, entry := range manifestEntryMap { - if suffix == "" { //empty suffix means that the file has no name - i.e. this is the default entry in a manifest. Since we cannot have files without a name, let us ignore this entry - log.Warn("Manifest has an empty-path (default) entry which will be ignored in FUSE mount.") - continue - } - addr := common.Hex2Bytes(entry.Hash) - fullpath := "/" + suffix - basepath := filepath.Dir(fullpath) - parentDir := rootDir - dirUntilNow := "" - paths := strings.Split(basepath, "/") - for i := range paths { - if paths[i] != "" { - thisDir := paths[i] - dirUntilNow = dirUntilNow + "/" + thisDir - - if _, ok := dirTree[dirUntilNow]; !ok { - dirTree[dirUntilNow] = NewSwarmDir(dirUntilNow, mi) - parentDir.directories = append(parentDir.directories, dirTree[dirUntilNow]) - parentDir = dirTree[dirUntilNow] - - } else { - parentDir = dirTree[dirUntilNow] - } - } - } - thisFile := NewSwarmFile(basepath, filepath.Base(fullpath), mi) - thisFile.addr = addr - - parentDir.files = append(parentDir.files, thisFile) - } - - fconn, err := fuse.Mount(cleanedMountPoint, fuse.FSName("swarmfs"), fuse.VolumeName(mhash)) - if isFUSEUnsupportedError(err) { - log.Error("swarmfs error - FUSE not installed", "mountpoint", cleanedMountPoint, "err", err) - return nil, err - } else if err != nil { - fuse.Unmount(cleanedMountPoint) - log.Error("swarmfs error mounting swarm manifest", "mountpoint", cleanedMountPoint, "err", err) - return nil, err - } - mi.fuseConnection = fconn - - serverr := make(chan error, 1) - go func() { - log.Info("swarmfs", "serving hash", mhash, "at", cleanedMountPoint) - filesys := &SwarmRoot{root: rootDir} - //start serving the actual file system; see note below - if err := fs.Serve(fconn, filesys); err != nil { - log.Warn("swarmfs could not serve the requested hash", "error", err) - serverr <- err - } - mi.serveClose <- struct{}{} - }() - - /* - IMPORTANT NOTE: the fs.Serve function is blocking; - Serve builds up the actual fuse file system by calling the - Attr functions on each SwarmFile, creating the file inodes; - specifically calling the swarm's LazySectionReader.Size() to set the file size. - - This can take some time, and it appears that if we access the fuse file system - too early, we can bring the tests to deadlock. The assumption so far is that - at this point, the fuse driver didn't finish to initialize the file system. - - Accessing files too early not only deadlocks the tests, but locks the access - of the fuse file completely, resulting in blocked resources at OS system level. - Even a simple `ls /tmp/testDir/testMountDir` could deadlock in a shell. - - Workaround so far is to wait some time to give the OS enough time to initialize - the fuse file system. During tests, this seemed to address the issue. - - HOWEVER IT SHOULD BE NOTED THAT THIS MAY ONLY BE AN EFFECT, - AND THE DEADLOCK CAUSED BY SOMETHING ELSE BLOCKING ACCESS DUE TO SOME RACE CONDITION - (caused in the bazil.org library and/or the SwarmRoot, SwarmDir and SwarmFile implementations) - */ - time.Sleep(2 * time.Second) - - timer := time.NewTimer(mountTimeout) - defer timer.Stop() - // Check if the mount process has an error to report. - select { - case <-timer.C: - log.Warn("swarmfs timed out mounting over FUSE", "mountpoint", cleanedMountPoint, "err", err) - err := fuse.Unmount(cleanedMountPoint) - if err != nil { - return nil, err - } - return nil, errMountTimeout - case err := <-serverr: - log.Warn("swarmfs error serving over FUSE", "mountpoint", cleanedMountPoint, "err", err) - err = fuse.Unmount(cleanedMountPoint) - return nil, err - - case <-fconn.Ready: - //this signals that the actual mount point from the fuse.Mount call is ready; - //it does not signal though that the file system from fs.Serve is actually fully built up - if err := fconn.MountError; err != nil { - log.Error("Mounting error from fuse driver: ", "err", err) - return nil, err - } - log.Info("swarmfs now served over FUSE", "manifest", mhash, "mountpoint", cleanedMountPoint) - } - - timer.Stop() - swarmfs.activeMounts[cleanedMountPoint] = mi - return mi, nil -} - -func (swarmfs *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) { - swarmfs.swarmFsLock.Lock() - defer swarmfs.swarmFsLock.Unlock() - - cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint)) - if err != nil { - return nil, err - } - - mountInfo := swarmfs.activeMounts[cleanedMountPoint] - - if mountInfo == nil || mountInfo.MountPoint != cleanedMountPoint { - return nil, fmt.Errorf("swarmfs %s is not mounted", cleanedMountPoint) - } - err = fuse.Unmount(cleanedMountPoint) - if err != nil { - err1 := externalUnmount(cleanedMountPoint) - if err1 != nil { - errStr := fmt.Sprintf("swarmfs unmount error: %v", err) - log.Warn(errStr) - return nil, err1 - } - } - - err = mountInfo.fuseConnection.Close() - if err != nil { - return nil, err - } - delete(swarmfs.activeMounts, cleanedMountPoint) - - <-mountInfo.serveClose - - succString := fmt.Sprintf("swarmfs unmounting %v succeeded", cleanedMountPoint) - log.Info(succString) - - return mountInfo, nil -} - -func (swarmfs *SwarmFS) Listmounts() []*MountInfo { - swarmfs.swarmFsLock.RLock() - defer swarmfs.swarmFsLock.RUnlock() - rows := make([]*MountInfo, 0, len(swarmfs.activeMounts)) - for _, mi := range swarmfs.activeMounts { - rows = append(rows, mi) - } - return rows -} - -func (swarmfs *SwarmFS) Stop() bool { - for mp := range swarmfs.activeMounts { - mountInfo := swarmfs.activeMounts[mp] - swarmfs.Unmount(mountInfo.MountPoint) - } - return true -} diff --git a/swarm/fuse/swarmfs_util.go b/swarm/fuse/swarmfs_util.go deleted file mode 100644 index 4f2e1416b6..0000000000 --- a/swarm/fuse/swarmfs_util.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build linux darwin freebsd - -package fuse - -import ( - "context" - "fmt" - "os/exec" - "runtime" - - "github.com/ethereum/go-ethereum/swarm/log" -) - -func externalUnmount(mountPoint string) error { - ctx, cancel := context.WithTimeout(context.Background(), unmountTimeout) - defer cancel() - - // Try generic umount. - if err := exec.CommandContext(ctx, "umount", mountPoint).Run(); err == nil { - return nil - } - // Try FUSE-specific commands if umount didn't work. - switch runtime.GOOS { - case "darwin": - return exec.CommandContext(ctx, "diskutil", "umount", mountPoint).Run() - case "linux": - return exec.CommandContext(ctx, "fusermount", "-u", mountPoint).Run() - default: - return fmt.Errorf("swarmfs unmount: unimplemented") - } -} - -func addFileToSwarm(sf *SwarmFile, content []byte, size int) error { - fkey, mhash, err := sf.mountInfo.swarmApi.AddFile(context.TODO(), sf.mountInfo.LatestManifest, sf.path, sf.name, content, true) - if err != nil { - return err - } - - sf.lock.Lock() - defer sf.lock.Unlock() - sf.addr = fkey - sf.fileSize = int64(size) - - sf.mountInfo.lock.Lock() - defer sf.mountInfo.lock.Unlock() - sf.mountInfo.LatestManifest = mhash - - log.Info("swarmfs added new file:", "fname", sf.name, "new Manifest hash", mhash) - return nil -} - -func removeFileFromSwarm(sf *SwarmFile) error { - mkey, err := sf.mountInfo.swarmApi.RemoveFile(context.TODO(), sf.mountInfo.LatestManifest, sf.path, sf.name, true) - if err != nil { - return err - } - - sf.mountInfo.lock.Lock() - defer sf.mountInfo.lock.Unlock() - sf.mountInfo.LatestManifest = mkey - - log.Info("swarmfs removed file:", "fname", sf.name, "new Manifest hash", mkey) - return nil -} - -func removeDirectoryFromSwarm(sd *SwarmDir) error { - if len(sd.directories) == 0 && len(sd.files) == 0 { - return nil - } - - for _, d := range sd.directories { - err := removeDirectoryFromSwarm(d) - if err != nil { - return err - } - } - - for _, f := range sd.files { - err := removeFileFromSwarm(f) - if err != nil { - return err - } - } - - return nil -} - -func appendToExistingFileInSwarm(sf *SwarmFile, content []byte, offset int64, length int64) error { - fkey, mhash, err := sf.mountInfo.swarmApi.AppendFile(context.TODO(), sf.mountInfo.LatestManifest, sf.path, sf.name, sf.fileSize, content, sf.addr, offset, length, true) - if err != nil { - return err - } - - sf.lock.Lock() - defer sf.lock.Unlock() - sf.addr = fkey - sf.fileSize = sf.fileSize + int64(len(content)) - - sf.mountInfo.lock.Lock() - defer sf.mountInfo.lock.Unlock() - sf.mountInfo.LatestManifest = mhash - - log.Info("swarmfs appended file:", "fname", sf.name, "new Manifest hash", mhash) - return nil -} diff --git a/swarm/log/log.go b/swarm/log/log.go deleted file mode 100644 index ce372632e8..0000000000 --- a/swarm/log/log.go +++ /dev/null @@ -1,48 +0,0 @@ -package log - -import ( - l "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" -) - -const ( - // CallDepth is set to 1 in order to influence to reported line number of - // the log message with 1 skipped stack frame of calling l.Output() - CallDepth = 1 -) - -// Warn is a convenient alias for log.Warn with stats -func Warn(msg string, ctx ...interface{}) { - metrics.GetOrRegisterCounter("warn", nil).Inc(1) - l.Output(msg, l.LvlWarn, CallDepth, ctx...) -} - -// Error is a convenient alias for log.Error with stats -func Error(msg string, ctx ...interface{}) { - metrics.GetOrRegisterCounter("error", nil).Inc(1) - l.Output(msg, l.LvlError, CallDepth, ctx...) -} - -// Crit is a convenient alias for log.Crit with stats -func Crit(msg string, ctx ...interface{}) { - metrics.GetOrRegisterCounter("crit", nil).Inc(1) - l.Output(msg, l.LvlCrit, CallDepth, ctx...) -} - -// Info is a convenient alias for log.Info with stats -func Info(msg string, ctx ...interface{}) { - metrics.GetOrRegisterCounter("info", nil).Inc(1) - l.Output(msg, l.LvlInfo, CallDepth, ctx...) -} - -// Debug is a convenient alias for log.Debug with stats -func Debug(msg string, ctx ...interface{}) { - metrics.GetOrRegisterCounter("debug", nil).Inc(1) - l.Output(msg, l.LvlDebug, CallDepth, ctx...) -} - -// Trace is a convenient alias for log.Trace with stats -func Trace(msg string, ctx ...interface{}) { - metrics.GetOrRegisterCounter("trace", nil).Inc(1) - l.Output(msg, l.LvlTrace, CallDepth, ctx...) -} diff --git a/swarm/metrics/flags.go b/swarm/metrics/flags.go deleted file mode 100644 index 39859a7b2d..0000000000 --- a/swarm/metrics/flags.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package metrics - -import ( - "os" - "path/filepath" - "time" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/metrics" - gethmetrics "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/metrics/influxdb" - "github.com/ethereum/go-ethereum/swarm/log" - cli "gopkg.in/urfave/cli.v1" -) - -var ( - MetricsEnableInfluxDBExportFlag = cli.BoolFlag{ - Name: "metrics.influxdb.export", - Usage: "Enable metrics export/push to an external InfluxDB database", - } - MetricsEnableInfluxDBAccountingExportFlag = cli.BoolFlag{ - Name: "metrics.influxdb.accounting", - Usage: "Enable accounting metrics export/push to an external InfluxDB database", - } - MetricsInfluxDBEndpointFlag = cli.StringFlag{ - Name: "metrics.influxdb.endpoint", - Usage: "Metrics InfluxDB endpoint", - Value: "http://127.0.0.1:8086", - } - MetricsInfluxDBDatabaseFlag = cli.StringFlag{ - Name: "metrics.influxdb.database", - Usage: "Metrics InfluxDB database", - Value: "metrics", - } - MetricsInfluxDBUsernameFlag = cli.StringFlag{ - Name: "metrics.influxdb.username", - Usage: "Metrics InfluxDB username", - Value: "", - } - MetricsInfluxDBPasswordFlag = cli.StringFlag{ - Name: "metrics.influxdb.password", - Usage: "Metrics InfluxDB password", - Value: "", - } - // Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. - // For example `host` tag could be used so that we can group all nodes and average a measurement - // across all of them, but also so that we can select a specific node and inspect its measurements. - // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key - MetricsInfluxDBTagsFlag = cli.StringFlag{ - Name: "metrics.influxdb.tags", - Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", - Value: "host=localhost", - } -) - -// Flags holds all command-line flags required for metrics collection. -var Flags = []cli.Flag{ - utils.MetricsEnabledFlag, - MetricsEnableInfluxDBExportFlag, - MetricsEnableInfluxDBAccountingExportFlag, - MetricsInfluxDBEndpointFlag, - MetricsInfluxDBDatabaseFlag, - MetricsInfluxDBUsernameFlag, - MetricsInfluxDBPasswordFlag, - MetricsInfluxDBTagsFlag, -} - -func Setup(ctx *cli.Context) { - if gethmetrics.Enabled { - log.Info("Enabling swarm metrics collection") - var ( - endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) - database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) - username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) - password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) - enableExport = ctx.GlobalBool(MetricsEnableInfluxDBExportFlag.Name) - enableAccountingExport = ctx.GlobalBool(MetricsEnableInfluxDBAccountingExportFlag.Name) - datadir = ctx.GlobalString("datadir") - ) - - // Start system runtime metrics collection - go gethmetrics.CollectProcessMetrics(4 * time.Second) - - // Start collecting disk metrics - go datadirDiskUsage(datadir, 4*time.Second) - - gethmetrics.RegisterRuntimeMemStats(metrics.DefaultRegistry) - go gethmetrics.CaptureRuntimeMemStats(metrics.DefaultRegistry, 4*time.Second) - - tagsMap := utils.SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) - - if enableExport { - log.Info("Enabling swarm metrics export to InfluxDB") - go influxdb.InfluxDBWithTags(gethmetrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "swarm.", tagsMap) - } - - if enableAccountingExport { - log.Info("Exporting swarm accounting metrics to InfluxDB") - go influxdb.InfluxDBWithTags(gethmetrics.AccountingRegistry, 10*time.Second, endpoint, database, username, password, "accounting.", tagsMap) - } - } -} - -func datadirDiskUsage(path string, d time.Duration) { - for range time.Tick(d) { - bytes, err := dirSize(path) - if err != nil { - log.Warn("cannot get disk space", "err", err) - } - - metrics.GetOrRegisterGauge("datadir.usage", nil).Update(bytes) - } -} - -func dirSize(path string) (int64, error) { - var size int64 - err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - size += info.Size() - } - return err - }) - return size, err -} diff --git a/swarm/network/README.md b/swarm/network/README.md deleted file mode 100644 index 684ad0c8c0..0000000000 --- a/swarm/network/README.md +++ /dev/null @@ -1,152 +0,0 @@ -## Streaming - -Streaming is a new protocol of the swarm bzz bundle of protocols. -This protocol provides the basic logic for chunk-based data flow. -It implements simple retrieve requests and delivery using priority queue. -A data exchange stream is a directional flow of chunks between peers. -The source of datachunks is the upstream, the receiver is called the -downstream peer. Each streaming protocol defines an outgoing streamer -and an incoming streamer, the former installing on the upstream, -the latter on the downstream peer. - -Subscribe on StreamerPeer launches an incoming streamer that sends -a subscribe msg upstream. The streamer on the upstream peer -handles the subscribe msg by installing the relevant outgoing streamer -. The modules now engage in a process of upstream sending a sequence of hashes of -chunks downstream (OfferedHashesMsg). The downstream peer evaluates which hashes are needed -and get it delivered by sending back a msg (WantedHashesMsg). - -Historical syncing is supported - currently not the right abstraction -- -state kept across sessions by saving a series of intervals after their last -batch actually arrived. - -Live streaming is also supported, by starting session from the first item -after the subscription. - -Provable data exchange. In case a stream represents a swarm document's data layer -or higher level chunks, streaming up to a certain index is always provable. It saves on -sending intermediate chunks. - -Using the streamer logic, various stream types are easy to implement: - -* light node requests: - * url lookup with offset - * document download - * document upload -* syncing - * live session syncing - * historical syncing -* simple retrieve requests and deliveries -* swarm feeds streams -* receipting for finger pointing - -## Syncing - -Syncing is the process that makes sure storer nodes end up storing all and only the chunks that are requested from them. - -### Requirements - -- eventual consistency: so each chunk historical should be syncable -- since the same chunk can and will arrive from many peers, (network traffic should be -optimised, only one transfer of data per chunk) -- explicit request deliveries should be prioritised higher than recent chunks received -during the ongoing session which in turn should be higher than historical chunks. -- insured chunks should get receipted for finger pointing litigation, the receipts storage -should be organised efficiently, upstream peer should also be able to find these -receipts for a deleted chunk easily to refute their challenge. -- syncing should be resilient to cut connections, metadata should be persisted that -keep track of syncing state across sessions, historical syncing state should survive restart -- extra data structures to support syncing should be kept at minimum -- syncing is not organized separately for chunk types (Swarm feed updates v regular content chunk) -- various types of streams should have common logic abstracted - -Syncing is now entirely mediated by the localstore, ie., no processes or memory leaks due to network contention. -When a new chunk is stored, its chunk hash is index by proximity bin - -peers syncronise by getting the chunks closer to the downstream peer than to the upstream one. -Consequently peers just sync all stored items for the kad bin the receiving peer falls into. -The special case of nearest neighbour sets is handled by the downstream peer -indicating they want to sync all kademlia bins with proximity equal to or higher -than their depth. - -This sync state represents the initial state of a sync connection session. -Retrieval is dictated by downstream peers simply using a special streamer protocol. - -Syncing chunks created during the session by the upstream peer is called live session syncing -while syncing of earlier chunks is historical syncing. - -Once the relevant chunk is retrieved, downstream peer looks up all hash segments in its localstore -and sends to the upstream peer a message with a a bitvector to indicate -missing chunks (e.g., for chunk `k`, hash with chunk internal index which case ) -new items. In turn upstream peer sends the relevant chunk data alongside their index. - -On sending chunks there is a priority queue system. If during looking up hashes in its localstore, -downstream peer hits on an open request then a retrieve request is sent immediately to the upstream peer indicating -that no extra round of checks is needed. If another peers syncer hits the same open request, it is slightly unsafe to not ask -that peer too: if the first one disconnects before delivering or fails to deliver and therefore gets -disconnected, we should still be able to continue with the other. The minimum redundant traffic coming from such simultaneous -eventualities should be sufficiently rare not to warrant more complex treatment. - -Session syncing involves downstream peer to request a new state on a bin from upstream. -using the new state, the range (of chunks) between the previous state and the new one are retrieved -and chunks are requested identical to the historical case. After receiving all the missing chunks -from the new hashes, downstream peer will request a new range. If this happens before upstream peer updates a new state, -we say that session syncing is live or the two peers are in sync. In general the time interval passed since downstream peer request up to the current session cursor is a good indication of a permanent (probably increasing) lag. - -If there is no historical backlog, and downstream peer has an acceptable 'last synced' tag, then it is said to be fully synced with the upstream peer. -If a peer is fully synced with all its storer peers, it can advertise itself as globally fully synced. - -The downstream peer persists the record of the last synced offset. When the two peers disconnect and -reconnect syncing can start from there. -This situation however can also happen while historical syncing is not yet complete. -Effectively this means that the peer needs to persist a record of an arbitrary array of offset ranges covered. - -### Delivery requests - -once the appropriate ranges of the hashstream are retrieved and buffered, downstream peer just scans the hashes, looks them up in localstore, if not found, create a request entry. -The range is referenced by the chunk index. Alongside the name (indicating the stream, e.g., content chunks for bin 6) and the range -downstream peer sends a 128 long bitvector indicating which chunks are needed. -Newly created requests are satisfied bound together in a waitgroup which when done, will promptt sending the next one. -to be able to do check and storage concurrently, we keep a buffer of one, we start with two batches of hashes. -If there is nothing to give, upstream peers SetNextBatch is blocking. Subscription ends with an unsubscribe. which removes the syncer from the map. - -Canceling requests (for instance the late chunks of an erasure batch) should be a chan closed -on the request - -Simple request is also a subscribe -different streaming protocols are different p2p protocols with same message types. -the constructor is the Run function itself. which takes a streamerpeer as argument - - -### provable streams - -The swarm hash over the hash stream has many advantages. It implements a provable data transfer -and provide efficient storage for receipts in the form of inclusion proofs useable for finger pointing litigation. -When challenged on a missing chunk, upstream peer will provide an inclusion proof of a chunk hash against the state of the -sync stream. In order to be able to generate such an inclusion proof, upstream peer needs to store the hash index (counting consecutive hash-size segments) alongside the chunk data and preserve it even when the chunk data is deleted until the chunk is no longer insured. -if there is no valid insurance on the files the entry may be deleted. -As long as the chunk is preserved, no takeover proof will be needed since the node can respond to any challenge. -However, once the node needs to delete an insured chunk for capacity reasons, a receipt should be available to -refute the challenge by finger pointing to a downstream peer. -As part of the deletion protocol then, hashes of insured chunks to be removed are pushed to an infinite stream for every bin. - -Downstream peer on the other hand needs to make sure that they can only be finger pointed about a chunk they did receive and store. -For this the check of a state should be exhaustive. If historical syncing finishes on one state, all hashes before are covered, no -surprises. In other words historical syncing this process is self verifying. With session syncing however, it is not enough to check going back covering the range from old offset to new. Continuity (i.e., that the new state is extension of the old) needs to be verified: after downstream peer reads the range into a buffer, it appends the buffer the last known state at the last known offset and verifies the resulting hash matches -the latest state. Past intervals of historical syncing are checked via the session root. -Upstream peer signs the states, downstream peers can use as handover proofs. -Downstream peers sign off on a state together with an initial offset. - -Once historical syncing is complete and the session does not lag, downstream peer only preserves the latest upstream state and store the signed version. - -Upstream peer needs to keep the latest takeover states: each deleted chunk's hash should be covered by takeover proof of at least one peer. If historical syncing is complete, upstream peer typically will store only the latest takeover proof from downstream peer. -Crucially, the structure is totally independent of the number of peers in the bin, so it scales extremely well. - -## implementation - -The simplest protocol just involves upstream peer to prefix the key with the kademlia proximity order (say 0-15 or 0-31) -and simply iterate on index per bin when syncing with a peer. - -priority queues are used for sending chunks so that user triggered requests should be responded to first, session syncing second, and historical with lower priority. -The request on chunks remains implemented as a dataless entry in the memory store. -The lifecycle of this object should be more carefully thought through, ie., when it fails to retrieve it should be removed. diff --git a/swarm/network/bitvector/bitvector.go b/swarm/network/bitvector/bitvector.go deleted file mode 100644 index 9583285023..0000000000 --- a/swarm/network/bitvector/bitvector.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package bitvector - -import ( - "errors" -) - -var errInvalidLength = errors.New("invalid length") - -type BitVector struct { - len int - b []byte -} - -func New(l int) (bv *BitVector, err error) { - return NewFromBytes(make([]byte, l/8+1), l) -} - -func NewFromBytes(b []byte, l int) (bv *BitVector, err error) { - if l <= 0 { - return nil, errInvalidLength - } - if len(b)*8 < l { - return nil, errInvalidLength - } - return &BitVector{ - len: l, - b: b, - }, nil -} - -func (bv *BitVector) Get(i int) bool { - bi := i / 8 - return bv.b[bi]&(0x1<. - -package bitvector - -import "testing" - -func TestBitvectorNew(t *testing.T) { - _, err := New(0) - if err != errInvalidLength { - t.Errorf("expected err %v, got %v", errInvalidLength, err) - } - - _, err = NewFromBytes(nil, 0) - if err != errInvalidLength { - t.Errorf("expected err %v, got %v", errInvalidLength, err) - } - - _, err = NewFromBytes([]byte{0}, 9) - if err != errInvalidLength { - t.Errorf("expected err %v, got %v", errInvalidLength, err) - } - - _, err = NewFromBytes(make([]byte, 8), 8) - if err != nil { - t.Error(err) - } -} - -func TestBitvectorGetSet(t *testing.T) { - for _, length := range []int{ - 1, - 2, - 4, - 8, - 9, - 15, - 16, - } { - bv, err := New(length) - if err != nil { - t.Errorf("error for length %v: %v", length, err) - } - - for i := 0; i < length; i++ { - if bv.Get(i) { - t.Errorf("expected false for element on index %v", i) - } - } - - func() { - defer func() { - if err := recover(); err == nil { - t.Errorf("expecting panic") - } - }() - bv.Get(length + 8) - }() - - for i := 0; i < length; i++ { - bv.Set(i, true) - for j := 0; j < length; j++ { - if j == i { - if !bv.Get(j) { - t.Errorf("element on index %v is not set to true", i) - } - } else { - if bv.Get(j) { - t.Errorf("element on index %v is not false", i) - } - } - } - - bv.Set(i, false) - - if bv.Get(i) { - t.Errorf("element on index %v is not set to false", i) - } - } - } -} - -func TestBitvectorNewFromBytesGet(t *testing.T) { - bv, err := NewFromBytes([]byte{8}, 8) - if err != nil { - t.Error(err) - } - if !bv.Get(3) { - t.Fatalf("element 3 is not set to true: state %08b", bv.b[0]) - } -} diff --git a/swarm/network/common.go b/swarm/network/common.go deleted file mode 100644 index 15b2e20604..0000000000 --- a/swarm/network/common.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "fmt" - "strings" -) - -func LogAddrs(nns [][]byte) string { - var nnsa []string - for _, nn := range nns { - nnsa = append(nnsa, fmt.Sprintf("%08x", nn[:4])) - } - return strings.Join(nnsa, ", ") -} diff --git a/swarm/network/discovery.go b/swarm/network/discovery.go deleted file mode 100644 index 54ecf257c3..0000000000 --- a/swarm/network/discovery.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "context" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/swarm/pot" -) - -// discovery bzz extension for requesting and relaying node address records - -var sortPeers = noSortPeers - -// Peer wraps BzzPeer and embeds Kademlia overlay connectivity driver -type Peer struct { - *BzzPeer - kad *Kademlia - sentPeers bool // whether we already sent peer closer to this address - mtx sync.RWMutex // - peers map[string]bool // tracks node records sent to the peer - depth uint8 // the proximity order advertised by remote as depth of saturation -} - -// NewPeer constructs a discovery peer -func NewPeer(p *BzzPeer, kad *Kademlia) *Peer { - d := &Peer{ - kad: kad, - BzzPeer: p, - peers: make(map[string]bool), - } - // record remote as seen so we never send a peer its own record - d.seen(p.BzzAddr) - return d -} - -// HandleMsg is the message handler that delegates incoming messages -func (d *Peer) HandleMsg(ctx context.Context, msg interface{}) error { - switch msg := msg.(type) { - - case *peersMsg: - return d.handlePeersMsg(msg) - - case *subPeersMsg: - return d.handleSubPeersMsg(msg) - - default: - return fmt.Errorf("unknown message type: %T", msg) - } -} - -// NotifyDepth sends a message to all connections if depth of saturation is changed -func NotifyDepth(depth uint8, kad *Kademlia) { - f := func(val *Peer, po int) bool { - val.NotifyDepth(depth) - return true - } - kad.EachConn(nil, 255, f) -} - -// NotifyPeer informs all peers about a newly added node -func NotifyPeer(p *BzzAddr, k *Kademlia) { - f := func(val *Peer, po int) bool { - val.NotifyPeer(p, uint8(po)) - return true - } - k.EachConn(p.Address(), 255, f) -} - -// NotifyPeer notifies the remote node (recipient) about a peer if -// the peer's PO is within the recipients advertised depth -// OR the peer is closer to the recipient than self -// unless already notified during the connection session -func (d *Peer) NotifyPeer(a *BzzAddr, po uint8) { - // immediately return - if (po < d.getDepth() && pot.ProxCmp(d.kad.BaseAddr(), d, a) != 1) || d.seen(a) { - return - } - resp := &peersMsg{ - Peers: []*BzzAddr{a}, - } - go d.Send(context.TODO(), resp) -} - -// NotifyDepth sends a subPeers Msg to the receiver notifying them about -// a change in the depth of saturation -func (d *Peer) NotifyDepth(po uint8) { - go d.Send(context.TODO(), &subPeersMsg{Depth: po}) -} - -/* -peersMsg is the message to pass peer information -It is always a response to a peersRequestMsg - -The encoding of a peer address is identical the devp2p base protocol peers -messages: [IP, Port, NodeID], -Note that a node's FileStore address is not the NodeID but the hash of the NodeID. - -TODO: -To mitigate against spurious peers messages, requests should be remembered -and correctness of responses should be checked - -If the proxBin of peers in the response is incorrect the sender should be -disconnected -*/ - -// peersMsg encapsulates an array of peer addresses -// used for communicating about known peers -// relevant for bootstrapping connectivity and updating peersets -type peersMsg struct { - Peers []*BzzAddr -} - -// String pretty prints a peersMsg -func (msg peersMsg) String() string { - return fmt.Sprintf("%T: %v", msg, msg.Peers) -} - -// handlePeersMsg called by the protocol when receiving peerset (for target address) -// list of nodes ([]PeerAddr in peersMsg) is added to the overlay db using the -// Register interface method -func (d *Peer) handlePeersMsg(msg *peersMsg) error { - // register all addresses - if len(msg.Peers) == 0 { - return nil - } - - for _, a := range msg.Peers { - d.seen(a) - NotifyPeer(a, d.kad) - } - return d.kad.Register(msg.Peers...) -} - -// subPeers msg is communicating the depth of the overlay table of a peer -type subPeersMsg struct { - Depth uint8 -} - -// String returns the pretty printer -func (msg subPeersMsg) String() string { - return fmt.Sprintf("%T: request peers > PO%02d. ", msg, msg.Depth) -} - -// handleSubPeersMsg handles incoming subPeersMsg -// this message represents the saturation depth of the remote peer -// saturation depth is the radius within which the peer subscribes to peers -// the first time this is received we send peer info on all -// our connected peers that fall within peers saturation depth -// otherwise this depth is just recorded on the peer, so that -// subsequent new connections are sent iff they fall within the radius -func (d *Peer) handleSubPeersMsg(msg *subPeersMsg) error { - d.setDepth(msg.Depth) - // only send peers after the initial subPeersMsg - if !d.sentPeers { - var peers []*BzzAddr - // iterate connection in ascending order of disctance from the remote address - d.kad.EachConn(d.Over(), 255, func(p *Peer, po int) bool { - // terminate if we are beyond the radius - if uint8(po) < msg.Depth { - return false - } - if !d.seen(p.BzzAddr) { // here just records the peer sent - peers = append(peers, p.BzzAddr) - } - return true - }) - // if useful peers are found, send them over - if len(peers) > 0 { - go d.Send(context.TODO(), &peersMsg{Peers: sortPeers(peers)}) - } - } - d.sentPeers = true - return nil -} - -// seen takes a peer address and checks if it was sent to a peer already -// if not, marks the peer as sent -func (d *Peer) seen(p *BzzAddr) bool { - d.mtx.Lock() - defer d.mtx.Unlock() - k := string(p.Address()) - if d.peers[k] { - return true - } - d.peers[k] = true - return false -} - -func (d *Peer) getDepth() uint8 { - d.mtx.RLock() - defer d.mtx.RUnlock() - return d.depth -} - -func (d *Peer) setDepth(depth uint8) { - d.mtx.Lock() - defer d.mtx.Unlock() - d.depth = depth -} - -func noSortPeers(peers []*BzzAddr) []*BzzAddr { - return peers -} diff --git a/swarm/network/discovery_test.go b/swarm/network/discovery_test.go deleted file mode 100644 index cf7ddc4fba..0000000000 --- a/swarm/network/discovery_test.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "crypto/ecdsa" - crand "crypto/rand" - "encoding/binary" - "fmt" - "math/rand" - "net" - "sort" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" - "github.com/ethereum/go-ethereum/swarm/pot" -) - -/*** - * - * - after connect, that outgoing subpeersmsg is sent - * - */ -func TestSubPeersMsg(t *testing.T) { - params := NewHiveParams() - s, pp, err := newHiveTester(params, 1, nil) - if err != nil { - t.Fatal(err) - } - - node := s.Nodes[0] - raddr := NewAddr(node) - pp.Register(raddr) - - // start the hive and wait for the connection - pp.Start(s.Server) - defer pp.Stop() - - // send subPeersMsg to the peer - err = s.TestExchanges(p2ptest.Exchange{ - Label: "outgoing subPeersMsg", - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &subPeersMsg{Depth: 0}, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -const ( - maxPO = 8 // PO of pivot and control; chosen to test enough cases but not run too long - maxPeerPO = 6 // pivot has no peers closer than this to the control peer - maxPeersPerPO = 3 -) - -// TestInitialPeersMsg tests if peersMsg response to incoming subPeersMsg is correct -func TestInitialPeersMsg(t *testing.T) { - for po := 0; po < maxPO; po++ { - for depth := 0; depth < maxPO; depth++ { - t.Run(fmt.Sprintf("PO=%d,advertised depth=%d", po, depth), func(t *testing.T) { - testInitialPeersMsg(t, po, depth) - }) - } - } -} - -// testInitialPeersMsg tests that the correct set of peer info is sent -// to another peer after receiving their subPeersMsg request -func testInitialPeersMsg(t *testing.T, peerPO, peerDepth int) { - // generate random pivot address - prvkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - defer func(orig func([]*BzzAddr) []*BzzAddr) { - sortPeers = orig - }(sortPeers) - sortPeers = testSortPeers - pivotAddr := pot.NewAddressFromBytes(PrivateKeyToBzzKey(prvkey)) - // generate control peers address at peerPO wrt pivot - peerAddr := pot.RandomAddressAt(pivotAddr, peerPO) - // construct kademlia and hive - to := NewKademlia(pivotAddr[:], NewKadParams()) - hive := NewHive(NewHiveParams(), to, nil) - - // expected addrs in peersMsg response - var expBzzAddrs []*BzzAddr - connect := func(a pot.Address, po int) (addrs []*BzzAddr) { - n := rand.Intn(maxPeersPerPO) - for i := 0; i < n; i++ { - peer, err := newDiscPeer(pot.RandomAddressAt(a, po)) - if err != nil { - t.Fatal(err) - } - hive.On(peer) - addrs = append(addrs, peer.BzzAddr) - } - return addrs - } - register := func(a pot.Address, po int) { - addr := pot.RandomAddressAt(a, po) - hive.Register(&BzzAddr{OAddr: addr[:]}) - } - - // generate connected and just registered peers - for po := maxPeerPO; po >= 0; po-- { - // create a fake connected peer at po from peerAddr - ons := connect(peerAddr, po) - // create a fake registered address at po from peerAddr - register(peerAddr, po) - // we collect expected peer addresses only up till peerPO - if po < peerDepth { - continue - } - expBzzAddrs = append(expBzzAddrs, ons...) - } - - // add extra connections closer to pivot than control - for po := peerPO + 1; po < maxPO; po++ { - ons := connect(pivotAddr, po) - if peerDepth <= peerPO { - expBzzAddrs = append(expBzzAddrs, ons...) - } - } - - // create a special bzzBaseTester in which we can associate `enode.ID` to the `bzzAddr` we created above - s, _, err := newBzzBaseTesterWithAddrs(prvkey, [][]byte{peerAddr[:]}, DiscoverySpec, hive.Run) - if err != nil { - t.Fatal(err) - } - defer s.Stop() - - // peerID to use in the protocol tester testExchange expect/trigger - peerID := s.Nodes[0].ID() - // block until control peer is found among hive peers - found := false - for attempts := 0; attempts < 2000; attempts++ { - found = hive.Peer(peerID) != nil - if found { - break - } - time.Sleep(1 * time.Millisecond) - } - - if !found { - t.Fatal("timeout waiting for peer connection to start") - } - - // pivotDepth is the advertised depth of the pivot node we expect in the outgoing subPeersMsg - pivotDepth := hive.Saturation() - // the test exchange is as follows: - // 1. pivot sends to the control peer a `subPeersMsg` advertising its depth (ignored) - // 2. peer sends to pivot a `subPeersMsg` advertising its own depth (arbitrarily chosen) - // 3. pivot responds with `peersMsg` with the set of expected peers - err = s.TestExchanges( - p2ptest.Exchange{ - Label: "outgoing subPeersMsg", - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &subPeersMsg{Depth: uint8(pivotDepth)}, - Peer: peerID, - }, - }, - }, - p2ptest.Exchange{ - Label: "trigger subPeersMsg and expect peersMsg", - Triggers: []p2ptest.Trigger{ - { - Code: 1, - Msg: &subPeersMsg{Depth: uint8(peerDepth)}, - Peer: peerID, - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 0, - Msg: &peersMsg{Peers: testSortPeers(expBzzAddrs)}, - Peer: peerID, - Timeout: 100 * time.Millisecond, - }, - }, - }) - - // for values MaxPeerPO < peerPO < MaxPO the pivot has no peers to offer to the control peer - // in this case, no peersMsg will be sent out, and we would run into a time out - if len(expBzzAddrs) == 0 { - if err != nil { - if err.Error() != "exchange #1 \"trigger subPeersMsg and expect peersMsg\": timed out" { - t.Fatalf("expected timeout, got %v", err) - } - return - } - t.Fatalf("expected timeout, got no error") - } - - if err != nil { - t.Fatal(err) - } -} - -func testSortPeers(peers []*BzzAddr) []*BzzAddr { - comp := func(i, j int) bool { - vi := binary.BigEndian.Uint64(peers[i].OAddr) - vj := binary.BigEndian.Uint64(peers[j].OAddr) - return vi < vj - } - sort.Slice(peers, comp) - return peers -} - -// as we are not creating a real node via the protocol, -// we need to create the discovery peer objects for the additional kademlia -// nodes manually -func newDiscPeer(addr pot.Address) (*Peer, error) { - pKey, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader) - if err != nil { - return nil, err - } - pubKey := pKey.PublicKey - nod := enode.NewV4(&pubKey, net.IPv4(127, 0, 0, 1), 0, 0) - bzzAddr := &BzzAddr{OAddr: addr[:], UAddr: []byte(nod.String())} - id := nod.ID() - p2pPeer := p2p.NewPeer(id, id.String(), nil) - return NewPeer(&BzzPeer{ - Peer: protocols.NewPeer(p2pPeer, &dummyMsgRW{}, DiscoverySpec), - BzzAddr: bzzAddr, - }, nil), nil -} - -type dummyMsgRW struct{} - -func (d *dummyMsgRW) ReadMsg() (p2p.Msg, error) { - return p2p.Msg{}, nil -} -func (d *dummyMsgRW) WriteMsg(msg p2p.Msg) error { - return nil -} diff --git a/swarm/network/enr.go b/swarm/network/enr.go deleted file mode 100644 index 6d7fa2ae40..0000000000 --- a/swarm/network/enr.go +++ /dev/null @@ -1,93 +0,0 @@ -package network - -import ( - "fmt" - "io" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/swarm/log" -) - -// ENRAddrEntry is the entry type to store the bzz key in the enode -type ENRAddrEntry struct { - data []byte -} - -func NewENRAddrEntry(addr []byte) *ENRAddrEntry { - return &ENRAddrEntry{ - data: addr, - } -} - -func (b ENRAddrEntry) Address() []byte { - return b.data -} - -// ENRKey implements enr.Entry -func (b ENRAddrEntry) ENRKey() string { - return "bzzkey" -} - -// EncodeRLP implements rlp.Encoder -func (b ENRAddrEntry) EncodeRLP(w io.Writer) error { - log.Debug("in encoderlp", "b", b, "p", fmt.Sprintf("%p", &b)) - return rlp.Encode(w, &b.data) -} - -// DecodeRLP implements rlp.Decoder -func (b *ENRAddrEntry) DecodeRLP(s *rlp.Stream) error { - byt, err := s.Bytes() - if err != nil { - return err - } - b.data = byt - log.Debug("in decoderlp", "b", b, "p", fmt.Sprintf("%p", &b)) - return nil -} - -type ENRLightNodeEntry bool - -func (b ENRLightNodeEntry) ENRKey() string { - return "bzzlightnode" -} - -type ENRBootNodeEntry bool - -func (b ENRBootNodeEntry) ENRKey() string { - return "bzzbootnode" -} - -func getENRBzzPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *protocols.Spec) *BzzPeer { - var lightnode ENRLightNodeEntry - var bootnode ENRBootNodeEntry - - // retrieve the ENR Record data - record := p.Node().Record() - record.Load(&lightnode) - record.Load(&bootnode) - - // get the address; separate function as long as we need swarm/network:NewAddr() to call it - addr := getENRBzzAddr(p.Node()) - - // build the peer using the retrieved data - return &BzzPeer{ - Peer: protocols.NewPeer(p, rw, spec), - LightNode: bool(lightnode), - BzzAddr: addr, - } -} - -func getENRBzzAddr(nod *enode.Node) *BzzAddr { - var addr ENRAddrEntry - - record := nod.Record() - record.Load(&addr) - - return &BzzAddr{ - OAddr: addr.data, - UAddr: []byte(nod.String()), - } -} diff --git a/swarm/network/fetcher.go b/swarm/network/fetcher.go deleted file mode 100644 index 5c0dfefce5..0000000000 --- a/swarm/network/fetcher.go +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/tracing" - olog "github.com/opentracing/opentracing-go/log" -) - -const ( - defaultSearchTimeout = 1 * time.Second - // maximum number of forwarded requests (hops), to make sure requests are not - // forwarded forever in peer loops - maxHopCount uint8 = 20 -) - -// Time to consider peer to be skipped. -// Also used in stream delivery. -var RequestTimeout = 10 * time.Second - -type RequestFunc func(context.Context, *Request) (*enode.ID, chan struct{}, error) - -// Fetcher is created when a chunk is not found locally. It starts a request handler loop once and -// keeps it alive until all active requests are completed. This can happen: -// 1. either because the chunk is delivered -// 2. or because the requester cancelled/timed out -// Fetcher self destroys itself after it is completed. -// TODO: cancel all forward requests after termination -type Fetcher struct { - protoRequestFunc RequestFunc // request function fetcher calls to issue retrieve request for a chunk - addr storage.Address // the address of the chunk to be fetched - offerC chan *enode.ID // channel of sources (peer node id strings) - requestC chan uint8 // channel for incoming requests (with the hopCount value in it) - searchTimeout time.Duration - skipCheck bool - ctx context.Context -} - -type Request struct { - Addr storage.Address // chunk address - Source *enode.ID // nodeID of peer to request from (can be nil) - SkipCheck bool // whether to offer the chunk first or deliver directly - peersToSkip *sync.Map // peers not to request chunk from (only makes sense if source is nil) - HopCount uint8 // number of forwarded requests (hops) -} - -// NewRequest returns a new instance of Request based on chunk address skip check and -// a map of peers to skip. -func NewRequest(addr storage.Address, skipCheck bool, peersToSkip *sync.Map) *Request { - return &Request{ - Addr: addr, - SkipCheck: skipCheck, - peersToSkip: peersToSkip, - } -} - -// SkipPeer returns if the peer with nodeID should not be requested to deliver a chunk. -// Peers to skip are kept per Request and for a time period of RequestTimeout. -// This function is used in stream package in Delivery.RequestFromPeers to optimize -// requests for chunks. -func (r *Request) SkipPeer(nodeID string) bool { - val, ok := r.peersToSkip.Load(nodeID) - if !ok { - return false - } - t, ok := val.(time.Time) - if ok && time.Now().After(t.Add(RequestTimeout)) { - // deadline expired - r.peersToSkip.Delete(nodeID) - return false - } - return true -} - -// FetcherFactory is initialised with a request function and can create fetchers -type FetcherFactory struct { - request RequestFunc - skipCheck bool -} - -// NewFetcherFactory takes a request function and skip check parameter and creates a FetcherFactory -func NewFetcherFactory(request RequestFunc, skipCheck bool) *FetcherFactory { - return &FetcherFactory{ - request: request, - skipCheck: skipCheck, - } -} - -// New constructs a new Fetcher, for the given chunk. All peers in peersToSkip -// are not requested to deliver the given chunk. peersToSkip should always -// contain the peers which are actively requesting this chunk, to make sure we -// don't request back the chunks from them. -// The created Fetcher is started and returned. -func (f *FetcherFactory) New(ctx context.Context, source storage.Address, peers *sync.Map) storage.NetFetcher { - fetcher := NewFetcher(ctx, source, f.request, f.skipCheck) - go fetcher.run(peers) - return fetcher -} - -// NewFetcher creates a new Fetcher for the given chunk address using the given request function. -func NewFetcher(ctx context.Context, addr storage.Address, rf RequestFunc, skipCheck bool) *Fetcher { - return &Fetcher{ - addr: addr, - protoRequestFunc: rf, - offerC: make(chan *enode.ID), - requestC: make(chan uint8), - searchTimeout: defaultSearchTimeout, - skipCheck: skipCheck, - ctx: ctx, - } -} - -// Offer is called when an upstream peer offers the chunk via syncing as part of `OfferedHashesMsg` and the node does not have the chunk locally. -func (f *Fetcher) Offer(source *enode.ID) { - // First we need to have this select to make sure that we return if context is done - select { - case <-f.ctx.Done(): - return - default: - } - - // This select alone would not guarantee that we return of context is done, it could potentially - // push to offerC instead if offerC is available (see number 2 in https://golang.org/ref/spec#Select_statements) - select { - case f.offerC <- source: - case <-f.ctx.Done(): - } -} - -// Request is called when an upstream peer request the chunk as part of `RetrieveRequestMsg`, or from a local request through FileStore, and the node does not have the chunk locally. -func (f *Fetcher) Request(hopCount uint8) { - // First we need to have this select to make sure that we return if context is done - select { - case <-f.ctx.Done(): - return - default: - } - - if hopCount >= maxHopCount { - log.Debug("fetcher request hop count limit reached", "hops", hopCount) - return - } - - // This select alone would not guarantee that we return of context is done, it could potentially - // push to offerC instead if offerC is available (see number 2 in https://golang.org/ref/spec#Select_statements) - select { - case f.requestC <- hopCount + 1: - case <-f.ctx.Done(): - } -} - -// start prepares the Fetcher -// it keeps the Fetcher alive within the lifecycle of the passed context -func (f *Fetcher) run(peers *sync.Map) { - var ( - doRequest bool // determines if retrieval is initiated in the current iteration - wait *time.Timer // timer for search timeout - waitC <-chan time.Time // timer channel - sources []*enode.ID // known sources, ie. peers that offered the chunk - requested bool // true if the chunk was actually requested - hopCount uint8 - ) - gone := make(chan *enode.ID) // channel to signal that a peer we requested from disconnected - - // loop that keeps the fetching process alive - // after every request a timer is set. If this goes off we request again from another peer - // note that the previous request is still alive and has the chance to deliver, so - // requesting again extends the search. ie., - // if a peer we requested from is gone we issue a new request, so the number of active - // requests never decreases - for { - select { - - // incoming offer - case source := <-f.offerC: - log.Trace("new source", "peer addr", source, "request addr", f.addr) - // 1) the chunk is offered by a syncing peer - // add to known sources - sources = append(sources, source) - // launch a request to the source iff the chunk was requested (not just expected because its offered by a syncing peer) - doRequest = requested - - // incoming request - case hopCount = <-f.requestC: - // 2) chunk is requested, set requested flag - // launch a request iff none been launched yet - doRequest = !requested - log.Trace("new request", "request addr", f.addr, "doRequest", doRequest) - requested = true - - // peer we requested from is gone. fall back to another - // and remove the peer from the peers map - case id := <-gone: - peers.Delete(id.String()) - doRequest = requested - log.Trace("peer gone", "peer id", id.String(), "request addr", f.addr, "doRequest", doRequest) - - // search timeout: too much time passed since the last request, - // extend the search to a new peer if we can find one - case <-waitC: - doRequest = requested - log.Trace("search timed out: requesting", "request addr", f.addr, "doRequest", doRequest) - - // all Fetcher context closed, can quit - case <-f.ctx.Done(): - log.Trace("terminate fetcher", "request addr", f.addr) - // TODO: send cancellations to all peers left over in peers map (i.e., those we requested from) - return - } - - // need to issue a new request - if doRequest { - var err error - sources, err = f.doRequest(gone, peers, sources, hopCount) - if err != nil { - log.Info("unable to request", "request addr", f.addr, "err", err) - } - } - - // if wait channel is not set, set it to a timer - if requested { - if wait == nil { - wait = time.NewTimer(f.searchTimeout) - defer wait.Stop() - waitC = wait.C - } else { - // stop the timer and drain the channel if it was not drained earlier - if !wait.Stop() { - select { - case <-wait.C: - default: - } - } - // reset the timer to go off after defaultSearchTimeout - wait.Reset(f.searchTimeout) - } - } - doRequest = false - } -} - -// doRequest attempts at finding a peer to request the chunk from -// * first it tries to request explicitly from peers that are known to have offered the chunk -// * if there are no such peers (available) it tries to request it from a peer closest to the chunk address -// excluding those in the peersToSkip map -// * if no such peer is found an error is returned -// -// if a request is successful, -// * the peer's address is added to the set of peers to skip -// * the peer's address is removed from prospective sources, and -// * a go routine is started that reports on the gone channel if the peer is disconnected (or terminated their streamer) -func (f *Fetcher) doRequest(gone chan *enode.ID, peersToSkip *sync.Map, sources []*enode.ID, hopCount uint8) ([]*enode.ID, error) { - var i int - var sourceID *enode.ID - var quit chan struct{} - - req := &Request{ - Addr: f.addr, - SkipCheck: f.skipCheck, - peersToSkip: peersToSkip, - HopCount: hopCount, - } - - foundSource := false - // iterate over known sources - for i = 0; i < len(sources); i++ { - req.Source = sources[i] - var err error - log.Trace("fetcher.doRequest", "request addr", f.addr, "peer", req.Source.String()) - sourceID, quit, err = f.protoRequestFunc(f.ctx, req) - if err == nil { - // remove the peer from known sources - // Note: we can modify the source although we are looping on it, because we break from the loop immediately - sources = append(sources[:i], sources[i+1:]...) - foundSource = true - break - } - } - - // if there are no known sources, or none available, we try request from a closest node - if !foundSource { - req.Source = nil - var err error - sourceID, quit, err = f.protoRequestFunc(f.ctx, req) - if err != nil { - // if no peers found to request from - return sources, err - } - } - // add peer to the set of peers to skip from now - peersToSkip.Store(sourceID.String(), time.Now()) - - // if the quit channel is closed, it indicates that the source peer we requested from - // disconnected or terminated its streamer - // here start a go routine that watches this channel and reports the source peer on the gone channel - // this go routine quits if the fetcher global context is done to prevent process leak - go func() { - select { - case <-quit: - gone <- sourceID - case <-f.ctx.Done(): - } - - // finish the request span - spanId := fmt.Sprintf("stream.send.request.%v.%v", *sourceID, req.Addr) - span := tracing.ShiftSpanByKey(spanId) - - if span != nil { - span.LogFields(olog.String("finish", "from doRequest")) - span.Finish() - } - }() - return sources, nil -} diff --git a/swarm/network/fetcher_test.go b/swarm/network/fetcher_test.go deleted file mode 100644 index 4e464f10f3..0000000000 --- a/swarm/network/fetcher_test.go +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -var requestedPeerID = enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") -var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") - -// mockRequester pushes every request to the requestC channel when its doRequest function is called -type mockRequester struct { - // requests []Request - requestC chan *Request // when a request is coming it is pushed to requestC - waitTimes []time.Duration // with waitTimes[i] you can define how much to wait on the ith request (optional) - count int //counts the number of requests - quitC chan struct{} -} - -func newMockRequester(waitTimes ...time.Duration) *mockRequester { - return &mockRequester{ - requestC: make(chan *Request), - waitTimes: waitTimes, - quitC: make(chan struct{}), - } -} - -func (m *mockRequester) doRequest(ctx context.Context, request *Request) (*enode.ID, chan struct{}, error) { - waitTime := time.Duration(0) - if m.count < len(m.waitTimes) { - waitTime = m.waitTimes[m.count] - m.count++ - } - time.Sleep(waitTime) - m.requestC <- request - - // if there is a Source in the request use that, if not use the global requestedPeerId - source := request.Source - if source == nil { - source = &requestedPeerID - } - return source, m.quitC, nil -} - -// TestFetcherSingleRequest creates a Fetcher using mockRequester, and run it with a sample set of peers to skip. -// mockRequester pushes a Request on a channel every time the request function is called. Using -// this channel we test if calling Fetcher.Request calls the request function, and whether it uses -// the correct peers to skip which we provided for the fetcher.run function. -func TestFetcherSingleRequest(t *testing.T) { - requester := newMockRequester() - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - - peers := []string{"a", "b", "c", "d"} - peersToSkip := &sync.Map{} - for _, p := range peers { - peersToSkip.Store(p, time.Now()) - } - - go fetcher.run(peersToSkip) - - fetcher.Request(0) - - select { - case request := <-requester.requestC: - // request should contain all peers from peersToSkip provided to the fetcher - for _, p := range peers { - if _, ok := request.peersToSkip.Load(p); !ok { - t.Fatalf("request.peersToSkip misses peer") - } - } - - // source peer should be also added to peersToSkip eventually - time.Sleep(100 * time.Millisecond) - if _, ok := request.peersToSkip.Load(requestedPeerID.String()); !ok { - t.Fatalf("request.peersToSkip does not contain peer returned by the request function") - } - - // hopCount in the forwarded request should be incremented - if request.HopCount != 1 { - t.Fatalf("Expected request.HopCount 1 got %v", request.HopCount) - } - - // fetch should trigger a request, if it doesn't happen in time, test should fail - case <-time.After(200 * time.Millisecond): - t.Fatalf("fetch timeout") - } -} - -// TestCancelStopsFetcher tests that a cancelled fetcher does not initiate further requests even if its fetch function is called -func TestFetcherCancelStopsFetcher(t *testing.T) { - requester := newMockRequester() - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} - - // we start the fetcher, and then we immediately cancel the context - go fetcher.run(peersToSkip) - cancel() - - // we call Request with an active context - fetcher.Request(0) - - // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening - select { - case <-requester.requestC: - t.Fatalf("cancelled fetcher initiated request") - case <-time.After(200 * time.Millisecond): - } -} - -// TestFetchCancelStopsRequest tests that calling a Request function with a cancelled context does not initiate a request -func TestFetcherCancelStopsRequest(t *testing.T) { - t.Skip("since context is now per fetcher, this test is likely redundant") - - requester := newMockRequester(100 * time.Millisecond) - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} - - // we start the fetcher with an active context - go fetcher.run(peersToSkip) - - // we call Request with a cancelled context - fetcher.Request(0) - - // fetcher should not initiate request, we can only check by waiting a bit and making sure no request is happening - select { - case <-requester.requestC: - t.Fatalf("cancelled fetch function initiated request") - case <-time.After(200 * time.Millisecond): - } - - // if there is another Request with active context, there should be a request, because the fetcher itself is not cancelled - fetcher.Request(0) - - select { - case <-requester.requestC: - case <-time.After(200 * time.Millisecond): - t.Fatalf("expected request") - } -} - -// TestOfferUsesSource tests Fetcher Offer behavior. -// In this case there should be 1 (and only one) request initiated from the source peer, and the -// source nodeid should appear in the peersToSkip map. -func TestFetcherOfferUsesSource(t *testing.T) { - requester := newMockRequester(100 * time.Millisecond) - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} - - // start the fetcher - go fetcher.run(peersToSkip) - - // call the Offer function with the source peer - fetcher.Offer(&sourcePeerID) - - // fetcher should not initiate request - select { - case <-requester.requestC: - t.Fatalf("fetcher initiated request") - case <-time.After(200 * time.Millisecond): - } - - // call Request after the Offer - fetcher.Request(0) - - // there should be exactly 1 request coming from fetcher - var request *Request - select { - case request = <-requester.requestC: - if *request.Source != sourcePeerID { - t.Fatalf("Expected source id %v got %v", sourcePeerID, request.Source) - } - case <-time.After(200 * time.Millisecond): - t.Fatalf("fetcher did not initiate request") - } - - select { - case <-requester.requestC: - t.Fatalf("Fetcher number of requests expected 1 got 2") - case <-time.After(200 * time.Millisecond): - } - - // source peer should be added to peersToSkip eventually - time.Sleep(100 * time.Millisecond) - if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { - t.Fatalf("SourcePeerId not added to peersToSkip") - } -} - -func TestFetcherOfferAfterRequestUsesSourceFromContext(t *testing.T) { - requester := newMockRequester(100 * time.Millisecond) - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} - - // start the fetcher - go fetcher.run(peersToSkip) - - // call Request first - fetcher.Request(0) - - // there should be a request coming from fetcher - var request *Request - select { - case request = <-requester.requestC: - if request.Source != nil { - t.Fatalf("Incorrect source peer id, expected nil got %v", request.Source) - } - case <-time.After(200 * time.Millisecond): - t.Fatalf("fetcher did not initiate request") - } - - // after the Request call Offer - fetcher.Offer(&sourcePeerID) - - // there should be a request coming from fetcher - select { - case request = <-requester.requestC: - if *request.Source != sourcePeerID { - t.Fatalf("Incorrect source peer id, expected %v got %v", sourcePeerID, request.Source) - } - case <-time.After(200 * time.Millisecond): - t.Fatalf("fetcher did not initiate request") - } - - // source peer should be added to peersToSkip eventually - time.Sleep(100 * time.Millisecond) - if _, ok := request.peersToSkip.Load(sourcePeerID.String()); !ok { - t.Fatalf("SourcePeerId not added to peersToSkip") - } -} - -// TestFetcherRetryOnTimeout tests that fetch retries after searchTimeOut has passed -func TestFetcherRetryOnTimeout(t *testing.T) { - requester := newMockRequester() - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - // set searchTimeOut to low value so the test is quicker - fetcher.searchTimeout = 250 * time.Millisecond - - peersToSkip := &sync.Map{} - - // start the fetcher - go fetcher.run(peersToSkip) - - // call the fetch function with an active context - fetcher.Request(0) - - // after 100ms the first request should be initiated - time.Sleep(100 * time.Millisecond) - - select { - case <-requester.requestC: - default: - t.Fatalf("fetch did not initiate request") - } - - // after another 100ms no new request should be initiated, because search timeout is 250ms - time.Sleep(100 * time.Millisecond) - - select { - case <-requester.requestC: - t.Fatalf("unexpected request from fetcher") - default: - } - - // after another 300ms search timeout is over, there should be a new request - time.Sleep(300 * time.Millisecond) - - select { - case <-requester.requestC: - default: - t.Fatalf("fetch did not retry request") - } -} - -// TestFetcherFactory creates a FetcherFactory and checks if the factory really creates and starts -// a Fetcher when it return a fetch function. We test the fetching functionality just by checking if -// a request is initiated when the fetch function is called -func TestFetcherFactory(t *testing.T) { - requester := newMockRequester(100 * time.Millisecond) - addr := make([]byte, 32) - fetcherFactory := NewFetcherFactory(requester.doRequest, false) - - peersToSkip := &sync.Map{} - - fetcher := fetcherFactory.New(context.Background(), addr, peersToSkip) - - fetcher.Request(0) - - // check if the created fetchFunction really starts a fetcher and initiates a request - select { - case <-requester.requestC: - case <-time.After(200 * time.Millisecond): - t.Fatalf("fetch timeout") - } - -} - -func TestFetcherRequestQuitRetriesRequest(t *testing.T) { - requester := newMockRequester() - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - - // make sure the searchTimeout is long so it is sure the request is not - // retried because of timeout - fetcher.searchTimeout = 10 * time.Second - - peersToSkip := &sync.Map{} - - go fetcher.run(peersToSkip) - - fetcher.Request(0) - - select { - case <-requester.requestC: - case <-time.After(200 * time.Millisecond): - t.Fatalf("request is not initiated") - } - - close(requester.quitC) - - select { - case <-requester.requestC: - case <-time.After(200 * time.Millisecond): - t.Fatalf("request is not initiated after failed request") - } -} - -// TestRequestSkipPeer checks if PeerSkip function will skip provided peer -// and not skip unknown one. -func TestRequestSkipPeer(t *testing.T) { - addr := make([]byte, 32) - peers := []enode.ID{ - enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8"), - enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9"), - } - - peersToSkip := new(sync.Map) - peersToSkip.Store(peers[0].String(), time.Now()) - r := NewRequest(addr, false, peersToSkip) - - if !r.SkipPeer(peers[0].String()) { - t.Errorf("peer not skipped") - } - - if r.SkipPeer(peers[1].String()) { - t.Errorf("peer skipped") - } -} - -// TestRequestSkipPeerExpired checks if a peer to skip is not skipped -// after RequestTimeout has passed. -func TestRequestSkipPeerExpired(t *testing.T) { - addr := make([]byte, 32) - peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") - - // set RequestTimeout to a low value and reset it after the test - defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) - RequestTimeout = 250 * time.Millisecond - - peersToSkip := new(sync.Map) - peersToSkip.Store(peer.String(), time.Now()) - r := NewRequest(addr, false, peersToSkip) - - if !r.SkipPeer(peer.String()) { - t.Errorf("peer not skipped") - } - - time.Sleep(500 * time.Millisecond) - - if r.SkipPeer(peer.String()) { - t.Errorf("peer skipped") - } -} - -// TestRequestSkipPeerPermanent checks if a peer to skip is not skipped -// after RequestTimeout is not skipped if it is set for a permanent skipping -// by value to peersToSkip map is not time.Duration. -func TestRequestSkipPeerPermanent(t *testing.T) { - addr := make([]byte, 32) - peer := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") - - // set RequestTimeout to a low value and reset it after the test - defer func(t time.Duration) { RequestTimeout = t }(RequestTimeout) - RequestTimeout = 250 * time.Millisecond - - peersToSkip := new(sync.Map) - peersToSkip.Store(peer.String(), true) - r := NewRequest(addr, false, peersToSkip) - - if !r.SkipPeer(peer.String()) { - t.Errorf("peer not skipped") - } - - time.Sleep(500 * time.Millisecond) - - if !r.SkipPeer(peer.String()) { - t.Errorf("peer not skipped") - } -} - -func TestFetcherMaxHopCount(t *testing.T) { - requester := newMockRequester() - addr := make([]byte, 32) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - fetcher := NewFetcher(ctx, addr, requester.doRequest, true) - - peersToSkip := &sync.Map{} - - go fetcher.run(peersToSkip) - - // if hopCount is already at max no request should be initiated - select { - case <-requester.requestC: - t.Fatalf("cancelled fetcher initiated request") - case <-time.After(200 * time.Millisecond): - } -} diff --git a/swarm/network/hive.go b/swarm/network/hive.go deleted file mode 100644 index ad51b29c2d..0000000000 --- a/swarm/network/hive.go +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/state" -) - -/* -Hive is the logistic manager of the swarm - -When the hive is started, a forever loop is launched that -asks the kademlia nodetable -to suggest peers to bootstrap connectivity -*/ - -// HiveParams holds the config options to hive -type HiveParams struct { - Discovery bool // if want discovery of not - PeersBroadcastSetSize uint8 // how many peers to use when relaying - MaxPeersPerRequest uint8 // max size for peer address batches - KeepAliveInterval time.Duration -} - -// NewHiveParams returns hive config with only the -func NewHiveParams() *HiveParams { - return &HiveParams{ - Discovery: true, - PeersBroadcastSetSize: 3, - MaxPeersPerRequest: 5, - KeepAliveInterval: 500 * time.Millisecond, - } -} - -// Hive manages network connections of the swarm node -type Hive struct { - *HiveParams // settings - *Kademlia // the overlay connectiviy driver - Store state.Store // storage interface to save peers across sessions - addPeer func(*enode.Node) // server callback to connect to a peer - // bookkeeping - lock sync.Mutex - peers map[enode.ID]*BzzPeer - ticker *time.Ticker -} - -// NewHive constructs a new hive -// HiveParams: config parameters -// Kademlia: connectivity driver using a network topology -// StateStore: to save peers across sessions -func NewHive(params *HiveParams, kad *Kademlia, store state.Store) *Hive { - return &Hive{ - HiveParams: params, - Kademlia: kad, - Store: store, - peers: make(map[enode.ID]*BzzPeer), - } -} - -// Start stars the hive, receives p2p.Server only at startup -// server is used to connect to a peer based on its NodeID or enode URL -// these are called on the p2p.Server which runs on the node -func (h *Hive) Start(server *p2p.Server) error { - log.Info("Starting hive", "baseaddr", fmt.Sprintf("%x", h.BaseAddr()[:4])) - // if state store is specified, load peers to prepopulate the overlay address book - if h.Store != nil { - log.Info("Detected an existing store. trying to load peers") - if err := h.loadPeers(); err != nil { - log.Error(fmt.Sprintf("%08x hive encoutered an error trying to load peers", h.BaseAddr()[:4])) - return err - } - } - // assigns the p2p.Server#AddPeer function to connect to peers - h.addPeer = server.AddPeer - // ticker to keep the hive alive - h.ticker = time.NewTicker(h.KeepAliveInterval) - // this loop is doing bootstrapping and maintains a healthy table - go h.connect() - return nil -} - -// Stop terminates the updateloop and saves the peers -func (h *Hive) Stop() error { - log.Info(fmt.Sprintf("%08x hive stopping, saving peers", h.BaseAddr()[:4])) - h.ticker.Stop() - if h.Store != nil { - if err := h.savePeers(); err != nil { - return fmt.Errorf("could not save peers to persistence store: %v", err) - } - if err := h.Store.Close(); err != nil { - return fmt.Errorf("could not close file handle to persistence store: %v", err) - } - } - log.Info(fmt.Sprintf("%08x hive stopped, dropping peers", h.BaseAddr()[:4])) - h.EachConn(nil, 255, func(p *Peer, _ int) bool { - log.Info(fmt.Sprintf("%08x dropping peer %08x", h.BaseAddr()[:4], p.Address()[:4])) - p.Drop() - return true - }) - - log.Info(fmt.Sprintf("%08x all peers dropped", h.BaseAddr()[:4])) - return nil -} - -// connect is a forever loop -// at each iteration, ask the overlay driver to suggest the most preferred peer to connect to -// as well as advertises saturation depth if needed -func (h *Hive) connect() { - for range h.ticker.C { - - addr, depth, changed := h.SuggestPeer() - if h.Discovery && changed { - NotifyDepth(uint8(depth), h.Kademlia) - } - if addr == nil { - continue - } - - log.Trace(fmt.Sprintf("%08x hive connect() suggested %08x", h.BaseAddr()[:4], addr.Address()[:4])) - under, err := enode.ParseV4(string(addr.Under())) - if err != nil { - log.Warn(fmt.Sprintf("%08x unable to connect to bee %08x: invalid node URL: %v", h.BaseAddr()[:4], addr.Address()[:4], err)) - continue - } - log.Trace(fmt.Sprintf("%08x attempt to connect to bee %08x", h.BaseAddr()[:4], addr.Address()[:4])) - h.addPeer(under) - } -} - -// Run protocol run function -func (h *Hive) Run(p *BzzPeer) error { - h.trackPeer(p) - defer h.untrackPeer(p) - - dp := NewPeer(p, h.Kademlia) - depth, changed := h.On(dp) - // if we want discovery, advertise change of depth - if h.Discovery { - if changed { - // if depth changed, send to all peers - NotifyDepth(depth, h.Kademlia) - } else { - // otherwise just send depth to new peer - dp.NotifyDepth(depth) - } - NotifyPeer(p.BzzAddr, h.Kademlia) - } - defer h.Off(dp) - return dp.Run(dp.HandleMsg) -} - -func (h *Hive) trackPeer(p *BzzPeer) { - h.lock.Lock() - h.peers[p.ID()] = p - h.lock.Unlock() -} - -func (h *Hive) untrackPeer(p *BzzPeer) { - h.lock.Lock() - delete(h.peers, p.ID()) - h.lock.Unlock() -} - -// NodeInfo function is used by the p2p.server RPC interface to display -// protocol specific node information -func (h *Hive) NodeInfo() interface{} { - return h.String() -} - -// PeerInfo function is used by the p2p.server RPC interface to display -// protocol specific information any connected peer referred to by their NodeID -func (h *Hive) PeerInfo(id enode.ID) interface{} { - p := h.Peer(id) - - if p == nil { - return nil - } - addr := NewAddr(p.Node()) - return struct { - OAddr hexutil.Bytes - UAddr hexutil.Bytes - }{ - OAddr: addr.OAddr, - UAddr: addr.UAddr, - } -} - -// Peer returns a bzz peer from the Hive. If there is no peer -// with the provided enode id, a nil value is returned. -func (h *Hive) Peer(id enode.ID) *BzzPeer { - h.lock.Lock() - defer h.lock.Unlock() - - return h.peers[id] -} - -// loadPeers, savePeer implement persistence callback/ -func (h *Hive) loadPeers() error { - var as []*BzzAddr - err := h.Store.Get("peers", &as) - if err != nil { - if err == state.ErrNotFound { - log.Info(fmt.Sprintf("hive %08x: no persisted peers found", h.BaseAddr()[:4])) - return nil - } - return err - } - log.Info(fmt.Sprintf("hive %08x: peers loaded", h.BaseAddr()[:4])) - - return h.Register(as...) -} - -// savePeers, savePeer implement persistence callback/ -func (h *Hive) savePeers() error { - var peers []*BzzAddr - h.Kademlia.EachAddr(nil, 256, func(pa *BzzAddr, i int) bool { - if pa == nil { - log.Warn(fmt.Sprintf("empty addr: %v", i)) - return true - } - log.Trace("saving peer", "peer", pa) - peers = append(peers, pa) - return true - }) - if err := h.Store.Put("peers", peers); err != nil { - return fmt.Errorf("could not save peers: %v", err) - } - return nil -} diff --git a/swarm/network/hive_test.go b/swarm/network/hive_test.go deleted file mode 100644 index 3e97322166..0000000000 --- a/swarm/network/hive_test.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "io/ioutil" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" - "github.com/ethereum/go-ethereum/swarm/state" -) - -func newHiveTester(params *HiveParams, n int, store state.Store) (*bzzTester, *Hive, error) { - // setup - prvkey, err := crypto.GenerateKey() - if err != nil { - return nil, nil, err - } - addr := PrivateKeyToBzzKey(prvkey) - to := NewKademlia(addr, NewKadParams()) - pp := NewHive(params, to, store) // hive - - bt, err := newBzzBaseTester(n, prvkey, DiscoverySpec, pp.Run) - if err != nil { - return nil, nil, err - } - return bt, pp, nil -} - -// TestRegisterAndConnect verifies that the protocol runs successfully -// and that the peer connection exists afterwards -func TestRegisterAndConnect(t *testing.T) { - params := NewHiveParams() - s, pp, err := newHiveTester(params, 1, nil) - if err != nil { - t.Fatal(err) - } - - node := s.Nodes[0] - raddr := NewAddr(node) - pp.Register(raddr) - - // start the hive - err = pp.Start(s.Server) - if err != nil { - t.Fatal(err) - } - defer pp.Stop() - - // both hive connect and disconect check have time delays - // therefore we need to verify that peer is connected - // so that we are sure that the disconnect timeout doesn't complete - // before the hive connect method is run at least once - timeout := time.After(time.Second) - for { - select { - case <-timeout: - t.Fatalf("expected connection") - default: - } - i := 0 - pp.Kademlia.EachConn(nil, 256, func(addr *Peer, po int) bool { - i++ - return true - }) - if i > 0 { - break - } - time.Sleep(time.Millisecond) - } - - // check that the connection actually exists - // the timeout error means no disconnection events - // were received within the a certain timeout - err = s.TestDisconnected(&p2ptest.Disconnect{ - Peer: s.Nodes[0].ID(), - Error: nil, - }) - - if err == nil || err.Error() != "timed out waiting for peers to disconnect" { - t.Fatalf("expected no disconnection event") - } -} - -// TestHiveStatePersistance creates a protocol simulation with n peers for a node -// After protocols complete, the node is shut down and the state is stored. -// Another simulation is created, where 0 nodes are created, but where the stored state is passed -// The test succeeds if all the peers from the stored state are known after the protocols of the -// second simulation have completed -// -// Actual connectivity is not in scope for this test, as the peers loaded from state are not known to -// the simulation; the test only verifies that the peers are known to the node -func TestHiveStatePersistance(t *testing.T) { - dir, err := ioutil.TempDir("", "hive_test_store") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - const peersCount = 5 - - startHive := func(t *testing.T, dir string) (h *Hive, cleanupFunc func()) { - store, err := state.NewDBStore(dir) - if err != nil { - t.Fatal(err) - } - - params := NewHiveParams() - params.Discovery = false - - prvkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - h = NewHive(params, NewKademlia(PrivateKeyToBzzKey(prvkey), NewKadParams()), store) - s := p2ptest.NewProtocolTester(prvkey, 0, func(p *p2p.Peer, rw p2p.MsgReadWriter) error { return nil }) - - if err := h.Start(s.Server); err != nil { - t.Fatal(err) - } - - cleanupFunc = func() { - err := h.Stop() - if err != nil { - t.Fatal(err) - } - - s.Stop() - } - return h, cleanupFunc - } - - h1, cleanup1 := startHive(t, dir) - peers := make(map[string]bool) - for i := 0; i < peersCount; i++ { - raddr := RandomAddr() - h1.Register(raddr) - peers[raddr.String()] = true - } - cleanup1() - - // start the hive and check that we know of all expected peers - h2, cleanup2 := startHive(t, dir) - cleanup2() - - i := 0 - h2.Kademlia.EachAddr(nil, 256, func(addr *BzzAddr, po int) bool { - delete(peers, addr.String()) - i++ - return true - }) - if i != peersCount { - t.Fatalf("invalid number of entries: got %v, want %v", i, peersCount) - } - if len(peers) != 0 { - t.Fatalf("%d peers left over: %v", len(peers), peers) - } -} diff --git a/swarm/network/kademlia.go b/swarm/network/kademlia.go deleted file mode 100644 index 90491ab312..0000000000 --- a/swarm/network/kademlia.go +++ /dev/null @@ -1,911 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "bytes" - "fmt" - "math/rand" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/pot" - sv "github.com/ethereum/go-ethereum/swarm/version" -) - -/* - -Taking the proximity order relative to a fix point x classifies the points in -the space (n byte long byte sequences) into bins. Items in each are at -most half as distant from x as items in the previous bin. Given a sample of -uniformly distributed items (a hash function over arbitrary sequence) the -proximity scale maps onto series of subsets with cardinalities on a negative -exponential scale. - -It also has the property that any two item belonging to the same bin are at -most half as distant from each other as they are from x. - -If we think of random sample of items in the bins as connections in a network of -interconnected nodes then relative proximity can serve as the basis for local -decisions for graph traversal where the task is to find a route between two -points. Since in every hop, the finite distance halves, there is -a guaranteed constant maximum limit on the number of hops needed to reach one -node from the other. -*/ - -var Pof = pot.DefaultPof(256) - -// KadParams holds the config params for Kademlia -type KadParams struct { - // adjustable parameters - MaxProxDisplay int // number of rows the table shows - NeighbourhoodSize int // nearest neighbour core minimum cardinality - MinBinSize int // minimum number of peers in a row - MaxBinSize int // maximum number of peers in a row before pruning - RetryInterval int64 // initial interval before a peer is first redialed - RetryExponent int // exponent to multiply retry intervals with - MaxRetries int // maximum number of redial attempts - // function to sanction or prevent suggesting a peer - Reachable func(*BzzAddr) bool `json:"-"` -} - -// NewKadParams returns a params struct with default values -func NewKadParams() *KadParams { - return &KadParams{ - MaxProxDisplay: 16, - NeighbourhoodSize: 2, - MinBinSize: 2, - MaxBinSize: 4, - RetryInterval: 4200000000, // 4.2 sec - MaxRetries: 42, - RetryExponent: 2, - } -} - -// Kademlia is a table of live peers and a db of known peers (node records) -type Kademlia struct { - lock sync.RWMutex - *KadParams // Kademlia configuration parameters - base []byte // immutable baseaddress of the table - addrs *pot.Pot // pots container for known peer addresses - conns *pot.Pot // pots container for live peer connections - depth uint8 // stores the last current depth of saturation - nDepth int // stores the last neighbourhood depth - nDepthMu sync.RWMutex // protects neighbourhood depth nDepth - nDepthSig []chan struct{} // signals when neighbourhood depth nDepth is changed -} - -// NewKademlia creates a Kademlia table for base address addr -// with parameters as in params -// if params is nil, it uses default values -func NewKademlia(addr []byte, params *KadParams) *Kademlia { - if params == nil { - params = NewKadParams() - } - return &Kademlia{ - base: addr, - KadParams: params, - addrs: pot.NewPot(nil, 0), - conns: pot.NewPot(nil, 0), - } -} - -// entry represents a Kademlia table entry (an extension of BzzAddr) -type entry struct { - *BzzAddr - conn *Peer - seenAt time.Time - retries int -} - -// newEntry creates a kademlia peer from a *Peer -func newEntry(p *BzzAddr) *entry { - return &entry{ - BzzAddr: p, - seenAt: time.Now(), - } -} - -// Label is a short tag for the entry for debug -func Label(e *entry) string { - return fmt.Sprintf("%s (%d)", e.Hex()[:4], e.retries) -} - -// Hex is the hexadecimal serialisation of the entry address -func (e *entry) Hex() string { - return fmt.Sprintf("%x", e.Address()) -} - -// Register enters each address as kademlia peer record into the -// database of known peer addresses -func (k *Kademlia) Register(peers ...*BzzAddr) error { - k.lock.Lock() - defer k.lock.Unlock() - - metrics.GetOrRegisterCounter("kad.register", nil).Inc(1) - - var known, size int - for _, p := range peers { - log.Trace("kademlia trying to register", "addr", p) - // error if self received, peer should know better - // and should be punished for this - if bytes.Equal(p.Address(), k.base) { - return fmt.Errorf("add peers: %x is self", k.base) - } - var found bool - k.addrs, _, found, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { - // if not found - if v == nil { - log.Trace("registering new peer", "addr", p) - // insert new offline peer into conns - return newEntry(p) - } - - e := v.(*entry) - - // if underlay address is different, still add - if !bytes.Equal(e.BzzAddr.UAddr, p.UAddr) { - log.Trace("underlay addr is different, so add again", "new", p, "old", e.BzzAddr) - // insert new offline peer into conns - return newEntry(p) - } - - return v - }) - if found { - known++ - } - size++ - } - - k.setNeighbourhoodDepth() - return nil -} - -// SuggestPeer returns an unconnected peer address as a peer suggestion for connection -func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, changed bool) { - k.lock.Lock() - defer k.lock.Unlock() - - metrics.GetOrRegisterCounter("kad.suggestpeer", nil).Inc(1) - - radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) - // collect undersaturated bins in ascending order of number of connected peers - // and from shallow to deep (ascending order of PO) - // insert them in a map of bin arrays, keyed with the number of connected peers - saturation := make(map[int][]int) - var lastPO int // the last non-empty PO bin in the iteration - saturationDepth = -1 // the deepest PO such that all shallower bins have >= k.MinBinSize peers - var pastDepth bool // whether po of iteration >= depth - k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { - // process skipped empty bins - for ; lastPO < po; lastPO++ { - // find the lowest unsaturated bin - if saturationDepth == -1 { - saturationDepth = lastPO - } - // if there is an empty bin, depth is surely passed - pastDepth = true - saturation[0] = append(saturation[0], lastPO) - } - lastPO = po + 1 - // past radius, depth is surely passed - if po >= radius { - pastDepth = true - } - // beyond depth the bin is treated as unsaturated even if size >= k.MinBinSize - // in order to achieve full connectivity to all neighbours - if pastDepth && size >= k.MinBinSize { - size = k.MinBinSize - 1 - } - // process non-empty unsaturated bins - if size < k.MinBinSize { - // find the lowest unsaturated bin - if saturationDepth == -1 { - saturationDepth = po - } - saturation[size] = append(saturation[size], po) - } - return true - }) - // to trigger peer requests for peers closer than closest connection, include - // all bins from nearest connection upto nearest address as unsaturated - var nearestAddrAt int - k.addrs.EachNeighbour(k.base, Pof, func(_ pot.Val, po int) bool { - nearestAddrAt = po - return false - }) - // including bins as size 0 has the effect that requesting connection - // is prioritised over non-empty shallower bins - for ; lastPO <= nearestAddrAt; lastPO++ { - saturation[0] = append(saturation[0], lastPO) - } - // all PO bins are saturated, ie., minsize >= k.MinBinSize, no peer suggested - if len(saturation) == 0 { - return nil, 0, false - } - // find the first callable peer in the address book - // starting from the bins with smallest size proceeding from shallow to deep - // for each bin (up until neighbourhood radius) we find callable candidate peers - for size := 0; size < k.MinBinSize && suggestedPeer == nil; size++ { - bins, ok := saturation[size] - if !ok { - // no bin with this size - continue - } - cur := 0 - curPO := bins[0] - k.addrs.EachBin(k.base, Pof, curPO, func(po, _ int, f func(func(pot.Val) bool) bool) bool { - curPO = bins[cur] - // find the next bin that has size size - if curPO == po { - cur++ - } else { - // skip bins that have no addresses - for ; cur < len(bins) && curPO < po; cur++ { - curPO = bins[cur] - } - if po < curPO { - cur-- - return true - } - // stop if there are no addresses - if curPO < po { - return false - } - } - // curPO found - // find a callable peer out of the addresses in the unsaturated bin - // stop if found - f(func(val pot.Val) bool { - e := val.(*entry) - if k.callable(e) { - suggestedPeer = e.BzzAddr - return false - } - return true - }) - return cur < len(bins) && suggestedPeer == nil - }) - } - - if uint8(saturationDepth) < k.depth { - k.depth = uint8(saturationDepth) - return suggestedPeer, saturationDepth, true - } - return suggestedPeer, 0, false -} - -// On inserts the peer as a kademlia peer into the live peers -func (k *Kademlia) On(p *Peer) (uint8, bool) { - k.lock.Lock() - defer k.lock.Unlock() - - metrics.GetOrRegisterCounter("kad.on", nil).Inc(1) - - var ins bool - k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(v pot.Val) pot.Val { - // if not found live - if v == nil { - ins = true - // insert new online peer into conns - return p - } - // found among live peers, do nothing - return v - }) - if ins && !p.BzzPeer.LightNode { - a := newEntry(p.BzzAddr) - a.conn = p - // insert new online peer into addrs - k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { - return a - }) - } - // calculate if depth of saturation changed - depth := uint8(k.saturation()) - var changed bool - if depth != k.depth { - changed = true - k.depth = depth - } - k.setNeighbourhoodDepth() - return k.depth, changed -} - -// setNeighbourhoodDepth calculates neighbourhood depth with depthForPot, -// sets it to the nDepth and sends a signal to every nDepthSig channel. -func (k *Kademlia) setNeighbourhoodDepth() { - nDepth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) - var changed bool - k.nDepthMu.Lock() - if nDepth != k.nDepth { - k.nDepth = nDepth - changed = true - } - k.nDepthMu.Unlock() - - if len(k.nDepthSig) > 0 && changed { - for _, c := range k.nDepthSig { - // Every nDepthSig channel has a buffer capacity of 1, - // so every receiver will get the signal even if the - // select statement has the default case to avoid blocking. - select { - case c <- struct{}{}: - default: - } - } - } -} - -// NeighbourhoodDepth returns the value calculated by depthForPot function -// in setNeighbourhoodDepth method. -func (k *Kademlia) NeighbourhoodDepth() int { - k.nDepthMu.RLock() - defer k.nDepthMu.RUnlock() - return k.nDepth -} - -// SubscribeToNeighbourhoodDepthChange returns the channel that signals -// when neighbourhood depth value is changed. The current neighbourhood depth -// is returned by NeighbourhoodDepth method. Returned function unsubscribes -// the channel from signaling and releases the resources. Returned function is safe -// to be called multiple times. -func (k *Kademlia) SubscribeToNeighbourhoodDepthChange() (c <-chan struct{}, unsubscribe func()) { - channel := make(chan struct{}, 1) - var closeOnce sync.Once - - k.lock.Lock() - defer k.lock.Unlock() - - k.nDepthSig = append(k.nDepthSig, channel) - - unsubscribe = func() { - k.lock.Lock() - defer k.lock.Unlock() - - for i, c := range k.nDepthSig { - if c == channel { - k.nDepthSig = append(k.nDepthSig[:i], k.nDepthSig[i+1:]...) - break - } - } - - closeOnce.Do(func() { close(channel) }) - } - - return channel, unsubscribe -} - -// Off removes a peer from among live peers -func (k *Kademlia) Off(p *Peer) { - k.lock.Lock() - defer k.lock.Unlock() - var del bool - if !p.BzzPeer.LightNode { - k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val { - // v cannot be nil, must check otherwise we overwrite entry - if v == nil { - panic(fmt.Sprintf("connected peer not found %v", p)) - } - del = true - return newEntry(p.BzzAddr) - }) - } else { - del = true - } - - if del { - k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val { - // v cannot be nil, but no need to check - return nil - }) - k.setNeighbourhoodDepth() - } -} - -func (k *Kademlia) ListKnown() []*BzzAddr { - res := []*BzzAddr{} - - k.addrs.Each(func(val pot.Val) bool { - e := val.(*entry) - res = append(res, e.BzzAddr) - return true - }) - - return res -} - -// EachConn is an iterator with args (base, po, f) applies f to each live peer -// that has proximity order po or less as measured from the base -// if base is nil, kademlia base address is used -func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int) bool) { - k.lock.RLock() - defer k.lock.RUnlock() - k.eachConn(base, o, f) -} - -func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int) bool) { - if len(base) == 0 { - base = k.base - } - k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { - if po > o { - return true - } - return f(val.(*Peer), po) - }) -} - -// EachAddr called with (base, po, f) is an iterator applying f to each known peer -// that has proximity order o or less as measured from the base -// if base is nil, kademlia base address is used -func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { - k.lock.RLock() - defer k.lock.RUnlock() - k.eachAddr(base, o, f) -} - -func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int) bool) { - if len(base) == 0 { - base = k.base - } - k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool { - if po > o { - return true - } - return f(val.(*entry).BzzAddr, po) - }) -} - -// neighbourhoodRadiusForPot returns the neighbourhood radius of the kademlia -// neighbourhood radius encloses the nearest neighbour set with size >= neighbourhoodSize -// i.e., neighbourhood radius is the deepest PO such that all bins not shallower altogether -// contain at least neighbourhoodSize connected peers -// if there is altogether less than neighbourhoodSize peers connected, it returns 0 -// caller must hold the lock -func neighbourhoodRadiusForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { - if p.Size() <= neighbourhoodSize { - return 0 - } - // total number of peers in iteration - var size int - f := func(v pot.Val, i int) bool { - // po == 256 means that addr is the pivot address(self) - if i == 256 { - return true - } - size++ - - // this means we have all nn-peers. - // depth is by default set to the bin of the farthest nn-peer - if size == neighbourhoodSize { - depth = i - return false - } - - return true - } - p.EachNeighbour(pivotAddr, Pof, f) - return depth -} - -// depthForPot returns the depth for the pot -// depth is the radius of the minimal extension of nearest neighbourhood that -// includes all empty PO bins. I.e., depth is the deepest PO such that -// - it is not deeper than neighbourhood radius -// - all bins shallower than depth are not empty -// caller must hold the lock -func depthForPot(p *pot.Pot, neighbourhoodSize int, pivotAddr []byte) (depth int) { - if p.Size() <= neighbourhoodSize { - return 0 - } - // determining the depth is a two-step process - // first we find the proximity bin of the shallowest of the neighbourhoodSize peers - // the numeric value of depth cannot be higher than this - maxDepth := neighbourhoodRadiusForPot(p, neighbourhoodSize, pivotAddr) - - // the second step is to test for empty bins in order from shallowest to deepest - // if an empty bin is found, this will be the actual depth - // we stop iterating if we hit the maxDepth determined in the first step - p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val) bool) bool) bool { - if po == depth { - if maxDepth == depth { - return false - } - depth++ - return true - } - return false - }) - - return depth -} - -// callable decides if an address entry represents a callable peer -func (k *Kademlia) callable(e *entry) bool { - // not callable if peer is live or exceeded maxRetries - if e.conn != nil || e.retries > k.MaxRetries { - return false - } - // calculate the allowed number of retries based on time lapsed since last seen - timeAgo := int64(time.Since(e.seenAt)) - div := int64(k.RetryExponent) - div += (150000 - rand.Int63n(300000)) * div / 1000000 - var retries int - for delta := timeAgo; delta > k.RetryInterval; delta /= div { - retries++ - } - // this is never called concurrently, so safe to increment - // peer can be retried again - if retries < e.retries { - log.Trace(fmt.Sprintf("%08x: %v long time since last try (at %v) needed before retry %v, wait only warrants %v", k.BaseAddr()[:4], e, timeAgo, e.retries, retries)) - return false - } - // function to sanction or prevent suggesting a peer - if k.Reachable != nil && !k.Reachable(e.BzzAddr) { - log.Trace(fmt.Sprintf("%08x: peer %v is temporarily not callable", k.BaseAddr()[:4], e)) - return false - } - e.retries++ - log.Trace(fmt.Sprintf("%08x: peer %v is callable", k.BaseAddr()[:4], e)) - - return true -} - -// BaseAddr return the kademlia base address -func (k *Kademlia) BaseAddr() []byte { - return k.base -} - -// String returns kademlia table + kaddb table displayed with ascii -func (k *Kademlia) String() string { - k.lock.RLock() - defer k.lock.RUnlock() - return k.string() -} - -// string returns kademlia table + kaddb table displayed with ascii -// caller must hold the lock -func (k *Kademlia) string() string { - wsrow := " " - var rows []string - - rows = append(rows, "=========================================================================") - if len(sv.GitCommit) > 0 { - rows = append(rows, fmt.Sprintf("commit hash: %s", sv.GitCommit)) - } - rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %x", time.Now().UTC().Format(time.UnixDate), k.BaseAddr())) - rows = append(rows, fmt.Sprintf("population: %d (%d), NeighbourhoodSize: %d, MinBinSize: %d, MaxBinSize: %d", k.conns.Size(), k.addrs.Size(), k.NeighbourhoodSize, k.MinBinSize, k.MaxBinSize)) - - liverows := make([]string, k.MaxProxDisplay) - peersrows := make([]string, k.MaxProxDisplay) - - depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) - rest := k.conns.Size() - k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { - var rowlen int - if po >= k.MaxProxDisplay { - po = k.MaxProxDisplay - 1 - } - row := []string{fmt.Sprintf("%2d", size)} - rest -= size - f(func(val pot.Val) bool { - e := val.(*Peer) - row = append(row, fmt.Sprintf("%x", e.Address()[:2])) - rowlen++ - return rowlen < 4 - }) - r := strings.Join(row, " ") - r = r + wsrow - liverows[po] = r[:31] - return true - }) - - k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { - var rowlen int - if po >= k.MaxProxDisplay { - po = k.MaxProxDisplay - 1 - } - if size < 0 { - panic("wtf") - } - row := []string{fmt.Sprintf("%2d", size)} - // we are displaying live peers too - f(func(val pot.Val) bool { - e := val.(*entry) - row = append(row, Label(e)) - rowlen++ - return rowlen < 4 - }) - peersrows[po] = strings.Join(row, " ") - return true - }) - - for i := 0; i < k.MaxProxDisplay; i++ { - if i == depth { - rows = append(rows, fmt.Sprintf("============ DEPTH: %d ==========================================", i)) - } - left := liverows[i] - right := peersrows[i] - if len(left) == 0 { - left = " 0 " - } - if len(right) == 0 { - right = " 0" - } - rows = append(rows, fmt.Sprintf("%03d %v | %v", i, left, right)) - } - rows = append(rows, "=========================================================================") - return "\n" + strings.Join(rows, "\n") -} - -// PeerPot keeps info about expected nearest neighbours -// used for testing only -// TODO move to separate testing tools file -type PeerPot struct { - NNSet [][]byte - PeersPerBin []int -} - -// NewPeerPotMap creates a map of pot record of *BzzAddr with keys -// as hexadecimal representations of the address. -// the NeighbourhoodSize of the passed kademlia is used -// used for testing only -// TODO move to separate testing tools file -func NewPeerPotMap(neighbourhoodSize int, addrs [][]byte) map[string]*PeerPot { - - // create a table of all nodes for health check - np := pot.NewPot(nil, 0) - for _, addr := range addrs { - np, _, _ = pot.Add(np, addr, Pof) - } - ppmap := make(map[string]*PeerPot) - - // generate an allknowing source of truth for connections - // for every kademlia passed - for i, a := range addrs { - - // actual kademlia depth - depth := depthForPot(np, neighbourhoodSize, a) - - // all nn-peers - var nns [][]byte - peersPerBin := make([]int, depth) - - // iterate through the neighbours, going from the deepest to the shallowest - np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool { - addr := val.([]byte) - // po == 256 means that addr is the pivot address(self) - // we do not include self in the map - if po == 256 { - return true - } - // append any neighbors found - // a neighbor is any peer in or deeper than the depth - if po >= depth { - nns = append(nns, addr) - } else { - // for peers < depth, we just count the number in each bin - // the bin is the index of the slice - peersPerBin[po]++ - } - return true - }) - - log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s, peersPerBin", addrs[i][:4], LogAddrs(nns))) - ppmap[common.Bytes2Hex(a)] = &PeerPot{ - NNSet: nns, - PeersPerBin: peersPerBin, - } - } - return ppmap -} - -// Saturation returns the smallest po value in which the node has less than MinBinSize peers -// if the iterator reaches neighbourhood radius, then the last bin + 1 is returned -func (k *Kademlia) Saturation() int { - k.lock.RLock() - defer k.lock.RUnlock() - - return k.saturation() -} - -func (k *Kademlia) saturation() int { - prev := -1 - radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) - k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { - prev++ - if po >= radius { - return false - } - return prev == po && size >= k.MinBinSize - }) - if prev < 0 { - return 0 - } - return prev -} - -// isSaturated returns true if the kademlia is considered saturated, or false if not. -// It checks this by checking an array of ints called unsaturatedBins; each item in that array corresponds -// to the bin which is unsaturated (number of connections < k.MinBinSize). -// The bin is considered unsaturated only if there are actual peers in that PeerPot's bin (peersPerBin) -// (if there is no peer for a given bin, then no connection could ever be established; -// in a God's view this is relevant as no more peers will ever appear on that bin) -func (k *Kademlia) isSaturated(peersPerBin []int, depth int) bool { - // depth could be calculated from k but as this is called from `GetHealthInfo()`, - // the depth has already been calculated so we can require it as a parameter - - // early check for depth - if depth != len(peersPerBin) { - return false - } - unsaturatedBins := make([]int, 0) - k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { - - if po >= depth { - return false - } - log.Trace("peers per bin", "peersPerBin[po]", peersPerBin[po], "po", po) - // if there are actually peers in the PeerPot who can fulfill k.MinBinSize - if size < k.MinBinSize && size < peersPerBin[po] { - log.Trace("connections for po", "po", po, "size", size) - unsaturatedBins = append(unsaturatedBins, po) - } - return true - }) - - log.Trace("list of unsaturated bins", "unsaturatedBins", unsaturatedBins) - return len(unsaturatedBins) == 0 -} - -// knowNeighbours tests if all neighbours in the peerpot -// are found among the peers known to the kademlia -// It is used in Healthy function for testing only -// TODO move to separate testing tools file -func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) { - pm := make(map[string]bool) - depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) - // create a map with all peers at depth and deeper known in the kademlia - k.eachAddr(nil, 255, func(p *BzzAddr, po int) bool { - // in order deepest to shallowest compared to the kademlia base address - // all bins (except self) are included (0 <= bin <= 255) - if po < depth { - return false - } - pk := common.Bytes2Hex(p.Address()) - pm[pk] = true - return true - }) - - // iterate through nearest neighbors in the peerpot map - // if we can't find the neighbor in the map we created above - // then we don't know all our neighbors - // (which sadly is all too common in modern society) - var gots int - var culprits [][]byte - for _, p := range addrs { - pk := common.Bytes2Hex(p) - if pm[pk] { - gots++ - } else { - log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk)) - culprits = append(culprits, p) - } - } - return gots == len(addrs), gots, culprits -} - -// connectedNeighbours tests if all neighbours in the peerpot -// are currently connected in the kademlia -// It is used in Healthy function for testing only -func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { - pm := make(map[string]bool) - - // create a map with all peers at depth and deeper that are connected in the kademlia - // in order deepest to shallowest compared to the kademlia base address - // all bins (except self) are included (0 <= bin <= 255) - depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) - k.eachConn(nil, 255, func(p *Peer, po int) bool { - if po < depth { - return false - } - pk := common.Bytes2Hex(p.Address()) - pm[pk] = true - return true - }) - - // iterate through nearest neighbors in the peerpot map - // if we can't find the neighbor in the map we created above - // then we don't know all our neighbors - var gots int - var culprits [][]byte - for _, p := range peers { - pk := common.Bytes2Hex(p) - if pm[pk] { - gots++ - } else { - log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk)) - culprits = append(culprits, p) - } - } - return gots == len(peers), gots, culprits -} - -// Health state of the Kademlia -// used for testing only -type Health struct { - KnowNN bool // whether node knows all its neighbours - CountKnowNN int // amount of neighbors known - MissingKnowNN [][]byte // which neighbours we should have known but we don't - ConnectNN bool // whether node is connected to all its neighbours - CountConnectNN int // amount of neighbours connected to - MissingConnectNN [][]byte // which neighbours we should have been connected to but we're not - // Saturated: if in all bins < depth number of connections >= MinBinsize or, - // if number of connections < MinBinSize, to the number of available peers in that bin - Saturated bool - Hive string -} - -// GetHealthInfo reports the health state of the kademlia connectivity -// -// The PeerPot argument provides an all-knowing view of the network -// The resulting Health object is a result of comparisons between -// what is the actual composition of the kademlia in question (the receiver), and -// what SHOULD it have been when we take all we know about the network into consideration. -// -// used for testing only -func (k *Kademlia) GetHealthInfo(pp *PeerPot) *Health { - k.lock.RLock() - defer k.lock.RUnlock() - if len(pp.NNSet) < k.NeighbourhoodSize { - log.Warn("peerpot NNSet < NeighbourhoodSize") - } - gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet) - knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet) - depth := depthForPot(k.conns, k.NeighbourhoodSize, k.base) - - // check saturation - saturated := k.isSaturated(pp.PeersPerBin, depth) - - log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated)) - return &Health{ - KnowNN: knownn, - CountKnowNN: countknownn, - MissingKnowNN: culpritsknownn, - ConnectNN: gotnn, - CountConnectNN: countgotnn, - MissingConnectNN: culpritsgotnn, - Saturated: saturated, - Hive: k.string(), - } -} - -// Healthy return the strict interpretation of `Healthy` given a `Health` struct -// definition of strict health: all conditions must be true: -// - we at least know one peer -// - we know all neighbors -// - we are connected to all known neighbors -// - it is saturated -func (h *Health) Healthy() bool { - return h.KnowNN && h.ConnectNN && h.CountKnowNN > 0 && h.Saturated -} diff --git a/swarm/network/kademlia_test.go b/swarm/network/kademlia_test.go deleted file mode 100644 index 035879cd3b..0000000000 --- a/swarm/network/kademlia_test.go +++ /dev/null @@ -1,672 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "fmt" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/swarm/pot" -) - -func init() { - h := log.LvlFilterHandler(log.LvlWarn, log.StreamHandler(os.Stderr, log.TerminalFormat(true))) - log.Root().SetHandler(h) -} - -func testKadPeerAddr(s string) *BzzAddr { - a := pot.NewAddressFromString(s) - return &BzzAddr{OAddr: a, UAddr: a} -} - -func newTestKademliaParams() *KadParams { - params := NewKadParams() - params.MinBinSize = 2 - params.NeighbourhoodSize = 2 - return params -} - -type testKademlia struct { - *Kademlia - t *testing.T -} - -func newTestKademlia(t *testing.T, b string) *testKademlia { - base := pot.NewAddressFromString(b) - return &testKademlia{ - Kademlia: NewKademlia(base, newTestKademliaParams()), - t: t, - } -} - -func (tk *testKademlia) newTestKadPeer(s string, lightNode bool) *Peer { - return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, tk.Kademlia) -} - -func (tk *testKademlia) On(ons ...string) { - for _, s := range ons { - tk.Kademlia.On(tk.newTestKadPeer(s, false)) - } -} - -func (tk *testKademlia) Off(offs ...string) { - for _, s := range offs { - tk.Kademlia.Off(tk.newTestKadPeer(s, false)) - } -} - -func (tk *testKademlia) Register(regs ...string) { - var as []*BzzAddr - for _, s := range regs { - as = append(as, testKadPeerAddr(s)) - } - err := tk.Kademlia.Register(as...) - if err != nil { - panic(err.Error()) - } -} - -// tests the validity of neighborhood depth calculations -// -// in particular, it tests that if there are one or more consecutive -// empty bins above the farthest "nearest neighbor-peer" then -// the depth should be set at the farthest of those empty bins -// -// TODO: Make test adapt to change in NeighbourhoodSize -func TestNeighbourhoodDepth(t *testing.T) { - baseAddressBytes := RandomAddr().OAddr - kad := NewKademlia(baseAddressBytes, NewKadParams()) - - baseAddress := pot.NewAddressFromBytes(baseAddressBytes) - - // generate the peers - var peers []*Peer - for i := 0; i < 7; i++ { - addr := pot.RandomAddressAt(baseAddress, i) - peers = append(peers, newTestDiscoveryPeer(addr, kad)) - } - var sevenPeers []*Peer - for i := 0; i < 2; i++ { - addr := pot.RandomAddressAt(baseAddress, 7) - sevenPeers = append(sevenPeers, newTestDiscoveryPeer(addr, kad)) - } - - testNum := 0 - // first try with empty kademlia - depth := kad.NeighbourhoodDepth() - if depth != 0 { - t.Fatalf("%d expected depth 0, was %d", testNum, depth) - } - testNum++ - - // add one peer on 7 - kad.On(sevenPeers[0]) - depth = kad.NeighbourhoodDepth() - if depth != 0 { - t.Fatalf("%d expected depth 0, was %d", testNum, depth) - } - testNum++ - - // add a second on 7 - kad.On(sevenPeers[1]) - depth = kad.NeighbourhoodDepth() - if depth != 0 { - t.Fatalf("%d expected depth 0, was %d", testNum, depth) - } - testNum++ - - // add from 0 to 6 - for i, p := range peers { - kad.On(p) - depth = kad.NeighbourhoodDepth() - if depth != i+1 { - t.Fatalf("%d.%d expected depth %d, was %d", i+1, testNum, i, depth) - } - } - testNum++ - - kad.Off(sevenPeers[1]) - depth = kad.NeighbourhoodDepth() - if depth != 6 { - t.Fatalf("%d expected depth 6, was %d", testNum, depth) - } - testNum++ - - kad.Off(peers[4]) - depth = kad.NeighbourhoodDepth() - if depth != 4 { - t.Fatalf("%d expected depth 4, was %d", testNum, depth) - } - testNum++ - - kad.Off(peers[3]) - depth = kad.NeighbourhoodDepth() - if depth != 3 { - t.Fatalf("%d expected depth 3, was %d", testNum, depth) - } - testNum++ -} - -// TestHighMinBinSize tests that the saturation function also works -// if MinBinSize is > 2, the connection count is < k.MinBinSize -// and there are more peers available than connected -func TestHighMinBinSize(t *testing.T) { - // a function to test for different MinBinSize values - testKad := func(minBinSize int) { - // create a test kademlia - tk := newTestKademlia(t, "11111111") - // set its MinBinSize to desired value - tk.KadParams.MinBinSize = minBinSize - - // add a couple of peers (so we have NN and depth) - tk.On("00000000") // bin 0 - tk.On("11100000") // bin 3 - tk.On("11110000") // bin 4 - - first := "10000000" // add a first peer at bin 1 - tk.Register(first) // register it - // we now have one registered peer at bin 1; - // iterate and connect one peer at each iteration; - // should be unhealthy until at minBinSize - 1 - // we connect the unconnected but registered peer - for i := 1; i < minBinSize; i++ { - peer := fmt.Sprintf("1000%b", 8|i) - tk.On(peer) - if i == minBinSize-1 { - tk.On(first) - tk.checkHealth(true) - return - } - tk.checkHealth(false) - } - } - // test MinBinSizes of 3 to 5 - testMinBinSizes := []int{3, 4, 5} - for _, k := range testMinBinSizes { - testKad(k) - } -} - -// TestHealthStrict tests the simplest definition of health -// Which means whether we are connected to all neighbors we know of -func TestHealthStrict(t *testing.T) { - - // base address is all zeros - // no peers - // unhealthy (and lonely) - tk := newTestKademlia(t, "11111111") - tk.checkHealth(false) - - // know one peer but not connected - // unhealthy - tk.Register("11100000") - tk.checkHealth(false) - - // know one peer and connected - // unhealthy: not saturated - tk.On("11100000") - tk.checkHealth(true) - - // know two peers, only one connected - // unhealthy - tk.Register("11111100") - tk.checkHealth(false) - - // know two peers and connected to both - // healthy - tk.On("11111100") - tk.checkHealth(true) - - // know three peers, connected to the two deepest - // healthy - tk.Register("00000000") - tk.checkHealth(false) - - // know three peers, connected to all three - // healthy - tk.On("00000000") - tk.checkHealth(true) - - // add fourth peer deeper than current depth - // unhealthy - tk.Register("11110000") - tk.checkHealth(false) - - // connected to three deepest peers - // healthy - tk.On("11110000") - tk.checkHealth(true) - - // add additional peer in same bin as deepest peer - // unhealthy - tk.Register("11111101") - tk.checkHealth(false) - - // four deepest of five peers connected - // healthy - tk.On("11111101") - tk.checkHealth(true) - - // add additional peer in bin 0 - // unhealthy: unsaturated bin 0, 2 known but 1 connected - tk.Register("00000001") - tk.checkHealth(false) - - // Connect second in bin 0 - // healthy - tk.On("00000001") - tk.checkHealth(true) - - // add peer in bin 1 - // unhealthy, as it is known but not connected - tk.Register("10000000") - tk.checkHealth(false) - - // connect peer in bin 1 - // depth change, is now 1 - // healthy, 1 peer in bin 1 known and connected - tk.On("10000000") - tk.checkHealth(true) - - // add second peer in bin 1 - // unhealthy, as it is known but not connected - tk.Register("10000001") - tk.checkHealth(false) - - // connect second peer in bin 1 - // healthy, - tk.On("10000001") - tk.checkHealth(true) - - // connect third peer in bin 1 - // healthy, - tk.On("10000011") - tk.checkHealth(true) - - // add peer in bin 2 - // unhealthy, no depth change - tk.Register("11000000") - tk.checkHealth(false) - - // connect peer in bin 2 - // depth change - as we already have peers in bin 3 and 4, - // we have contiguous bins, no bin < po 5 is empty -> depth 5 - // healthy, every bin < depth has the max available peers, - // even if they are < MinBinSize - tk.On("11000000") - tk.checkHealth(true) - - // add peer in bin 2 - // unhealthy, peer bin is below depth 5 but - // has more available peers (2) than connected ones (1) - // --> unsaturated - tk.Register("11000011") - tk.checkHealth(false) -} - -func (tk *testKademlia) checkHealth(expectHealthy bool) { - tk.t.Helper() - kid := common.Bytes2Hex(tk.BaseAddr()) - addrs := [][]byte{tk.BaseAddr()} - tk.EachAddr(nil, 255, func(addr *BzzAddr, po int) bool { - addrs = append(addrs, addr.Address()) - return true - }) - - pp := NewPeerPotMap(tk.NeighbourhoodSize, addrs) - healthParams := tk.GetHealthInfo(pp[kid]) - - // definition of health, all conditions but be true: - // - we at least know one peer - // - we know all neighbors - // - we are connected to all known neighbors - health := healthParams.Healthy() - if expectHealthy != health { - tk.t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, tk.String()) - } -} - -func (tk *testKademlia) checkSuggestPeer(expAddr string, expDepth int, expChanged bool) { - tk.t.Helper() - addr, depth, changed := tk.SuggestPeer() - log.Trace("suggestPeer return", "addr", addr, "depth", depth, "changed", changed) - if binStr(addr) != expAddr { - tk.t.Fatalf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr)) - } - if depth != expDepth { - tk.t.Fatalf("incorrect saturation depth suggested. expected %v, got %v", expDepth, depth) - } - if changed != expChanged { - tk.t.Fatalf("expected depth change = %v, got %v", expChanged, changed) - } -} - -func binStr(a *BzzAddr) string { - if a == nil { - return "" - } - return pot.ToBin(a.Address())[:8] -} - -func TestSuggestPeerFindPeers(t *testing.T) { - tk := newTestKademlia(t, "00000000") - tk.On("00100000") - tk.checkSuggestPeer("", 0, false) - - tk.On("00010000") - tk.checkSuggestPeer("", 0, false) - - tk.On("10000000", "10000001") - tk.checkSuggestPeer("", 0, false) - - tk.On("01000000") - tk.Off("10000001") - tk.checkSuggestPeer("10000001", 0, true) - - tk.On("00100001") - tk.Off("01000000") - tk.checkSuggestPeer("01000000", 0, false) - - // second time disconnected peer not callable - // with reasonably set Interval - tk.checkSuggestPeer("", 0, false) - - // on and off again, peer callable again - tk.On("01000000") - tk.Off("01000000") - tk.checkSuggestPeer("01000000", 0, false) - - tk.On("01000000", "10000001") - tk.checkSuggestPeer("", 0, false) - - tk.Register("00010001") - tk.checkSuggestPeer("00010001", 0, false) - - tk.On("00010001") - tk.Off("01000000") - tk.checkSuggestPeer("01000000", 0, false) - - tk.On("01000000") - tk.checkSuggestPeer("", 0, false) - - tk.Register("01000001") - tk.checkSuggestPeer("01000001", 0, false) - - tk.On("01000001") - tk.checkSuggestPeer("", 0, false) - - tk.Register("10000010", "01000010", "00100010") - tk.checkSuggestPeer("", 0, false) - - tk.Register("00010010") - tk.checkSuggestPeer("00010010", 0, false) - - tk.Off("00100001") - tk.checkSuggestPeer("00100010", 2, true) - - tk.Off("01000001") - tk.checkSuggestPeer("01000010", 1, true) - - tk.checkSuggestPeer("01000001", 0, false) - tk.checkSuggestPeer("00100001", 0, false) - tk.checkSuggestPeer("", 0, false) - - tk.On("01000001", "00100001") - tk.Register("10000100", "01000100", "00100100") - tk.Register("00000100", "00000101", "00000110") - tk.Register("00000010", "00000011", "00000001") - - tk.checkSuggestPeer("00000110", 0, false) - tk.checkSuggestPeer("00000101", 0, false) - tk.checkSuggestPeer("00000100", 0, false) - tk.checkSuggestPeer("00000011", 0, false) - tk.checkSuggestPeer("00000010", 0, false) - tk.checkSuggestPeer("00000001", 0, false) - tk.checkSuggestPeer("", 0, false) - -} - -// a node should stay in the address book if it's removed from the kademlia -func TestOffEffectingAddressBookNormalNode(t *testing.T) { - tk := newTestKademlia(t, "00000000") - // peer added to kademlia - tk.On("01000000") - // peer should be in the address book - if tk.addrs.Size() != 1 { - t.Fatal("known peer addresses should contain 1 entry") - } - // peer should be among live connections - if tk.conns.Size() != 1 { - t.Fatal("live peers should contain 1 entry") - } - // remove peer from kademlia - tk.Off("01000000") - // peer should be in the address book - if tk.addrs.Size() != 1 { - t.Fatal("known peer addresses should contain 1 entry") - } - // peer should not be among live connections - if tk.conns.Size() != 0 { - t.Fatal("live peers should contain 0 entry") - } -} - -// a light node should not be in the address book -func TestOffEffectingAddressBookLightNode(t *testing.T) { - tk := newTestKademlia(t, "00000000") - // light node peer added to kademlia - tk.Kademlia.On(tk.newTestKadPeer("01000000", true)) - // peer should not be in the address book - if tk.addrs.Size() != 0 { - t.Fatal("known peer addresses should contain 0 entry") - } - // peer should be among live connections - if tk.conns.Size() != 1 { - t.Fatal("live peers should contain 1 entry") - } - // remove peer from kademlia - tk.Kademlia.Off(tk.newTestKadPeer("01000000", true)) - // peer should not be in the address book - if tk.addrs.Size() != 0 { - t.Fatal("known peer addresses should contain 0 entry") - } - // peer should not be among live connections - if tk.conns.Size() != 0 { - t.Fatal("live peers should contain 0 entry") - } -} - -func TestSuggestPeerRetries(t *testing.T) { - tk := newTestKademlia(t, "00000000") - tk.RetryInterval = int64(300 * time.Millisecond) // cycle - tk.MaxRetries = 50 - tk.RetryExponent = 2 - sleep := func(n int) { - ts := tk.RetryInterval - for i := 1; i < n; i++ { - ts *= int64(tk.RetryExponent) - } - time.Sleep(time.Duration(ts)) - } - - tk.Register("01000000") - tk.On("00000001", "00000010") - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("", 0, false) - - sleep(1) - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("", 0, false) - - sleep(1) - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("", 0, false) - - sleep(2) - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("", 0, false) - - sleep(2) - tk.checkSuggestPeer("", 0, false) -} - -func TestKademliaHiveString(t *testing.T) { - tk := newTestKademlia(t, "00000000") - tk.On("01000000", "00100000") - tk.Register("10000000", "10000001") - tk.MaxProxDisplay = 8 - h := tk.String() - expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 0000000000000000000000000000000000000000000000000000000000000000\npopulation: 2 (4), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 0 | 2 8100 (0) 8000 (0)\n001 1 4000 | 1 4000 (0)\n002 1 2000 | 1 2000 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n=========================================================================" - if expH[104:] != h[104:] { - t.Fatalf("incorrect hive output. expected %v, got %v", expH, h) - } -} - -func newTestDiscoveryPeer(addr pot.Address, kad *Kademlia) *Peer { - rw := &p2p.MsgPipeRW{} - p := p2p.NewPeer(enode.ID{}, "foo", []p2p.Cap{}) - pp := protocols.NewPeer(p, rw, &protocols.Spec{}) - bp := &BzzPeer{ - Peer: pp, - BzzAddr: &BzzAddr{ - OAddr: addr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", addr[:])), - }, - } - return NewPeer(bp, kad) -} - -// TestKademlia_SubscribeToNeighbourhoodDepthChange checks if correct -// signaling over SubscribeToNeighbourhoodDepthChange channels are made -// when neighbourhood depth is changed. -func TestKademlia_SubscribeToNeighbourhoodDepthChange(t *testing.T) { - - testSignal := func(t *testing.T, k *testKademlia, prevDepth int, c <-chan struct{}) (newDepth int) { - t.Helper() - - select { - case _, ok := <-c: - if !ok { - t.Error("closed signal channel") - } - newDepth = k.NeighbourhoodDepth() - if prevDepth == newDepth { - t.Error("depth not changed") - } - return newDepth - case <-time.After(2 * time.Second): - t.Error("timeout") - } - return newDepth - } - - t.Run("single subscription", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c, u := k.SubscribeToNeighbourhoodDepthChange() - defer u() - - depth := k.NeighbourhoodDepth() - - k.On("11111101", "01000000", "10000000", "00000010") - - testSignal(t, k, depth, c) - }) - - t.Run("multiple subscriptions", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c1, u1 := k.SubscribeToNeighbourhoodDepthChange() - defer u1() - - c2, u2 := k.SubscribeToNeighbourhoodDepthChange() - defer u2() - - depth := k.NeighbourhoodDepth() - - k.On("11111101", "01000000", "10000000", "00000010") - - testSignal(t, k, depth, c1) - - testSignal(t, k, depth, c2) - }) - - t.Run("multiple changes", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c, u := k.SubscribeToNeighbourhoodDepthChange() - defer u() - - depth := k.NeighbourhoodDepth() - - k.On("11111101", "01000000", "10000000", "00000010") - - depth = testSignal(t, k, depth, c) - - k.On("11111101", "01000010", "10000010", "00000110") - - testSignal(t, k, depth, c) - }) - - t.Run("no depth change", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c, u := k.SubscribeToNeighbourhoodDepthChange() - defer u() - - // does not trigger the depth change - k.On("11111101") - - select { - case _, ok := <-c: - if !ok { - t.Error("closed signal channel") - } - t.Error("signal received") - case <-time.After(1 * time.Second): - // all fine - } - }) - - t.Run("no new peers", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - changeC, unsubscribe := k.SubscribeToNeighbourhoodDepthChange() - defer unsubscribe() - - select { - case _, ok := <-changeC: - if !ok { - t.Error("closed signal channel") - } - t.Error("signal received") - case <-time.After(1 * time.Second): - // all fine - } - }) -} diff --git a/swarm/network/network.go b/swarm/network/network.go deleted file mode 100644 index c5c7e9b2fa..0000000000 --- a/swarm/network/network.go +++ /dev/null @@ -1,105 +0,0 @@ -package network - -import ( - "crypto/ecdsa" - "fmt" - "net" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" -) - -// BzzAddr implements the PeerAddr interface -type BzzAddr struct { - OAddr []byte - UAddr []byte -} - -// Address implements OverlayPeer interface to be used in Overlay. -func (a *BzzAddr) Address() []byte { - return a.OAddr -} - -// Over returns the overlay address. -func (a *BzzAddr) Over() []byte { - return a.OAddr -} - -// Under returns the underlay address. -func (a *BzzAddr) Under() []byte { - return a.UAddr -} - -// ID returns the node identifier in the underlay. -func (a *BzzAddr) ID() enode.ID { - n, err := enode.ParseV4(string(a.UAddr)) - if err != nil { - return enode.ID{} - } - return n.ID() -} - -// Update updates the underlay address of a peer record -func (a *BzzAddr) Update(na *BzzAddr) *BzzAddr { - return &BzzAddr{a.OAddr, na.UAddr} -} - -// String pretty prints the address -func (a *BzzAddr) String() string { - return fmt.Sprintf("%x <%s>", a.OAddr, a.UAddr) -} - -// RandomAddr is a utility method generating an address from a public key -func RandomAddr() *BzzAddr { - key, err := crypto.GenerateKey() - if err != nil { - panic("unable to generate key") - } - node := enode.NewV4(&key.PublicKey, net.IP{127, 0, 0, 1}, 30303, 30303) - return NewAddr(node) -} - -// NewAddr constucts a BzzAddr from a node record. -func NewAddr(node *enode.Node) *BzzAddr { - return &BzzAddr{OAddr: node.ID().Bytes(), UAddr: []byte(node.String())} -} - -func PrivateKeyToBzzKey(prvKey *ecdsa.PrivateKey) []byte { - pubkeyBytes := crypto.FromECDSAPub(&prvKey.PublicKey) - return crypto.Keccak256Hash(pubkeyBytes).Bytes() -} - -type EnodeParams struct { - PrivateKey *ecdsa.PrivateKey - EnodeKey *ecdsa.PrivateKey - Lightnode bool - Bootnode bool -} - -func NewEnodeRecord(params *EnodeParams) (*enr.Record, error) { - - if params.PrivateKey == nil { - return nil, fmt.Errorf("all param private keys must be defined") - } - - bzzkeybytes := PrivateKeyToBzzKey(params.PrivateKey) - - var record enr.Record - record.Set(NewENRAddrEntry(bzzkeybytes)) - record.Set(ENRLightNodeEntry(params.Lightnode)) - record.Set(ENRBootNodeEntry(params.Bootnode)) - return &record, nil -} - -func NewEnode(params *EnodeParams) (*enode.Node, error) { - record, err := NewEnodeRecord(params) - if err != nil { - return nil, err - } - err = enode.SignV4(record, params.EnodeKey) - if err != nil { - return nil, fmt.Errorf("ENR create fail: %v", err) - } - return enode.New(enode.V4ID{}, record) -} diff --git a/swarm/network/networkid_test.go b/swarm/network/networkid_test.go deleted file mode 100644 index 9d47cf9f6a..0000000000 --- a/swarm/network/networkid_test.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "bytes" - "context" - "flag" - "fmt" - "math/rand" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" -) - -var ( - currentNetworkID int - cnt int - nodeMap map[int][]enode.ID - kademlias map[enode.ID]*Kademlia -) - -const ( - NumberOfNets = 4 - MaxTimeout = 15 * time.Second -) - -func init() { - flag.Parse() - rand.Seed(time.Now().Unix()) -} - -/* -Run the network ID test. -The test creates one simulations.Network instance, -a number of nodes, then connects nodes with each other in this network. - -Each node gets a network ID assigned according to the number of networks. -Having more network IDs is just arbitrary in order to exclude -false positives. - -Nodes should only connect with other nodes with the same network ID. -After the setup phase, the test checks on each node if it has the -expected node connections (excluding those not sharing the network ID). -*/ -func TestNetworkID(t *testing.T) { - log.Debug("Start test") - //arbitrarily set the number of nodes. It could be any number - numNodes := 24 - //the nodeMap maps all nodes (slice value) with the same network ID (key) - nodeMap = make(map[int][]enode.ID) - //set up the network and connect nodes - net, err := setupNetwork(numNodes) - if err != nil { - t.Fatalf("Error setting up network: %v", err) - } - //let's sleep to ensure all nodes are connected - time.Sleep(1 * time.Second) - // shutdown the the network to avoid race conditions - // on accessing kademlias global map while network nodes - // are accepting messages - net.Shutdown() - //for each group sharing the same network ID... - for _, netIDGroup := range nodeMap { - log.Trace("netIDGroup size", "size", len(netIDGroup)) - //...check that their size of the kademlia is of the expected size - //the assumption is that it should be the size of the group minus 1 (the node itself) - for _, node := range netIDGroup { - if kademlias[node].addrs.Size() != len(netIDGroup)-1 { - t.Fatalf("Kademlia size has not expected peer size. Kademlia size: %d, expected size: %d", kademlias[node].addrs.Size(), len(netIDGroup)-1) - } - kademlias[node].EachAddr(nil, 0, func(addr *BzzAddr, _ int) bool { - found := false - for _, nd := range netIDGroup { - if bytes.Equal(kademlias[nd].BaseAddr(), addr.Address()) { - found = true - } - } - if !found { - t.Fatalf("Expected node not found for node %s", node.String()) - } - return true - }) - } - } - log.Info("Test terminated successfully") -} - -// setup simulated network with bzz/discovery and pss services. -// connects nodes in a circle -// if allowRaw is set, omission of builtin pss encryption is enabled (see PssParams) -func setupNetwork(numnodes int) (net *simulations.Network, err error) { - log.Debug("Setting up network") - quitC := make(chan struct{}) - errc := make(chan error) - nodes := make([]*simulations.Node, numnodes) - if numnodes < 16 { - return nil, fmt.Errorf("Minimum sixteen nodes in network") - } - adapter := adapters.NewSimAdapter(newServices()) - //create the network - net = simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - ID: "NetworkIdTestNet", - DefaultService: "bzz", - }) - log.Debug("Creating networks and nodes") - - var connCount int - - //create nodes and connect them to each other - for i := 0; i < numnodes; i++ { - log.Trace("iteration: ", "i", i) - nodeconf := adapters.RandomNodeConfig() - nodes[i], err = net.NewNodeWithConfig(nodeconf) - if err != nil { - return nil, fmt.Errorf("error creating node %d: %v", i, err) - } - err = net.Start(nodes[i].ID()) - if err != nil { - return nil, fmt.Errorf("error starting node %d: %v", i, err) - } - client, err := nodes[i].Client() - if err != nil { - return nil, fmt.Errorf("create node %d rpc client fail: %v", i, err) - } - //now setup and start event watching in order to know when we can upload - ctx, watchCancel := context.WithTimeout(context.Background(), MaxTimeout) - defer watchCancel() - watchSubscriptionEvents(ctx, nodes[i].ID(), client, errc, quitC) - //on every iteration we connect to all previous ones - for k := i - 1; k >= 0; k-- { - connCount++ - log.Debug(fmt.Sprintf("Connecting node %d with node %d; connection count is %d", i, k, connCount)) - err = net.Connect(nodes[i].ID(), nodes[k].ID()) - if err != nil { - if !strings.Contains(err.Error(), "already connected") { - return nil, fmt.Errorf("error connecting nodes: %v", err) - } - } - } - } - //now wait until the number of expected subscriptions has been finished - //`watchSubscriptionEvents` will write with a `nil` value to errc - for err := range errc { - if err != nil { - return nil, err - } - //`nil` received, decrement count - connCount-- - log.Trace("count down", "cnt", connCount) - //all subscriptions received - if connCount == 0 { - close(quitC) - break - } - } - log.Debug("Network setup phase terminated") - return net, nil -} - -func newServices() adapters.Services { - kademlias = make(map[enode.ID]*Kademlia) - kademlia := func(id enode.ID) *Kademlia { - if k, ok := kademlias[id]; ok { - return k - } - params := NewKadParams() - params.NeighbourhoodSize = 2 - params.MaxBinSize = 3 - params.MinBinSize = 1 - params.MaxRetries = 1000 - params.RetryExponent = 2 - params.RetryInterval = 1000000 - kademlias[id] = NewKademlia(id[:], params) - return kademlias[id] - } - return adapters.Services{ - "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { - addr := NewAddr(ctx.Config.Node()) - hp := NewHiveParams() - hp.Discovery = false - cnt++ - //assign the network ID - currentNetworkID = cnt % NumberOfNets - if ok := nodeMap[currentNetworkID]; ok == nil { - nodeMap[currentNetworkID] = make([]enode.ID, 0) - } - //add this node to the group sharing the same network ID - nodeMap[currentNetworkID] = append(nodeMap[currentNetworkID], ctx.Config.ID) - log.Debug("current network ID:", "id", currentNetworkID) - config := &BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - NetworkID: uint64(currentNetworkID), - } - return NewBzz(config, kademlia(ctx.Config.ID), nil, nil, nil), nil - }, - } -} - -func watchSubscriptionEvents(ctx context.Context, id enode.ID, client *rpc.Client, errc chan error, quitC chan struct{}) { - events := make(chan *p2p.PeerEvent) - sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") - if err != nil { - log.Error(err.Error()) - errc <- fmt.Errorf("error getting peer events for node %v: %s", id, err) - return - } - go func() { - defer func() { - sub.Unsubscribe() - log.Trace("watch subscription events: unsubscribe", "id", id) - }() - - for { - select { - case <-quitC: - return - case <-ctx.Done(): - select { - case errc <- ctx.Err(): - case <-quitC: - } - return - case e := <-events: - if e.Type == p2p.PeerEventTypeAdd { - errc <- nil - } - case err := <-sub.Err(): - if err != nil { - select { - case errc <- fmt.Errorf("error getting peer events for node %v: %v", id, err): - case <-quitC: - } - return - } - } - } - }() -} diff --git a/swarm/network/priorityqueue/priorityqueue.go b/swarm/network/priorityqueue/priorityqueue.go deleted file mode 100644 index 056e85ec13..0000000000 --- a/swarm/network/priorityqueue/priorityqueue.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// package priority_queue implement a channel based priority queue -// over arbitrary types. It provides an -// an autopop loop applying a function to the items always respecting -// their priority. The structure is only quasi consistent ie., if a lower -// priority item is autopopped, it is guaranteed that there was a point -// when no higher priority item was present, ie. it is not guaranteed -// that there was any point where the lower priority item was present -// but the higher was not - -package priorityqueue - -import ( - "context" - "errors" - "time" - - "github.com/ethereum/go-ethereum/metrics" -) - -var ( - ErrContention = errors.New("contention") - - errBadPriority = errors.New("bad priority") - - wakey = struct{}{} -) - -// PriorityQueue is the basic structure -type PriorityQueue struct { - Queues []chan interface{} - wakeup chan struct{} -} - -// New is the constructor for PriorityQueue -func New(n int, l int) *PriorityQueue { - var queues = make([]chan interface{}, n) - for i := range queues { - queues[i] = make(chan interface{}, l) - } - return &PriorityQueue{ - Queues: queues, - wakeup: make(chan struct{}, 1), - } -} - -// Run is a forever loop popping items from the queues -func (pq *PriorityQueue) Run(ctx context.Context, f func(interface{})) { - top := len(pq.Queues) - 1 - p := top -READ: - for { - q := pq.Queues[p] - select { - case <-ctx.Done(): - return - case x := <-q: - val := x.(struct { - v interface{} - t time.Time - }) - f(val.v) - metrics.GetOrRegisterResettingTimer("pq.run", nil).UpdateSince(val.t) - p = top - default: - if p > 0 { - p-- - continue READ - } - p = top - select { - case <-ctx.Done(): - return - case <-pq.wakeup: - } - } - } -} - -// Push pushes an item to the appropriate queue specified in the priority argument -// if context is given it waits until either the item is pushed or the Context aborts -func (pq *PriorityQueue) Push(x interface{}, p int) error { - if p < 0 || p >= len(pq.Queues) { - return errBadPriority - } - val := struct { - v interface{} - t time.Time - }{ - x, - time.Now(), - } - select { - case pq.Queues[p] <- val: - default: - return ErrContention - } - select { - case pq.wakeup <- wakey: - default: - } - return nil -} diff --git a/swarm/network/priorityqueue/priorityqueue_test.go b/swarm/network/priorityqueue/priorityqueue_test.go deleted file mode 100644 index ed8b575c20..0000000000 --- a/swarm/network/priorityqueue/priorityqueue_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package priorityqueue - -import ( - "context" - "sync" - "testing" -) - -func TestPriorityQueue(t *testing.T) { - var results []string - wg := sync.WaitGroup{} - pq := New(3, 2) - wg.Add(1) - go pq.Run(context.Background(), func(v interface{}) { - results = append(results, v.(string)) - wg.Done() - }) - pq.Push("2.0", 2) - wg.Wait() - if results[0] != "2.0" { - t.Errorf("expected first result %q, got %q", "2.0", results[0]) - } - -Loop: - for i, tc := range []struct { - priorities []int - values []string - results []string - errors []error - }{ - { - priorities: []int{0}, - values: []string{""}, - results: []string{""}, - }, - { - priorities: []int{0, 1}, - values: []string{"0.0", "1.0"}, - results: []string{"1.0", "0.0"}, - }, - { - priorities: []int{1, 0}, - values: []string{"1.0", "0.0"}, - results: []string{"1.0", "0.0"}, - }, - { - priorities: []int{0, 1, 1}, - values: []string{"0.0", "1.0", "1.1"}, - results: []string{"1.0", "1.1", "0.0"}, - }, - { - priorities: []int{0, 0, 0}, - values: []string{"0.0", "0.0", "0.1"}, - errors: []error{nil, nil, ErrContention}, - }, - } { - var results []string - wg := sync.WaitGroup{} - pq := New(3, 2) - wg.Add(len(tc.values)) - for j, value := range tc.values { - err := pq.Push(value, tc.priorities[j]) - if tc.errors != nil && err != tc.errors[j] { - t.Errorf("expected push error %v, got %v", tc.errors[j], err) - continue Loop - } - if err != nil { - continue Loop - } - } - go pq.Run(context.Background(), func(v interface{}) { - results = append(results, v.(string)) - wg.Done() - }) - wg.Wait() - for k, result := range tc.results { - if results[k] != result { - t.Errorf("test case %v: expected %v element %q, got %q", i, k, result, results[k]) - } - } - } -} diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go deleted file mode 100644 index dd8a86c0b3..0000000000 --- a/swarm/network/protocol.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "context" - "errors" - "fmt" - "math/rand" - "sync" - "time" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/state" -) - -const ( - DefaultNetworkID = 4 - // timeout for waiting - bzzHandshakeTimeout = 3000 * time.Millisecond -) - -var DefaultTestNetworkID = rand.Uint64() - -// BzzSpec is the spec of the generic swarm handshake -var BzzSpec = &protocols.Spec{ - Name: "bzz", - Version: 9, - MaxMsgSize: 10 * 1024 * 1024, - Messages: []interface{}{ - HandshakeMsg{}, - }, -} - -// DiscoverySpec is the spec for the bzz discovery subprotocols -var DiscoverySpec = &protocols.Spec{ - Name: "hive", - Version: 8, - MaxMsgSize: 10 * 1024 * 1024, - Messages: []interface{}{ - peersMsg{}, - subPeersMsg{}, - }, -} - -// BzzConfig captures the config params used by the hive -type BzzConfig struct { - OverlayAddr []byte // base address of the overlay network - UnderlayAddr []byte // node's underlay address - HiveParams *HiveParams - NetworkID uint64 - LightNode bool - BootnodeMode bool -} - -// Bzz is the swarm protocol bundle -type Bzz struct { - *Hive - NetworkID uint64 - LightNode bool - localAddr *BzzAddr - mtx sync.Mutex - handshakes map[enode.ID]*HandshakeMsg - streamerSpec *protocols.Spec - streamerRun func(*BzzPeer) error -} - -// NewBzz is the swarm protocol constructor -// arguments -// * bzz config -// * overlay driver -// * peer store -func NewBzz(config *BzzConfig, kad *Kademlia, store state.Store, streamerSpec *protocols.Spec, streamerRun func(*BzzPeer) error) *Bzz { - bzz := &Bzz{ - Hive: NewHive(config.HiveParams, kad, store), - NetworkID: config.NetworkID, - LightNode: config.LightNode, - localAddr: &BzzAddr{config.OverlayAddr, config.UnderlayAddr}, - handshakes: make(map[enode.ID]*HandshakeMsg), - streamerRun: streamerRun, - streamerSpec: streamerSpec, - } - - if config.BootnodeMode { - bzz.streamerRun = nil - bzz.streamerSpec = nil - } - - return bzz -} - -// UpdateLocalAddr updates underlayaddress of the running node -func (b *Bzz) UpdateLocalAddr(byteaddr []byte) *BzzAddr { - b.localAddr = b.localAddr.Update(&BzzAddr{ - UAddr: byteaddr, - OAddr: b.localAddr.OAddr, - }) - return b.localAddr -} - -// NodeInfo returns the node's overlay address -func (b *Bzz) NodeInfo() interface{} { - return b.localAddr.Address() -} - -// Protocols return the protocols swarm offers -// Bzz implements the node.Service interface -// * handshake/hive -// * discovery -func (b *Bzz) Protocols() []p2p.Protocol { - protocol := []p2p.Protocol{ - { - Name: BzzSpec.Name, - Version: BzzSpec.Version, - Length: BzzSpec.Length(), - Run: b.runBzz, - NodeInfo: b.NodeInfo, - }, - { - Name: DiscoverySpec.Name, - Version: DiscoverySpec.Version, - Length: DiscoverySpec.Length(), - Run: b.RunProtocol(DiscoverySpec, b.Hive.Run), - NodeInfo: b.Hive.NodeInfo, - PeerInfo: b.Hive.PeerInfo, - }, - } - if b.streamerSpec != nil && b.streamerRun != nil { - protocol = append(protocol, p2p.Protocol{ - Name: b.streamerSpec.Name, - Version: b.streamerSpec.Version, - Length: b.streamerSpec.Length(), - Run: b.RunProtocol(b.streamerSpec, b.streamerRun), - }) - } - return protocol -} - -// APIs returns the APIs offered by bzz -// * hive -// Bzz implements the node.Service interface -func (b *Bzz) APIs() []rpc.API { - return []rpc.API{{ - Namespace: "hive", - Version: "3.0", - Service: b.Hive, - }} -} - -// RunProtocol is a wrapper for swarm subprotocols -// returns a p2p protocol run function that can be assigned to p2p.Protocol#Run field -// arguments: -// * p2p protocol spec -// * run function taking BzzPeer as argument -// this run function is meant to block for the duration of the protocol session -// on return the session is terminated and the peer is disconnected -// the protocol waits for the bzz handshake is negotiated -// the overlay address on the BzzPeer is set from the remote handshake -func (b *Bzz) RunProtocol(spec *protocols.Spec, run func(*BzzPeer) error) func(*p2p.Peer, p2p.MsgReadWriter) error { - return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { - // wait for the bzz protocol to perform the handshake - handshake, _ := b.GetOrCreateHandshake(p.ID()) - defer b.removeHandshake(p.ID()) - select { - case <-handshake.done: - case <-time.After(bzzHandshakeTimeout): - return fmt.Errorf("%08x: %s protocol timeout waiting for handshake on %08x", b.BaseAddr()[:4], spec.Name, p.ID().Bytes()[:4]) - } - if handshake.err != nil { - return fmt.Errorf("%08x: %s protocol closed: %v", b.BaseAddr()[:4], spec.Name, handshake.err) - } - // the handshake has succeeded so construct the BzzPeer and run the protocol - peer := &BzzPeer{ - Peer: protocols.NewPeer(p, rw, spec), - BzzAddr: handshake.peerAddr, - lastActive: time.Now(), - LightNode: handshake.LightNode, - } - - log.Debug("peer created", "addr", handshake.peerAddr.String()) - - return run(peer) - } -} - -// performHandshake implements the negotiation of the bzz handshake -// shared among swarm subprotocols -func (b *Bzz) performHandshake(p *protocols.Peer, handshake *HandshakeMsg) error { - ctx, cancel := context.WithTimeout(context.Background(), bzzHandshakeTimeout) - defer func() { - close(handshake.done) - cancel() - }() - rsh, err := p.Handshake(ctx, handshake, b.checkHandshake) - if err != nil { - handshake.err = err - return err - } - handshake.peerAddr = rsh.(*HandshakeMsg).Addr - handshake.LightNode = rsh.(*HandshakeMsg).LightNode - return nil -} - -// runBzz is the p2p protocol run function for the bzz base protocol -// that negotiates the bzz handshake -func (b *Bzz) runBzz(p *p2p.Peer, rw p2p.MsgReadWriter) error { - handshake, _ := b.GetOrCreateHandshake(p.ID()) - if !<-handshake.init { - return fmt.Errorf("%08x: bzz already started on peer %08x", b.localAddr.Over()[:4], p.ID().Bytes()[:4]) - } - close(handshake.init) - defer b.removeHandshake(p.ID()) - peer := protocols.NewPeer(p, rw, BzzSpec) - err := b.performHandshake(peer, handshake) - if err != nil { - log.Warn(fmt.Sprintf("%08x: handshake failed with remote peer %08x: %v", b.localAddr.Over()[:4], p.ID().Bytes()[:4], err)) - - return err - } - // fail if we get another handshake - msg, err := rw.ReadMsg() - if err != nil { - return err - } - msg.Discard() - return errors.New("received multiple handshakes") -} - -// BzzPeer is the bzz protocol view of a protocols.Peer (itself an extension of p2p.Peer) -// implements the Peer interface and all interfaces Peer implements: Addr, OverlayPeer -type BzzPeer struct { - *protocols.Peer // represents the connection for online peers - *BzzAddr // remote address -> implements Addr interface = protocols.Peer - lastActive time.Time // time is updated whenever mutexes are releasing - LightNode bool -} - -func NewBzzPeer(p *protocols.Peer) *BzzPeer { - return &BzzPeer{Peer: p, BzzAddr: NewAddr(p.Node())} -} - -// ID returns the peer's underlay node identifier. -func (p *BzzPeer) ID() enode.ID { - // This is here to resolve a method tie: both protocols.Peer and BzzAddr are embedded - // into the struct and provide ID(). The protocols.Peer version is faster, ensure it - // gets used. - return p.Peer.ID() -} - -/* - Handshake - -* Version: 8 byte integer version of the protocol -* NetworkID: 8 byte integer network identifier -* Addr: the address advertised by the node including underlay and overlay connecctions -*/ -type HandshakeMsg struct { - Version uint64 - NetworkID uint64 - Addr *BzzAddr - LightNode bool - - // peerAddr is the address received in the peer handshake - peerAddr *BzzAddr - - init chan bool - done chan struct{} - err error -} - -// String pretty prints the handshake -func (bh *HandshakeMsg) String() string { - return fmt.Sprintf("Handshake: Version: %v, NetworkID: %v, Addr: %v, LightNode: %v, peerAddr: %v", bh.Version, bh.NetworkID, bh.Addr, bh.LightNode, bh.peerAddr) -} - -// Perform initiates the handshake and validates the remote handshake message -func (b *Bzz) checkHandshake(hs interface{}) error { - rhs := hs.(*HandshakeMsg) - if rhs.NetworkID != b.NetworkID { - return fmt.Errorf("network id mismatch %d (!= %d)", rhs.NetworkID, b.NetworkID) - } - if rhs.Version != uint64(BzzSpec.Version) { - return fmt.Errorf("version mismatch %d (!= %d)", rhs.Version, BzzSpec.Version) - } - return nil -} - -// removeHandshake removes handshake for peer with peerID -// from the bzz handshake store -func (b *Bzz) removeHandshake(peerID enode.ID) { - b.mtx.Lock() - defer b.mtx.Unlock() - delete(b.handshakes, peerID) -} - -// GetHandshake returns the bzz handhake that the remote peer with peerID sent -func (b *Bzz) GetOrCreateHandshake(peerID enode.ID) (*HandshakeMsg, bool) { - b.mtx.Lock() - defer b.mtx.Unlock() - handshake, found := b.handshakes[peerID] - if !found { - handshake = &HandshakeMsg{ - Version: uint64(BzzSpec.Version), - NetworkID: b.NetworkID, - Addr: b.localAddr, - LightNode: b.LightNode, - init: make(chan bool, 1), - done: make(chan struct{}), - } - // when handhsake is first created for a remote peer - // it is initialised with the init - handshake.init <- true - b.handshakes[peerID] = handshake - } - - return handshake, found -} diff --git a/swarm/network/protocol_test.go b/swarm/network/protocol_test.go deleted file mode 100644 index 616abde9ed..0000000000 --- a/swarm/network/protocol_test.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package network - -import ( - "crypto/ecdsa" - "flag" - "fmt" - "os" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/p2p/protocols" - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" - "github.com/ethereum/go-ethereum/swarm/pot" -) - -const ( - TestProtocolVersion = 9 -) - -var TestProtocolNetworkID = DefaultTestNetworkID - -var ( - loglevel = flag.Int("loglevel", 2, "verbosity of logs") -) - -func init() { - flag.Parse() - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) -} - -func HandshakeMsgExchange(lhs, rhs *HandshakeMsg, id enode.ID) []p2ptest.Exchange { - return []p2ptest.Exchange{ - { - Expects: []p2ptest.Expect{ - { - Code: 0, - Msg: lhs, - Peer: id, - }, - }, - }, - { - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: rhs, - Peer: id, - }, - }, - }, - } -} - -func newBzzBaseTester(n int, prvkey *ecdsa.PrivateKey, spec *protocols.Spec, run func(*BzzPeer) error) (*bzzTester, error) { - var addrs [][]byte - for i := 0; i < n; i++ { - addr := pot.RandomAddress() - addrs = append(addrs, addr[:]) - } - pt, _, err := newBzzBaseTesterWithAddrs(prvkey, addrs, spec, run) - return pt, err -} - -func newBzzBaseTesterWithAddrs(prvkey *ecdsa.PrivateKey, addrs [][]byte, spec *protocols.Spec, run func(*BzzPeer) error) (*bzzTester, [][]byte, error) { - n := len(addrs) - cs := make(map[enode.ID]chan bool) - var csMu sync.Mutex - - srv := func(p *BzzPeer) error { - defer func() { - csMu.Lock() - defer csMu.Unlock() - if cs[p.ID()] != nil { - close(cs[p.ID()]) - } - }() - return run(p) - } - mu := &sync.Mutex{} - nodeToAddr := make(map[enode.ID][]byte) - protocol := func(p *p2p.Peer, rw p2p.MsgReadWriter) error { - mu.Lock() - nodeToAddr[p.ID()] = addrs[0] - mu.Unlock() - bzzAddr := &BzzAddr{addrs[0], []byte(p.Node().String())} - addrs = addrs[1:] - return srv(&BzzPeer{Peer: protocols.NewPeer(p, rw, spec), BzzAddr: bzzAddr}) - } - - s := p2ptest.NewProtocolTester(prvkey, n, protocol) - var record enr.Record - bzzKey := PrivateKeyToBzzKey(prvkey) - record.Set(NewENRAddrEntry(bzzKey)) - err := enode.SignV4(&record, prvkey) - if err != nil { - return nil, nil, fmt.Errorf("unable to generate ENR: %v", err) - } - nod, err := enode.New(enode.V4ID{}, &record) - if err != nil { - return nil, nil, fmt.Errorf("unable to create enode: %v", err) - } - addr := getENRBzzAddr(nod) - - csMu.Lock() - for _, node := range s.Nodes { - log.Warn("node", "node", node) - cs[node.ID()] = make(chan bool) - } - csMu.Unlock() - - var nodeAddrs [][]byte - pt := &bzzTester{ - addr: addr, - ProtocolTester: s, - cs: cs, - } - mu.Lock() - for _, n := range pt.Nodes { - nodeAddrs = append(nodeAddrs, nodeToAddr[n.ID()]) - } - mu.Unlock() - - return pt, nodeAddrs, nil -} - -type bzzTester struct { - *p2ptest.ProtocolTester - addr *BzzAddr - cs map[enode.ID]chan bool - bzz *Bzz -} - -func newBzz(addr *BzzAddr, lightNode bool) *Bzz { - config := &BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: NewHiveParams(), - NetworkID: DefaultTestNetworkID, - LightNode: lightNode, - } - kad := NewKademlia(addr.OAddr, NewKadParams()) - bzz := NewBzz(config, kad, nil, nil, nil) - return bzz -} - -func newBzzHandshakeTester(n int, prvkey *ecdsa.PrivateKey, lightNode bool) (*bzzTester, error) { - - var record enr.Record - bzzkey := PrivateKeyToBzzKey(prvkey) - record.Set(NewENRAddrEntry(bzzkey)) - record.Set(ENRLightNodeEntry(lightNode)) - err := enode.SignV4(&record, prvkey) - if err != nil { - return nil, err - } - nod, err := enode.New(enode.V4ID{}, &record) - addr := getENRBzzAddr(nod) - - bzz := newBzz(addr, lightNode) - - pt := p2ptest.NewProtocolTester(prvkey, n, bzz.runBzz) - - return &bzzTester{ - addr: addr, - ProtocolTester: pt, - bzz: bzz, - }, nil -} - -// should test handshakes in one exchange? parallelisation -func (s *bzzTester) testHandshake(lhs, rhs *HandshakeMsg, disconnects ...*p2ptest.Disconnect) error { - if err := s.TestExchanges(HandshakeMsgExchange(lhs, rhs, rhs.Addr.ID())...); err != nil { - return err - } - - if len(disconnects) > 0 { - return s.TestDisconnected(disconnects...) - } - - // If we don't expect disconnect, ensure peers remain connected - err := s.TestDisconnected(&p2ptest.Disconnect{ - Peer: s.Nodes[0].ID(), - Error: nil, - }) - - if err == nil { - return fmt.Errorf("Unexpected peer disconnect") - } - - if err.Error() != "timed out waiting for peers to disconnect" { - return err - } - - return nil -} - -func correctBzzHandshake(addr *BzzAddr, lightNode bool) *HandshakeMsg { - return &HandshakeMsg{ - Version: TestProtocolVersion, - NetworkID: TestProtocolNetworkID, - Addr: addr, - LightNode: lightNode, - } -} - -func TestBzzHandshakeNetworkIDMismatch(t *testing.T) { - lightNode := false - prvkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - s, err := newBzzHandshakeTester(1, prvkey, lightNode) - if err != nil { - t.Fatal(err) - } - defer s.Stop() - node := s.Nodes[0] - - err = s.testHandshake( - correctBzzHandshake(s.addr, lightNode), - &HandshakeMsg{Version: TestProtocolVersion, NetworkID: 321, Addr: NewAddr(node)}, - &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): network id mismatch 321 (!= %v)", TestProtocolNetworkID)}, - ) - - if err != nil { - t.Fatal(err) - } -} - -func TestBzzHandshakeVersionMismatch(t *testing.T) { - lightNode := false - prvkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - s, err := newBzzHandshakeTester(1, prvkey, lightNode) - if err != nil { - t.Fatal(err) - } - defer s.Stop() - node := s.Nodes[0] - - err = s.testHandshake( - correctBzzHandshake(s.addr, lightNode), - &HandshakeMsg{Version: 0, NetworkID: TestProtocolNetworkID, Addr: NewAddr(node)}, - &p2ptest.Disconnect{Peer: node.ID(), Error: fmt.Errorf("Handshake error: Message handler error: (msg code 0): version mismatch 0 (!= %d)", TestProtocolVersion)}, - ) - - if err != nil { - t.Fatal(err) - } -} - -func TestBzzHandshakeSuccess(t *testing.T) { - lightNode := false - prvkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - s, err := newBzzHandshakeTester(1, prvkey, lightNode) - if err != nil { - t.Fatal(err) - } - defer s.Stop() - node := s.Nodes[0] - - err = s.testHandshake( - correctBzzHandshake(s.addr, lightNode), - &HandshakeMsg{Version: TestProtocolVersion, NetworkID: TestProtocolNetworkID, Addr: NewAddr(node)}, - ) - - if err != nil { - t.Fatal(err) - } -} - -func TestBzzHandshakeLightNode(t *testing.T) { - var lightNodeTests = []struct { - name string - lightNode bool - }{ - {"on", true}, - {"off", false}, - } - - for _, test := range lightNodeTests { - t.Run(test.name, func(t *testing.T) { - prvkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - pt, err := newBzzHandshakeTester(1, prvkey, false) - if err != nil { - t.Fatal(err) - } - defer pt.Stop() - - node := pt.Nodes[0] - addr := NewAddr(node) - - err = pt.testHandshake( - correctBzzHandshake(pt.addr, false), - &HandshakeMsg{Version: TestProtocolVersion, NetworkID: TestProtocolNetworkID, Addr: addr, LightNode: test.lightNode}, - ) - - if err != nil { - t.Fatal(err) - } - - select { - - case <-pt.bzz.handshakes[node.ID()].done: - if pt.bzz.handshakes[node.ID()].LightNode != test.lightNode { - t.Fatalf("peer LightNode flag is %v, should be %v", pt.bzz.handshakes[node.ID()].LightNode, test.lightNode) - } - case <-time.After(10 * time.Second): - t.Fatal("test timeout") - } - }) - } -} diff --git a/swarm/network/simulation/bucket.go b/swarm/network/simulation/bucket.go deleted file mode 100644 index 49a1f43091..0000000000 --- a/swarm/network/simulation/bucket.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import "github.com/ethereum/go-ethereum/p2p/enode" - -// BucketKey is the type that should be used for keys in simulation buckets. -type BucketKey string - -// NodeItem returns an item set in ServiceFunc function for a particular node. -func (s *Simulation) NodeItem(id enode.ID, key interface{}) (value interface{}, ok bool) { - s.mu.Lock() - defer s.mu.Unlock() - - if _, ok := s.buckets[id]; !ok { - return nil, false - } - return s.buckets[id].Load(key) -} - -// SetNodeItem sets a new item associated with the node with provided NodeID. -// Buckets should be used to avoid managing separate simulation global state. -func (s *Simulation) SetNodeItem(id enode.ID, key interface{}, value interface{}) { - s.mu.Lock() - defer s.mu.Unlock() - - s.buckets[id].Store(key, value) -} - -// NodesItems returns a map of items from all nodes that are all set under the -// same BucketKey. -func (s *Simulation) NodesItems(key interface{}) (values map[enode.ID]interface{}) { - s.mu.RLock() - defer s.mu.RUnlock() - - ids := s.NodeIDs() - values = make(map[enode.ID]interface{}, len(ids)) - for _, id := range ids { - if _, ok := s.buckets[id]; !ok { - continue - } - if v, ok := s.buckets[id].Load(key); ok { - values[id] = v - } - } - return values -} - -// UpNodesItems returns a map of items with the same BucketKey from all nodes that are up. -func (s *Simulation) UpNodesItems(key interface{}) (values map[enode.ID]interface{}) { - s.mu.RLock() - defer s.mu.RUnlock() - - ids := s.UpNodeIDs() - values = make(map[enode.ID]interface{}) - for _, id := range ids { - if _, ok := s.buckets[id]; !ok { - continue - } - if v, ok := s.buckets[id].Load(key); ok { - values[id] = v - } - } - return values -} diff --git a/swarm/network/simulation/bucket_test.go b/swarm/network/simulation/bucket_test.go deleted file mode 100644 index 2273d35a29..0000000000 --- a/swarm/network/simulation/bucket_test.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "sync" - "testing" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -// TestServiceBucket tests all bucket functionality using subtests. -// It constructs a simulation of two nodes by adding items to their buckets -// in ServiceFunc constructor, then by SetNodeItem. Testing UpNodesItems -// is done by stopping one node and validating availability of its items. -func TestServiceBucket(t *testing.T) { - testKey := "Key" - testValue := "Value" - - sim := New(map[string]ServiceFunc{ - "noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - b.Store(testKey, testValue+ctx.Config.ID.String()) - return newNoopService(), nil, nil - }, - }) - defer sim.Close() - - id1, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - id2, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - t.Run("ServiceFunc bucket Store", func(t *testing.T) { - v, ok := sim.NodeItem(id1, testKey) - if !ok { - t.Fatal("bucket item not found") - } - s, ok := v.(string) - if !ok { - t.Fatal("bucket item value is not string") - } - if s != testValue+id1.String() { - t.Fatalf("expected %q, got %q", testValue+id1.String(), s) - } - - v, ok = sim.NodeItem(id2, testKey) - if !ok { - t.Fatal("bucket item not found") - } - s, ok = v.(string) - if !ok { - t.Fatal("bucket item value is not string") - } - if s != testValue+id2.String() { - t.Fatalf("expected %q, got %q", testValue+id2.String(), s) - } - }) - - customKey := "anotherKey" - customValue := "anotherValue" - - t.Run("SetNodeItem", func(t *testing.T) { - sim.SetNodeItem(id1, customKey, customValue) - - v, ok := sim.NodeItem(id1, customKey) - if !ok { - t.Fatal("bucket item not found") - } - s, ok := v.(string) - if !ok { - t.Fatal("bucket item value is not string") - } - if s != customValue { - t.Fatalf("expected %q, got %q", customValue, s) - } - - _, ok = sim.NodeItem(id2, customKey) - if ok { - t.Fatal("bucket item should not be found") - } - }) - - if err := sim.StopNode(id2); err != nil { - t.Fatal(err) - } - - t.Run("UpNodesItems", func(t *testing.T) { - items := sim.UpNodesItems(testKey) - - v, ok := items[id1] - if !ok { - t.Errorf("node 1 item not found") - } - s, ok := v.(string) - if !ok { - t.Fatal("node 1 item value is not string") - } - if s != testValue+id1.String() { - t.Fatalf("expected %q, got %q", testValue+id1.String(), s) - } - - _, ok = items[id2] - if ok { - t.Errorf("node 2 item should not be found") - } - }) - - t.Run("NodeItems", func(t *testing.T) { - items := sim.NodesItems(testKey) - - v, ok := items[id1] - if !ok { - t.Errorf("node 1 item not found") - } - s, ok := v.(string) - if !ok { - t.Fatal("node 1 item value is not string") - } - if s != testValue+id1.String() { - t.Fatalf("expected %q, got %q", testValue+id1.String(), s) - } - - v, ok = items[id2] - if !ok { - t.Errorf("node 2 item not found") - } - s, ok = v.(string) - if !ok { - t.Fatal("node 1 item value is not string") - } - if s != testValue+id2.String() { - t.Fatalf("expected %q, got %q", testValue+id2.String(), s) - } - }) -} diff --git a/swarm/network/simulation/events.go b/swarm/network/simulation/events.go deleted file mode 100644 index d73c3af4ee..0000000000 --- a/swarm/network/simulation/events.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "sync" - - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" -) - -// PeerEvent is the type of the channel returned by Simulation.PeerEvents. -type PeerEvent struct { - // NodeID is the ID of node that the event is caught on. - NodeID enode.ID - // PeerID is the ID of the peer node that the event is caught on. - PeerID enode.ID - // Event is the event that is caught. - Event *simulations.Event - // Error is the error that may have happened during event watching. - Error error -} - -// PeerEventsFilter defines a filter on PeerEvents to exclude messages with -// defined properties. Use PeerEventsFilter methods to set required options. -type PeerEventsFilter struct { - eventType simulations.EventType - - connUp *bool - - msgReceive *bool - protocol *string - msgCode *uint64 -} - -// NewPeerEventsFilter returns a new PeerEventsFilter instance. -func NewPeerEventsFilter() *PeerEventsFilter { - return &PeerEventsFilter{} -} - -// Connect sets the filter to events when two nodes connect. -func (f *PeerEventsFilter) Connect() *PeerEventsFilter { - f.eventType = simulations.EventTypeConn - b := true - f.connUp = &b - return f -} - -// Drop sets the filter to events when two nodes disconnect. -func (f *PeerEventsFilter) Drop() *PeerEventsFilter { - f.eventType = simulations.EventTypeConn - b := false - f.connUp = &b - return f -} - -// ReceivedMessages sets the filter to only messages that are received. -func (f *PeerEventsFilter) ReceivedMessages() *PeerEventsFilter { - f.eventType = simulations.EventTypeMsg - b := true - f.msgReceive = &b - return f -} - -// SentMessages sets the filter to only messages that are sent. -func (f *PeerEventsFilter) SentMessages() *PeerEventsFilter { - f.eventType = simulations.EventTypeMsg - b := false - f.msgReceive = &b - return f -} - -// Protocol sets the filter to only one message protocol. -func (f *PeerEventsFilter) Protocol(p string) *PeerEventsFilter { - f.eventType = simulations.EventTypeMsg - f.protocol = &p - return f -} - -// MsgCode sets the filter to only one msg code. -func (f *PeerEventsFilter) MsgCode(c uint64) *PeerEventsFilter { - f.eventType = simulations.EventTypeMsg - f.msgCode = &c - return f -} - -// PeerEvents returns a channel of events that are captured by admin peerEvents -// subscription nodes with provided NodeIDs. Additional filters can be set to ignore -// events that are not relevant. -func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ...*PeerEventsFilter) <-chan PeerEvent { - eventC := make(chan PeerEvent) - - // wait group to make sure all subscriptions to admin peerEvents are established - // before this function returns. - var subsWG sync.WaitGroup - for _, id := range ids { - s.shutdownWG.Add(1) - subsWG.Add(1) - go func(id enode.ID) { - defer s.shutdownWG.Done() - - events := make(chan *simulations.Event) - sub := s.Net.Events().Subscribe(events) - defer sub.Unsubscribe() - - subsWG.Done() - - for { - select { - case <-ctx.Done(): - if err := ctx.Err(); err != nil { - select { - case eventC <- PeerEvent{NodeID: id, Error: err}: - case <-s.Done(): - } - } - return - case <-s.Done(): - return - case e := <-events: - // ignore control events - if e.Control { - continue - } - match := len(filters) == 0 // if there are no filters match all events - for _, f := range filters { - if f.eventType == simulations.EventTypeConn && e.Conn != nil { - if *f.connUp != e.Conn.Up { - continue - } - // all connection filter parameters matched, break the loop - match = true - break - } - if f.eventType == simulations.EventTypeMsg && e.Msg != nil { - if f.msgReceive != nil && *f.msgReceive != e.Msg.Received { - continue - } - if f.protocol != nil && *f.protocol != e.Msg.Protocol { - continue - } - if f.msgCode != nil && *f.msgCode != e.Msg.Code { - continue - } - // all message filter parameters matched, break the loop - match = true - break - } - } - var peerID enode.ID - switch e.Type { - case simulations.EventTypeConn: - peerID = e.Conn.One - if peerID == id { - peerID = e.Conn.Other - } - case simulations.EventTypeMsg: - peerID = e.Msg.One - if peerID == id { - peerID = e.Msg.Other - } - } - if match { - select { - case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Event: e}: - case <-ctx.Done(): - if err := ctx.Err(); err != nil { - select { - case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Error: err}: - case <-s.Done(): - } - } - return - case <-s.Done(): - return - } - } - case err := <-sub.Err(): - if err != nil { - select { - case eventC <- PeerEvent{NodeID: id, Error: err}: - case <-ctx.Done(): - if err := ctx.Err(); err != nil { - select { - case eventC <- PeerEvent{NodeID: id, Error: err}: - case <-s.Done(): - } - } - return - case <-s.Done(): - return - } - } - } - } - }(id) - } - - // wait all subscriptions - subsWG.Wait() - return eventC -} diff --git a/swarm/network/simulation/events_test.go b/swarm/network/simulation/events_test.go deleted file mode 100644 index 529844816f..0000000000 --- a/swarm/network/simulation/events_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "sync" - "testing" - "time" -) - -// TestPeerEvents creates simulation, adds two nodes, -// register for peer events, connects nodes in a chain -// and waits for the number of connection events to -// be received. -func TestPeerEvents(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - _, err := sim.AddNodes(2) - if err != nil { - t.Fatal(err) - } - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - events := sim.PeerEvents(ctx, sim.NodeIDs()) - - // two nodes -> two connection events - expectedEventCount := 2 - - var wg sync.WaitGroup - wg.Add(expectedEventCount) - - go func() { - for e := range events { - if e.Error != nil { - if e.Error == context.Canceled { - return - } - t.Error(e.Error) - continue - } - wg.Done() - } - }() - - err = sim.Net.ConnectNodesChain(sim.NodeIDs()) - if err != nil { - t.Fatal(err) - } - - wg.Wait() -} - -func TestPeerEventsTimeout(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - _, err := sim.AddNodes(2) - if err != nil { - t.Fatal(err) - } - - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) - defer cancel() - events := sim.PeerEvents(ctx, sim.NodeIDs()) - - done := make(chan struct{}) - errC := make(chan error) - go func() { - for e := range events { - if e.Error == context.Canceled { - return - } - if e.Error == context.DeadlineExceeded { - close(done) - return - } else { - errC <- e.Error - } - } - }() - - select { - case <-time.After(time.Second): - t.Fatal("no context deadline received") - case err := <-errC: - t.Fatal(err) - case <-done: - // all good, context deadline detected - } -} diff --git a/swarm/network/simulation/example_test.go b/swarm/network/simulation/example_test.go deleted file mode 100644 index 9d14929795..0000000000 --- a/swarm/network/simulation/example_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation_test - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" -) - -// Every node can have a Kademlia associated using the node bucket under -// BucketKeyKademlia key. This allows to use WaitTillHealthy to block until -// all nodes have the their Kademlias healthy. -func ExampleSimulation_WaitTillHealthy() { - - sim := simulation.New(map[string]simulation.ServiceFunc{ - "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) - hp := network.NewHiveParams() - hp.Discovery = false - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - // store kademlia in node's bucket under BucketKeyKademlia - // so that it can be found by WaitTillHealthy method. - b.Store(simulation.BucketKeyKademlia, kad) - return network.NewBzz(config, kad, nil, nil, nil), nil, nil - }, - }) - defer sim.Close() - - _, err := sim.AddNodesAndConnectRing(10) - if err != nil { - // handle error properly... - panic(err) - } - - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - ill, err := sim.WaitTillHealthy(ctx) - if err != nil { - // inspect the latest detected not healthy kademlias - for id, kad := range ill { - fmt.Println("Node", id) - fmt.Println(kad.String()) - } - // handle error... - } - - // continue with the test - -} - -// Watch all peer events in the simulation network, buy receiving from a channel. -func ExampleSimulation_PeerEvents() { - sim := simulation.New(nil) - defer sim.Close() - - events := sim.PeerEvents(context.Background(), sim.NodeIDs()) - - go func() { - for e := range events { - if e.Error != nil { - log.Error("peer event", "err", e.Error) - continue - } - log.Info("peer event", "node", e.NodeID, "peer", e.PeerID, "type", e.Event.Type) - } - }() -} - -// Detect when a nodes drop a peer. -func ExampleSimulation_PeerEvents_disconnections() { - sim := simulation.New(nil) - defer sim.Close() - - disconnections := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Drop(), - ) - - go func() { - for d := range disconnections { - if d.Error != nil { - log.Error("peer drop", "err", d.Error) - continue - } - log.Warn("peer drop", "node", d.NodeID, "peer", d.PeerID) - } - }() -} - -// Watch multiple types of events or messages. In this case, they differ only -// by MsgCode, but filters can be set for different types or protocols, too. -func ExampleSimulation_PeerEvents_multipleFilters() { - sim := simulation.New(nil) - defer sim.Close() - - msgs := sim.PeerEvents( - context.Background(), - sim.NodeIDs(), - // Watch when bzz messages 1 and 4 are received. - simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(1), - simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("bzz").MsgCode(4), - ) - - go func() { - for m := range msgs { - if m.Error != nil { - log.Error("bzz message", "err", m.Error) - continue - } - log.Info("bzz message", "node", m.NodeID, "peer", m.PeerID) - } - }() -} diff --git a/swarm/network/simulation/http.go b/swarm/network/simulation/http.go deleted file mode 100644 index 69ae3baec2..0000000000 --- a/swarm/network/simulation/http.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "fmt" - "net/http" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/simulations" -) - -// Package defaults. -var ( - DefaultHTTPSimAddr = ":8888" -) - -//WithServer implements the builder pattern constructor for Simulation to -//start with a HTTP server -func (s *Simulation) WithServer(addr string) *Simulation { - //assign default addr if nothing provided - if addr == "" { - addr = DefaultHTTPSimAddr - } - log.Info(fmt.Sprintf("Initializing simulation server on %s...", addr)) - //initialize the HTTP server - s.handler = simulations.NewServer(s.Net) - s.runC = make(chan struct{}) - //add swarm specific routes to the HTTP server - s.addSimulationRoutes() - s.httpSrv = &http.Server{ - Addr: addr, - Handler: s.handler, - } - go func() { - err := s.httpSrv.ListenAndServe() - if err != nil { - log.Error("Error starting the HTTP server", "error", err) - } - }() - return s -} - -//register additional HTTP routes -func (s *Simulation) addSimulationRoutes() { - s.handler.POST("/runsim", s.RunSimulation) -} - -// RunSimulation is the actual POST endpoint runner -func (s *Simulation) RunSimulation(w http.ResponseWriter, req *http.Request) { - log.Debug("RunSimulation endpoint running") - s.runC <- struct{}{} - w.WriteHeader(http.StatusOK) -} diff --git a/swarm/network/simulation/http_test.go b/swarm/network/simulation/http_test.go deleted file mode 100644 index dffd03a032..0000000000 --- a/swarm/network/simulation/http_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "fmt" - "net/http" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -func TestSimulationWithHTTPServer(t *testing.T) { - log.Debug("Init simulation") - - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - - sim := New( - map[string]ServiceFunc{ - "noop": func(_ *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - return newNoopService(), nil, nil - }, - }).WithServer(DefaultHTTPSimAddr) - defer sim.Close() - log.Debug("Done.") - - _, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - log.Debug("Starting sim round and let it time out...") - //first test that running without sending to the channel will actually - //block the simulation, so let it time out - result := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { - log.Debug("Just start the sim without any action and wait for the timeout") - //ensure with a Sleep that simulation doesn't terminate before the timeout - time.Sleep(2 * time.Second) - return nil - }) - - if result.Error != nil { - if result.Error.Error() == "context deadline exceeded" { - log.Debug("Expected timeout error received") - } else { - t.Fatal(result.Error) - } - } - - //now run it again and send the expected signal on the waiting channel, - //then close the simulation - log.Debug("Starting sim round and wait for frontend signal...") - //this time the timeout should be long enough so that it doesn't kick in too early - ctx, cancel2 := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel2() - errC := make(chan error, 1) - go triggerSimulationRun(t, errC) - result = sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { - log.Debug("This run waits for the run signal from `frontend`...") - //ensure with a Sleep that simulation doesn't terminate before the signal is received - time.Sleep(2 * time.Second) - return nil - }) - if result.Error != nil { - t.Fatal(result.Error) - } - if err := <-errC; err != nil { - t.Fatal(err) - } - log.Debug("Test terminated successfully") -} - -func triggerSimulationRun(t *testing.T, errC chan error) { - //We need to first wait for the sim HTTP server to start running... - time.Sleep(2 * time.Second) - //then we can send the signal - - log.Debug("Sending run signal to simulation: POST /runsim...") - resp, err := http.Post(fmt.Sprintf("http://localhost%s/runsim", DefaultHTTPSimAddr), "application/json", nil) - if err != nil { - errC <- fmt.Errorf("Request failed: %v", err) - return - } - log.Debug("Signal sent") - if resp.StatusCode != http.StatusOK { - errC <- fmt.Errorf("err %s", resp.Status) - return - } - errC <- resp.Body.Close() -} diff --git a/swarm/network/simulation/kademlia.go b/swarm/network/simulation/kademlia.go deleted file mode 100644 index 00e870a070..0000000000 --- a/swarm/network/simulation/kademlia.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "encoding/binary" - "encoding/hex" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/swarm/network" -) - -// BucketKeyKademlia is the key to be used for storing the kademlia -// instance for particular node, usually inside the ServiceFunc function. -var BucketKeyKademlia BucketKey = "kademlia" - -// WaitTillHealthy is blocking until the health of all kademlias is true. -// If error is not nil, a map of kademlia that was found not healthy is returned. -// TODO: Check correctness since change in kademlia depth calculation logic -func (s *Simulation) WaitTillHealthy(ctx context.Context) (ill map[enode.ID]*network.Kademlia, err error) { - // Prepare PeerPot map for checking Kademlia health - var ppmap map[string]*network.PeerPot - kademlias := s.kademlias() - addrs := make([][]byte, 0, len(kademlias)) - // TODO verify that all kademlias have same params - for _, k := range kademlias { - addrs = append(addrs, k.BaseAddr()) - } - ppmap = network.NewPeerPotMap(s.neighbourhoodSize, addrs) - - // Wait for healthy Kademlia on every node before checking files - ticker := time.NewTicker(200 * time.Millisecond) - defer ticker.Stop() - - ill = make(map[enode.ID]*network.Kademlia) - for { - select { - case <-ctx.Done(): - return ill, ctx.Err() - case <-ticker.C: - for k := range ill { - delete(ill, k) - } - log.Debug("kademlia health check", "addr count", len(addrs), "kad len", len(kademlias)) - for id, k := range kademlias { - //PeerPot for this node - addr := common.Bytes2Hex(k.BaseAddr()) - pp := ppmap[addr] - //call Healthy RPC - h := k.GetHealthInfo(pp) - //print info - log.Debug(k.String()) - log.Debug("kademlia", "connectNN", h.ConnectNN, "knowNN", h.KnowNN) - log.Debug("kademlia", "health", h.ConnectNN && h.KnowNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) - log.Debug("kademlia", "ill condition", !h.ConnectNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) - if !h.Healthy() { - ill[id] = k - } - } - if len(ill) == 0 { - return nil, nil - } - } - } -} - -// kademlias returns all Kademlia instances that are set -// in simulation bucket. -func (s *Simulation) kademlias() (ks map[enode.ID]*network.Kademlia) { - items := s.UpNodesItems(BucketKeyKademlia) - log.Debug("kademlia len items", "len", len(items)) - ks = make(map[enode.ID]*network.Kademlia, len(items)) - for id, v := range items { - k, ok := v.(*network.Kademlia) - if !ok { - continue - } - ks[id] = k - } - return ks -} - -// WaitTillSnapshotRecreated is blocking until all the connections specified -// in the snapshot are registered in the kademlia. -// It differs from WaitTillHealthy, which waits only until all the kademlias are -// healthy (it might happen even before all the connections are established). -func (s *Simulation) WaitTillSnapshotRecreated(ctx context.Context, snap *simulations.Snapshot) error { - expected := getSnapshotConnections(snap.Conns) - ticker := time.NewTicker(150 * time.Millisecond) - defer ticker.Stop() - - for { - select { - case <-ctx.Done(): - return ctx.Err() - case <-ticker.C: - actual := s.getActualConnections() - if isAllDeployed(expected, actual) { - return nil - } - } - } -} - -func (s *Simulation) getActualConnections() (res []uint64) { - kademlias := s.kademlias() - for base, k := range kademlias { - k.EachConn(base[:], 256, func(p *network.Peer, _ int) bool { - res = append(res, getConnectionHash(base, p.ID())) - return true - }) - } - - // only list those connections that appear twice (both peers should recognize connection as active) - res = removeDuplicatesAndSingletons(res) - return res -} - -func getSnapshotConnections(conns []simulations.Conn) (res []uint64) { - for _, c := range conns { - res = append(res, getConnectionHash(c.One, c.Other)) - } - return res -} - -// returns an integer connection identifier (similar to 8-byte hash) -func getConnectionHash(a, b enode.ID) uint64 { - var h [8]byte - for i := 0; i < 8; i++ { - h[i] = a[i] ^ b[i] - } - res := binary.LittleEndian.Uint64(h[:]) - return res -} - -// returns true if all connections in expected are listed in actual -func isAllDeployed(expected []uint64, actual []uint64) bool { - if len(expected) == 0 { - return true - } - - exp := make([]uint64, len(expected)) - copy(exp, expected) - for _, c := range actual { - // remove value c from exp - for i := 0; i < len(exp); i++ { - if exp[i] == c { - exp = removeListElement(exp, i) - if len(exp) == 0 { - return true - } - } - } - } - return len(exp) == 0 -} - -func removeListElement(arr []uint64, i int) []uint64 { - last := len(arr) - 1 - arr[i] = arr[last] - arr = arr[:last] - return arr -} - -func removeDuplicatesAndSingletons(arr []uint64) []uint64 { - for i := 0; i < len(arr); { - found := false - for j := i + 1; j < len(arr); j++ { - if arr[i] == arr[j] { - arr = removeListElement(arr, j) // remove duplicate - found = true - break - } - } - - if found { - i++ - } else { - arr = removeListElement(arr, i) // remove singleton - } - } - - return arr -} diff --git a/swarm/network/simulation/kademlia_test.go b/swarm/network/simulation/kademlia_test.go deleted file mode 100644 index af50aacfd9..0000000000 --- a/swarm/network/simulation/kademlia_test.go +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" -) - -/* - TestWaitTillHealthy tests that we indeed get a healthy network after we wait for it. - For this to be tested, a bit of a snake tail bite needs to happen: - * First we create a first simulation - * Run it as nodes connected in a ring - * Wait until the network is healthy - * Then we create a snapshot - * With this snapshot we create a new simulation - * This simulation is expected to have a healthy configuration, as it uses the snapshot - * Thus we just iterate all nodes and check that their kademlias are healthy - * If all kademlias are healthy, the test succeeded, otherwise it failed -*/ -func TestWaitTillHealthy(t *testing.T) { - t.Skip("this test is flaky; disabling till underlying problem is solved") - testNodesNum := 10 - - // create the first simulation - sim := New(createSimServiceMap(true)) - - // connect and... - nodeIDs, err := sim.AddNodesAndConnectRing(testNodesNum) - if err != nil { - t.Fatal(err) - } - - // array of all overlay addresses - var addrs [][]byte - // iterate once to be able to build the peer map - for _, node := range nodeIDs { - //get the kademlia overlay address from this ID - a := node.Bytes() - //append it to the array of all overlay addresses - addrs = append(addrs, a) - } - // build a PeerPot only once - pp := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) - - ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) - defer cancel() - - // ...wait until healthy - ill, err := sim.WaitTillHealthy(ctx) - if err != nil { - for id, kad := range ill { - t.Log("Node", id) - t.Log(kad.String()) - } - t.Fatal(err) - } - - // now create a snapshot of this network - snap, err := sim.Net.Snapshot() - if err != nil { - t.Fatal(err) - } - - // close the initial simulation - sim.Close() - // create a control simulation - controlSim := New(createSimServiceMap(false)) - defer controlSim.Close() - - // load the snapshot into this control simulation - err = controlSim.Net.Load(snap) - if err != nil { - t.Fatal(err) - } - _, err = controlSim.WaitTillHealthy(ctx) - if err != nil { - t.Fatal(err) - } - - for _, node := range nodeIDs { - // ...get its kademlia - item, ok := controlSim.NodeItem(node, BucketKeyKademlia) - if !ok { - t.Fatal("No kademlia bucket item") - } - kad := item.(*network.Kademlia) - // get its base address - kid := common.Bytes2Hex(kad.BaseAddr()) - - //get the health info - info := kad.GetHealthInfo(pp[kid]) - log.Trace("Health info", "info", info) - // check that it is healthy - healthy := info.Healthy() - if !healthy { - t.Fatalf("Expected node %v of control simulation to be healthy, but it is not, unhealthy kademlias: %v", node, kad.String()) - } - } -} - -// createSimServiceMap returns the services map -// this function will create the sim services with or without discovery enabled -// based on the flag passed -func createSimServiceMap(discovery bool) map[string]ServiceFunc { - return map[string]ServiceFunc{ - "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) - hp := network.NewHiveParams() - hp.Discovery = discovery - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - // store kademlia in node's bucket under BucketKeyKademlia - // so that it can be found by WaitTillHealthy method. - b.Store(BucketKeyKademlia, kad) - return network.NewBzz(config, kad, nil, nil, nil), nil, nil - }, - } -} - -// TestWaitTillSnapshotRecreated tests that we indeed have a network -// configuration specified in the snapshot file, after we wait for it. -// -// First we create a first simulation -// Run it as nodes connected in a ring -// Wait until the network is healthy -// Then we create a snapshot -// With this snapshot we create a new simulation -// Call WaitTillSnapshotRecreated() function and wait until it returns -// Iterate the nodes and check if all the connections are successfully recreated -func TestWaitTillSnapshotRecreated(t *testing.T) { - t.Skip("test is flaky. disabling until underlying problem is addressed") - var err error - sim := New(createSimServiceMap(true)) - _, err = sim.AddNodesAndConnectRing(16) - if err != nil { - t.Fatal(err) - } - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - _, err = sim.WaitTillHealthy(ctx) - if err != nil { - t.Fatal(err) - } - - originalConnections := sim.getActualConnections() - snap, err := sim.Net.Snapshot() - sim.Close() - if err != nil { - t.Fatal(err) - } - - controlSim := New(createSimServiceMap(false)) - defer controlSim.Close() - err = controlSim.Net.Load(snap) - if err != nil { - t.Fatal(err) - } - err = controlSim.WaitTillSnapshotRecreated(ctx, snap) - if err != nil { - t.Fatal(err) - } - controlConnections := controlSim.getActualConnections() - - for _, c := range originalConnections { - if !exist(controlConnections, c) { - t.Fatal("connection was not recreated") - } - } -} - -// exist returns true if val is found in arr -func exist(arr []uint64, val uint64) bool { - for _, c := range arr { - if c == val { - return true - } - } - return false -} - -func TestRemoveDuplicatesAndSingletons(t *testing.T) { - singletons := []uint64{ - 0x3c127c6f6cb026b0, - 0x0f45190d72e71fc5, - 0xb0184c02449e0bb6, - 0xa85c7b84239c54d3, - 0xe3b0c44298fc1c14, - 0x9afbf4c8996fb924, - 0x27ae41e4649b934c, - 0xa495991b7852b855, - } - - doubles := []uint64{ - 0x1b879f878de7fc7a, - 0xc6791470521bdab4, - 0xdd34b0ee39bbccc6, - 0x4d904fbf0f31da10, - 0x6403c2560432c8f8, - 0x18954e33cf3ad847, - 0x90db00e98dc7a8a6, - 0x92886b0dfcc1809b, - } - - var arr []uint64 - arr = append(arr, doubles...) - arr = append(arr, singletons...) - arr = append(arr, doubles...) - arr = removeDuplicatesAndSingletons(arr) - - for _, i := range singletons { - if exist(arr, i) { - t.Fatalf("singleton not removed: %d", i) - } - } - - for _, i := range doubles { - if !exist(arr, i) { - t.Fatalf("wrong value removed: %d", i) - } - } - - for j := 0; j < len(doubles); j++ { - v := doubles[j] + singletons[j] - if exist(arr, v) { - t.Fatalf("non-existing value found, index: %d", j) - } - } -} - -func TestIsAllDeployed(t *testing.T) { - a := []uint64{ - 0x3c127c6f6cb026b0, - 0x0f45190d72e71fc5, - 0xb0184c02449e0bb6, - 0xa85c7b84239c54d3, - 0xe3b0c44298fc1c14, - 0x9afbf4c8996fb924, - 0x27ae41e4649b934c, - 0xa495991b7852b855, - } - - b := []uint64{ - 0x1b879f878de7fc7a, - 0xc6791470521bdab4, - 0xdd34b0ee39bbccc6, - 0x4d904fbf0f31da10, - 0x6403c2560432c8f8, - 0x18954e33cf3ad847, - 0x90db00e98dc7a8a6, - 0x92886b0dfcc1809b, - } - - var c []uint64 - c = append(c, a...) - c = append(c, b...) - - if !isAllDeployed(a, c) { - t.Fatal("isAllDeployed failed") - } - - if !isAllDeployed(b, c) { - t.Fatal("isAllDeployed failed") - } - - if isAllDeployed(c, a) { - t.Fatal("isAllDeployed failed: false positive") - } - - if isAllDeployed(c, b) { - t.Fatal("isAllDeployed failed: false positive") - } - - c = c[2:] - - if isAllDeployed(a, c) { - t.Fatal("isAllDeployed failed: false positive") - } - - if !isAllDeployed(b, c) { - t.Fatal("isAllDeployed failed") - } -} diff --git a/swarm/network/simulation/node.go b/swarm/network/simulation/node.go deleted file mode 100644 index f66b0afd0d..0000000000 --- a/swarm/network/simulation/node.go +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "bytes" - "context" - "crypto/ecdsa" - "encoding/json" - "errors" - "io/ioutil" - "math/rand" - "os" - "sync" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" -) - -var ( - BucketKeyBzzPrivateKey BucketKey = "bzzprivkey" -) - -// NodeIDs returns NodeIDs for all nodes in the network. -func (s *Simulation) NodeIDs() (ids []enode.ID) { - nodes := s.Net.GetNodes() - ids = make([]enode.ID, len(nodes)) - for i, node := range nodes { - ids[i] = node.ID() - } - return ids -} - -// UpNodeIDs returns NodeIDs for nodes that are up in the network. -func (s *Simulation) UpNodeIDs() (ids []enode.ID) { - nodes := s.Net.GetNodes() - for _, node := range nodes { - if node.Up() { - ids = append(ids, node.ID()) - } - } - return ids -} - -// DownNodeIDs returns NodeIDs for nodes that are stopped in the network. -func (s *Simulation) DownNodeIDs() (ids []enode.ID) { - nodes := s.Net.GetNodes() - for _, node := range nodes { - if !node.Up() { - ids = append(ids, node.ID()) - } - } - return ids -} - -// AddNodeOption defines the option that can be passed -// to Simulation.AddNode method. -type AddNodeOption func(*adapters.NodeConfig) - -// AddNodeWithMsgEvents sets the EnableMsgEvents option -// to NodeConfig. -func AddNodeWithMsgEvents(enable bool) AddNodeOption { - return func(o *adapters.NodeConfig) { - o.EnableMsgEvents = enable - } -} - -// AddNodeWithService specifies a service that should be -// started on a node. This option can be repeated as variadic -// argument toe AddNode and other add node related methods. -// If AddNodeWithService is not specified, all services will be started. -func AddNodeWithService(serviceName string) AddNodeOption { - return func(o *adapters.NodeConfig) { - o.Services = append(o.Services, serviceName) - } -} - -// AddNode creates a new node with random configuration, -// applies provided options to the config and adds the node to network. -// By default all services will be started on a node. If one or more -// AddNodeWithService option are provided, only specified services will be started. -func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) { - conf := adapters.RandomNodeConfig() - for _, o := range opts { - o(conf) - } - if len(conf.Services) == 0 { - conf.Services = s.serviceNames - } - - // add ENR records to the underlying node - // most importantly the bzz overlay address - // - // for now we have no way of setting bootnodes or lightnodes in sims - // so we just let them be set to false - // they should perhaps be possible to override them with AddNodeOption - bzzPrivateKey, err := BzzPrivateKeyFromConfig(conf) - if err != nil { - return enode.ID{}, err - } - - enodeParams := &network.EnodeParams{ - PrivateKey: bzzPrivateKey, - } - record, err := network.NewEnodeRecord(enodeParams) - conf.Record = *record - - // Add the bzz address to the node config - node, err := s.Net.NewNodeWithConfig(conf) - if err != nil { - return id, err - } - s.buckets[node.ID()] = new(sync.Map) - s.SetNodeItem(node.ID(), BucketKeyBzzPrivateKey, bzzPrivateKey) - - return node.ID(), s.Net.Start(node.ID()) -} - -// AddNodes creates new nodes with random configurations, -// applies provided options to the config and adds nodes to network. -func (s *Simulation) AddNodes(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { - ids = make([]enode.ID, 0, count) - for i := 0; i < count; i++ { - id, err := s.AddNode(opts...) - if err != nil { - return nil, err - } - ids = append(ids, id) - } - return ids, nil -} - -// AddNodesAndConnectFull is a helpper method that combines -// AddNodes and ConnectNodesFull. Only new nodes will be connected. -func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { - if count < 2 { - return nil, errors.New("count of nodes must be at least 2") - } - ids, err = s.AddNodes(count, opts...) - if err != nil { - return nil, err - } - err = s.Net.ConnectNodesFull(ids) - if err != nil { - return nil, err - } - return ids, nil -} - -// AddNodesAndConnectChain is a helpper method that combines -// AddNodes and ConnectNodesChain. The chain will be continued from the last -// added node, if there is one in simulation using ConnectToLastNode method. -func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { - if count < 2 { - return nil, errors.New("count of nodes must be at least 2") - } - id, err := s.AddNode(opts...) - if err != nil { - return nil, err - } - err = s.Net.ConnectToLastNode(id) - if err != nil { - return nil, err - } - ids, err = s.AddNodes(count-1, opts...) - if err != nil { - return nil, err - } - ids = append([]enode.ID{id}, ids...) - err = s.Net.ConnectNodesChain(ids) - if err != nil { - return nil, err - } - return ids, nil -} - -// AddNodesAndConnectRing is a helpper method that combines -// AddNodes and ConnectNodesRing. -func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { - if count < 2 { - return nil, errors.New("count of nodes must be at least 2") - } - ids, err = s.AddNodes(count, opts...) - if err != nil { - return nil, err - } - err = s.Net.ConnectNodesRing(ids) - if err != nil { - return nil, err - } - return ids, nil -} - -// AddNodesAndConnectStar is a helpper method that combines -// AddNodes and ConnectNodesStar. -func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { - if count < 2 { - return nil, errors.New("count of nodes must be at least 2") - } - ids, err = s.AddNodes(count, opts...) - if err != nil { - return nil, err - } - err = s.Net.ConnectNodesStar(ids[1:], ids[0]) - if err != nil { - return nil, err - } - return ids, nil -} - -// UploadSnapshot uploads a snapshot to the simulation -// This method tries to open the json file provided, applies the config to all nodes -// and then loads the snapshot into the Simulation network -func (s *Simulation) UploadSnapshot(ctx context.Context, snapshotFile string, opts ...AddNodeOption) error { - f, err := os.Open(snapshotFile) - if err != nil { - return err - } - - jsonbyte, err := ioutil.ReadAll(f) - f.Close() - if err != nil { - return err - } - var snap simulations.Snapshot - if err := json.Unmarshal(jsonbyte, &snap); err != nil { - return err - } - - //the snapshot probably has the property EnableMsgEvents not set - //set it to true (we need this to wait for messages before uploading) - for i := range snap.Nodes { - snap.Nodes[i].Node.Config.EnableMsgEvents = true - snap.Nodes[i].Node.Config.Services = s.serviceNames - for _, o := range opts { - o(snap.Nodes[i].Node.Config) - } - } - - if err := s.Net.Load(&snap); err != nil { - return err - } - return s.WaitTillSnapshotRecreated(ctx, &snap) -} - -// StartNode starts a node by NodeID. -func (s *Simulation) StartNode(id enode.ID) (err error) { - return s.Net.Start(id) -} - -// StartRandomNode starts a random node. -func (s *Simulation) StartRandomNode() (id enode.ID, err error) { - n := s.Net.GetRandomDownNode() - if n == nil { - return id, ErrNodeNotFound - } - return n.ID(), s.Net.Start(n.ID()) -} - -// StartRandomNodes starts random nodes. -func (s *Simulation) StartRandomNodes(count int) (ids []enode.ID, err error) { - ids = make([]enode.ID, 0, count) - for i := 0; i < count; i++ { - n := s.Net.GetRandomDownNode() - if n == nil { - return nil, ErrNodeNotFound - } - err = s.Net.Start(n.ID()) - if err != nil { - return nil, err - } - ids = append(ids, n.ID()) - } - return ids, nil -} - -// StopNode stops a node by NodeID. -func (s *Simulation) StopNode(id enode.ID) (err error) { - return s.Net.Stop(id) -} - -// StopRandomNode stops a random node. -func (s *Simulation) StopRandomNode() (id enode.ID, err error) { - n := s.Net.GetRandomUpNode() - if n == nil { - return id, ErrNodeNotFound - } - return n.ID(), s.Net.Stop(n.ID()) -} - -// StopRandomNodes stops random nodes. -func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error) { - ids = make([]enode.ID, 0, count) - for i := 0; i < count; i++ { - n := s.Net.GetRandomUpNode() - if n == nil { - return nil, ErrNodeNotFound - } - err = s.Net.Stop(n.ID()) - if err != nil { - return nil, err - } - ids = append(ids, n.ID()) - } - return ids, nil -} - -// seed the random generator for Simulation.randomNode. -func init() { - rand.Seed(time.Now().UnixNano()) -} - -// derive a private key for swarm for the node key -// returns the private key used to generate the bzz key -func BzzPrivateKeyFromConfig(conf *adapters.NodeConfig) (*ecdsa.PrivateKey, error) { - // pad the seed key some arbitrary data as ecdsa.GenerateKey takes 40 bytes seed data - privKeyBuf := append(crypto.FromECDSA(conf.PrivateKey), []byte{0x62, 0x7a, 0x7a, 0x62, 0x7a, 0x7a, 0x62, 0x7a}...) - bzzPrivateKey, err := ecdsa.GenerateKey(crypto.S256(), bytes.NewReader(privKeyBuf)) - if err != nil { - return nil, err - } - return bzzPrivateKey, nil -} diff --git a/swarm/network/simulation/node_test.go b/swarm/network/simulation/node_test.go deleted file mode 100644 index e1e20a0f13..0000000000 --- a/swarm/network/simulation/node_test.go +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" -) - -func TestUpDownNodeIDs(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodes(10) - if err != nil { - t.Fatal(err) - } - - gotIDs := sim.NodeIDs() - - if !equalNodeIDs(ids, gotIDs) { - t.Error("returned nodes are not equal to added ones") - } - - stoppedIDs, err := sim.StopRandomNodes(3) - if err != nil { - t.Fatal(err) - } - - gotIDs = sim.UpNodeIDs() - - for _, id := range gotIDs { - if !sim.Net.GetNode(id).Up() { - t.Errorf("node %s should not be down", id) - } - } - - if !equalNodeIDs(ids, append(gotIDs, stoppedIDs...)) { - t.Error("returned nodes are not equal to added ones") - } - - gotIDs = sim.DownNodeIDs() - - for _, id := range gotIDs { - if sim.Net.GetNode(id).Up() { - t.Errorf("node %s should not be up", id) - } - } - - if !equalNodeIDs(stoppedIDs, gotIDs) { - t.Error("returned nodes are not equal to the stopped ones") - } -} - -func equalNodeIDs(one, other []enode.ID) bool { - if len(one) != len(other) { - return false - } - var count int - for _, a := range one { - var found bool - for _, b := range other { - if a == b { - found = true - break - } - } - if found { - count++ - } else { - return false - } - } - return count == len(one) -} - -func TestAddNode(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - id, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - n := sim.Net.GetNode(id) - if n == nil { - t.Fatal("node not found") - } - - if !n.Up() { - t.Error("node not started") - } -} - -func TestAddNodeWithMsgEvents(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - id, err := sim.AddNode(AddNodeWithMsgEvents(true)) - if err != nil { - t.Fatal(err) - } - - if !sim.Net.GetNode(id).Config.EnableMsgEvents { - t.Error("EnableMsgEvents is false") - } - - id, err = sim.AddNode(AddNodeWithMsgEvents(false)) - if err != nil { - t.Fatal(err) - } - - if sim.Net.GetNode(id).Config.EnableMsgEvents { - t.Error("EnableMsgEvents is true") - } -} - -func TestAddNodeWithService(t *testing.T) { - sim := New(map[string]ServiceFunc{ - "noop1": noopServiceFunc, - "noop2": noopServiceFunc, - }) - defer sim.Close() - - id, err := sim.AddNode(AddNodeWithService("noop1")) - if err != nil { - t.Fatal(err) - } - - n := sim.Net.GetNode(id).Node.(*adapters.SimNode) - if n.Service("noop1") == nil { - t.Error("service noop1 not found on node") - } - if n.Service("noop2") != nil { - t.Error("service noop2 should not be found on node") - } -} - -func TestAddNodeMultipleServices(t *testing.T) { - sim := New(map[string]ServiceFunc{ - "noop1": noopServiceFunc, - "noop2": noopService2Func, - }) - defer sim.Close() - - id, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - n := sim.Net.GetNode(id).Node.(*adapters.SimNode) - if n.Service("noop1") == nil { - t.Error("service noop1 not found on node") - } - if n.Service("noop2") == nil { - t.Error("service noop2 not found on node") - } -} - -func TestAddNodeDuplicateServiceError(t *testing.T) { - sim := New(map[string]ServiceFunc{ - "noop1": noopServiceFunc, - "noop2": noopServiceFunc, - }) - defer sim.Close() - - wantErr := "duplicate service: *simulation.noopService" - _, err := sim.AddNode() - if err.Error() != wantErr { - t.Errorf("got error %q, want %q", err, wantErr) - } -} - -func TestAddNodes(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - nodesCount := 12 - - ids, err := sim.AddNodes(nodesCount) - if err != nil { - t.Fatal(err) - } - - count := len(ids) - if count != nodesCount { - t.Errorf("expected %v nodes, got %v", nodesCount, count) - } - - count = len(sim.Net.GetNodes()) - if count != nodesCount { - t.Errorf("expected %v nodes, got %v", nodesCount, count) - } -} - -func TestAddNodesAndConnectFull(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - n := 12 - - ids, err := sim.AddNodesAndConnectFull(n) - if err != nil { - t.Fatal(err) - } - - simulations.VerifyFull(t, sim.Net, ids) -} - -func TestAddNodesAndConnectChain(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - _, err := sim.AddNodesAndConnectChain(12) - if err != nil { - t.Fatal(err) - } - - // add another set of nodes to test - // if two chains are connected - _, err = sim.AddNodesAndConnectChain(7) - if err != nil { - t.Fatal(err) - } - - simulations.VerifyChain(t, sim.Net, sim.UpNodeIDs()) -} - -func TestAddNodesAndConnectRing(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodesAndConnectRing(12) - if err != nil { - t.Fatal(err) - } - - simulations.VerifyRing(t, sim.Net, ids) -} - -func TestAddNodesAndConnectStar(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - ids, err := sim.AddNodesAndConnectStar(12) - if err != nil { - t.Fatal(err) - } - - simulations.VerifyStar(t, sim.Net, ids, 0) -} - -//To test that uploading a snapshot works -func TestUploadSnapshot(t *testing.T) { - log.Debug("Creating simulation") - s := New(map[string]ServiceFunc{ - "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) - hp := network.NewHiveParams() - hp.Discovery = false - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - b.Store(BucketKeyKademlia, kad) - return network.NewBzz(config, kad, nil, nil, nil), nil, nil - }, - }) - defer s.Close() - - nodeCount := 16 - log.Debug("Uploading snapshot") - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - err := s.UploadSnapshot(ctx, fmt.Sprintf("../stream/testing/snapshot_%d.json", nodeCount)) - if err != nil { - t.Fatalf("Error uploading snapshot to simulation network: %v", err) - } - - log.Debug("Starting simulation...") - s.Run(ctx, func(ctx context.Context, sim *Simulation) error { - log.Debug("Checking") - nodes := sim.UpNodeIDs() - if len(nodes) != nodeCount { - t.Fatal("Simulation network node number doesn't match snapshot node number") - } - return nil - }) - log.Debug("Done.") -} - -func TestStartStopNode(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - id, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - n := sim.Net.GetNode(id) - if n == nil { - t.Fatal("node not found") - } - if !n.Up() { - t.Error("node not started") - } - - err = sim.StopNode(id) - if err != nil { - t.Fatal(err) - } - if n.Up() { - t.Error("node not stopped") - } - - waitForPeerEventPropagation() - - err = sim.StartNode(id) - if err != nil { - t.Fatal(err) - } - if !n.Up() { - t.Error("node not started") - } -} - -func TestStartStopRandomNode(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - _, err := sim.AddNodes(3) - if err != nil { - t.Fatal(err) - } - - id, err := sim.StopRandomNode() - if err != nil { - t.Fatal(err) - } - - n := sim.Net.GetNode(id) - if n == nil { - t.Fatal("node not found") - } - if n.Up() { - t.Error("node not stopped") - } - - id2, err := sim.StopRandomNode() - if err != nil { - t.Fatal(err) - } - - waitForPeerEventPropagation() - - idStarted, err := sim.StartRandomNode() - if err != nil { - t.Fatal(err) - } - - if idStarted != id && idStarted != id2 { - t.Error("unexpected started node ID") - } -} - -func TestStartStopRandomNodes(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - _, err := sim.AddNodes(10) - if err != nil { - t.Fatal(err) - } - - ids, err := sim.StopRandomNodes(3) - if err != nil { - t.Fatal(err) - } - - for _, id := range ids { - n := sim.Net.GetNode(id) - if n == nil { - t.Fatal("node not found") - } - if n.Up() { - t.Error("node not stopped") - } - } - - waitForPeerEventPropagation() - - ids, err = sim.StartRandomNodes(2) - if err != nil { - t.Fatal(err) - } - - for _, id := range ids { - n := sim.Net.GetNode(id) - if n == nil { - t.Fatal("node not found") - } - if !n.Up() { - t.Error("node not started") - } - } -} - -func waitForPeerEventPropagation() { - // Sleep here to ensure that Network.watchPeerEvents defer function - // has set the `node.Up() = false` before we start the node again. - // - // The same node is stopped and started again, and upon start - // watchPeerEvents is started in a goroutine. If the node is stopped - // and then very quickly started, that goroutine may be scheduled later - // then start and force `node.Up() = false` in its defer function. - // This will make this test unreliable. - time.Sleep(1 * time.Second) -} diff --git a/swarm/network/simulation/service.go b/swarm/network/simulation/service.go deleted file mode 100644 index 0ac8149a94..0000000000 --- a/swarm/network/simulation/service.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -// Service returns a single Service by name on a particular node -// with provided id. -func (s *Simulation) Service(name string, id enode.ID) node.Service { - simNode, ok := s.Net.GetNode(id).Node.(*adapters.SimNode) - if !ok { - return nil - } - services := simNode.ServiceMap() - if len(services) == 0 { - return nil - } - return services[name] -} - -// RandomService returns a single Service by name on a -// randomly chosen node that is up. -func (s *Simulation) RandomService(name string) node.Service { - n := s.Net.GetRandomUpNode().Node.(*adapters.SimNode) - if n == nil { - return nil - } - return n.Service(name) -} - -// Services returns all services with a provided name -// from nodes that are up. -func (s *Simulation) Services(name string) (services map[enode.ID]node.Service) { - nodes := s.Net.GetNodes() - services = make(map[enode.ID]node.Service) - for _, node := range nodes { - if !node.Up() { - continue - } - simNode, ok := node.Node.(*adapters.SimNode) - if !ok { - continue - } - services[node.ID()] = simNode.Service(name) - } - return services -} diff --git a/swarm/network/simulation/service_test.go b/swarm/network/simulation/service_test.go deleted file mode 100644 index 23b0d86f24..0000000000 --- a/swarm/network/simulation/service_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "testing" -) - -func TestService(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - id, err := sim.AddNode() - if err != nil { - t.Fatal(err) - } - - _, ok := sim.Service("noop", id).(*noopService) - if !ok { - t.Fatalf("service is not of %T type", &noopService{}) - } - - _, ok = sim.RandomService("noop").(*noopService) - if !ok { - t.Fatalf("service is not of %T type", &noopService{}) - } - - _, ok = sim.Services("noop")[id].(*noopService) - if !ok { - t.Fatalf("service is not of %T type", &noopService{}) - } -} diff --git a/swarm/network/simulation/simulation.go b/swarm/network/simulation/simulation.go deleted file mode 100644 index 5787cafdae..0000000000 --- a/swarm/network/simulation/simulation.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "errors" - "net/http" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" -) - -// Common errors that are returned by functions in this package. -var ( - ErrNodeNotFound = errors.New("node not found") -) - -// Simulation provides methods on network, nodes and services -// to manage them. -type Simulation struct { - // Net is exposed as a way to access lower level functionalities - // of p2p/simulations.Network. - Net *simulations.Network - - serviceNames []string - cleanupFuncs []func() - buckets map[enode.ID]*sync.Map - shutdownWG sync.WaitGroup - done chan struct{} - mu sync.RWMutex - neighbourhoodSize int - - httpSrv *http.Server //attach a HTTP server via SimulationOptions - handler *simulations.Server //HTTP handler for the server - runC chan struct{} //channel where frontend signals it is ready -} - -// ServiceFunc is used in New to declare new service constructor. -// The first argument provides ServiceContext from the adapters package -// giving for example the access to NodeID. Second argument is the sync.Map -// where all "global" state related to the service should be kept. -// All cleanups needed for constructed service and any other constructed -// objects should ne provided in a single returned cleanup function. -// Returned cleanup function will be called by Close function -// after network shutdown. -type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) - -// New creates a new simulation instance -// Services map must have unique keys as service names and -// every ServiceFunc must return a node.Service of the unique type. -// This restriction is required by node.Node.Start() function -// which is used to start node.Service returned by ServiceFunc. -func New(services map[string]ServiceFunc) (s *Simulation) { - s = &Simulation{ - buckets: make(map[enode.ID]*sync.Map), - done: make(chan struct{}), - neighbourhoodSize: network.NewKadParams().NeighbourhoodSize, - } - - adapterServices := make(map[string]adapters.ServiceFunc, len(services)) - for name, serviceFunc := range services { - // Scope this variables correctly - // as they will be in the adapterServices[name] function accessed later. - name, serviceFunc := name, serviceFunc - s.serviceNames = append(s.serviceNames, name) - adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) { - s.mu.Lock() - defer s.mu.Unlock() - b, ok := s.buckets[ctx.Config.ID] - if !ok { - b = new(sync.Map) - } - service, cleanup, err := serviceFunc(ctx, b) - if err != nil { - return nil, err - } - if cleanup != nil { - s.cleanupFuncs = append(s.cleanupFuncs, cleanup) - } - s.buckets[ctx.Config.ID] = b - return service, nil - } - } - - s.Net = simulations.NewNetwork( - adapters.NewTCPAdapter(adapterServices), - &simulations.NetworkConfig{ID: "0"}, - ) - - return s -} - -// RunFunc is the function that will be called -// on Simulation.Run method call. -type RunFunc func(context.Context, *Simulation) error - -// Result is the returned value of Simulation.Run method. -type Result struct { - Duration time.Duration - Error error -} - -// Run calls the RunFunc function while taking care of -// cancellation provided through the Context. -func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) { - //if the option is set to run a HTTP server with the simulation, - //init the server and start it - start := time.Now() - if s.httpSrv != nil { - log.Info("Waiting for frontend to be ready...(send POST /runsim to HTTP server)") - //wait for the frontend to connect - select { - case <-s.runC: - case <-ctx.Done(): - return Result{ - Duration: time.Since(start), - Error: ctx.Err(), - } - } - log.Info("Received signal from frontend - starting simulation run.") - } - errc := make(chan error) - quit := make(chan struct{}) - defer close(quit) - go func() { - select { - case errc <- f(ctx, s): - case <-quit: - } - }() - var err error - select { - case <-ctx.Done(): - err = ctx.Err() - case err = <-errc: - } - return Result{ - Duration: time.Since(start), - Error: err, - } -} - -// Maximal number of parallel calls to cleanup functions on -// Simulation.Close. -var maxParallelCleanups = 10 - -// Close calls all cleanup functions that are returned by -// ServiceFunc, waits for all of them to finish and other -// functions that explicitly block shutdownWG -// (like Simulation.PeerEvents) and shuts down the network -// at the end. It is used to clean all resources from the -// simulation. -func (s *Simulation) Close() { - close(s.done) - - sem := make(chan struct{}, maxParallelCleanups) - s.mu.RLock() - cleanupFuncs := make([]func(), len(s.cleanupFuncs)) - for i, f := range s.cleanupFuncs { - if f != nil { - cleanupFuncs[i] = f - } - } - s.mu.RUnlock() - var cleanupWG sync.WaitGroup - for _, cleanup := range cleanupFuncs { - cleanupWG.Add(1) - sem <- struct{}{} - go func(cleanup func()) { - defer cleanupWG.Done() - defer func() { <-sem }() - - cleanup() - }(cleanup) - } - cleanupWG.Wait() - - if s.httpSrv != nil { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - err := s.httpSrv.Shutdown(ctx) - if err != nil { - log.Error("Error shutting down HTTP server!", "err", err) - } - close(s.runC) - } - - s.shutdownWG.Wait() - s.Net.Shutdown() -} - -// Done returns a channel that is closed when the simulation -// is closed by Close method. It is useful for signaling termination -// of all possible goroutines that are created within the test. -func (s *Simulation) Done() <-chan struct{} { - return s.done -} diff --git a/swarm/network/simulation/simulation_test.go b/swarm/network/simulation/simulation_test.go deleted file mode 100644 index 1d0338f593..0000000000 --- a/swarm/network/simulation/simulation_test.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package simulation - -import ( - "context" - "errors" - "flag" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/mattn/go-colorable" -) - -var ( - loglevel = flag.Int("loglevel", 2, "verbosity of logs") -) - -func init() { - flag.Parse() - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) -} - -// TestRun tests if Run method calls RunFunc and if it handles context properly. -func TestRun(t *testing.T) { - sim := New(noopServiceFuncMap) - defer sim.Close() - - t.Run("call", func(t *testing.T) { - expect := "something" - var got string - r := sim.Run(context.Background(), func(ctx context.Context, sim *Simulation) error { - got = expect - return nil - }) - - if r.Error != nil { - t.Errorf("unexpected error: %v", r.Error) - } - if got != expect { - t.Errorf("expected %q, got %q", expect, got) - } - }) - - t.Run("cancellation", func(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) - defer cancel() - - r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { - time.Sleep(time.Second) - return nil - }) - - if r.Error != context.DeadlineExceeded { - t.Errorf("unexpected error: %v", r.Error) - } - }) - - t.Run("context value and duration", func(t *testing.T) { - ctx := context.WithValue(context.Background(), "hey", "there") - sleep := 50 * time.Millisecond - - r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { - if ctx.Value("hey") != "there" { - return errors.New("expected context value not passed") - } - time.Sleep(sleep) - return nil - }) - - if r.Error != nil { - t.Errorf("unexpected error: %v", r.Error) - } - if r.Duration < sleep { - t.Errorf("reported run duration less then expected: %s", r.Duration) - } - }) -} - -// TestClose tests are Close method triggers all close functions and are all nodes not up anymore. -func TestClose(t *testing.T) { - var mu sync.Mutex - var cleanupCount int - - sleep := 50 * time.Millisecond - - sim := New(map[string]ServiceFunc{ - "noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - return newNoopService(), func() { - time.Sleep(sleep) - mu.Lock() - defer mu.Unlock() - cleanupCount++ - }, nil - }, - }) - - nodeCount := 30 - - _, err := sim.AddNodes(nodeCount) - if err != nil { - t.Fatal(err) - } - - var upNodeCount int - for _, n := range sim.Net.GetNodes() { - if n.Up() { - upNodeCount++ - } - } - if upNodeCount != nodeCount { - t.Errorf("all nodes should be up, insted only %v are up", upNodeCount) - } - - sim.Close() - - if cleanupCount != nodeCount { - t.Errorf("number of cleanups expected %v, got %v", nodeCount, cleanupCount) - } - - upNodeCount = 0 - for _, n := range sim.Net.GetNodes() { - if n.Up() { - upNodeCount++ - } - } - if upNodeCount != 0 { - t.Errorf("all nodes should be down, insted %v are up", upNodeCount) - } -} - -// TestDone checks if Close method triggers the closing of done channel. -func TestDone(t *testing.T) { - sim := New(noopServiceFuncMap) - sleep := 50 * time.Millisecond - timeout := 2 * time.Second - - start := time.Now() - go func() { - time.Sleep(sleep) - sim.Close() - }() - - select { - case <-time.After(timeout): - t.Error("done channel closing timed out") - case <-sim.Done(): - if d := time.Since(start); d < sleep { - t.Errorf("done channel closed sooner then expected: %s", d) - } - } -} - -// a helper map for usual services that do not do anything -var noopServiceFuncMap = map[string]ServiceFunc{ - "noop": noopServiceFunc, -} - -// a helper function for most basic noop service -func noopServiceFunc(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) { - return newNoopService(), nil, nil -} - -func newNoopService() node.Service { - return &noopService{} -} - -// a helper function for most basic Noop service -// of a different type then NoopService to test -// multiple services on one node. -func noopService2Func(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) { - return new(noopService2), nil, nil -} - -// NoopService2 is the service that does not do anything -// but implements node.Service interface. -type noopService2 struct { - simulations.NoopService -} - -type noopService struct { - simulations.NoopService -} diff --git a/swarm/network/simulations/discovery/discovery.go b/swarm/network/simulations/discovery/discovery.go deleted file mode 100644 index a6ff5fd45e..0000000000 --- a/swarm/network/simulations/discovery/discovery.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package discovery diff --git a/swarm/network/simulations/discovery/discovery_test.go b/swarm/network/simulations/discovery/discovery_test.go deleted file mode 100644 index 99a0c77224..0000000000 --- a/swarm/network/simulations/discovery/discovery_test.go +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package discovery - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - "os" - "path" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/testutil" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/state" - colorable "github.com/mattn/go-colorable" -) - -// serviceName is used with the exec adapter so the exec'd binary knows which -// service to execute -const serviceName = "discovery" -const testNeighbourhoodSize = 2 -const discoveryPersistenceDatadir = "discovery_persistence_test_store" - -var discoveryPersistencePath = path.Join(os.TempDir(), discoveryPersistenceDatadir) -var discoveryEnabled = true -var persistenceEnabled = false - -var services = adapters.Services{ - serviceName: newService, -} - -func cleanDbStores() error { - entries, err := ioutil.ReadDir(os.TempDir()) - if err != nil { - return err - } - - for _, f := range entries { - if strings.HasPrefix(f.Name(), discoveryPersistenceDatadir) { - os.RemoveAll(path.Join(os.TempDir(), f.Name())) - } - } - return nil - -} - -func getDbStore(nodeID string) (*state.DBStore, error) { - if _, err := os.Stat(discoveryPersistencePath + "_" + nodeID); os.IsNotExist(err) { - log.Info(fmt.Sprintf("directory for nodeID %s does not exist. creating...", nodeID)) - ioutil.TempDir("", discoveryPersistencePath+"_"+nodeID) - } - log.Info(fmt.Sprintf("opening storage directory for nodeID %s", nodeID)) - store, err := state.NewDBStore(discoveryPersistencePath + "_" + nodeID) - if err != nil { - return nil, err - } - return store, nil -} - -var ( - nodeCount = flag.Int("nodes", defaultNodeCount(), "number of nodes to create (default 32)") - initCount = flag.Int("conns", 1, "number of originally connected peers (default 1)") - loglevel = flag.Int("loglevel", 3, "verbosity of logs") - rawlog = flag.Bool("rawlog", false, "remove terminal formatting from logs") -) - -func defaultNodeCount() int { - if testutil.RaceEnabled { - return 8 - } - return 32 -} - -func init() { - flag.Parse() - // register the discovery service which will run as a devp2p - // protocol when using the exec adapter - adapters.RegisterServices(services) - - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(!*rawlog)))) -} - -// Benchmarks to test the average time it takes for an N-node ring -// to full a healthy kademlia topology -func BenchmarkDiscovery_8_1(b *testing.B) { benchmarkDiscovery(b, 8, 1) } -func BenchmarkDiscovery_16_1(b *testing.B) { benchmarkDiscovery(b, 16, 1) } -func BenchmarkDiscovery_32_1(b *testing.B) { benchmarkDiscovery(b, 32, 1) } -func BenchmarkDiscovery_64_1(b *testing.B) { benchmarkDiscovery(b, 64, 1) } -func BenchmarkDiscovery_128_1(b *testing.B) { benchmarkDiscovery(b, 128, 1) } -func BenchmarkDiscovery_256_1(b *testing.B) { benchmarkDiscovery(b, 256, 1) } - -func BenchmarkDiscovery_8_2(b *testing.B) { benchmarkDiscovery(b, 8, 2) } -func BenchmarkDiscovery_16_2(b *testing.B) { benchmarkDiscovery(b, 16, 2) } -func BenchmarkDiscovery_32_2(b *testing.B) { benchmarkDiscovery(b, 32, 2) } -func BenchmarkDiscovery_64_2(b *testing.B) { benchmarkDiscovery(b, 64, 2) } -func BenchmarkDiscovery_128_2(b *testing.B) { benchmarkDiscovery(b, 128, 2) } -func BenchmarkDiscovery_256_2(b *testing.B) { benchmarkDiscovery(b, 256, 2) } - -func BenchmarkDiscovery_8_4(b *testing.B) { benchmarkDiscovery(b, 8, 4) } -func BenchmarkDiscovery_16_4(b *testing.B) { benchmarkDiscovery(b, 16, 4) } -func BenchmarkDiscovery_32_4(b *testing.B) { benchmarkDiscovery(b, 32, 4) } -func BenchmarkDiscovery_64_4(b *testing.B) { benchmarkDiscovery(b, 64, 4) } -func BenchmarkDiscovery_128_4(b *testing.B) { benchmarkDiscovery(b, 128, 4) } -func BenchmarkDiscovery_256_4(b *testing.B) { benchmarkDiscovery(b, 256, 4) } - -func TestDiscoverySimulationExecAdapter(t *testing.T) { - testDiscoverySimulationExecAdapter(t, *nodeCount, *initCount) -} - -func testDiscoverySimulationExecAdapter(t *testing.T, nodes, conns int) { - baseDir, err := ioutil.TempDir("", "swarm-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(baseDir) - testDiscoverySimulation(t, nodes, conns, adapters.NewExecAdapter(baseDir)) -} - -func TestDiscoverySimulationSimAdapter(t *testing.T) { - testDiscoverySimulationSimAdapter(t, *nodeCount, *initCount) -} - -func TestDiscoveryPersistenceSimulationSimAdapter(t *testing.T) { - testDiscoveryPersistenceSimulationSimAdapter(t, *nodeCount, *initCount) -} - -func testDiscoveryPersistenceSimulationSimAdapter(t *testing.T, nodes, conns int) { - testDiscoveryPersistenceSimulation(t, nodes, conns, adapters.NewSimAdapter(services)) -} - -func testDiscoverySimulationSimAdapter(t *testing.T, nodes, conns int) { - testDiscoverySimulation(t, nodes, conns, adapters.NewSimAdapter(services)) -} - -func testDiscoverySimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) { - startedAt := time.Now() - result, err := discoverySimulation(nodes, conns, adapter) - if err != nil { - t.Fatalf("Setting up simulation failed: %v", err) - } - if result.Error != nil { - t.Fatalf("Simulation failed: %s", result.Error) - } - t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt)) - var min, max time.Duration - var sum int - for _, pass := range result.Passes { - duration := pass.Sub(result.StartedAt) - if sum == 0 || duration < min { - min = duration - } - if duration > max { - max = duration - } - sum += int(duration.Nanoseconds()) - } - t.Logf("Min: %s, Max: %s, Average: %s", min, max, time.Duration(sum/len(result.Passes))*time.Nanosecond) - finishedAt := time.Now() - t.Logf("Setup: %s, shutdown: %s", result.StartedAt.Sub(startedAt), finishedAt.Sub(result.FinishedAt)) -} - -func testDiscoveryPersistenceSimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) map[int][]byte { - persistenceEnabled = true - discoveryEnabled = true - - result, err := discoveryPersistenceSimulation(nodes, conns, adapter) - - if err != nil { - t.Fatalf("Setting up simulation failed: %v", err) - } - if result.Error != nil { - t.Fatalf("Simulation failed: %s", result.Error) - } - t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt)) - // set the discovery and persistence flags again to default so other - // tests will not be affected - discoveryEnabled = true - persistenceEnabled = false - return nil -} - -func benchmarkDiscovery(b *testing.B, nodes, conns int) { - for i := 0; i < b.N; i++ { - result, err := discoverySimulation(nodes, conns, adapters.NewSimAdapter(services)) - if err != nil { - b.Fatalf("setting up simulation failed: %v", err) - } - if result.Error != nil { - b.Logf("simulation failed: %s", result.Error) - } - } -} - -func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) { - // create network - net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - ID: "0", - DefaultService: serviceName, - }) - defer net.Shutdown() - trigger := make(chan enode.ID) - ids := make([]enode.ID, nodes) - for i := 0; i < nodes; i++ { - conf := adapters.RandomNodeConfig() - node, err := net.NewNodeWithConfig(conf) - if err != nil { - return nil, fmt.Errorf("error starting node: %s", err) - } - if err := net.Start(node.ID()); err != nil { - return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err) - } - if err := triggerChecks(trigger, net, node.ID()); err != nil { - return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err) - } - ids[i] = node.ID() - } - - // run a simulation which connects the 10 nodes in a ring and waits - // for full peer discovery - var addrs [][]byte - action := func(ctx context.Context) error { - return nil - } - for i := range ids { - // collect the overlay addresses, to - addrs = append(addrs, ids[i].Bytes()) - } - err := net.ConnectNodesChain(nil) - if err != nil { - return nil, err - } - log.Debug(fmt.Sprintf("nodes: %v", len(addrs))) - // construct the peer pot, so that kademlia health can be checked - ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) - check := func(ctx context.Context, id enode.ID) (bool, error) { - select { - case <-ctx.Done(): - return false, ctx.Err() - default: - } - - node := net.GetNode(id) - if node == nil { - return false, fmt.Errorf("unknown node: %s", id) - } - client, err := node.Client() - if err != nil { - return false, fmt.Errorf("error getting node client: %s", err) - } - - healthy := &network.Health{} - if err := client.Call(&healthy, "hive_getHealthInfo", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil { - return false, fmt.Errorf("error getting node health: %s", err) - } - log.Debug(fmt.Sprintf("node %4s healthy: connected nearest neighbours: %v, know nearest neighbours: %v,\n\n%v", id, healthy.ConnectNN, healthy.KnowNN, healthy.Hive)) - return healthy.KnowNN && healthy.ConnectNN, nil - } - - // 64 nodes ~ 1min - // 128 nodes ~ - timeout := 300 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{ - Action: action, - Trigger: trigger, - Expect: &simulations.Expectation{ - Nodes: ids, - Check: check, - }, - }) - if result.Error != nil { - return result, nil - } - return result, nil -} - -func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) { - cleanDbStores() - defer cleanDbStores() - - // create network - net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - ID: "0", - DefaultService: serviceName, - }) - defer net.Shutdown() - trigger := make(chan enode.ID) - ids := make([]enode.ID, nodes) - var addrs [][]byte - - for i := 0; i < nodes; i++ { - conf := adapters.RandomNodeConfig() - node, err := net.NewNodeWithConfig(conf) - if err != nil { - panic(err) - } - if err != nil { - return nil, fmt.Errorf("error starting node: %s", err) - } - if err := net.Start(node.ID()); err != nil { - return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err) - } - if err := triggerChecks(trigger, net, node.ID()); err != nil { - return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err) - } - // TODO we shouldn't be equating underaddr and overaddr like this, as they are not the same in production - ids[i] = node.ID() - a := ids[i].Bytes() - - addrs = append(addrs, a) - } - - // run a simulation which connects the 10 nodes in a ring and waits - // for full peer discovery - - var restartTime time.Time - - action := func(ctx context.Context) error { - ticker := time.NewTicker(500 * time.Millisecond) - - for range ticker.C { - isHealthy := true - for _, id := range ids { - //call Healthy RPC - node := net.GetNode(id) - if node == nil { - return fmt.Errorf("unknown node: %s", id) - } - client, err := node.Client() - if err != nil { - return fmt.Errorf("error getting node client: %s", err) - } - healthy := &network.Health{} - addr := id.String() - ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) - if err := client.Call(&healthy, "hive_getHealthInfo", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil { - return fmt.Errorf("error getting node health: %s", err) - } - - log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.ConnectNN && healthy.KnowNN && healthy.CountKnowNN > 0)) - var nodeStr string - if err := client.Call(&nodeStr, "hive_string"); err != nil { - return fmt.Errorf("error getting node string %s", err) - } - log.Info(nodeStr) - if !healthy.ConnectNN || healthy.CountKnowNN == 0 { - isHealthy = false - break - } - } - if isHealthy { - break - } - } - ticker.Stop() - - log.Info("reached healthy kademlia. starting to shutdown nodes.") - shutdownStarted := time.Now() - // stop all ids, then start them again - for _, id := range ids { - node := net.GetNode(id) - - if err := net.Stop(node.ID()); err != nil { - return fmt.Errorf("error stopping node %s: %s", node.ID().TerminalString(), err) - } - } - log.Info(fmt.Sprintf("shutting down nodes took: %s", time.Since(shutdownStarted))) - persistenceEnabled = true - discoveryEnabled = false - restartTime = time.Now() - for _, id := range ids { - node := net.GetNode(id) - if err := net.Start(node.ID()); err != nil { - return fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err) - } - if err := triggerChecks(trigger, net, node.ID()); err != nil { - return fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err) - } - } - - log.Info(fmt.Sprintf("restarting nodes took: %s", time.Since(restartTime))) - - return nil - } - net.ConnectNodesChain(nil) - log.Debug(fmt.Sprintf("nodes: %v", len(addrs))) - // construct the peer pot, so that kademlia health can be checked - check := func(ctx context.Context, id enode.ID) (bool, error) { - select { - case <-ctx.Done(): - return false, ctx.Err() - default: - } - - node := net.GetNode(id) - if node == nil { - return false, fmt.Errorf("unknown node: %s", id) - } - client, err := node.Client() - if err != nil { - return false, fmt.Errorf("error getting node client: %s", err) - } - healthy := &network.Health{} - ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs) - - if err := client.Call(&healthy, "hive_getHealthInfo", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil { - return false, fmt.Errorf("error getting node health: %s", err) - } - log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v", id, healthy.ConnectNN, healthy.KnowNN)) - - return healthy.KnowNN && healthy.ConnectNN, nil - } - - // 64 nodes ~ 1min - // 128 nodes ~ - timeout := 300 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{ - Action: action, - Trigger: trigger, - Expect: &simulations.Expectation{ - Nodes: ids, - Check: check, - }, - }) - if result.Error != nil { - return result, nil - } - - return result, nil -} - -// triggerChecks triggers a simulation step check whenever a peer is added or -// removed from the given node, and also every second to avoid a race between -// peer events and kademlia becoming healthy -func triggerChecks(trigger chan enode.ID, net *simulations.Network, id enode.ID) error { - node := net.GetNode(id) - if node == nil { - return fmt.Errorf("unknown node: %s", id) - } - client, err := node.Client() - if err != nil { - return err - } - events := make(chan *p2p.PeerEvent) - sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") - if err != nil { - return fmt.Errorf("error getting peer events for node %v: %s", id, err) - } - go func() { - defer sub.Unsubscribe() - - tick := time.NewTicker(time.Second) - defer tick.Stop() - - for { - select { - case <-events: - trigger <- id - case <-tick.C: - trigger <- id - case err := <-sub.Err(): - if err != nil { - log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err) - } - return - } - } - }() - return nil -} - -func newService(ctx *adapters.ServiceContext) (node.Service, error) { - addr := network.NewAddr(ctx.Config.Node()) - - kp := network.NewKadParams() - kp.NeighbourhoodSize = testNeighbourhoodSize - - if ctx.Config.Reachable != nil { - kp.Reachable = func(o *network.BzzAddr) bool { - return ctx.Config.Reachable(o.ID()) - } - } - kad := network.NewKademlia(addr.Over(), kp) - hp := network.NewHiveParams() - hp.KeepAliveInterval = time.Duration(200) * time.Millisecond - hp.Discovery = discoveryEnabled - - log.Info(fmt.Sprintf("discovery for nodeID %s is %t", ctx.Config.ID.String(), hp.Discovery)) - - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - - if persistenceEnabled { - log.Info(fmt.Sprintf("persistence enabled for nodeID %s", ctx.Config.ID.String())) - store, err := getDbStore(ctx.Config.ID.String()) - if err != nil { - return nil, err - } - return network.NewBzz(config, kad, store, nil, nil), nil - } - - return network.NewBzz(config, kad, nil, nil, nil), nil -} diff --git a/swarm/network/simulations/discovery/snapshot.json b/swarm/network/simulations/discovery/snapshot.json deleted file mode 100755 index f7f400eb67..0000000000 --- a/swarm/network/simulations/discovery/snapshot.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}},{"node":{"config":null,"up":false}}],"conns":[{"one":"c04a0c47cb0c522ecf28d8841e93721e73f58790b30e92382816a4b453be2988","other":"d9283e5247a18d6564b3581217e9f4d9c93a4359944894c00bb2b22c690faadc","up":true},{"one":"dd99c11abe2abae112d64d902b96fe0c75243ea67eca759a2769058a30cc0e77","other":"c04a0c47cb0c522ecf28d8841e93721e73f58790b30e92382816a4b453be2988","up":true},{"one":"4f5dad2aa4f26ac5a23d4fbcc807296b474eab77761db6594debd60ef4287aed","other":"dd99c11abe2abae112d64d902b96fe0c75243ea67eca759a2769058a30cc0e77","up":true},{"one":"4f47f4e176d1c9f78d9a7e19723689ffe2a0603004a3d4506a2349e55a56fc17","other":"4f5dad2aa4f26ac5a23d4fbcc807296b474eab77761db6594debd60ef4287aed","up":true},{"one":"20b6a1be2cb8f966151682350e029d4f8da8ee92de10a2a1cb1727d110acebfa","other":"4f47f4e176d1c9f78d9a7e19723689ffe2a0603004a3d4506a2349e55a56fc17","up":true},{"one":"50cb92e77710582fa9cbee7a54cf25c95fd27d8d54b13ba5520a50139c309a22","other":"20b6a1be2cb8f966151682350e029d4f8da8ee92de10a2a1cb1727d110acebfa","up":true},{"one":"319dc901f99940f1339c540bc36fbabb10a96d326b13b9d7f53e7496980e2996","other":"50cb92e77710582fa9cbee7a54cf25c95fd27d8d54b13ba5520a50139c309a22","up":true},{"one":"dc285b6436a8bfd4d2e586d478b18d3fe7b705ce0b4fb27a651adcf6d27984f1","other":"319dc901f99940f1339c540bc36fbabb10a96d326b13b9d7f53e7496980e2996","up":true},{"one":"974dbe511377280f945a53a194b4bb397875b10b1ecb119a92425bbb16db68f1","other":"dc285b6436a8bfd4d2e586d478b18d3fe7b705ce0b4fb27a651adcf6d27984f1","up":true},{"one":"d9283e5247a18d6564b3581217e9f4d9c93a4359944894c00bb2b22c690faadc","other":"974dbe511377280f945a53a194b4bb397875b10b1ecb119a92425bbb16db68f1","up":true}]} \ No newline at end of file diff --git a/swarm/network/simulations/overlay.go b/swarm/network/simulations/overlay.go deleted file mode 100644 index 63938809e4..0000000000 --- a/swarm/network/simulations/overlay.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// You can run this simulation using -// -// go run ./swarm/network/simulations/overlay.go -package main - -import ( - "flag" - "fmt" - "net/http" - "runtime" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/state" - colorable "github.com/mattn/go-colorable" -) - -var ( - noDiscovery = flag.Bool("no-discovery", false, "disable discovery (useful if you want to load a snapshot)") - vmodule = flag.String("vmodule", "", "log filters for logger via Vmodule") - verbosity = flag.Int("verbosity", 0, "log filters for logger via Vmodule") - httpSimPort = 8888 -) - -func init() { - flag.Parse() - //initialize the logger - //this is a demonstration on how to use Vmodule for filtering logs - //provide -vmodule as param, and comma-separated values, e.g.: - //-vmodule overlay_test.go=4,simulations=3 - //above examples sets overlay_test.go logs to level 4, while packages ending with "simulations" to 3 - if *vmodule != "" { - //only enable the pattern matching handler if the flag has been provided - glogger := log.NewGlogHandler(log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))) - if *verbosity > 0 { - glogger.Verbosity(log.Lvl(*verbosity)) - } - glogger.Vmodule(*vmodule) - log.Root().SetHandler(glogger) - } -} - -type Simulation struct { - mtx sync.Mutex - stores map[enode.ID]state.Store -} - -func NewSimulation() *Simulation { - return &Simulation{ - stores: make(map[enode.ID]state.Store), - } -} - -func (s *Simulation) NewService(ctx *adapters.ServiceContext) (node.Service, error) { - node := ctx.Config.Node() - s.mtx.Lock() - store, ok := s.stores[node.ID()] - if !ok { - store = state.NewInmemoryStore() - s.stores[node.ID()] = store - } - s.mtx.Unlock() - - addr := network.NewAddr(node) - - kp := network.NewKadParams() - kp.NeighbourhoodSize = 2 - kp.MaxBinSize = 4 - kp.MinBinSize = 1 - kp.MaxRetries = 1000 - kp.RetryExponent = 2 - kp.RetryInterval = 1000000 - kad := network.NewKademlia(addr.Over(), kp) - hp := network.NewHiveParams() - hp.Discovery = !*noDiscovery - hp.KeepAliveInterval = 300 * time.Millisecond - - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - - return network.NewBzz(config, kad, store, nil, nil), nil -} - -//create the simulation network -func newSimulationNetwork() *simulations.Network { - - s := NewSimulation() - services := adapters.Services{ - "overlay": s.NewService, - } - adapter := adapters.NewSimAdapter(services) - simNetwork := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - DefaultService: "overlay", - }) - return simNetwork -} - -//return a new http server -func newOverlaySim(sim *simulations.Network) *simulations.Server { - return simulations.NewServer(sim) -} - -// var server -func main() { - //cpu optimization - runtime.GOMAXPROCS(runtime.NumCPU()) - //run the sim - runOverlaySim() -} - -func runOverlaySim() { - //create the simulation network - net := newSimulationNetwork() - //create a http server with it - sim := newOverlaySim(net) - log.Info(fmt.Sprintf("starting simulation server on 0.0.0.0:%d...", httpSimPort)) - //start the HTTP server - http.ListenAndServe(fmt.Sprintf(":%d", httpSimPort), sim) -} diff --git a/swarm/network/simulations/overlay_test.go b/swarm/network/simulations/overlay_test.go deleted file mode 100644 index e024e2b123..0000000000 --- a/swarm/network/simulations/overlay_test.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package main - -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "testing" - "time" - - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/swarm/log" -) - -var ( - nodeCount = 10 -) - -//This test is used to test the overlay simulation. -//As the simulation is executed via a main, it is easily missed on changes -//An automated test will prevent that -//The test just connects to the simulations, starts the network, -//starts the mocker, gets the number of nodes, and stops it again. -//It also provides a documentation on the steps needed by frontends -//to use the simulations -func TestOverlaySim(t *testing.T) { - //start the simulation - log.Info("Start simulation backend") - //get the simulation networ; needed to subscribe for up events - net := newSimulationNetwork() - //create the overlay simulation - sim := newOverlaySim(net) - //create a http test server with it - srv := httptest.NewServer(sim) - defer srv.Close() - - log.Debug("Http simulation server started. Start simulation network") - //start the simulation network (initialization of simulation) - resp, err := http.Post(srv.URL+"/start", "application/json", nil) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("Expected Status Code %d, got %d", http.StatusOK, resp.StatusCode) - } - - log.Debug("Start mocker") - //start the mocker, needs a node count and an ID - resp, err = http.PostForm(srv.URL+"/mocker/start", - url.Values{ - "node-count": {fmt.Sprintf("%d", nodeCount)}, - "mocker-type": {simulations.GetMockerList()[0]}, - }) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - reason, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - t.Fatalf("Expected Status Code %d, got %d, response body %s", http.StatusOK, resp.StatusCode, string(reason)) - } - - //variables needed to wait for nodes being up - var upCount int - trigger := make(chan enode.ID) - - //wait for all nodes to be up - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - //start watching node up events... - go watchSimEvents(net, ctx, trigger) - - //...and wait until all expected up events (nodeCount) have been received -LOOP: - for { - select { - case <-trigger: - //new node up event received, increase counter - upCount++ - //all expected node up events received - if upCount == nodeCount { - break LOOP - } - case <-ctx.Done(): - t.Fatalf("Timed out waiting for up events") - } - - } - - //at this point we can query the server - log.Info("Get number of nodes") - //get the number of nodes - resp, err = http.Get(srv.URL + "/nodes") - if err != nil { - t.Fatal(err) - } - - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - - //unmarshal number of nodes from JSON response - var nodesArr []simulations.Node - err = json.Unmarshal(b, &nodesArr) - if err != nil { - t.Fatal(err) - } - - //check if number of nodes received is same as sent - if len(nodesArr) != nodeCount { - t.Fatal(fmt.Errorf("Expected %d number of nodes, got %d", nodeCount, len(nodesArr))) - } - - //need to let it run for a little while, otherwise stopping it immediately can crash due running nodes - //wanting to connect to already stopped nodes - time.Sleep(1 * time.Second) - - log.Info("Stop the network") - //stop the network - resp, err = http.Post(srv.URL+"/stop", "application/json", nil) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } - - log.Info("Reset the network") - //reset the network (removes all nodes and connections) - resp, err = http.Post(srv.URL+"/reset", "application/json", nil) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("err %s", resp.Status) - } -} - -//watch for events so we know when all nodes are up -func watchSimEvents(net *simulations.Network, ctx context.Context, trigger chan enode.ID) { - events := make(chan *simulations.Event) - sub := net.Events().Subscribe(events) - defer sub.Unsubscribe() - - for { - select { - case ev := <-events: - //only catch node up events - if ev.Type == simulations.EventTypeNode { - if ev.Node.Up() { - log.Debug("got node up event", "event", ev, "node", ev.Node.Config.ID) - select { - case trigger <- ev.Node.Config.ID: - case <-ctx.Done(): - return - } - } - } - case <-ctx.Done(): - return - } - } -} diff --git a/swarm/network/stream/common_test.go b/swarm/network/stream/common_test.go deleted file mode 100644 index 615b3b68f9..0000000000 --- a/swarm/network/stream/common_test.go +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "math/rand" - "os" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - "github.com/ethereum/go-ethereum/swarm/testutil" - colorable "github.com/mattn/go-colorable" -) - -var ( - loglevel = flag.Int("loglevel", 2, "verbosity of logs") - nodes = flag.Int("nodes", 0, "number of nodes") - chunks = flag.Int("chunks", 0, "number of chunks") - useMockStore = flag.Bool("mockstore", false, "disabled mock store (default: enabled)") - longrunning = flag.Bool("longrunning", false, "do run long-running tests") - - bucketKeyStore = simulation.BucketKey("store") - bucketKeyFileStore = simulation.BucketKey("filestore") - bucketKeyNetStore = simulation.BucketKey("netstore") - bucketKeyDelivery = simulation.BucketKey("delivery") - bucketKeyRegistry = simulation.BucketKey("registry") - - chunkSize = 4096 - pof = network.Pof -) - -func init() { - flag.Parse() - rand.Seed(time.Now().UnixNano()) - - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) -} - -// newNetStoreAndDelivery is a default constructor for BzzAddr, NetStore and Delivery, used in Simulations -func newNetStoreAndDelivery(ctx *adapters.ServiceContext, bucket *sync.Map) (*network.BzzAddr, *storage.NetStore, *Delivery, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) - - netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) - if err != nil { - return nil, nil, nil, nil, err - } - - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New - - return addr, netStore, delivery, cleanup, nil -} - -// newNetStoreAndDeliveryWithBzzAddr is a constructor for NetStore and Delivery, used in Simulations, accepting any BzzAddr -func newNetStoreAndDeliveryWithBzzAddr(ctx *adapters.ServiceContext, bucket *sync.Map, addr *network.BzzAddr) (*storage.NetStore, *Delivery, func(), error) { - netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) - if err != nil { - return nil, nil, nil, err - } - - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New - - return netStore, delivery, cleanup, nil -} - -// newNetStoreAndDeliveryWithRequestFunc is a constructor for NetStore and Delivery, used in Simulations, accepting any NetStore.RequestFunc -func newNetStoreAndDeliveryWithRequestFunc(ctx *adapters.ServiceContext, bucket *sync.Map, rf network.RequestFunc) (*network.BzzAddr, *storage.NetStore, *Delivery, func(), error) { - addr := network.NewAddr(ctx.Config.Node()) - - netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) - if err != nil { - return nil, nil, nil, nil, err - } - - netStore.NewNetFetcherFunc = network.NewFetcherFactory(rf, true).New - - return addr, netStore, delivery, cleanup, nil -} - -func netStoreAndDeliveryWithAddr(ctx *adapters.ServiceContext, bucket *sync.Map, addr *network.BzzAddr) (*storage.NetStore, *Delivery, func(), error) { - n := ctx.Config.Node() - - localStore, localStoreCleanup, err := newTestLocalStore(n.ID(), addr, nil) - if err != nil { - return nil, nil, nil, err - } - - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - localStore.Close() - localStoreCleanup() - return nil, nil, nil, err - } - - fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams(), chunk.NewTags()) - - kad := network.NewKademlia(addr.Over(), network.NewKadParams()) - delivery := NewDelivery(kad, netStore) - - bucket.Store(bucketKeyStore, localStore) - bucket.Store(bucketKeyDelivery, delivery) - bucket.Store(bucketKeyFileStore, fileStore) - // for the kademlia object, we use the global key from the simulation package, - // as the simulation will try to access it in the WaitTillHealthy with that key - bucket.Store(simulation.BucketKeyKademlia, kad) - - cleanup := func() { - netStore.Close() - localStoreCleanup() - } - - return netStore, delivery, cleanup, nil -} - -func newStreamerTester(registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *localstore.DB, func(), error) { - // setup - addr := network.RandomAddr() // tested peers peer address - to := network.NewKademlia(addr.OAddr, network.NewKadParams()) - - // temp datadir - datadir, err := ioutil.TempDir("", "streamer") - if err != nil { - return nil, nil, nil, nil, err - } - removeDataDir := func() { - os.RemoveAll(datadir) - } - - localStore, err := localstore.New(datadir, addr.Over(), nil) - if err != nil { - removeDataDir() - return nil, nil, nil, nil, err - } - - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - localStore.Close() - removeDataDir() - return nil, nil, nil, nil, err - } - - delivery := NewDelivery(to, netStore) - netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New - intervalsStore := state.NewInmemoryStore() - streamer := NewRegistry(addr.ID(), delivery, netStore, intervalsStore, registryOptions, nil) - - prvkey, err := crypto.GenerateKey() - if err != nil { - removeDataDir() - return nil, nil, nil, nil, err - } - - protocolTester := p2ptest.NewProtocolTester(prvkey, 1, streamer.runProtocol) - teardown := func() { - protocolTester.Stop() - streamer.Close() - intervalsStore.Close() - netStore.Close() - removeDataDir() - } - err = waitForPeers(streamer, 10*time.Second, 1) - if err != nil { - teardown() - return nil, nil, nil, nil, errors.New("timeout: peer is not created") - } - - return protocolTester, streamer, localStore, teardown, nil -} - -func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error { - ticker := time.NewTicker(10 * time.Millisecond) - timeoutTimer := time.NewTimer(timeout) - for { - select { - case <-ticker.C: - if streamer.peersCount() >= expectedPeers { - return nil - } - case <-timeoutTimer.C: - return errors.New("timeout") - } - } -} - -type roundRobinStore struct { - index uint32 - stores []storage.ChunkStore -} - -func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { - return &roundRobinStore{ - stores: stores, - } -} - -// not used in this context, only to fulfill ChunkStore interface -func (rrs *roundRobinStore) Has(_ context.Context, _ storage.Address) (bool, error) { - return false, errors.New("roundRobinStore doesn't support Has") -} - -func (rrs *roundRobinStore) Get(_ context.Context, _ chunk.ModeGet, _ storage.Address) (storage.Chunk, error) { - return nil, errors.New("roundRobinStore doesn't support Get") -} - -func (rrs *roundRobinStore) Put(ctx context.Context, mode chunk.ModePut, ch storage.Chunk) (bool, error) { - i := atomic.AddUint32(&rrs.index, 1) - idx := int(i) % len(rrs.stores) - return rrs.stores[idx].Put(ctx, mode, ch) -} - -func (rrs *roundRobinStore) Set(ctx context.Context, mode chunk.ModeSet, addr chunk.Address) (err error) { - return errors.New("roundRobinStore doesn't support Set") -} - -func (rrs *roundRobinStore) LastPullSubscriptionBinID(bin uint8) (id uint64, err error) { - return 0, errors.New("roundRobinStore doesn't support LastPullSubscriptionBinID") -} - -func (rrs *roundRobinStore) SubscribePull(ctx context.Context, bin uint8, since, until uint64) (c <-chan chunk.Descriptor, stop func()) { - return nil, nil -} - -func (rrs *roundRobinStore) Close() error { - for _, store := range rrs.stores { - store.Close() - } - return nil -} - -func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) { - r, _ := fileStore.Retrieve(context.TODO(), hash) - buf := make([]byte, 1024) - var n int - var total int64 - var err error - for (total == 0 || n > 0) && err == nil { - n, err = r.ReadAt(buf, total) - total += int64(n) - } - if err != nil && err != io.EOF { - return total, err - } - return total, nil -} - -func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) { - nodes := sim.UpNodeIDs() - nodeCnt := len(nodes) - log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt)) - //array holding generated files - rfiles := make([]string, nodeCnt) - //array holding the root hashes of the files - rootAddrs := make([]storage.Address, nodeCnt) - - var err error - //for every node, generate a file and upload - for i, id := range nodes { - item, ok := sim.NodeItem(id, bucketKeyFileStore) - if !ok { - return nil, nil, fmt.Errorf("Error accessing localstore") - } - fileStore := item.(*storage.FileStore) - //generate a file - rfiles[i], err = generateRandomFile() - if err != nil { - return nil, nil, err - } - //store it (upload it) on the FileStore - ctx := context.TODO() - rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) - log.Debug("Uploaded random string file to node") - if err != nil { - return nil, nil, err - } - err = wait(ctx) - if err != nil { - return nil, nil, err - } - rootAddrs[i] = rk - } - return rootAddrs, rfiles, nil -} - -//generate a random file (string) -func generateRandomFile() (string, error) { - //generate a random file size between minFileSize and maxFileSize - fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize - log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize)) - b := testutil.RandomBytes(1, fileSize*1024) - return string(b), nil -} - -func newTestLocalStore(id enode.ID, addr *network.BzzAddr, globalStore mock.GlobalStorer) (localStore *localstore.DB, cleanup func(), err error) { - dir, err := ioutil.TempDir("", "swarm-stream-") - if err != nil { - return nil, nil, err - } - cleanup = func() { - os.RemoveAll(dir) - } - - var mockStore *mock.NodeStore - if globalStore != nil { - mockStore = globalStore.NewNodeStore(common.BytesToAddress(id.Bytes())) - } - - localStore, err = localstore.New(dir, addr.Over(), &localstore.Options{ - MockStore: mockStore, - }) - if err != nil { - cleanup() - return nil, nil, err - } - return localStore, cleanup, nil -} - -// watchDisconnections receives simulation peer events in a new goroutine and sets atomic value -// disconnected to true in case of a disconnect event. -func watchDisconnections(ctx context.Context, sim *simulation.Simulation) (disconnected *boolean) { - log.Debug("Watching for disconnections") - disconnections := sim.PeerEvents( - ctx, - sim.NodeIDs(), - simulation.NewPeerEventsFilter().Drop(), - ) - disconnected = new(boolean) - go func() { - for { - select { - case <-ctx.Done(): - return - case d := <-disconnections: - if d.Error != nil { - log.Error("peer drop event error", "node", d.NodeID, "peer", d.PeerID, "err", d.Error) - } else { - log.Error("peer drop", "node", d.NodeID, "peer", d.PeerID) - } - disconnected.set(true) - } - } - }() - return disconnected -} - -// boolean is used to concurrently set -// and read a boolean value. -type boolean struct { - v bool - mu sync.RWMutex -} - -// set sets the value. -func (b *boolean) set(v bool) { - b.mu.Lock() - defer b.mu.Unlock() - - b.v = v -} - -// bool reads the value. -func (b *boolean) bool() bool { - b.mu.RLock() - defer b.mu.RUnlock() - - return b.v -} diff --git a/swarm/network/stream/delivery.go b/swarm/network/stream/delivery.go deleted file mode 100644 index 1b4a14ea2c..0000000000 --- a/swarm/network/stream/delivery.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/spancontext" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/tracing" - opentracing "github.com/opentracing/opentracing-go" - olog "github.com/opentracing/opentracing-go/log" -) - -var ( - processReceivedChunksCount = metrics.NewRegisteredCounter("network.stream.received_chunks.count", nil) - handleRetrieveRequestMsgCount = metrics.NewRegisteredCounter("network.stream.handle_retrieve_request_msg.count", nil) - retrieveChunkFail = metrics.NewRegisteredCounter("network.stream.retrieve_chunks_fail.count", nil) - - requestFromPeersCount = metrics.NewRegisteredCounter("network.stream.request_from_peers.count", nil) - requestFromPeersEachCount = metrics.NewRegisteredCounter("network.stream.request_from_peers_each.count", nil) - - lastReceivedChunksMsg = metrics.GetOrRegisterGauge("network.stream.received_chunks", nil) -) - -type Delivery struct { - netStore *storage.NetStore - kad *network.Kademlia - getPeer func(enode.ID) *Peer - quit chan struct{} -} - -func NewDelivery(kad *network.Kademlia, netStore *storage.NetStore) *Delivery { - return &Delivery{ - netStore: netStore, - kad: kad, - quit: make(chan struct{}), - } -} - -// RetrieveRequestMsg is the protocol msg for chunk retrieve requests -type RetrieveRequestMsg struct { - Addr storage.Address - SkipCheck bool - HopCount uint8 -} - -func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req *RetrieveRequestMsg) error { - log.Trace("received request", "peer", sp.ID(), "hash", req.Addr) - handleRetrieveRequestMsgCount.Inc(1) - - var osp opentracing.Span - ctx, osp = spancontext.StartSpan( - ctx, - "stream.handle.retrieve") - - osp.LogFields(olog.String("ref", req.Addr.String())) - - var cancel func() - // TODO: do something with this hardcoded timeout, maybe use TTL in the future - ctx = context.WithValue(ctx, "peer", sp.ID().String()) - ctx = context.WithValue(ctx, "hopcount", req.HopCount) - ctx, cancel = context.WithTimeout(ctx, network.RequestTimeout) - - go func() { - select { - case <-ctx.Done(): - case <-d.quit: - } - cancel() - }() - - go func() { - defer osp.Finish() - ch, err := d.netStore.Get(ctx, chunk.ModeGetRequest, req.Addr) - if err != nil { - retrieveChunkFail.Inc(1) - log.Debug("ChunkStore.Get can not retrieve chunk", "peer", sp.ID().String(), "addr", req.Addr, "hopcount", req.HopCount, "err", err) - return - } - syncing := false - - err = sp.Deliver(ctx, ch, Top, syncing) - if err != nil { - log.Warn("ERROR in handleRetrieveRequestMsg", "err", err) - } - osp.LogFields(olog.Bool("delivered", true)) - }() - - return nil -} - -//Chunk delivery always uses the same message type.... -type ChunkDeliveryMsg struct { - Addr storage.Address - SData []byte // the stored chunk Data (incl size) - peer *Peer // set in handleChunkDeliveryMsg -} - -//...but swap accounting needs to disambiguate if it is a delivery for syncing or for retrieval -//as it decides based on message type if it needs to account for this message or not - -//defines a chunk delivery for retrieval (with accounting) -type ChunkDeliveryMsgRetrieval ChunkDeliveryMsg - -//defines a chunk delivery for syncing (without accounting) -type ChunkDeliveryMsgSyncing ChunkDeliveryMsg - -// chunk delivery msg is response to retrieverequest msg -func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req interface{}) error { - var osp opentracing.Span - ctx, osp = spancontext.StartSpan( - ctx, - "handle.chunk.delivery") - - processReceivedChunksCount.Inc(1) - - // record the last time we received a chunk delivery message - lastReceivedChunksMsg.Update(time.Now().UnixNano()) - - var msg *ChunkDeliveryMsg - var mode chunk.ModePut - switch r := req.(type) { - case *ChunkDeliveryMsgRetrieval: - msg = (*ChunkDeliveryMsg)(r) - peerPO := chunk.Proximity(sp.BzzAddr.Over(), msg.Addr) - po := chunk.Proximity(d.kad.BaseAddr(), msg.Addr) - depth := d.kad.NeighbourhoodDepth() - // chunks within the area of responsibility should always sync - // https://github.com/ethersphere/go-ethereum/pull/1282#discussion_r269406125 - if po >= depth || peerPO < po { - mode = chunk.ModePutSync - } else { - // do not sync if peer that is sending us a chunk is closer to the chunk then we are - mode = chunk.ModePutRequest - } - case *ChunkDeliveryMsgSyncing: - msg = (*ChunkDeliveryMsg)(r) - mode = chunk.ModePutSync - case *ChunkDeliveryMsg: - msg = r - mode = chunk.ModePutSync - } - - log.Trace("handle.chunk.delivery", "ref", msg.Addr, "from peer", sp.ID()) - - go func() { - defer osp.Finish() - - msg.peer = sp - log.Trace("handle.chunk.delivery", "put", msg.Addr) - _, err := d.netStore.Put(ctx, mode, storage.NewChunk(msg.Addr, msg.SData)) - if err != nil { - if err == storage.ErrChunkInvalid { - // we removed this log because it spams the logs - // TODO: Enable this log line - // log.Warn("invalid chunk delivered", "peer", sp.ID(), "chunk", msg.Addr, ) - msg.peer.Drop() - } - } - log.Trace("handle.chunk.delivery", "done put", msg.Addr, "err", err) - }() - return nil -} - -func (d *Delivery) Close() { - close(d.quit) -} - -// RequestFromPeers sends a chunk retrieve request to a peer -// The most eligible peer that hasn't already been sent to is chosen -// TODO: define "eligible" -func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) (*enode.ID, chan struct{}, error) { - requestFromPeersCount.Inc(1) - var sp *Peer - spID := req.Source - - if spID != nil { - sp = d.getPeer(*spID) - if sp == nil { - return nil, nil, fmt.Errorf("source peer %v not found", spID.String()) - } - } else { - d.kad.EachConn(req.Addr[:], 255, func(p *network.Peer, po int) bool { - id := p.ID() - if p.LightNode { - // skip light nodes - return true - } - if req.SkipPeer(id.String()) { - log.Trace("Delivery.RequestFromPeers: skip peer", "peer id", id) - return true - } - sp = d.getPeer(id) - // sp is nil, when we encounter a peer that is not registered for delivery, i.e. doesn't support the `stream` protocol - if sp == nil { - return true - } - spID = &id - return false - }) - if sp == nil { - return nil, nil, errors.New("no peer found") - } - } - - // setting this value in the context creates a new span that can persist across the sendpriority queue and the network roundtrip - // this span will finish only when delivery is handled (or times out) - ctx = context.WithValue(ctx, tracing.StoreLabelId, "stream.send.request") - ctx = context.WithValue(ctx, tracing.StoreLabelMeta, fmt.Sprintf("%v.%v", sp.ID(), req.Addr)) - log.Trace("request.from.peers", "peer", sp.ID(), "ref", req.Addr) - err := sp.SendPriority(ctx, &RetrieveRequestMsg{ - Addr: req.Addr, - SkipCheck: req.SkipCheck, - HopCount: req.HopCount, - }, Top) - if err != nil { - return nil, nil, err - } - requestFromPeersEachCount.Inc(1) - - return spID, sp.quit, nil -} diff --git a/swarm/network/stream/delivery_test.go b/swarm/network/stream/delivery_test.go deleted file mode 100644 index fc0f9d5dfc..0000000000 --- a/swarm/network/stream/delivery_test.go +++ /dev/null @@ -1,593 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "bytes" - "context" - "errors" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - pq "github.com/ethereum/go-ethereum/swarm/network/priorityqueue" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -//Test requesting a chunk from a peer then issuing a "empty" OfferedHashesMsg (no hashes available yet) -//Should time out as the peer does not have the chunk (no syncing happened previously) -func TestStreamerUpstreamRetrieveRequestMsgExchangeWithoutStore(t *testing.T) { - tester, _, _, teardown, err := newStreamerTester(&RegistryOptions{ - Syncing: SyncingDisabled, //do no syncing - }) - if err != nil { - t.Fatal(err) - } - defer teardown() - - node := tester.Nodes[0] - - chunk := storage.NewChunk(storage.Address(hash0[:]), nil) - - //test the exchange - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "RetrieveRequestMsg", - Triggers: []p2ptest.Trigger{ - { //then the actual RETRIEVE_REQUEST.... - Code: 5, - Msg: &RetrieveRequestMsg{ - Addr: chunk.Address()[:], - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { //to which the peer responds with offered hashes - Code: 1, - Msg: &OfferedHashesMsg{ - HandoverProof: nil, - Hashes: nil, - From: 0, - To: 0, - }, - Peer: node.ID(), - }, - }, - }) - - //should fail with a timeout as the peer we are requesting - //the chunk from does not have the chunk - expectedError := `exchange #0 "RetrieveRequestMsg": timed out` - if err == nil || err.Error() != expectedError { - t.Fatalf("Expected error %v, got %v", expectedError, err) - } -} - -// upstream request server receives a retrieve Request and responds with -// offered hashes or delivery if skipHash is set to true -func TestStreamerUpstreamRetrieveRequestMsgExchange(t *testing.T) { - tester, _, localStore, teardown, err := newStreamerTester(&RegistryOptions{ - Syncing: SyncingDisabled, - }) - if err != nil { - t.Fatal(err) - } - defer teardown() - - node := tester.Nodes[0] - - hash := storage.Address(hash1[:]) - ch := storage.NewChunk(hash, hash1[:]) - _, err = localStore.Put(context.TODO(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatalf("Expected no err got %v", err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "RetrieveRequestMsg", - Triggers: []p2ptest.Trigger{ - { - Code: 5, - Msg: &RetrieveRequestMsg{ - Addr: hash, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 6, - Msg: &ChunkDeliveryMsg{ - Addr: ch.Address(), - SData: ch.Data(), - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -// if there is one peer in the Kademlia, RequestFromPeers should return it -func TestRequestFromPeers(t *testing.T) { - dummyPeerID := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") - - addr := network.RandomAddr() - to := network.NewKademlia(addr.OAddr, network.NewKadParams()) - delivery := NewDelivery(to, nil) - protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", nil), nil, nil) - peer := network.NewPeer(&network.BzzPeer{ - BzzAddr: network.RandomAddr(), - LightNode: false, - Peer: protocolsPeer, - }, to) - to.On(peer) - r := NewRegistry(addr.ID(), delivery, nil, nil, nil, nil) - - // an empty priorityQueue has to be created to prevent a goroutine being called after the test has finished - sp := &Peer{ - BzzPeer: &network.BzzPeer{Peer: protocolsPeer, BzzAddr: addr}, - pq: pq.New(int(PriorityQueue), PriorityQueueCap), - streamer: r, - } - r.setPeer(sp) - req := network.NewRequest( - storage.Address(hash0[:]), - true, - &sync.Map{}, - ) - ctx := context.Background() - id, _, err := delivery.RequestFromPeers(ctx, req) - - if err != nil { - t.Fatal(err) - } - if *id != dummyPeerID { - t.Fatalf("Expected an id, got %v", id) - } -} - -// RequestFromPeers should not return light nodes -func TestRequestFromPeersWithLightNode(t *testing.T) { - dummyPeerID := enode.HexID("3431c3939e1ee2a6345e976a8234f9870152d64879f30bc272a074f6859e75e8") - - addr := network.RandomAddr() - to := network.NewKademlia(addr.OAddr, network.NewKadParams()) - delivery := NewDelivery(to, nil) - - protocolsPeer := protocols.NewPeer(p2p.NewPeer(dummyPeerID, "dummy", nil), nil, nil) - // setting up a lightnode - peer := network.NewPeer(&network.BzzPeer{ - BzzAddr: network.RandomAddr(), - LightNode: true, - Peer: protocolsPeer, - }, to) - to.On(peer) - r := NewRegistry(addr.ID(), delivery, nil, nil, nil, nil) - // an empty priorityQueue has to be created to prevent a goroutine being called after the test has finished - sp := &Peer{ - BzzPeer: &network.BzzPeer{Peer: protocolsPeer, BzzAddr: addr}, - pq: pq.New(int(PriorityQueue), PriorityQueueCap), - streamer: r, - } - r.setPeer(sp) - - req := network.NewRequest( - storage.Address(hash0[:]), - true, - &sync.Map{}, - ) - - ctx := context.Background() - // making a request which should return with "no peer found" - _, _, err := delivery.RequestFromPeers(ctx, req) - - expectedError := "no peer found" - if err.Error() != expectedError { - t.Fatalf("expected '%v', got %v", expectedError, err) - } -} - -func TestStreamerDownstreamChunkDeliveryMsgExchange(t *testing.T) { - tester, streamer, localStore, teardown, err := newStreamerTester(&RegistryOptions{ - Syncing: SyncingDisabled, - }) - if err != nil { - t.Fatal(err) - } - defer teardown() - - streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { - return &testClient{ - t: t, - }, nil - }) - - node := tester.Nodes[0] - - //subscribe to custom stream - stream := NewStream("foo", "", true) - err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - chunkKey := hash0[:] - chunkData := hash1[:] - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Expects: []p2ptest.Expect{ - { //first expect subscription to the custom stream... - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - }, - p2ptest.Exchange{ - Label: "ChunkDelivery message", - Triggers: []p2ptest.Trigger{ - { //...then trigger a chunk delivery for the given chunk from peer in order for - //local node to get the chunk delivered - Code: 6, - Msg: &ChunkDeliveryMsg{ - Addr: chunkKey, - SData: chunkData, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - - // wait for the chunk to get stored - storedChunk, err := localStore.Get(ctx, chunk.ModeGetRequest, chunkKey) - for err != nil { - select { - case <-ctx.Done(): - t.Fatalf("Chunk is not in localstore after timeout, err: %v", err) - default: - } - storedChunk, err = localStore.Get(ctx, chunk.ModeGetRequest, chunkKey) - time.Sleep(50 * time.Millisecond) - } - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - if !bytes.Equal(storedChunk.Data(), chunkData) { - t.Fatal("Retrieved chunk has different data than original") - } - -} - -func TestDeliveryFromNodes(t *testing.T) { - testDeliveryFromNodes(t, 2, dataChunkCount, true) - testDeliveryFromNodes(t, 2, dataChunkCount, false) - testDeliveryFromNodes(t, 4, dataChunkCount, true) - testDeliveryFromNodes(t, 4, dataChunkCount, false) - - if testutil.RaceEnabled { - // Travis cannot handle more nodes with -race; would time out. - return - } - - testDeliveryFromNodes(t, 8, dataChunkCount, true) - testDeliveryFromNodes(t, 8, dataChunkCount, false) - testDeliveryFromNodes(t, 16, dataChunkCount, true) - testDeliveryFromNodes(t, 16, dataChunkCount, false) -} - -func testDeliveryFromNodes(t *testing.T, nodes, chunkCount int, skipCheck bool) { - t.Helper() - t.Run(fmt.Sprintf("testDeliveryFromNodes_%d_%d_skipCheck_%t", nodes, chunkCount, skipCheck), func(t *testing.T) { - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - SkipCheck: skipCheck, - Syncing: SyncingDisabled, - }, nil) - bucket.Store(bucketKeyRegistry, r) - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, - }) - defer sim.Close() - - log.Info("Adding nodes to simulation") - _, err := sim.AddNodesAndConnectChain(nodes) - if err != nil { - t.Fatal(err) - } - - log.Info("Starting simulation") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { - nodeIDs := sim.UpNodeIDs() - //determine the pivot node to be the first node of the simulation - pivot := nodeIDs[0] - - //distribute chunks of a random file into Stores of nodes 1 to nodes - //we will do this by creating a file store with an underlying round-robin store: - //the file store will create a hash for the uploaded file, but every chunk will be - //distributed to different nodes via round-robin scheduling - log.Debug("Writing file to round-robin file store") - //to do this, we create an array for chunkstores (length minus one, the pivot node) - stores := make([]storage.ChunkStore, len(nodeIDs)-1) - //we then need to get all stores from the sim.... - lStores := sim.NodesItems(bucketKeyStore) - i := 0 - //...iterate the buckets... - for id, bucketVal := range lStores { - //...and remove the one which is the pivot node - if id == pivot { - continue - } - //the other ones are added to the array... - stores[i] = bucketVal.(storage.ChunkStore) - i++ - } - //...which then gets passed to the round-robin file store - roundRobinFileStore := storage.NewFileStore(newRoundRobinStore(stores...), storage.NewFileStoreParams(), chunk.NewTags()) - //now we can actually upload a (random) file to the round-robin store - size := chunkCount * chunkSize - log.Debug("Storing data to file store") - fileHash, wait, err := roundRobinFileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false) - // wait until all chunks stored - if err != nil { - return err - } - err = wait(ctx) - if err != nil { - return err - } - - //get the pivot node's filestore - item, ok := sim.NodeItem(pivot, bucketKeyFileStore) - if !ok { - return fmt.Errorf("No filestore") - } - pivotFileStore := item.(*storage.FileStore) - log.Debug("Starting retrieval routine") - retErrC := make(chan error) - go func() { - // start the retrieval on the pivot node - this will spawn retrieve requests for missing chunks - // we must wait for the peer connections to have started before requesting - n, err := readAll(pivotFileStore, fileHash) - log.Info(fmt.Sprintf("retrieved %v", fileHash), "read", n, "err", err) - retErrC <- err - }() - - disconnected := watchDisconnections(ctx, sim) - defer func() { - if err != nil && disconnected.bool() { - err = errors.New("disconnect events received") - } - }() - - //finally check that the pivot node gets all chunks via the root hash - log.Debug("Check retrieval") - success := true - var total int64 - total, err = readAll(pivotFileStore, fileHash) - if err != nil { - return err - } - log.Info(fmt.Sprintf("check if %08x is available locally: number of bytes read %v/%v (error: %v)", fileHash, total, size, err)) - if err != nil || total != int64(size) { - success = false - } - - if !success { - return fmt.Errorf("Test failed, chunks not available on all nodes") - } - if err := <-retErrC; err != nil { - return fmt.Errorf("requesting chunks: %v", err) - } - log.Debug("Test terminated successfully") - return nil - }) - if result.Error != nil { - t.Fatal(result.Error) - } - }) -} - -func BenchmarkDeliveryFromNodesWithoutCheck(b *testing.B) { - for chunks := 32; chunks <= 128; chunks *= 2 { - for i := 2; i < 32; i *= 2 { - b.Run( - fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), - func(b *testing.B) { - benchmarkDeliveryFromNodes(b, i, chunks, true) - }, - ) - } - } -} - -func BenchmarkDeliveryFromNodesWithCheck(b *testing.B) { - for chunks := 32; chunks <= 128; chunks *= 2 { - for i := 2; i < 32; i *= 2 { - b.Run( - fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), - func(b *testing.B) { - benchmarkDeliveryFromNodes(b, i, chunks, false) - }, - ) - } - } -} - -func benchmarkDeliveryFromNodes(b *testing.B, nodes, chunkCount int, skipCheck bool) { - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - SkipCheck: skipCheck, - Syncing: SyncingDisabled, - SyncUpdateDelay: 0, - }, nil) - bucket.Store(bucketKeyRegistry, r) - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, - }) - defer sim.Close() - - log.Info("Initializing test config") - _, err := sim.AddNodesAndConnectChain(nodes) - if err != nil { - b.Fatal(err) - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { - nodeIDs := sim.UpNodeIDs() - node := nodeIDs[len(nodeIDs)-1] - - item, ok := sim.NodeItem(node, bucketKeyFileStore) - if !ok { - return errors.New("No filestore") - } - remoteFileStore := item.(*storage.FileStore) - - pivotNode := nodeIDs[0] - item, ok = sim.NodeItem(pivotNode, bucketKeyNetStore) - if !ok { - return errors.New("No filestore") - } - netStore := item.(*storage.NetStore) - - if _, err := sim.WaitTillHealthy(ctx); err != nil { - return err - } - - disconnected := watchDisconnections(ctx, sim) - defer func() { - if err != nil && disconnected.bool() { - err = errors.New("disconnect events received") - } - }() - // benchmark loop - b.ResetTimer() - b.StopTimer() - Loop: - for i := 0; i < b.N; i++ { - // uploading chunkCount random chunks to the last node - hashes := make([]storage.Address, chunkCount) - for i := 0; i < chunkCount; i++ { - // create actual size real chunks - ctx := context.TODO() - hash, wait, err := remoteFileStore.Store(ctx, testutil.RandomReader(i, chunkSize), int64(chunkSize), false) - if err != nil { - return fmt.Errorf("store: %v", err) - } - // wait until all chunks stored - err = wait(ctx) - if err != nil { - return fmt.Errorf("wait store: %v", err) - } - // collect the hashes - hashes[i] = hash - } - // now benchmark the actual retrieval - // netstore.Get is called for each hash in a go routine and errors are collected - b.StartTimer() - errs := make(chan error) - for _, hash := range hashes { - go func(h storage.Address) { - _, err := netStore.Get(ctx, chunk.ModeGetRequest, h) - log.Warn("test check netstore get", "hash", h, "err", err) - errs <- err - }(hash) - } - // count and report retrieval errors - // if there are misses then chunk timeout is too low for the distance and volume (?) - var total, misses int - for err := range errs { - if err != nil { - log.Warn(err.Error()) - misses++ - } - total++ - if total == chunkCount { - break - } - } - b.StopTimer() - - if misses > 0 { - err = fmt.Errorf("%v chunk not found out of %v", misses, total) - break Loop - } - } - return err - }) - if result.Error != nil { - b.Fatal(result.Error) - } - -} diff --git a/swarm/network/stream/intervals/dbstore_test.go b/swarm/network/stream/intervals/dbstore_test.go deleted file mode 100644 index 6716e593ab..0000000000 --- a/swarm/network/stream/intervals/dbstore_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package intervals - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/ethereum/go-ethereum/swarm/state" -) - -// TestDBStore tests basic functionality of DBStore. -func TestDBStore(t *testing.T) { - dir, err := ioutil.TempDir("", "intervals_test_db_store") - if err != nil { - panic(err) - } - defer os.RemoveAll(dir) - - store, err := state.NewDBStore(dir) - if err != nil { - t.Fatal(err) - } - defer store.Close() - - testStore(t, store) -} diff --git a/swarm/network/stream/intervals/intervals.go b/swarm/network/stream/intervals/intervals.go deleted file mode 100644 index 562c3df9ae..0000000000 --- a/swarm/network/stream/intervals/intervals.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package intervals - -import ( - "bytes" - "fmt" - "strconv" - "sync" -) - -// Intervals store a list of intervals. Its purpose is to provide -// methods to add new intervals and retrieve missing intervals that -// need to be added. -// It may be used in synchronization of streaming data to persist -// retrieved data ranges between sessions. -type Intervals struct { - start uint64 - ranges [][2]uint64 - mu sync.RWMutex -} - -// New creates a new instance of Intervals. -// Start argument limits the lower bound of intervals. -// No range bellow start bound will be added by Add method or -// returned by Next method. This limit may be used for -// tracking "live" synchronization, where the sync session -// starts from a specific value, and if "live" sync intervals -// need to be merged with historical ones, it can be safely done. -func NewIntervals(start uint64) *Intervals { - return &Intervals{ - start: start, - } -} - -// Add adds a new range to intervals. Range start and end are values -// are both inclusive. -func (i *Intervals) Add(start, end uint64) { - i.mu.Lock() - defer i.mu.Unlock() - - i.add(start, end) -} - -func (i *Intervals) add(start, end uint64) { - if start < i.start { - start = i.start - } - if end < i.start { - return - } - minStartJ := -1 - maxEndJ := -1 - j := 0 - for ; j < len(i.ranges); j++ { - if minStartJ < 0 { - if (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) || (start <= i.ranges[j][1]+1 && end+1 >= i.ranges[j][1]) { - if i.ranges[j][0] < start { - start = i.ranges[j][0] - } - minStartJ = j - } - } - if (start <= i.ranges[j][1] && end+1 >= i.ranges[j][1]) || (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) { - if i.ranges[j][1] > end { - end = i.ranges[j][1] - } - maxEndJ = j - } - if end+1 <= i.ranges[j][0] { - break - } - } - if minStartJ < 0 && maxEndJ < 0 { - i.ranges = append(i.ranges[:j], append([][2]uint64{{start, end}}, i.ranges[j:]...)...) - return - } - if minStartJ >= 0 { - i.ranges[minStartJ][0] = start - } - if maxEndJ >= 0 { - i.ranges[maxEndJ][1] = end - } - if minStartJ >= 0 && maxEndJ >= 0 && minStartJ != maxEndJ { - i.ranges[maxEndJ][0] = start - i.ranges = append(i.ranges[:minStartJ], i.ranges[maxEndJ:]...) - } -} - -// Merge adds all the intervals from the m Interval to current one. -func (i *Intervals) Merge(m *Intervals) { - m.mu.RLock() - defer m.mu.RUnlock() - i.mu.Lock() - defer i.mu.Unlock() - - for _, r := range m.ranges { - i.add(r[0], r[1]) - } -} - -// Next returns the first range interval that is not fulfilled. Returned -// start and end values are both inclusive, meaning that the whole range -// including start and end need to be added in order to full the gap -// in intervals. -// Returned value for end is 0 if the next interval is after the whole -// range that is stored in Intervals. Zero end value represents no limit -// on the next interval length. -func (i *Intervals) Next() (start, end uint64) { - i.mu.RLock() - defer i.mu.RUnlock() - - l := len(i.ranges) - if l == 0 { - return i.start, 0 - } - if i.ranges[0][0] != i.start { - return i.start, i.ranges[0][0] - 1 - } - if l == 1 { - return i.ranges[0][1] + 1, 0 - } - return i.ranges[0][1] + 1, i.ranges[1][0] - 1 -} - -// Last returns the value that is at the end of the last interval. -func (i *Intervals) Last() (end uint64) { - i.mu.RLock() - defer i.mu.RUnlock() - - l := len(i.ranges) - if l == 0 { - return 0 - } - return i.ranges[l-1][1] -} - -// String returns a descriptive representation of range intervals -// in [] notation, as a list of two element vectors. -func (i *Intervals) String() string { - return fmt.Sprint(i.ranges) -} - -// MarshalBinary encodes Intervals parameters into a semicolon separated list. -// The first element in the list is base36-encoded start value. The following -// elements are two base36-encoded value ranges separated by comma. -func (i *Intervals) MarshalBinary() (data []byte, err error) { - d := make([][]byte, len(i.ranges)+1) - d[0] = []byte(strconv.FormatUint(i.start, 36)) - for j := range i.ranges { - r := i.ranges[j] - d[j+1] = []byte(strconv.FormatUint(r[0], 36) + "," + strconv.FormatUint(r[1], 36)) - } - return bytes.Join(d, []byte(";")), nil -} - -// UnmarshalBinary decodes data according to the Intervals.MarshalBinary format. -func (i *Intervals) UnmarshalBinary(data []byte) (err error) { - d := bytes.Split(data, []byte(";")) - l := len(d) - if l == 0 { - return nil - } - if l >= 1 { - i.start, err = strconv.ParseUint(string(d[0]), 36, 64) - if err != nil { - return err - } - } - if l == 1 { - return nil - } - - i.ranges = make([][2]uint64, 0, l-1) - for j := 1; j < l; j++ { - r := bytes.SplitN(d[j], []byte(","), 2) - if len(r) < 2 { - return fmt.Errorf("range %d has less then 2 elements", j) - } - start, err := strconv.ParseUint(string(r[0]), 36, 64) - if err != nil { - return fmt.Errorf("parsing the first element in range %d: %v", j, err) - } - end, err := strconv.ParseUint(string(r[1]), 36, 64) - if err != nil { - return fmt.Errorf("parsing the second element in range %d: %v", j, err) - } - i.ranges = append(i.ranges, [2]uint64{start, end}) - } - - return nil -} diff --git a/swarm/network/stream/intervals/intervals_test.go b/swarm/network/stream/intervals/intervals_test.go deleted file mode 100644 index b5212f0d91..0000000000 --- a/swarm/network/stream/intervals/intervals_test.go +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package intervals - -import "testing" - -// Test tests Interval methods Add, Next and Last for various -// initial state. -func Test(t *testing.T) { - for i, tc := range []struct { - startLimit uint64 - initial [][2]uint64 - start uint64 - end uint64 - expected string - nextStart uint64 - nextEnd uint64 - last uint64 - }{ - { - initial: nil, - start: 0, - end: 0, - expected: "[[0 0]]", - nextStart: 1, - nextEnd: 0, - last: 0, - }, - { - initial: nil, - start: 0, - end: 10, - expected: "[[0 10]]", - nextStart: 11, - nextEnd: 0, - last: 10, - }, - { - initial: nil, - start: 5, - end: 15, - expected: "[[5 15]]", - nextStart: 0, - nextEnd: 4, - last: 15, - }, - { - initial: [][2]uint64{{0, 0}}, - start: 0, - end: 0, - expected: "[[0 0]]", - nextStart: 1, - nextEnd: 0, - last: 0, - }, - { - initial: [][2]uint64{{0, 0}}, - start: 5, - end: 15, - expected: "[[0 0] [5 15]]", - nextStart: 1, - nextEnd: 4, - last: 15, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 5, - end: 15, - expected: "[[5 15]]", - nextStart: 0, - nextEnd: 4, - last: 15, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 5, - end: 20, - expected: "[[5 20]]", - nextStart: 0, - nextEnd: 4, - last: 20, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 10, - end: 20, - expected: "[[5 20]]", - nextStart: 0, - nextEnd: 4, - last: 20, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 0, - end: 20, - expected: "[[0 20]]", - nextStart: 21, - nextEnd: 0, - last: 20, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 2, - end: 10, - expected: "[[2 15]]", - nextStart: 0, - nextEnd: 1, - last: 15, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 2, - end: 4, - expected: "[[2 15]]", - nextStart: 0, - nextEnd: 1, - last: 15, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 2, - end: 5, - expected: "[[2 15]]", - nextStart: 0, - nextEnd: 1, - last: 15, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 2, - end: 3, - expected: "[[2 3] [5 15]]", - nextStart: 0, - nextEnd: 1, - last: 15, - }, - { - initial: [][2]uint64{{5, 15}}, - start: 2, - end: 4, - expected: "[[2 15]]", - nextStart: 0, - nextEnd: 1, - last: 15, - }, - { - initial: [][2]uint64{{0, 1}, {5, 15}}, - start: 2, - end: 4, - expected: "[[0 15]]", - nextStart: 16, - nextEnd: 0, - last: 15, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}}, - start: 2, - end: 10, - expected: "[[0 10] [15 20]]", - nextStart: 11, - nextEnd: 14, - last: 20, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}}, - start: 8, - end: 18, - expected: "[[0 5] [8 20]]", - nextStart: 6, - nextEnd: 7, - last: 20, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}}, - start: 2, - end: 17, - expected: "[[0 20]]", - nextStart: 21, - nextEnd: 0, - last: 20, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}}, - start: 2, - end: 25, - expected: "[[0 25]]", - nextStart: 26, - nextEnd: 0, - last: 25, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}}, - start: 5, - end: 14, - expected: "[[0 20]]", - nextStart: 21, - nextEnd: 0, - last: 20, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}}, - start: 6, - end: 14, - expected: "[[0 20]]", - nextStart: 21, - nextEnd: 0, - last: 20, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}}, - start: 6, - end: 29, - expected: "[[0 40]]", - nextStart: 41, - nextEnd: 0, - last: 40, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, - start: 3, - end: 55, - expected: "[[0 60]]", - nextStart: 61, - nextEnd: 0, - last: 60, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, - start: 21, - end: 49, - expected: "[[0 5] [15 60]]", - nextStart: 6, - nextEnd: 14, - last: 60, - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, - start: 0, - end: 100, - expected: "[[0 100]]", - nextStart: 101, - nextEnd: 0, - last: 100, - }, - { - startLimit: 100, - initial: nil, - start: 0, - end: 0, - expected: "[]", - nextStart: 100, - nextEnd: 0, - last: 0, - }, - { - startLimit: 100, - initial: nil, - start: 20, - end: 30, - expected: "[]", - nextStart: 100, - nextEnd: 0, - last: 0, - }, - { - startLimit: 100, - initial: nil, - start: 50, - end: 100, - expected: "[[100 100]]", - nextStart: 101, - nextEnd: 0, - last: 100, - }, - { - startLimit: 100, - initial: nil, - start: 50, - end: 110, - expected: "[[100 110]]", - nextStart: 111, - nextEnd: 0, - last: 110, - }, - { - startLimit: 100, - initial: nil, - start: 120, - end: 130, - expected: "[[120 130]]", - nextStart: 100, - nextEnd: 119, - last: 130, - }, - { - startLimit: 100, - initial: nil, - start: 120, - end: 130, - expected: "[[120 130]]", - nextStart: 100, - nextEnd: 119, - last: 130, - }, - } { - intervals := NewIntervals(tc.startLimit) - intervals.ranges = tc.initial - intervals.Add(tc.start, tc.end) - got := intervals.String() - if got != tc.expected { - t.Errorf("interval #%d: expected %s, got %s", i, tc.expected, got) - } - nextStart, nextEnd := intervals.Next() - if nextStart != tc.nextStart { - t.Errorf("interval #%d, expected next start %d, got %d", i, tc.nextStart, nextStart) - } - if nextEnd != tc.nextEnd { - t.Errorf("interval #%d, expected next end %d, got %d", i, tc.nextEnd, nextEnd) - } - last := intervals.Last() - if last != tc.last { - t.Errorf("interval #%d, expected last %d, got %d", i, tc.last, last) - } - } -} - -func TestMerge(t *testing.T) { - for i, tc := range []struct { - initial [][2]uint64 - merge [][2]uint64 - expected string - }{ - { - initial: nil, - merge: nil, - expected: "[]", - }, - { - initial: [][2]uint64{{10, 20}}, - merge: nil, - expected: "[[10 20]]", - }, - { - initial: nil, - merge: [][2]uint64{{15, 25}}, - expected: "[[15 25]]", - }, - { - initial: [][2]uint64{{0, 100}}, - merge: [][2]uint64{{150, 250}}, - expected: "[[0 100] [150 250]]", - }, - { - initial: [][2]uint64{{0, 100}}, - merge: [][2]uint64{{101, 250}}, - expected: "[[0 250]]", - }, - { - initial: [][2]uint64{{0, 10}, {30, 40}}, - merge: [][2]uint64{{20, 25}, {41, 50}}, - expected: "[[0 10] [20 25] [30 50]]", - }, - { - initial: [][2]uint64{{0, 5}, {15, 20}, {30, 40}, {50, 60}}, - merge: [][2]uint64{{6, 25}}, - expected: "[[0 25] [30 40] [50 60]]", - }, - } { - intervals := NewIntervals(0) - intervals.ranges = tc.initial - m := NewIntervals(0) - m.ranges = tc.merge - - intervals.Merge(m) - - got := intervals.String() - if got != tc.expected { - t.Errorf("interval #%d: expected %s, got %s", i, tc.expected, got) - } - } -} diff --git a/swarm/network/stream/intervals/store_test.go b/swarm/network/stream/intervals/store_test.go deleted file mode 100644 index a36814b717..0000000000 --- a/swarm/network/stream/intervals/store_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package intervals - -import ( - "testing" - - "github.com/ethereum/go-ethereum/swarm/state" -) - -// TestInmemoryStore tests basic functionality of InmemoryStore. -func TestInmemoryStore(t *testing.T) { - testStore(t, state.NewInmemoryStore()) -} - -// testStore is a helper function to test various Store implementations. -func testStore(t *testing.T, s state.Store) { - key1 := "key1" - i1 := NewIntervals(0) - i1.Add(10, 20) - if err := s.Put(key1, i1); err != nil { - t.Fatal(err) - } - i := &Intervals{} - err := s.Get(key1, i) - if err != nil { - t.Fatal(err) - } - if i.String() != i1.String() { - t.Errorf("expected interval %s, got %s", i1, i) - } - - key2 := "key2" - i2 := NewIntervals(0) - i2.Add(10, 20) - if err := s.Put(key2, i2); err != nil { - t.Fatal(err) - } - err = s.Get(key2, i) - if err != nil { - t.Fatal(err) - } - if i.String() != i2.String() { - t.Errorf("expected interval %s, got %s", i2, i) - } - - if err := s.Delete(key1); err != nil { - t.Fatal(err) - } - if err := s.Get(key1, i); err != state.ErrNotFound { - t.Errorf("expected error %v, got %s", state.ErrNotFound, err) - } - if err := s.Get(key2, i); err != nil { - t.Errorf("expected error %v, got %s", nil, err) - } - - if err := s.Delete(key2); err != nil { - t.Fatal(err) - } - if err := s.Get(key2, i); err != state.ErrNotFound { - t.Errorf("expected error %v, got %s", state.ErrNotFound, err) - } -} diff --git a/swarm/network/stream/intervals_test.go b/swarm/network/stream/intervals_test.go deleted file mode 100644 index 660954857e..0000000000 --- a/swarm/network/stream/intervals_test.go +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "encoding/binary" - "errors" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -func TestIntervalsLive(t *testing.T) { - testIntervals(t, true, nil, false) - testIntervals(t, true, nil, true) -} - -func TestIntervalsHistory(t *testing.T) { - testIntervals(t, false, NewRange(9, 26), false) - testIntervals(t, false, NewRange(9, 26), true) -} - -func TestIntervalsLiveAndHistory(t *testing.T) { - testIntervals(t, true, NewRange(9, 26), false) - testIntervals(t, true, NewRange(9, 26), true) -} - -func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { - - nodes := 2 - chunkCount := dataChunkCount - externalStreamName := "externalStream" - externalStreamSessionAt := uint64(50) - externalStreamMaxKeys := uint64(100) - - sim := simulation.New(map[string]simulation.ServiceFunc{ - "intervalsStreamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Syncing: SyncingRegisterOnly, - SkipCheck: skipCheck, - }, nil) - bucket.Store(bucketKeyRegistry, r) - - r.RegisterClientFunc(externalStreamName, func(p *Peer, t string, live bool) (Client, error) { - return newTestExternalClient(netStore), nil - }) - r.RegisterServerFunc(externalStreamName, func(p *Peer, t string, live bool) (Server, error) { - return newTestExternalServer(t, externalStreamSessionAt, externalStreamMaxKeys, nil), nil - }) - - cleanup := func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, - }) - defer sim.Close() - - log.Info("Adding nodes to simulation") - _, err := sim.AddNodesAndConnectChain(nodes) - if err != nil { - t.Fatal(err) - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - defer cancel() - - if _, err := sim.WaitTillHealthy(ctx); err != nil { - t.Fatal(err) - } - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { - nodeIDs := sim.UpNodeIDs() - storer := nodeIDs[0] - checker := nodeIDs[1] - - item, ok := sim.NodeItem(storer, bucketKeyFileStore) - if !ok { - return fmt.Errorf("No filestore") - } - fileStore := item.(*storage.FileStore) - - size := chunkCount * chunkSize - - _, wait, err := fileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false) - if err != nil { - return fmt.Errorf("store: %v", err) - } - err = wait(ctx) - if err != nil { - return fmt.Errorf("wait store: %v", err) - } - - item, ok = sim.NodeItem(checker, bucketKeyRegistry) - if !ok { - return fmt.Errorf("No registry") - } - registry := item.(*Registry) - - liveErrC := make(chan error) - historyErrC := make(chan error) - - err = registry.Subscribe(storer, NewStream(externalStreamName, "", live), history, Top) - if err != nil { - return err - } - - disconnected := watchDisconnections(ctx, sim) - defer func() { - if err != nil && disconnected.bool() { - err = errors.New("disconnect events received") - } - }() - - go func() { - if !live { - close(liveErrC) - return - } - - var err error - defer func() { - liveErrC <- err - }() - - // live stream - var liveHashesChan chan []byte - liveHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", true)) - if err != nil { - log.Error("get hashes", "err", err) - return - } - i := externalStreamSessionAt - - // we have subscribed, enable notifications - err = enableNotifications(registry, storer, NewStream(externalStreamName, "", true)) - if err != nil { - return - } - - for { - select { - case hash := <-liveHashesChan: - h := binary.BigEndian.Uint64(hash) - if h != i { - err = fmt.Errorf("expected live hash %d, got %d", i, h) - return - } - i++ - if i > externalStreamMaxKeys { - return - } - case <-ctx.Done(): - return - } - } - }() - - go func() { - if live && history == nil { - close(historyErrC) - return - } - - var err error - defer func() { - historyErrC <- err - }() - - // history stream - var historyHashesChan chan []byte - historyHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", false)) - if err != nil { - log.Error("get hashes", "err", err) - return - } - - var i uint64 - historyTo := externalStreamMaxKeys - if history != nil { - i = history.From - if history.To != 0 { - historyTo = history.To - } - } - - // we have subscribed, enable notifications - err = enableNotifications(registry, storer, NewStream(externalStreamName, "", false)) - if err != nil { - return - } - - for { - select { - case hash := <-historyHashesChan: - h := binary.BigEndian.Uint64(hash) - if h != i { - err = fmt.Errorf("expected history hash %d, got %d", i, h) - return - } - i++ - if i > historyTo { - return - } - case <-ctx.Done(): - return - } - } - }() - - if err := <-liveErrC; err != nil { - return err - } - if err := <-historyErrC; err != nil { - return err - } - - return nil - }) - - if result.Error != nil { - t.Fatal(result.Error) - } -} - -func getHashes(ctx context.Context, r *Registry, peerID enode.ID, s Stream) (chan []byte, error) { - peer := r.getPeer(peerID) - - client, err := peer.getClient(ctx, s) - if err != nil { - return nil, err - } - - c := client.Client.(*testExternalClient) - - return c.hashes, nil -} - -func enableNotifications(r *Registry, peerID enode.ID, s Stream) error { - peer := r.getPeer(peerID) - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - client, err := peer.getClient(ctx, s) - if err != nil { - return err - } - - close(client.Client.(*testExternalClient).enableNotificationsC) - - return nil -} - -type testExternalClient struct { - hashes chan []byte - netStore *storage.NetStore - enableNotificationsC chan struct{} -} - -func newTestExternalClient(netStore *storage.NetStore) *testExternalClient { - return &testExternalClient{ - hashes: make(chan []byte), - netStore: netStore, - enableNotificationsC: make(chan struct{}), - } -} - -func (c *testExternalClient) NeedData(ctx context.Context, hash []byte) func(context.Context) error { - wait := c.netStore.FetchFunc(ctx, storage.Address(hash)) - if wait == nil { - return nil - } - select { - case c.hashes <- hash: - case <-ctx.Done(): - log.Warn("testExternalClient NeedData context", "err", ctx.Err()) - return func(_ context.Context) error { - return ctx.Err() - } - } - return wait -} - -func (c *testExternalClient) BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) { - return nil -} - -func (c *testExternalClient) Close() {} - -type testExternalServer struct { - t string - keyFunc func(key []byte, index uint64) - sessionAt uint64 - maxKeys uint64 -} - -func newTestExternalServer(t string, sessionAt, maxKeys uint64, keyFunc func(key []byte, index uint64)) *testExternalServer { - if keyFunc == nil { - keyFunc = binary.BigEndian.PutUint64 - } - return &testExternalServer{ - t: t, - keyFunc: keyFunc, - sessionAt: sessionAt, - maxKeys: maxKeys, - } -} - -func (s *testExternalServer) SessionIndex() (uint64, error) { - return s.sessionAt, nil -} - -func (s *testExternalServer) SetNextBatch(from uint64, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { - if to > s.maxKeys { - to = s.maxKeys - } - b := make([]byte, HashSize*(to-from+1)) - for i := from; i <= to; i++ { - s.keyFunc(b[(i-from)*HashSize:(i-from+1)*HashSize], i) - } - return b, from, to, nil, nil -} - -func (s *testExternalServer) GetData(context.Context, []byte) ([]byte, error) { - return make([]byte, 4096), nil -} - -func (s *testExternalServer) Close() {} diff --git a/swarm/network/stream/lightnode_test.go b/swarm/network/stream/lightnode_test.go deleted file mode 100644 index eb4e73d475..0000000000 --- a/swarm/network/stream/lightnode_test.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package stream - -import ( - "testing" - - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" -) - -// This test checks the default behavior of the server, that is -// when syncing is enabled. -func TestLigthnodeRequestSubscriptionWithSync(t *testing.T) { - registryOptions := &RegistryOptions{ - Syncing: SyncingRegisterOnly, - } - tester, _, _, teardown, err := newStreamerTester(registryOptions) - if err != nil { - t.Fatal(err) - } - defer teardown() - - node := tester.Nodes[0] - - syncStream := NewStream("SYNC", FormatSyncBinKey(1), false) - - err = tester.TestExchanges( - p2ptest.Exchange{ - Label: "RequestSubscription", - Triggers: []p2ptest.Trigger{ - { - Code: 8, - Msg: &RequestSubscriptionMsg{ - Stream: syncStream, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: syncStream, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatalf("Got %v", err) - } -} - -// This test checks the Lightnode behavior of the server, that is -// when syncing is disabled. -func TestLigthnodeRequestSubscriptionWithoutSync(t *testing.T) { - registryOptions := &RegistryOptions{ - Syncing: SyncingDisabled, - } - tester, _, _, teardown, err := newStreamerTester(registryOptions) - if err != nil { - t.Fatal(err) - } - defer teardown() - - node := tester.Nodes[0] - - syncStream := NewStream("SYNC", FormatSyncBinKey(1), false) - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "RequestSubscription", - Triggers: []p2ptest.Trigger{ - { - Code: 8, - Msg: &RequestSubscriptionMsg{ - Stream: syncStream, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 7, - Msg: &SubscribeErrorMsg{ - Error: "stream SYNC not registered", - }, - Peer: node.ID(), - }, - }, - }, p2ptest.Exchange{ - Label: "RequestSubscription", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: syncStream, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 7, - Msg: &SubscribeErrorMsg{ - Error: "stream SYNC not registered", - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatalf("Got %v", err) - } -} diff --git a/swarm/network/stream/messages.go b/swarm/network/stream/messages.go deleted file mode 100644 index 339101b883..0000000000 --- a/swarm/network/stream/messages.go +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/log" - bv "github.com/ethereum/go-ethereum/swarm/network/bitvector" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -var syncBatchTimeout = 30 * time.Second - -// Stream defines a unique stream identifier. -type Stream struct { - // Name is used for Client and Server functions identification. - Name string - // Key is the name of specific stream data. - Key string - // Live defines whether the stream delivers only new data - // for the specific stream. - Live bool -} - -func NewStream(name string, key string, live bool) Stream { - return Stream{ - Name: name, - Key: key, - Live: live, - } -} - -// String return a stream id based on all Stream fields. -func (s Stream) String() string { - t := "h" - if s.Live { - t = "l" - } - return fmt.Sprintf("%s|%s|%s", s.Name, s.Key, t) -} - -// SubcribeMsg is the protocol msg for requesting a stream(section) -type SubscribeMsg struct { - Stream Stream - History *Range `rlp:"nil"` - Priority uint8 // delivered on priority channel -} - -// RequestSubscriptionMsg is the protocol msg for a node to request subscription to a -// specific stream -type RequestSubscriptionMsg struct { - Stream Stream - History *Range `rlp:"nil"` - Priority uint8 // delivered on priority channel -} - -func (p *Peer) handleRequestSubscription(ctx context.Context, req *RequestSubscriptionMsg) (err error) { - log.Debug(fmt.Sprintf("handleRequestSubscription: streamer %s to subscribe to %s with stream %s", p.streamer.addr, p.ID(), req.Stream)) - if err = p.streamer.Subscribe(p.ID(), req.Stream, req.History, req.Priority); err != nil { - // The error will be sent as a subscribe error message - // and will not be returned as it will prevent any new message - // exchange between peers over p2p. Instead, error will be returned - // only if there is one from sending subscribe error message. - err = p.Send(ctx, SubscribeErrorMsg{ - Error: err.Error(), - }) - } - return err -} - -func (p *Peer) handleSubscribeMsg(ctx context.Context, req *SubscribeMsg) (err error) { - metrics.GetOrRegisterCounter("peer.handlesubscribemsg", nil).Inc(1) - - defer func() { - if err != nil { - // The error will be sent as a subscribe error message - // and will not be returned as it will prevent any new message - // exchange between peers over p2p. Instead, error will be returned - // only if there is one from sending subscribe error message. - err = p.Send(context.TODO(), SubscribeErrorMsg{ - Error: err.Error(), - }) - } - }() - - log.Debug("received subscription", "from", p.streamer.addr, "peer", p.ID(), "stream", req.Stream, "history", req.History) - - f, err := p.streamer.GetServerFunc(req.Stream.Name) - if err != nil { - return err - } - - s, err := f(p, req.Stream.Key, req.Stream.Live) - if err != nil { - return err - } - os, err := p.setServer(req.Stream, s, req.Priority) - if err != nil { - return err - } - - var from uint64 - var to uint64 - if !req.Stream.Live && req.History != nil { - from = req.History.From - to = req.History.To - } - - go func() { - if err := p.SendOfferedHashes(os, from, to); err != nil { - log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) - } - }() - - if req.Stream.Live && req.History != nil { - // subscribe to the history stream - s, err := f(p, req.Stream.Key, false) - if err != nil { - return err - } - - os, err := p.setServer(getHistoryStream(req.Stream), s, getHistoryPriority(req.Priority)) - if err != nil { - return err - } - go func() { - if err := p.SendOfferedHashes(os, req.History.From, req.History.To); err != nil { - log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) - } - }() - } - - return nil -} - -type SubscribeErrorMsg struct { - Error string -} - -func (p *Peer) handleSubscribeErrorMsg(req *SubscribeErrorMsg) (err error) { - //TODO the error should be channeled to whoever calls the subscribe - return fmt.Errorf("subscribe to peer %s: %v", p.ID(), req.Error) -} - -type UnsubscribeMsg struct { - Stream Stream -} - -func (p *Peer) handleUnsubscribeMsg(req *UnsubscribeMsg) error { - return p.removeServer(req.Stream) -} - -type QuitMsg struct { - Stream Stream -} - -func (p *Peer) handleQuitMsg(req *QuitMsg) error { - err := p.removeClient(req.Stream) - if _, ok := err.(*notFoundError); ok { - return nil - } - return err -} - -// OfferedHashesMsg is the protocol msg for offering to hand over a -// stream section -type OfferedHashesMsg struct { - Stream Stream // name of Stream - From, To uint64 // peer and db-specific entry count - Hashes []byte // stream of hashes (128) - *HandoverProof // HandoverProof -} - -// String pretty prints OfferedHashesMsg -func (m OfferedHashesMsg) String() string { - return fmt.Sprintf("Stream '%v' [%v-%v] (%v)", m.Stream, m.From, m.To, len(m.Hashes)/HashSize) -} - -// handleOfferedHashesMsg protocol msg handler calls the incoming streamer interface -// Filter method -func (p *Peer) handleOfferedHashesMsg(ctx context.Context, req *OfferedHashesMsg) error { - metrics.GetOrRegisterCounter("peer.handleofferedhashes", nil).Inc(1) - - c, _, err := p.getOrSetClient(req.Stream, req.From, req.To) - if err != nil { - return err - } - - hashes := req.Hashes - lenHashes := len(hashes) - if lenHashes%HashSize != 0 { - return fmt.Errorf("error invalid hashes length (len: %v)", lenHashes) - } - - want, err := bv.New(lenHashes / HashSize) - if err != nil { - return fmt.Errorf("error initiaising bitvector of length %v: %v", lenHashes/HashSize, err) - } - - var wantDelaySet bool - var wantDelay time.Time - - ctr := 0 - errC := make(chan error) - ctx, cancel := context.WithTimeout(ctx, syncBatchTimeout) - - ctx = context.WithValue(ctx, "source", p.ID().String()) - for i := 0; i < lenHashes; i += HashSize { - hash := hashes[i : i+HashSize] - - if wait := c.NeedData(ctx, hash); wait != nil { - ctr++ - want.Set(i/HashSize, true) - - // measure how long it takes before we mark chunks for retrieval, and actually send the request - if !wantDelaySet { - wantDelaySet = true - wantDelay = time.Now() - } - - // create request and wait until the chunk data arrives and is stored - go func(w func(context.Context) error) { - select { - case errC <- w(ctx): - case <-ctx.Done(): - } - }(wait) - } - } - - go func() { - defer cancel() - for i := 0; i < ctr; i++ { - select { - case err := <-errC: - if err != nil { - log.Debug("client.handleOfferedHashesMsg() error waiting for chunk, dropping peer", "peer", p.ID(), "err", err) - p.Drop() - return - } - case <-ctx.Done(): - log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) - return - case <-c.quit: - log.Debug("client.handleOfferedHashesMsg() quit") - return - } - } - select { - case c.next <- c.batchDone(p, req, hashes): - case <-c.quit: - log.Debug("client.handleOfferedHashesMsg() quit") - case <-ctx.Done(): - log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) - } - }() - // only send wantedKeysMsg if all missing chunks of the previous batch arrived - // except - if c.stream.Live { - c.sessionAt = req.From - } - from, to := c.nextBatch(req.To + 1) - log.Trace("set next batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "addr", p.streamer.addr) - if from == to { - return nil - } - - msg := &WantedHashesMsg{ - Stream: req.Stream, - Want: want.Bytes(), - From: from, - To: to, - } - - log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) - select { - case err := <-c.next: - if err != nil { - log.Warn("c.next error dropping peer", "err", err) - p.Drop() - return err - } - case <-c.quit: - log.Debug("client.handleOfferedHashesMsg() quit") - return nil - case <-ctx.Done(): - log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) - return nil - } - log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) - - // record want delay - if wantDelaySet { - metrics.GetOrRegisterResettingTimer("handleoffered.wantdelay", nil).UpdateSince(wantDelay) - } - - err = p.SendPriority(ctx, msg, c.priority) - if err != nil { - log.Warn("SendPriority error", "err", err) - } - - return nil -} - -// WantedHashesMsg is the protocol msg data for signaling which hashes -// offered in OfferedHashesMsg downstream peer actually wants sent over -type WantedHashesMsg struct { - Stream Stream - Want []byte // bitvector indicating which keys of the batch needed - From, To uint64 // next interval offset - empty if not to be continued -} - -// String pretty prints WantedHashesMsg -func (m WantedHashesMsg) String() string { - return fmt.Sprintf("Stream '%v', Want: %x, Next: [%v-%v]", m.Stream, m.Want, m.From, m.To) -} - -// handleWantedHashesMsg protocol msg handler -// * sends the next batch of unsynced keys -// * sends the actual data chunks as per WantedHashesMsg -func (p *Peer) handleWantedHashesMsg(ctx context.Context, req *WantedHashesMsg) error { - metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg", nil).Inc(1) - - log.Trace("received wanted batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To) - s, err := p.getServer(req.Stream) - if err != nil { - return err - } - hashes := s.currentBatch - // launch in go routine since GetBatch blocks until new hashes arrive - go func() { - if err := p.SendOfferedHashes(s, req.From, req.To); err != nil { - log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) - } - }() - // go p.SendOfferedHashes(s, req.From, req.To) - l := len(hashes) / HashSize - - log.Trace("wanted batch length", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "lenhashes", len(hashes), "l", l) - want, err := bv.NewFromBytes(req.Want, l) - if err != nil { - return fmt.Errorf("error initiaising bitvector of length %v: %v", l, err) - } - for i := 0; i < l; i++ { - if want.Get(i) { - metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg.actualget", nil).Inc(1) - - hash := hashes[i*HashSize : (i+1)*HashSize] - data, err := s.GetData(ctx, hash) - if err != nil { - return fmt.Errorf("handleWantedHashesMsg get data %x: %v", hash, err) - } - chunk := storage.NewChunk(hash, data) - syncing := true - if err := p.Deliver(ctx, chunk, s.priority, syncing); err != nil { - return err - } - } - } - return nil -} - -// Handover represents a statement that the upstream peer hands over the stream section -type Handover struct { - Stream Stream // name of stream - Start, End uint64 // index of hashes - Root []byte // Root hash for indexed segment inclusion proofs -} - -// HandoverProof represents a signed statement that the upstream peer handed over the stream section -type HandoverProof struct { - Sig []byte // Sign(Hash(Serialisation(Handover))) - *Handover -} - -// Takeover represents a statement that downstream peer took over (stored all data) -// handed over -type Takeover Handover - -// TakeoverProof represents a signed statement that the downstream peer took over -// the stream section -type TakeoverProof struct { - Sig []byte // Sign(Hash(Serialisation(Takeover))) - *Takeover -} - -// TakeoverProofMsg is the protocol msg sent by downstream peer -type TakeoverProofMsg TakeoverProof - -// String pretty prints TakeoverProofMsg -func (m TakeoverProofMsg) String() string { - return fmt.Sprintf("Stream: '%v' [%v-%v], Root: %x, Sig: %x", m.Stream, m.Start, m.End, m.Root, m.Sig) -} - -func (p *Peer) handleTakeoverProofMsg(ctx context.Context, req *TakeoverProofMsg) error { - _, err := p.getServer(req.Stream) - // store the strongest takeoverproof for the stream in streamer - return err -} diff --git a/swarm/network/stream/peer.go b/swarm/network/stream/peer.go deleted file mode 100644 index 28fd06e4d5..0000000000 --- a/swarm/network/stream/peer.go +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "errors" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - pq "github.com/ethereum/go-ethereum/swarm/network/priorityqueue" - "github.com/ethereum/go-ethereum/swarm/network/stream/intervals" - "github.com/ethereum/go-ethereum/swarm/spancontext" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/tracing" - opentracing "github.com/opentracing/opentracing-go" -) - -type notFoundError struct { - t string - s Stream -} - -func newNotFoundError(t string, s Stream) *notFoundError { - return ¬FoundError{t: t, s: s} -} - -func (e *notFoundError) Error() string { - return fmt.Sprintf("%s not found for stream %q", e.t, e.s) -} - -// ErrMaxPeerServers will be returned if peer server limit is reached. -// It will be sent in the SubscribeErrorMsg. -var ErrMaxPeerServers = errors.New("max peer servers") - -// Peer is the Peer extension for the streaming protocol -type Peer struct { - *network.BzzPeer - streamer *Registry - pq *pq.PriorityQueue - serverMu sync.RWMutex - clientMu sync.RWMutex // protects both clients and clientParams - servers map[Stream]*server - clients map[Stream]*client - // clientParams map keeps required client arguments - // that are set on Registry.Subscribe and used - // on creating a new client in offered hashes handler. - clientParams map[Stream]*clientParams - quit chan struct{} -} - -type WrappedPriorityMsg struct { - Context context.Context - Msg interface{} -} - -// NewPeer is the constructor for Peer -func NewPeer(peer *network.BzzPeer, streamer *Registry) *Peer { - p := &Peer{ - BzzPeer: peer, - pq: pq.New(int(PriorityQueue), PriorityQueueCap), - streamer: streamer, - servers: make(map[Stream]*server), - clients: make(map[Stream]*client), - clientParams: make(map[Stream]*clientParams), - quit: make(chan struct{}), - } - ctx, cancel := context.WithCancel(context.Background()) - go p.pq.Run(ctx, func(i interface{}) { - wmsg := i.(WrappedPriorityMsg) - err := p.Send(wmsg.Context, wmsg.Msg) - if err != nil { - log.Error("Message send error, dropping peer", "peer", p.ID(), "err", err) - p.Drop() - } - }) - - // basic monitoring for pq contention - go func(pq *pq.PriorityQueue) { - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - for { - select { - case <-ticker.C: - var lenMaxi int - var capMaxi int - for k := range pq.Queues { - if lenMaxi < len(pq.Queues[k]) { - lenMaxi = len(pq.Queues[k]) - } - - if capMaxi < cap(pq.Queues[k]) { - capMaxi = cap(pq.Queues[k]) - } - } - - metrics.GetOrRegisterGauge(fmt.Sprintf("pq_len_%s", p.ID().TerminalString()), nil).Update(int64(lenMaxi)) - metrics.GetOrRegisterGauge(fmt.Sprintf("pq_cap_%s", p.ID().TerminalString()), nil).Update(int64(capMaxi)) - case <-p.quit: - return - } - } - }(p.pq) - - go func() { - <-p.quit - - cancel() - }() - return p -} - -// Deliver sends a storeRequestMsg protocol message to the peer -// Depending on the `syncing` parameter we send different message types -func (p *Peer) Deliver(ctx context.Context, chunk storage.Chunk, priority uint8, syncing bool) error { - var msg interface{} - - metrics.GetOrRegisterCounter("peer.deliver", nil).Inc(1) - - //we send different types of messages if delivery is for syncing or retrievals, - //even if handling and content of the message are the same, - //because swap accounting decides which messages need accounting based on the message type - if syncing { - msg = &ChunkDeliveryMsgSyncing{ - Addr: chunk.Address(), - SData: chunk.Data(), - } - } else { - msg = &ChunkDeliveryMsgRetrieval{ - Addr: chunk.Address(), - SData: chunk.Data(), - } - } - - return p.SendPriority(ctx, msg, priority) -} - -// SendPriority sends message to the peer using the outgoing priority queue -func (p *Peer) SendPriority(ctx context.Context, msg interface{}, priority uint8) error { - defer metrics.GetOrRegisterResettingTimer(fmt.Sprintf("peer.sendpriority_t.%d", priority), nil).UpdateSince(time.Now()) - ctx = tracing.StartSaveSpan(ctx) - metrics.GetOrRegisterCounter(fmt.Sprintf("peer.sendpriority.%d", priority), nil).Inc(1) - wmsg := WrappedPriorityMsg{ - Context: ctx, - Msg: msg, - } - err := p.pq.Push(wmsg, int(priority)) - if err != nil { - log.Error("err on p.pq.Push", "err", err, "peer", p.ID()) - } - return err -} - -// SendOfferedHashes sends OfferedHashesMsg protocol msg -func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error { - var sp opentracing.Span - ctx, sp := spancontext.StartSpan( - context.TODO(), - "send.offered.hashes", - ) - defer sp.Finish() - - defer metrics.GetOrRegisterResettingTimer("send.offered.hashes", nil).UpdateSince(time.Now()) - - hashes, from, to, proof, err := s.setNextBatch(f, t) - if err != nil { - return err - } - // true only when quitting - if len(hashes) == 0 { - return nil - } - if proof == nil { - proof = &HandoverProof{ - Handover: &Handover{}, - } - } - s.currentBatch = hashes - msg := &OfferedHashesMsg{ - HandoverProof: proof, - Hashes: hashes, - From: from, - To: to, - Stream: s.stream, - } - log.Trace("Swarm syncer offer batch", "peer", p.ID(), "stream", s.stream, "len", len(hashes), "from", from, "to", to) - ctx = context.WithValue(ctx, "stream_send_tag", "send.offered.hashes") - return p.SendPriority(ctx, msg, s.priority) -} - -func (p *Peer) getServer(s Stream) (*server, error) { - p.serverMu.RLock() - defer p.serverMu.RUnlock() - - server := p.servers[s] - if server == nil { - return nil, newNotFoundError("server", s) - } - return server, nil -} - -func (p *Peer) setServer(s Stream, o Server, priority uint8) (*server, error) { - p.serverMu.Lock() - defer p.serverMu.Unlock() - - if p.servers[s] != nil { - return nil, fmt.Errorf("server %s already registered", s) - } - - if p.streamer.maxPeerServers > 0 && len(p.servers) >= p.streamer.maxPeerServers { - return nil, ErrMaxPeerServers - } - - sessionIndex, err := o.SessionIndex() - if err != nil { - return nil, err - } - os := &server{ - Server: o, - stream: s, - priority: priority, - sessionIndex: sessionIndex, - } - p.servers[s] = os - return os, nil -} - -func (p *Peer) removeServer(s Stream) error { - p.serverMu.Lock() - defer p.serverMu.Unlock() - - server, ok := p.servers[s] - if !ok { - return newNotFoundError("server", s) - } - server.Close() - delete(p.servers, s) - return nil -} - -func (p *Peer) getClient(ctx context.Context, s Stream) (c *client, err error) { - var params *clientParams - func() { - p.clientMu.RLock() - defer p.clientMu.RUnlock() - - c = p.clients[s] - if c != nil { - return - } - params = p.clientParams[s] - }() - if c != nil { - return c, nil - } - - if params != nil { - //debug.PrintStack() - if err := params.waitClient(ctx); err != nil { - return nil, err - } - } - - p.clientMu.RLock() - defer p.clientMu.RUnlock() - - c = p.clients[s] - if c != nil { - return c, nil - } - return nil, newNotFoundError("client", s) -} - -func (p *Peer) getOrSetClient(s Stream, from, to uint64) (c *client, created bool, err error) { - p.clientMu.Lock() - defer p.clientMu.Unlock() - - c = p.clients[s] - if c != nil { - return c, false, nil - } - - f, err := p.streamer.GetClientFunc(s.Name) - if err != nil { - return nil, false, err - } - - is, err := f(p, s.Key, s.Live) - if err != nil { - return nil, false, err - } - - cp, err := p.getClientParams(s) - if err != nil { - return nil, false, err - } - defer func() { - if err == nil { - if err := p.removeClientParams(s); err != nil { - log.Error("stream set client: remove client params", "stream", s, "peer", p, "err", err) - } - } - }() - - intervalsKey := peerStreamIntervalsKey(p, s) - if s.Live { - // try to find previous history and live intervals and merge live into history - historyKey := peerStreamIntervalsKey(p, NewStream(s.Name, s.Key, false)) - historyIntervals := &intervals.Intervals{} - err := p.streamer.intervalsStore.Get(historyKey, historyIntervals) - switch err { - case nil: - liveIntervals := &intervals.Intervals{} - err := p.streamer.intervalsStore.Get(intervalsKey, liveIntervals) - switch err { - case nil: - historyIntervals.Merge(liveIntervals) - if err := p.streamer.intervalsStore.Put(historyKey, historyIntervals); err != nil { - log.Error("stream set client: put history intervals", "stream", s, "peer", p, "err", err) - } - case state.ErrNotFound: - default: - log.Error("stream set client: get live intervals", "stream", s, "peer", p, "err", err) - } - case state.ErrNotFound: - default: - log.Error("stream set client: get history intervals", "stream", s, "peer", p, "err", err) - } - } - - if err := p.streamer.intervalsStore.Put(intervalsKey, intervals.NewIntervals(from)); err != nil { - return nil, false, err - } - - next := make(chan error, 1) - c = &client{ - Client: is, - stream: s, - priority: cp.priority, - to: cp.to, - next: next, - quit: make(chan struct{}), - intervalsStore: p.streamer.intervalsStore, - intervalsKey: intervalsKey, - } - p.clients[s] = c - cp.clientCreated() // unblock all possible getClient calls that are waiting - next <- nil // this is to allow wantedKeysMsg before first batch arrives - return c, true, nil -} - -func (p *Peer) removeClient(s Stream) error { - p.clientMu.Lock() - defer p.clientMu.Unlock() - - client, ok := p.clients[s] - if !ok { - return newNotFoundError("client", s) - } - client.close() - delete(p.clients, s) - return nil -} - -func (p *Peer) setClientParams(s Stream, params *clientParams) error { - p.clientMu.Lock() - defer p.clientMu.Unlock() - - if p.clients[s] != nil { - return fmt.Errorf("client %s already exists", s) - } - if p.clientParams[s] != nil { - return fmt.Errorf("client params %s already set", s) - } - p.clientParams[s] = params - return nil -} - -func (p *Peer) getClientParams(s Stream) (*clientParams, error) { - params := p.clientParams[s] - if params == nil { - return nil, fmt.Errorf("client params '%v' not provided to peer %v", s, p.ID()) - } - return params, nil -} - -func (p *Peer) removeClientParams(s Stream) error { - _, ok := p.clientParams[s] - if !ok { - return newNotFoundError("client params", s) - } - delete(p.clientParams, s) - return nil -} - -func (p *Peer) close() { - p.serverMu.Lock() - defer p.serverMu.Unlock() - - for _, s := range p.servers { - s.Close() - } - - p.servers = nil -} - -// runUpdateSyncing is a long running function that creates the initial -// syncing subscriptions to the peer and waits for neighbourhood depth change -// to create new ones or quit existing ones based on the new neighbourhood depth -// and if peer enters or leaves nearest neighbourhood by using -// syncSubscriptionsDiff and updateSyncSubscriptions functions. -func (p *Peer) runUpdateSyncing() { - timer := time.NewTimer(p.streamer.syncUpdateDelay) - defer timer.Stop() - - select { - case <-timer.C: - case <-p.streamer.quit: - return - } - - kad := p.streamer.delivery.kad - po := chunk.Proximity(p.BzzAddr.Over(), kad.BaseAddr()) - - depth := kad.NeighbourhoodDepth() - - log.Debug("update syncing subscriptions: initial", "peer", p.ID(), "po", po, "depth", depth) - - // initial subscriptions - p.updateSyncSubscriptions(syncSubscriptionsDiff(po, -1, depth, kad.MaxProxDisplay)) - - depthChangeSignal, unsubscribeDepthChangeSignal := kad.SubscribeToNeighbourhoodDepthChange() - defer unsubscribeDepthChangeSignal() - - prevDepth := depth - for { - select { - case _, ok := <-depthChangeSignal: - if !ok { - return - } - // update subscriptions for this peer when depth changes - depth := kad.NeighbourhoodDepth() - log.Debug("update syncing subscriptions", "peer", p.ID(), "po", po, "depth", depth) - p.updateSyncSubscriptions(syncSubscriptionsDiff(po, prevDepth, depth, kad.MaxProxDisplay)) - prevDepth = depth - case <-p.streamer.quit: - return - } - } - log.Debug("update syncing subscriptions: exiting", "peer", p.ID()) -} - -// updateSyncSubscriptions accepts two slices of integers, the first one -// representing proximity order bins for required syncing subscriptions -// and the second one representing bins for syncing subscriptions that -// need to be removed. This function sends request for subscription -// messages and quit messages for provided bins. -func (p *Peer) updateSyncSubscriptions(subBins, quitBins []int) { - if p.streamer.getPeer(p.ID()) == nil { - log.Debug("update syncing subscriptions", "peer not found", p.ID()) - return - } - log.Debug("update syncing subscriptions", "peer", p.ID(), "subscribe", subBins, "quit", quitBins) - for _, po := range subBins { - p.subscribeSync(po) - } - for _, po := range quitBins { - p.quitSync(po) - } -} - -// subscribeSync send the request for syncing subscriptions to the peer -// using subscriptionFunc. This function is used to request syncing subscriptions -// when new peer is added to the registry and on neighbourhood depth change. -func (p *Peer) subscribeSync(po int) { - err := subscriptionFunc(p.streamer, p.ID(), uint8(po)) - if err != nil { - log.Error("subscription", "err", err) - } -} - -// quitSync sends the quit message for live and history syncing streams to the peer. -// This function is used in runUpdateSyncing indirectly over updateSyncSubscriptions -// to remove unneeded syncing subscriptions on neighbourhood depth change. -func (p *Peer) quitSync(po int) { - live := NewStream("SYNC", FormatSyncBinKey(uint8(po)), true) - history := getHistoryStream(live) - err := p.streamer.Quit(p.ID(), live) - if err != nil && err != p2p.ErrShuttingDown { - log.Error("quit", "err", err, "peer", p.ID(), "stream", live) - } - err = p.streamer.Quit(p.ID(), history) - if err != nil && err != p2p.ErrShuttingDown { - log.Error("quit", "err", err, "peer", p.ID(), "stream", history) - } - - err = p.removeServer(live) - if err != nil { - log.Error("remove server", "err", err, "peer", p.ID(), "stream", live) - } - err = p.removeServer(history) - if err != nil { - log.Error("remove server", "err", err, "peer", p.ID(), "stream", live) - } -} - -// syncSubscriptionsDiff calculates to which proximity order bins a peer -// (with po peerPO) needs to be subscribed after kademlia neighbourhood depth -// change from prevDepth to newDepth. Max argument limits the number of -// proximity order bins. Returned values are slices of integers which represent -// proximity order bins, the first one to which additional subscriptions need to -// be requested and the second one which subscriptions need to be quit. Argument -// prevDepth with value less then 0 represents no previous depth, used for -// initial syncing subscriptions. -func syncSubscriptionsDiff(peerPO, prevDepth, newDepth, max int) (subBins, quitBins []int) { - newStart, newEnd := syncBins(peerPO, newDepth, max) - if prevDepth < 0 { - // no previous depth, return the complete range - // for subscriptions requests and nothing for quitting - return intRange(newStart, newEnd), nil - } - - prevStart, prevEnd := syncBins(peerPO, prevDepth, max) - - if newStart < prevStart { - subBins = append(subBins, intRange(newStart, prevStart)...) - } - - if prevStart < newStart { - quitBins = append(quitBins, intRange(prevStart, newStart)...) - } - - if newEnd < prevEnd { - quitBins = append(quitBins, intRange(newEnd, prevEnd)...) - } - - if prevEnd < newEnd { - subBins = append(subBins, intRange(prevEnd, newEnd)...) - } - - return subBins, quitBins -} - -// syncBins returns the range to which proximity order bins syncing -// subscriptions need to be requested, based on peer proximity and -// kademlia neighbourhood depth. Returned range is [start,end), inclusive for -// start and exclusive for end. -func syncBins(peerPO, depth, max int) (start, end int) { - if peerPO < depth { - // subscribe only to peerPO bin if it is not - // in the nearest neighbourhood - return peerPO, peerPO + 1 - } - // subscribe from depth to max bin if the peer - // is in the nearest neighbourhood - return depth, max + 1 -} - -// intRange returns the slice of integers [start,end). The start -// is inclusive and the end is not. -func intRange(start, end int) (r []int) { - for i := start; i < end; i++ { - r = append(r, i) - } - return r -} diff --git a/swarm/network/stream/peer_test.go b/swarm/network/stream/peer_test.go deleted file mode 100644 index 98c5cc0109..0000000000 --- a/swarm/network/stream/peer_test.go +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "fmt" - "reflect" - "sort" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/state" -) - -// TestSyncSubscriptionsDiff validates the output of syncSubscriptionsDiff -// function for various arguments. -func TestSyncSubscriptionsDiff(t *testing.T) { - max := network.NewKadParams().MaxProxDisplay - for _, tc := range []struct { - po, prevDepth, newDepth int - subBins, quitBins []int - }{ - { - po: 0, prevDepth: -1, newDepth: 0, - subBins: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 1, prevDepth: -1, newDepth: 0, - subBins: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 2, prevDepth: -1, newDepth: 0, - subBins: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 0, prevDepth: -1, newDepth: 1, - subBins: []int{0}, - }, - { - po: 1, prevDepth: -1, newDepth: 1, - subBins: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 2, prevDepth: -1, newDepth: 2, - subBins: []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 3, prevDepth: -1, newDepth: 2, - subBins: []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 1, prevDepth: -1, newDepth: 2, - subBins: []int{1}, - }, - { - po: 0, prevDepth: 0, newDepth: 0, // 0-16 -> 0-16 - }, - { - po: 1, prevDepth: 0, newDepth: 0, // 0-16 -> 0-16 - }, - { - po: 0, prevDepth: 0, newDepth: 1, // 0-16 -> 0 - quitBins: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 0, prevDepth: 0, newDepth: 2, // 0-16 -> 0 - quitBins: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 1, prevDepth: 0, newDepth: 1, // 0-16 -> 1-16 - quitBins: []int{0}, - }, - { - po: 1, prevDepth: 1, newDepth: 0, // 1-16 -> 0-16 - subBins: []int{0}, - }, - { - po: 4, prevDepth: 0, newDepth: 1, // 0-16 -> 1-16 - quitBins: []int{0}, - }, - { - po: 4, prevDepth: 0, newDepth: 4, // 0-16 -> 4-16 - quitBins: []int{0, 1, 2, 3}, - }, - { - po: 4, prevDepth: 0, newDepth: 5, // 0-16 -> 4 - quitBins: []int{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 4, prevDepth: 5, newDepth: 0, // 4 -> 0-16 - subBins: []int{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - }, - { - po: 4, prevDepth: 5, newDepth: 6, // 4 -> 4 - }, - } { - subBins, quitBins := syncSubscriptionsDiff(tc.po, tc.prevDepth, tc.newDepth, max) - if fmt.Sprint(subBins) != fmt.Sprint(tc.subBins) { - t.Errorf("po: %v, prevDepth: %v, newDepth: %v: got subBins %v, want %v", tc.po, tc.prevDepth, tc.newDepth, subBins, tc.subBins) - } - if fmt.Sprint(quitBins) != fmt.Sprint(tc.quitBins) { - t.Errorf("po: %v, prevDepth: %v, newDepth: %v: got quitBins %v, want %v", tc.po, tc.prevDepth, tc.newDepth, quitBins, tc.quitBins) - } - } -} - -// TestUpdateSyncingSubscriptions validates that syncing subscriptions are correctly -// made on initial node connections and that subscriptions are correctly changed -// when kademlia neighbourhood depth is changed by connecting more nodes. -func TestUpdateSyncingSubscriptions(t *testing.T) { - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - SyncUpdateDelay: 100 * time.Millisecond, - Syncing: SyncingAutoSubscribe, - }, nil) - cleanup = func() { - r.Close() - clean() - } - bucket.Store("bzz-address", addr) - return r, cleanup, nil - }, - }) - defer sim.Close() - - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancel() - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { - // initial nodes, first one as pivot center of the start - ids, err := sim.AddNodesAndConnectStar(10) - if err != nil { - return err - } - - // pivot values - pivotRegistryID := ids[0] - pivotRegistry := sim.Service("streamer", pivotRegistryID).(*Registry) - pivotKademlia := pivotRegistry.delivery.kad - // nodes proximities from the pivot node - nodeProximities := make(map[string]int) - for _, id := range ids[1:] { - bzzAddr, ok := sim.NodeItem(id, "bzz-address") - if !ok { - t.Fatal("no bzz address for node") - } - nodeProximities[id.String()] = chunk.Proximity(pivotKademlia.BaseAddr(), bzzAddr.(*network.BzzAddr).Over()) - } - // wait until sync subscriptions are done for all nodes - waitForSubscriptions(t, pivotRegistry, ids[1:]...) - - // check initial sync streams - err = checkSyncStreamsWithRetry(pivotRegistry, nodeProximities) - if err != nil { - return err - } - - // add more nodes until the depth is changed - prevDepth := pivotKademlia.NeighbourhoodDepth() - var noDepthChangeChecked bool // true it there was a check when no depth is changed - for { - ids, err := sim.AddNodes(5) - if err != nil { - return err - } - // add new nodes to sync subscriptions check - for _, id := range ids { - bzzAddr, ok := sim.NodeItem(id, "bzz-address") - if !ok { - t.Fatal("no bzz address for node") - } - nodeProximities[id.String()] = chunk.Proximity(pivotKademlia.BaseAddr(), bzzAddr.(*network.BzzAddr).Over()) - } - err = sim.Net.ConnectNodesStar(ids, pivotRegistryID) - if err != nil { - return err - } - waitForSubscriptions(t, pivotRegistry, ids...) - - newDepth := pivotKademlia.NeighbourhoodDepth() - // depth is not changed, check if streams are still correct - if newDepth == prevDepth { - err = checkSyncStreamsWithRetry(pivotRegistry, nodeProximities) - if err != nil { - return err - } - noDepthChangeChecked = true - } - // do the final check when depth is changed and - // there has been at least one check - // for the case when depth is not changed - if newDepth != prevDepth && noDepthChangeChecked { - // check sync streams for changed depth - return checkSyncStreamsWithRetry(pivotRegistry, nodeProximities) - } - prevDepth = newDepth - } - }) - if result.Error != nil { - t.Fatal(result.Error) - } -} - -// waitForSubscriptions is a test helper function that blocks until -// stream server subscriptions are established on the provided registry -// to the nodes with provided IDs. -func waitForSubscriptions(t *testing.T, r *Registry, ids ...enode.ID) { - t.Helper() - - for retries := 0; retries < 100; retries++ { - subs := r.api.GetPeerServerSubscriptions() - if allSubscribed(subs, ids) { - return - } - time.Sleep(50 * time.Millisecond) - } - t.Fatalf("missing subscriptions") -} - -// allSubscribed returns true if nodes with ids have subscriptions -// in provided subs map. -func allSubscribed(subs map[string][]string, ids []enode.ID) bool { - for _, id := range ids { - if s, ok := subs[id.String()]; !ok || len(s) == 0 { - return false - } - } - return true -} - -// checkSyncStreamsWithRetry is calling checkSyncStreams with retries. -func checkSyncStreamsWithRetry(r *Registry, nodeProximities map[string]int) (err error) { - for retries := 0; retries < 5; retries++ { - err = checkSyncStreams(r, nodeProximities) - if err == nil { - return nil - } - time.Sleep(500 * time.Millisecond) - } - return err -} - -// checkSyncStreams validates that registry contains expected sync -// subscriptions to nodes with proximities in a map nodeProximities. -func checkSyncStreams(r *Registry, nodeProximities map[string]int) error { - depth := r.delivery.kad.NeighbourhoodDepth() - maxPO := r.delivery.kad.MaxProxDisplay - for id, po := range nodeProximities { - wantStreams := syncStreams(po, depth, maxPO) - gotStreams := nodeStreams(r, id) - - if r.getPeer(enode.HexID(id)) == nil { - // ignore removed peer - continue - } - - if !reflect.DeepEqual(gotStreams, wantStreams) { - return fmt.Errorf("node %s got streams %v, want %v", id, gotStreams, wantStreams) - } - } - return nil -} - -// syncStreams returns expected sync streams that need to be -// established between a node with kademlia neighbourhood depth -// and a node with proximity order po. -func syncStreams(po, depth, maxPO int) (streams []string) { - start, end := syncBins(po, depth, maxPO) - for bin := start; bin < end; bin++ { - streams = append(streams, NewStream("SYNC", FormatSyncBinKey(uint8(bin)), false).String()) - streams = append(streams, NewStream("SYNC", FormatSyncBinKey(uint8(bin)), true).String()) - } - return streams -} - -// nodeStreams returns stream server subscriptions on a registry -// to the peer with provided id. -func nodeStreams(r *Registry, id string) []string { - streams := r.api.GetPeerServerSubscriptions()[id] - sort.Strings(streams) - return streams -} diff --git a/swarm/network/stream/snapshot_retrieval_test.go b/swarm/network/stream/snapshot_retrieval_test.go deleted file mode 100644 index 50617b5cf5..0000000000 --- a/swarm/network/stream/snapshot_retrieval_test.go +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package stream - -import ( - "bytes" - "context" - "fmt" - "io" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -// constants for random file generation -const ( - minFileSize = 2 - maxFileSize = 40 -) - -// TestFileRetrieval is a retrieval test for nodes. -// A configurable number of nodes can be -// provided to the test. -// Files are uploaded to nodes, other nodes try to retrieve the file -// Number of nodes can be provided via commandline too. -func TestFileRetrieval(t *testing.T) { - var nodeCount []int - - if *nodes != 0 { - nodeCount = []int{*nodes} - } else { - nodeCount = []int{16} - - if *longrunning { - nodeCount = append(nodeCount, 32, 64) - } else if testutil.RaceEnabled { - nodeCount = []int{4} - } - - } - - for _, nc := range nodeCount { - runFileRetrievalTest(t, nc) - } -} - -// TestPureRetrieval tests pure retrieval without syncing -// A configurable number of nodes and chunks -// can be provided to the test. -// A number of random chunks is generated, then stored directly in -// each node's localstore according to their address. -// Each chunk is supposed to end up at certain nodes -// With retrieval we then make sure that every node can actually retrieve -// the chunks. -func TestPureRetrieval(t *testing.T) { - var nodeCount []int - var chunkCount []int - - if *nodes != 0 && *chunks != 0 { - nodeCount = []int{*nodes} - chunkCount = []int{*chunks} - } else { - nodeCount = []int{16} - chunkCount = []int{150} - - if *longrunning { - nodeCount = append(nodeCount, 32, 64) - chunkCount = append(chunkCount, 32, 256) - } else if testutil.RaceEnabled { - nodeCount = []int{4} - chunkCount = []int{4} - } - - } - - for _, nc := range nodeCount { - for _, c := range chunkCount { - runPureRetrievalTest(t, nc, c) - } - } -} - -// TestRetrieval tests retrieval of chunks by random nodes. -// One node is randomly selected to be the pivot node. -// A configurable number of chunks and nodes can be -// provided to the test, the number of chunks is uploaded -// to the pivot node and other nodes try to retrieve the chunk(s). -// Number of chunks and nodes can be provided via commandline too. -func TestRetrieval(t *testing.T) { - // if nodes/chunks have been provided via commandline, - // run the tests with these values - if *nodes != 0 && *chunks != 0 { - runRetrievalTest(t, *chunks, *nodes) - } else { - nodeCnt := []int{16} - chnkCnt := []int{32} - - if *longrunning { - nodeCnt = []int{16, 32, 64} - chnkCnt = []int{4, 32, 256} - } else if testutil.RaceEnabled { - nodeCnt = []int{4} - chnkCnt = []int{4} - } - - for _, n := range nodeCnt { - for _, c := range chnkCnt { - t.Run(fmt.Sprintf("TestRetrieval_%d_%d", n, c), func(t *testing.T) { - runRetrievalTest(t, c, n) - }) - } - } - } -} - -var retrievalSimServiceMap = map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - - syncUpdateDelay := 1 * time.Second - if *longrunning { - syncUpdateDelay = 3 * time.Second - } - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Syncing: SyncingAutoSubscribe, - SyncUpdateDelay: syncUpdateDelay, - }, nil) - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, -} - -// runPureRetrievalTest by uploading a snapshot, -// then starting a simulation, distribute chunks to nodes -// and start retrieval. -// The snapshot should have 'streamer' in its service list. -func runPureRetrievalTest(t *testing.T, nodeCount int, chunkCount int) { - - t.Helper() - // the pure retrieval test needs a different service map, as we want - // syncing disabled and we don't need to set the syncUpdateDelay - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Syncing: SyncingDisabled, - }, nil) - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, - }, - ) - defer sim.Close() - - log.Info("Initializing test config", "node count", nodeCount) - - conf := &synctestConfig{} - //map of discover ID to indexes of chunks expected at that ID - conf.idToChunksMap = make(map[enode.ID][]int) - //map of overlay address to discover ID - conf.addrToIDMap = make(map[string]enode.ID) - //array where the generated chunk hashes will be stored - conf.hashes = make([]storage.Address, 0) - - ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancelSimRun() - - filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) - err := sim.UploadSnapshot(ctx, filename) - if err != nil { - t.Fatal(err) - } - - log.Info("Starting simulation") - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - nodeIDs := sim.UpNodeIDs() - // first iteration: create addresses - for _, n := range nodeIDs { - //get the kademlia overlay address from this ID - a := n.Bytes() - //append it to the array of all overlay addresses - conf.addrs = append(conf.addrs, a) - //the proximity calculation is on overlay addr, - //the p2p/simulations check func triggers on enode.ID, - //so we need to know which overlay addr maps to which nodeID - conf.addrToIDMap[string(a)] = n - } - - // now create random chunks - chunks := storage.GenerateRandomChunks(int64(chunkSize), chunkCount) - for _, chunk := range chunks { - conf.hashes = append(conf.hashes, chunk.Address()) - } - - log.Debug("random chunks generated, mapping keys to nodes") - - // map addresses to nodes - mapKeysToNodes(conf) - - // second iteration: storing chunks at the peer whose - // overlay address is closest to a particular chunk's hash - log.Debug("storing every chunk at correspondent node store") - for _, id := range nodeIDs { - // for every chunk for this node (which are only indexes)... - for _, ch := range conf.idToChunksMap[id] { - item, ok := sim.NodeItem(id, bucketKeyStore) - if !ok { - return fmt.Errorf("Error accessing localstore") - } - lstore := item.(chunk.Store) - // ...get the actual chunk - for _, chnk := range chunks { - if bytes.Equal(chnk.Address(), conf.hashes[ch]) { - // ...and store it in the localstore - if _, err = lstore.Put(ctx, chunk.ModePutUpload, chnk); err != nil { - return err - } - } - } - } - } - - // now try to retrieve every chunk from every node - log.Debug("starting retrieval") - cnt := 0 - - for _, id := range nodeIDs { - item, ok := sim.NodeItem(id, bucketKeyFileStore) - if !ok { - return fmt.Errorf("No filestore") - } - fileStore := item.(*storage.FileStore) - for _, chunk := range chunks { - reader, _ := fileStore.Retrieve(context.TODO(), chunk.Address()) - content := make([]byte, chunkSize) - size, err := reader.Read(content) - //check chunk size and content - ok := true - if err != io.EOF { - log.Debug("Retrieve error", "err", err, "hash", chunk.Address(), "nodeId", id) - ok = false - } - if size != chunkSize { - log.Debug("size not equal chunkSize", "size", size, "hash", chunk.Address(), "nodeId", id) - ok = false - } - // skip chunk "metadata" for chunk.Data() - if !bytes.Equal(content, chunk.Data()[8:]) { - log.Debug("content not equal chunk data", "hash", chunk.Address(), "nodeId", id) - ok = false - } - if !ok { - return fmt.Errorf("Expected test to succeed at first run, but failed with chunk not found") - } - log.Debug(fmt.Sprintf("chunk with root hash %x successfully retrieved", chunk.Address())) - cnt++ - } - } - log.Info("retrieval terminated, chunks retrieved: ", "count", cnt) - return nil - - }) - - log.Info("Simulation terminated") - - if result.Error != nil { - t.Fatal(result.Error) - } -} - -// runFileRetrievalTest loads a snapshot file to construct the swarm network. -// The snapshot should have 'streamer' in its service list. -func runFileRetrievalTest(t *testing.T, nodeCount int) { - - t.Helper() - - sim := simulation.New(retrievalSimServiceMap) - defer sim.Close() - - log.Info("Initializing test config", "node count", nodeCount) - - conf := &synctestConfig{} - //map of discover ID to indexes of chunks expected at that ID - conf.idToChunksMap = make(map[enode.ID][]int) - //map of overlay address to discover ID - conf.addrToIDMap = make(map[string]enode.ID) - //array where the generated chunk hashes will be stored - conf.hashes = make([]storage.Address, 0) - - ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancelSimRun() - - filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) - err := sim.UploadSnapshot(ctx, filename) - if err != nil { - t.Fatal(err) - } - - log.Info("Starting simulation") - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - nodeIDs := sim.UpNodeIDs() - for _, n := range nodeIDs { - //get the kademlia overlay address from this ID - a := n.Bytes() - //append it to the array of all overlay addresses - conf.addrs = append(conf.addrs, a) - //the proximity calculation is on overlay addr, - //the p2p/simulations check func triggers on enode.ID, - //so we need to know which overlay addr maps to which nodeID - conf.addrToIDMap[string(a)] = n - } - - //an array for the random files - var randomFiles []string - - conf.hashes, randomFiles, err = uploadFilesToNodes(sim) - if err != nil { - return err - } - - log.Info("network healthy, start file checks") - - // File retrieval check is repeated until all uploaded files are retrieved from all nodes - // or until the timeout is reached. - REPEAT: - for { - for _, id := range nodeIDs { - //for each expected file, check if it is in the local store - item, ok := sim.NodeItem(id, bucketKeyFileStore) - if !ok { - return fmt.Errorf("No filestore") - } - fileStore := item.(*storage.FileStore) - //check all chunks - for i, hash := range conf.hashes { - reader, _ := fileStore.Retrieve(context.TODO(), hash) - //check that we can read the file size and that it corresponds to the generated file size - if s, err := reader.Size(ctx, nil); err != nil || s != int64(len(randomFiles[i])) { - log.Debug("Retrieve error", "err", err, "hash", hash, "nodeId", id) - time.Sleep(500 * time.Millisecond) - continue REPEAT - } - log.Debug(fmt.Sprintf("File with root hash %x successfully retrieved", hash)) - } - } - return nil - } - }) - - log.Info("Simulation terminated") - - if result.Error != nil { - t.Fatal(result.Error) - } -} - -// runRetrievalTest generates the given number of chunks. -// The test loads a snapshot file to construct the swarm network. -// The snapshot should have 'streamer' in its service list. -func runRetrievalTest(t *testing.T, chunkCount int, nodeCount int) { - - t.Helper() - - sim := simulation.New(retrievalSimServiceMap) - defer sim.Close() - - conf := &synctestConfig{} - //map of discover ID to indexes of chunks expected at that ID - conf.idToChunksMap = make(map[enode.ID][]int) - //map of overlay address to discover ID - conf.addrToIDMap = make(map[string]enode.ID) - //array where the generated chunk hashes will be stored - conf.hashes = make([]storage.Address, 0) - - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) - err := sim.UploadSnapshot(ctx, filename) - if err != nil { - t.Fatal(err) - } - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - nodeIDs := sim.UpNodeIDs() - for _, n := range nodeIDs { - //get the kademlia overlay address from this ID - a := n.Bytes() - //append it to the array of all overlay addresses - conf.addrs = append(conf.addrs, a) - //the proximity calculation is on overlay addr, - //the p2p/simulations check func triggers on enode.ID, - //so we need to know which overlay addr maps to which nodeID - conf.addrToIDMap[string(a)] = n - } - - //this is the node selected for upload - node := sim.Net.GetRandomUpNode() - item, ok := sim.NodeItem(node.ID(), bucketKeyStore) - if !ok { - return fmt.Errorf("No localstore") - } - lstore := item.(chunk.Store) - conf.hashes, err = uploadFileToSingleNodeStore(node.ID(), chunkCount, lstore) - if err != nil { - return err - } - - // File retrieval check is repeated until all uploaded files are retrieved from all nodes - // or until the timeout is reached. - REPEAT: - for { - for _, id := range nodeIDs { - //for each expected chunk, check if it is in the local store - //check on the node's FileStore (netstore) - item, ok := sim.NodeItem(id, bucketKeyFileStore) - if !ok { - return fmt.Errorf("No filestore") - } - fileStore := item.(*storage.FileStore) - //check all chunks - for _, hash := range conf.hashes { - reader, _ := fileStore.Retrieve(context.TODO(), hash) - //check that we can read the chunk size and that it corresponds to the generated chunk size - if s, err := reader.Size(ctx, nil); err != nil || s != int64(chunkSize) { - log.Debug("Retrieve error", "err", err, "hash", hash, "nodeId", id, "size", s) - time.Sleep(500 * time.Millisecond) - continue REPEAT - } - log.Debug(fmt.Sprintf("Chunk with root hash %x successfully retrieved", hash)) - } - } - // all nodes and files found, exit loop and return without error - return nil - } - }) - - if result.Error != nil { - t.Fatal(result.Error) - } -} diff --git a/swarm/network/stream/snapshot_sync_test.go b/swarm/network/stream/snapshot_sync_test.go deleted file mode 100644 index da4ff673b1..0000000000 --- a/swarm/network/stream/snapshot_sync_test.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package stream - -import ( - "context" - "errors" - "fmt" - "os" - "runtime" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/pot" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - mockmem "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -type synctestConfig struct { - addrs [][]byte - hashes []storage.Address - idToChunksMap map[enode.ID][]int - //chunksToNodesMap map[string][]int - addrToIDMap map[string]enode.ID -} - -const ( - // EventTypeNode is the type of event emitted when a node is either - // created, started or stopped - EventTypeChunkCreated simulations.EventType = "chunkCreated" - EventTypeChunkOffered simulations.EventType = "chunkOffered" - EventTypeChunkWanted simulations.EventType = "chunkWanted" - EventTypeChunkDelivered simulations.EventType = "chunkDelivered" - EventTypeChunkArrived simulations.EventType = "chunkArrived" - EventTypeSimTerminated simulations.EventType = "simTerminated" -) - -// Tests in this file should not request chunks from peers. -// This function will panic indicating that there is a problem if request has been made. -func dummyRequestFromPeers(_ context.Context, req *network.Request) (*enode.ID, chan struct{}, error) { - panic(fmt.Sprintf("unexpected request: address %s, source %s", req.Addr.String(), req.Source.String())) -} - -//This test is a syncing test for nodes. -//One node is randomly selected to be the pivot node. -//A configurable number of chunks and nodes can be -//provided to the test, the number of chunks is uploaded -//to the pivot node, and we check that nodes get the chunks -//they are expected to store based on the syncing protocol. -//Number of chunks and nodes can be provided via commandline too. -func TestSyncingViaGlobalSync(t *testing.T) { - if runtime.GOOS == "darwin" && os.Getenv("TRAVIS") == "true" { - t.Skip("Flaky on mac on travis") - } - - if testutil.RaceEnabled { - t.Skip("Segfaults on Travis with -race") - } - - //if nodes/chunks have been provided via commandline, - //run the tests with these values - if *nodes != 0 && *chunks != 0 { - log.Info(fmt.Sprintf("Running test with %d chunks and %d nodes...", *chunks, *nodes)) - testSyncingViaGlobalSync(t, *chunks, *nodes) - } else { - chunkCounts := []int{4, 32} - nodeCounts := []int{32, 16} - - //if the `longrunning` flag has been provided - //run more test combinations - if *longrunning { - chunkCounts = []int{64, 128} - nodeCounts = []int{32, 64} - } - - for _, chunkCount := range chunkCounts { - for _, n := range nodeCounts { - log.Info(fmt.Sprintf("Long running test with %d chunks and %d nodes...", chunkCount, n)) - testSyncingViaGlobalSync(t, chunkCount, n) - } - } - } -} - -var simServiceMap = map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDeliveryWithRequestFunc(ctx, bucket, dummyRequestFromPeers) - if err != nil { - return nil, nil, err - } - - store := state.NewInmemoryStore() - - r := NewRegistry(addr.ID(), delivery, netStore, store, &RegistryOptions{ - Syncing: SyncingAutoSubscribe, - SyncUpdateDelay: 3 * time.Second, - }, nil) - - bucket.Store(bucketKeyRegistry, r) - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, -} - -func testSyncingViaGlobalSync(t *testing.T, chunkCount int, nodeCount int) { - sim := simulation.New(simServiceMap) - defer sim.Close() - - log.Info("Initializing test config") - - conf := &synctestConfig{} - //map of discover ID to indexes of chunks expected at that ID - conf.idToChunksMap = make(map[enode.ID][]int) - //map of overlay address to discover ID - conf.addrToIDMap = make(map[string]enode.ID) - //array where the generated chunk hashes will be stored - conf.hashes = make([]storage.Address, 0) - - ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancelSimRun() - - filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) - err := sim.UploadSnapshot(ctx, filename) - if err != nil { - t.Fatal(err) - } - - result := runSim(conf, ctx, sim, chunkCount) - if result.Error != nil { - t.Fatal(result.Error) - } - log.Info("Simulation ended") -} - -func runSim(conf *synctestConfig, ctx context.Context, sim *simulation.Simulation, chunkCount int) simulation.Result { - - return sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { - disconnected := watchDisconnections(ctx, sim) - defer func() { - if err != nil && disconnected.bool() { - err = errors.New("disconnect events received") - } - }() - - nodeIDs := sim.UpNodeIDs() - for _, n := range nodeIDs { - //get the kademlia overlay address from this ID - a := n.Bytes() - //append it to the array of all overlay addresses - conf.addrs = append(conf.addrs, a) - //the proximity calculation is on overlay addr, - //the p2p/simulations check func triggers on enode.ID, - //so we need to know which overlay addr maps to which nodeID - conf.addrToIDMap[string(a)] = n - } - - //get the node at that index - //this is the node selected for upload - node := sim.Net.GetRandomUpNode() - item, ok := sim.NodeItem(node.ID(), bucketKeyStore) - if !ok { - return errors.New("no store in simulation bucket") - } - store := item.(chunk.Store) - hashes, err := uploadFileToSingleNodeStore(node.ID(), chunkCount, store) - if err != nil { - return err - } - for _, h := range hashes { - evt := &simulations.Event{ - Type: EventTypeChunkCreated, - Node: sim.Net.GetNode(node.ID()), - Data: h.String(), - } - sim.Net.Events().Send(evt) - } - conf.hashes = append(conf.hashes, hashes...) - mapKeysToNodes(conf) - - // File retrieval check is repeated until all uploaded files are retrieved from all nodes - // or until the timeout is reached. - var globalStore mock.GlobalStorer - if *useMockStore { - globalStore = mockmem.NewGlobalStore() - } - REPEAT: - for { - for _, id := range nodeIDs { - //for each expected chunk, check if it is in the local store - localChunks := conf.idToChunksMap[id] - for _, ch := range localChunks { - //get the real chunk by the index in the index array - ch := conf.hashes[ch] - log.Trace("node has chunk", "address", ch) - //check if the expected chunk is indeed in the localstore - var err error - if *useMockStore { - //use the globalStore if the mockStore should be used; in that case, - //the complete localStore stack is bypassed for getting the chunk - _, err = globalStore.Get(common.BytesToAddress(id.Bytes()), ch) - } else { - //use the actual localstore - item, ok := sim.NodeItem(id, bucketKeyStore) - if !ok { - return errors.New("no store in simulation bucket") - } - store := item.(chunk.Store) - _, err = store.Get(ctx, chunk.ModeGetLookup, ch) - } - if err != nil { - log.Debug("chunk not found", "address", ch.Hex(), "node", id) - // Do not get crazy with logging the warn message - time.Sleep(500 * time.Millisecond) - continue REPEAT - } - evt := &simulations.Event{ - Type: EventTypeChunkArrived, - Node: sim.Net.GetNode(id), - Data: ch.String(), - } - sim.Net.Events().Send(evt) - log.Trace("chunk found", "address", ch.Hex(), "node", id) - } - } - return nil - } - }) -} - -//map chunk keys to addresses which are responsible -func mapKeysToNodes(conf *synctestConfig) { - nodemap := make(map[string][]int) - //build a pot for chunk hashes - np := pot.NewPot(nil, 0) - indexmap := make(map[string]int) - for i, a := range conf.addrs { - indexmap[string(a)] = i - np, _, _ = pot.Add(np, a, pof) - } - - ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, conf.addrs) - - //for each address, run EachNeighbour on the chunk hashes pot to identify closest nodes - log.Trace(fmt.Sprintf("Generated hash chunk(s): %v", conf.hashes)) - for i := 0; i < len(conf.hashes); i++ { - var a []byte - np.EachNeighbour([]byte(conf.hashes[i]), pof, func(val pot.Val, po int) bool { - // take the first address - a = val.([]byte) - return false - }) - - nns := ppmap[common.Bytes2Hex(a)].NNSet - nns = append(nns, a) - - for _, p := range nns { - nodemap[string(p)] = append(nodemap[string(p)], i) - } - } - for addr, chunks := range nodemap { - //this selects which chunks are expected to be found with the given node - conf.idToChunksMap[conf.addrToIDMap[addr]] = chunks - } - log.Debug(fmt.Sprintf("Map of expected chunks by ID: %v", conf.idToChunksMap)) -} - -//upload a file(chunks) to a single local node store -func uploadFileToSingleNodeStore(id enode.ID, chunkCount int, store chunk.Store) ([]storage.Address, error) { - log.Debug(fmt.Sprintf("Uploading to node id: %s", id)) - fileStore := storage.NewFileStore(store, storage.NewFileStoreParams(), chunk.NewTags()) - size := chunkSize - var rootAddrs []storage.Address - for i := 0; i < chunkCount; i++ { - rk, wait, err := fileStore.Store(context.TODO(), testutil.RandomReader(i, size), int64(size), false) - if err != nil { - return nil, err - } - err = wait(context.TODO()) - if err != nil { - return nil, err - } - rootAddrs = append(rootAddrs, (rk)) - } - - return rootAddrs, nil -} diff --git a/swarm/network/stream/stream.go b/swarm/network/stream/stream.go deleted file mode 100644 index 9cdf5c04b4..0000000000 --- a/swarm/network/stream/stream.go +++ /dev/null @@ -1,811 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "fmt" - "math" - "reflect" - "sync" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/stream/intervals" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -const ( - Low uint8 = iota - Mid - High - Top - PriorityQueue = 4 // number of priority queues - Low, Mid, High, Top - PriorityQueueCap = 4096 // queue capacity - HashSize = 32 -) - -// Enumerate options for syncing and retrieval -type SyncingOption int - -// Syncing options -const ( - // Syncing disabled - SyncingDisabled SyncingOption = iota - // Register the client and the server but not subscribe - SyncingRegisterOnly - // Both client and server funcs are registered, subscribe sent automatically - SyncingAutoSubscribe -) - -// subscriptionFunc is used to determine what to do in order to perform subscriptions -// usually we would start to really subscribe to nodes, but for tests other functionality may be needed -// (see TestRequestPeerSubscriptions in streamer_test.go) -var subscriptionFunc = doRequestSubscription - -// Registry registry for outgoing and incoming streamer constructors -type Registry struct { - addr enode.ID - api *API - skipCheck bool - clientMu sync.RWMutex - serverMu sync.RWMutex - peersMu sync.RWMutex - serverFuncs map[string]func(*Peer, string, bool) (Server, error) - clientFuncs map[string]func(*Peer, string, bool) (Client, error) - peers map[enode.ID]*Peer - delivery *Delivery - intervalsStore state.Store - maxPeerServers int - spec *protocols.Spec //this protocol's spec - balance protocols.Balance //implements protocols.Balance, for accounting - prices protocols.Prices //implements protocols.Prices, provides prices to accounting - quit chan struct{} // terminates registry goroutines - syncMode SyncingOption - syncUpdateDelay time.Duration -} - -// RegistryOptions holds optional values for NewRegistry constructor. -type RegistryOptions struct { - SkipCheck bool - Syncing SyncingOption // Defines syncing behavior - SyncUpdateDelay time.Duration - MaxPeerServers int // The limit of servers for each peer in registry -} - -// NewRegistry is Streamer constructor -func NewRegistry(localID enode.ID, delivery *Delivery, netStore *storage.NetStore, intervalsStore state.Store, options *RegistryOptions, balance protocols.Balance) *Registry { - if options == nil { - options = &RegistryOptions{} - } - if options.SyncUpdateDelay <= 0 { - options.SyncUpdateDelay = 15 * time.Second - } - - quit := make(chan struct{}) - - streamer := &Registry{ - addr: localID, - skipCheck: options.SkipCheck, - serverFuncs: make(map[string]func(*Peer, string, bool) (Server, error)), - clientFuncs: make(map[string]func(*Peer, string, bool) (Client, error)), - peers: make(map[enode.ID]*Peer), - delivery: delivery, - intervalsStore: intervalsStore, - maxPeerServers: options.MaxPeerServers, - balance: balance, - quit: quit, - syncUpdateDelay: options.SyncUpdateDelay, - syncMode: options.Syncing, - } - - streamer.setupSpec() - - streamer.api = NewAPI(streamer) - delivery.getPeer = streamer.getPeer - - // If syncing is not disabled, the syncing functions are registered (both client and server) - if options.Syncing != SyncingDisabled { - RegisterSwarmSyncerServer(streamer, netStore) - RegisterSwarmSyncerClient(streamer, netStore) - } - - return streamer -} - -// This is an accounted protocol, therefore we need to provide a pricing Hook to the spec -// For simulations to be able to run multiple nodes and not override the hook's balance, -// we need to construct a spec instance per node instance -func (r *Registry) setupSpec() { - // first create the "bare" spec - r.createSpec() - // now create the pricing object - r.createPriceOracle() - // if balance is nil, this node has been started without swap support (swapEnabled flag is false) - if r.balance != nil && !reflect.ValueOf(r.balance).IsNil() { - // swap is enabled, so setup the hook - r.spec.Hook = protocols.NewAccounting(r.balance, r.prices) - } -} - -// RegisterClient registers an incoming streamer constructor -func (r *Registry) RegisterClientFunc(stream string, f func(*Peer, string, bool) (Client, error)) { - r.clientMu.Lock() - defer r.clientMu.Unlock() - - r.clientFuncs[stream] = f -} - -// RegisterServer registers an outgoing streamer constructor -func (r *Registry) RegisterServerFunc(stream string, f func(*Peer, string, bool) (Server, error)) { - r.serverMu.Lock() - defer r.serverMu.Unlock() - - r.serverFuncs[stream] = f -} - -// GetClient accessor for incoming streamer constructors -func (r *Registry) GetClientFunc(stream string) (func(*Peer, string, bool) (Client, error), error) { - r.clientMu.RLock() - defer r.clientMu.RUnlock() - - f := r.clientFuncs[stream] - if f == nil { - return nil, fmt.Errorf("stream %v not registered", stream) - } - return f, nil -} - -// GetServer accessor for incoming streamer constructors -func (r *Registry) GetServerFunc(stream string) (func(*Peer, string, bool) (Server, error), error) { - r.serverMu.RLock() - defer r.serverMu.RUnlock() - - f := r.serverFuncs[stream] - if f == nil { - return nil, fmt.Errorf("stream %v not registered", stream) - } - return f, nil -} - -func (r *Registry) RequestSubscription(peerId enode.ID, s Stream, h *Range, prio uint8) error { - // check if the stream is registered - if _, err := r.GetServerFunc(s.Name); err != nil { - return err - } - - peer := r.getPeer(peerId) - if peer == nil { - return fmt.Errorf("peer not found %v", peerId) - } - - if _, err := peer.getServer(s); err != nil { - if e, ok := err.(*notFoundError); ok && e.t == "server" { - // request subscription only if the server for this stream is not created - log.Debug("RequestSubscription ", "peer", peerId, "stream", s, "history", h) - return peer.Send(context.TODO(), &RequestSubscriptionMsg{ - Stream: s, - History: h, - Priority: prio, - }) - } - return err - } - log.Trace("RequestSubscription: already subscribed", "peer", peerId, "stream", s, "history", h) - return nil -} - -// Subscribe initiates the streamer -func (r *Registry) Subscribe(peerId enode.ID, s Stream, h *Range, priority uint8) error { - // check if the stream is registered - if _, err := r.GetClientFunc(s.Name); err != nil { - return err - } - - peer := r.getPeer(peerId) - if peer == nil { - return fmt.Errorf("peer not found %v", peerId) - } - - var to uint64 - if !s.Live && h != nil { - to = h.To - } - - err := peer.setClientParams(s, newClientParams(priority, to)) - if err != nil { - return err - } - if s.Live && h != nil { - if err := peer.setClientParams( - getHistoryStream(s), - newClientParams(getHistoryPriority(priority), h.To), - ); err != nil { - return err - } - } - - msg := &SubscribeMsg{ - Stream: s, - History: h, - Priority: priority, - } - log.Debug("Subscribe ", "peer", peerId, "stream", s, "history", h) - - return peer.Send(context.TODO(), msg) -} - -func (r *Registry) Unsubscribe(peerId enode.ID, s Stream) error { - peer := r.getPeer(peerId) - if peer == nil { - return fmt.Errorf("peer not found %v", peerId) - } - - msg := &UnsubscribeMsg{ - Stream: s, - } - log.Debug("Unsubscribe ", "peer", peerId, "stream", s) - - if err := peer.Send(context.TODO(), msg); err != nil { - return err - } - return peer.removeClient(s) -} - -// Quit sends the QuitMsg to the peer to remove the -// stream peer client and terminate the streaming. -func (r *Registry) Quit(peerId enode.ID, s Stream) error { - peer := r.getPeer(peerId) - if peer == nil { - log.Debug("stream quit: peer not found", "peer", peerId, "stream", s) - // if the peer is not found, abort the request - return nil - } - - msg := &QuitMsg{ - Stream: s, - } - log.Debug("Quit ", "peer", peerId, "stream", s) - - return peer.Send(context.TODO(), msg) -} - -func (r *Registry) Close() error { - // Stop sending neighborhood depth change and address count - // change from Kademlia that were initiated in NewRegistry constructor. - r.delivery.Close() - close(r.quit) - return r.intervalsStore.Close() -} - -func (r *Registry) getPeer(peerId enode.ID) *Peer { - r.peersMu.RLock() - defer r.peersMu.RUnlock() - - return r.peers[peerId] -} - -func (r *Registry) setPeer(peer *Peer) { - r.peersMu.Lock() - r.peers[peer.ID()] = peer - metrics.GetOrRegisterCounter("registry.setpeer", nil).Inc(1) - metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers))) - r.peersMu.Unlock() -} - -func (r *Registry) deletePeer(peer *Peer) { - r.peersMu.Lock() - delete(r.peers, peer.ID()) - metrics.GetOrRegisterCounter("registry.deletepeer", nil).Inc(1) - metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers))) - r.peersMu.Unlock() -} - -func (r *Registry) peersCount() (c int) { - r.peersMu.Lock() - c = len(r.peers) - r.peersMu.Unlock() - return -} - -// Run protocol run function -func (r *Registry) Run(p *network.BzzPeer) error { - sp := NewPeer(p, r) - r.setPeer(sp) - - if r.syncMode == SyncingAutoSubscribe { - go sp.runUpdateSyncing() - } - - defer r.deletePeer(sp) - defer close(sp.quit) - defer sp.close() - - return sp.Run(sp.HandleMsg) -} - -// doRequestSubscription sends the actual RequestSubscription to the peer -func doRequestSubscription(r *Registry, id enode.ID, bin uint8) error { - log.Debug("Requesting subscription by registry:", "registry", r.addr, "peer", id, "bin", bin) - // bin is always less then 256 and it is safe to convert it to type uint8 - stream := NewStream("SYNC", FormatSyncBinKey(bin), true) - err := r.RequestSubscription(id, stream, NewRange(0, 0), High) - if err != nil { - log.Debug("Request subscription", "err", err, "peer", id, "stream", stream) - return err - } - return nil -} - -func (r *Registry) runProtocol(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := protocols.NewPeer(p, rw, r.spec) - bp := network.NewBzzPeer(peer) - np := network.NewPeer(bp, r.delivery.kad) - r.delivery.kad.On(np) - defer r.delivery.kad.Off(np) - return r.Run(bp) -} - -// HandleMsg is the message handler that delegates incoming messages -func (p *Peer) HandleMsg(ctx context.Context, msg interface{}) error { - select { - case <-p.streamer.quit: - log.Trace("message received after the streamer is closed", "peer", p.ID()) - // return without an error since streamer is closed and - // no messages should be handled as other subcomponents like - // storage leveldb may be closed - return nil - default: - } - - switch msg := msg.(type) { - - case *SubscribeMsg: - return p.handleSubscribeMsg(ctx, msg) - - case *SubscribeErrorMsg: - return p.handleSubscribeErrorMsg(msg) - - case *UnsubscribeMsg: - return p.handleUnsubscribeMsg(msg) - - case *OfferedHashesMsg: - go func() { - err := p.handleOfferedHashesMsg(ctx, msg) - if err != nil { - log.Error(err.Error()) - p.Drop() - } - }() - return nil - - case *TakeoverProofMsg: - go func() { - err := p.handleTakeoverProofMsg(ctx, msg) - if err != nil { - log.Error(err.Error()) - p.Drop() - } - }() - return nil - - case *WantedHashesMsg: - go func() { - err := p.handleWantedHashesMsg(ctx, msg) - if err != nil { - log.Error(err.Error()) - p.Drop() - } - }() - return nil - - case *ChunkDeliveryMsgRetrieval: - // handling chunk delivery is the same for retrieval and syncing, so let's cast the msg - go func() { - err := p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, ((*ChunkDeliveryMsg)(msg))) - if err != nil { - log.Error(err.Error()) - p.Drop() - } - }() - return nil - - case *ChunkDeliveryMsgSyncing: - // handling chunk delivery is the same for retrieval and syncing, so let's cast the msg - go func() { - err := p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, ((*ChunkDeliveryMsg)(msg))) - if err != nil { - log.Error(err.Error()) - p.Drop() - } - }() - return nil - - case *RetrieveRequestMsg: - go func() { - err := p.streamer.delivery.handleRetrieveRequestMsg(ctx, p, msg) - if err != nil { - log.Error(err.Error()) - p.Drop() - } - }() - return nil - - case *RequestSubscriptionMsg: - return p.handleRequestSubscription(ctx, msg) - - case *QuitMsg: - return p.handleQuitMsg(msg) - - default: - return fmt.Errorf("unknown message type: %T", msg) - } -} - -type server struct { - Server - stream Stream - priority uint8 - currentBatch []byte - sessionIndex uint64 -} - -// setNextBatch adjusts passed interval based on session index and whether -// stream is live or history. It calls Server SetNextBatch with adjusted -// interval and returns batch hashes and their interval. -func (s *server) setNextBatch(from, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { - if s.stream.Live { - if from == 0 { - from = s.sessionIndex - } - if to <= from || from >= s.sessionIndex { - to = math.MaxUint64 - } - } else { - if (to < from && to != 0) || from > s.sessionIndex { - return nil, 0, 0, nil, nil - } - if to == 0 || to > s.sessionIndex { - to = s.sessionIndex - } - } - return s.SetNextBatch(from, to) -} - -// Server interface for outgoing peer Streamer -type Server interface { - // SessionIndex is called when a server is initialized - // to get the current cursor state of the stream data. - // Based on this index, live and history stream intervals - // will be adjusted before calling SetNextBatch. - SessionIndex() (uint64, error) - SetNextBatch(uint64, uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error) - GetData(context.Context, []byte) ([]byte, error) - Close() -} - -type client struct { - Client - stream Stream - priority uint8 - sessionAt uint64 - to uint64 - next chan error - quit chan struct{} - - intervalsKey string - intervalsStore state.Store -} - -func peerStreamIntervalsKey(p *Peer, s Stream) string { - return p.ID().String() + s.String() -} - -func (c *client) AddInterval(start, end uint64) (err error) { - i := &intervals.Intervals{} - if err = c.intervalsStore.Get(c.intervalsKey, i); err != nil { - return err - } - i.Add(start, end) - return c.intervalsStore.Put(c.intervalsKey, i) -} - -func (c *client) NextInterval() (start, end uint64, err error) { - i := &intervals.Intervals{} - err = c.intervalsStore.Get(c.intervalsKey, i) - if err != nil { - return 0, 0, err - } - start, end = i.Next() - return start, end, nil -} - -// Client interface for incoming peer Streamer -type Client interface { - NeedData(context.Context, []byte) func(context.Context) error - BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) - Close() -} - -func (c *client) nextBatch(from uint64) (nextFrom uint64, nextTo uint64) { - if c.to > 0 && from >= c.to { - return 0, 0 - } - if c.stream.Live { - return from, 0 - } else if from >= c.sessionAt { - if c.to > 0 { - return from, c.to - } - return from, math.MaxUint64 - } - nextFrom, nextTo, err := c.NextInterval() - if err != nil { - log.Error("next intervals", "stream", c.stream) - return - } - if nextTo > c.to { - nextTo = c.to - } - if nextTo == 0 { - nextTo = c.sessionAt - } - return -} - -func (c *client) batchDone(p *Peer, req *OfferedHashesMsg, hashes []byte) error { - if tf := c.BatchDone(req.Stream, req.From, hashes, req.Root); tf != nil { - tp, err := tf() - if err != nil { - return err - } - - if err := p.Send(context.TODO(), tp); err != nil { - return err - } - if c.to > 0 && tp.Takeover.End >= c.to { - return p.streamer.Unsubscribe(p.Peer.ID(), req.Stream) - } - return nil - } - return c.AddInterval(req.From, req.To) -} - -func (c *client) close() { - select { - case <-c.quit: - default: - close(c.quit) - } - c.Close() -} - -// clientParams store parameters for the new client -// between a subscription and initial offered hashes request handling. -type clientParams struct { - priority uint8 - to uint64 - // signal when the client is created - clientCreatedC chan struct{} -} - -func newClientParams(priority uint8, to uint64) *clientParams { - return &clientParams{ - priority: priority, - to: to, - clientCreatedC: make(chan struct{}), - } -} - -func (c *clientParams) waitClient(ctx context.Context) error { - select { - case <-ctx.Done(): - return ctx.Err() - case <-c.clientCreatedC: - return nil - } -} - -func (c *clientParams) clientCreated() { - close(c.clientCreatedC) -} - -// GetSpec returns the streamer spec to callers -// This used to be a global variable but for simulations with -// multiple nodes its fields (notably the Hook) would be overwritten -func (r *Registry) GetSpec() *protocols.Spec { - return r.spec -} - -func (r *Registry) createSpec() { - // Spec is the spec of the streamer protocol - var spec = &protocols.Spec{ - Name: "stream", - Version: 8, - MaxMsgSize: 10 * 1024 * 1024, - Messages: []interface{}{ - UnsubscribeMsg{}, - OfferedHashesMsg{}, - WantedHashesMsg{}, - TakeoverProofMsg{}, - SubscribeMsg{}, - RetrieveRequestMsg{}, - ChunkDeliveryMsgRetrieval{}, - SubscribeErrorMsg{}, - RequestSubscriptionMsg{}, - QuitMsg{}, - ChunkDeliveryMsgSyncing{}, - }, - } - r.spec = spec -} - -// An accountable message needs some meta information attached to it -// in order to evaluate the correct price -type StreamerPrices struct { - priceMatrix map[reflect.Type]*protocols.Price - registry *Registry -} - -// Price implements the accounting interface and returns the price for a specific message -func (sp *StreamerPrices) Price(msg interface{}) *protocols.Price { - t := reflect.TypeOf(msg).Elem() - return sp.priceMatrix[t] -} - -// Instead of hardcoding the price, get it -// through a function - it could be quite complex in the future -func (sp *StreamerPrices) getRetrieveRequestMsgPrice() uint64 { - return uint64(1) -} - -// Instead of hardcoding the price, get it -// through a function - it could be quite complex in the future -func (sp *StreamerPrices) getChunkDeliveryMsgRetrievalPrice() uint64 { - return uint64(1) -} - -// createPriceOracle sets up a matrix which can be queried to get -// the price for a message via the Price method -func (r *Registry) createPriceOracle() { - sp := &StreamerPrices{ - registry: r, - } - sp.priceMatrix = map[reflect.Type]*protocols.Price{ - reflect.TypeOf(ChunkDeliveryMsgRetrieval{}): { - Value: sp.getChunkDeliveryMsgRetrievalPrice(), // arbitrary price for now - PerByte: true, - Payer: protocols.Receiver, - }, - reflect.TypeOf(RetrieveRequestMsg{}): { - Value: sp.getRetrieveRequestMsgPrice(), // arbitrary price for now - PerByte: false, - Payer: protocols.Sender, - }, - } - r.prices = sp -} - -func (r *Registry) Protocols() []p2p.Protocol { - return []p2p.Protocol{ - { - Name: r.spec.Name, - Version: r.spec.Version, - Length: r.spec.Length(), - Run: r.runProtocol, - }, - } -} - -func (r *Registry) APIs() []rpc.API { - return []rpc.API{ - { - Namespace: "stream", - Version: "3.0", - Service: r.api, - Public: false, - }, - } -} - -func (r *Registry) Start(server *p2p.Server) error { - log.Info("Streamer started") - return nil -} - -func (r *Registry) Stop() error { - return nil -} - -type Range struct { - From, To uint64 -} - -func NewRange(from, to uint64) *Range { - return &Range{ - From: from, - To: to, - } -} - -func (r *Range) String() string { - return fmt.Sprintf("%v-%v", r.From, r.To) -} - -func getHistoryPriority(priority uint8) uint8 { - if priority == 0 { - return 0 - } - return priority - 1 -} - -func getHistoryStream(s Stream) Stream { - return NewStream(s.Name, s.Key, false) -} - -type API struct { - streamer *Registry -} - -func NewAPI(r *Registry) *API { - return &API{ - streamer: r, - } -} - -func (api *API) SubscribeStream(peerId enode.ID, s Stream, history *Range, priority uint8) error { - return api.streamer.Subscribe(peerId, s, history, priority) -} - -func (api *API) UnsubscribeStream(peerId enode.ID, s Stream) error { - return api.streamer.Unsubscribe(peerId, s) -} - -/* -GetPeerServerSubscriptions is a API function which allows to query a peer for stream subscriptions it has. -It can be called via RPC. -It returns a map of node IDs with an array of string representations of Stream objects. -*/ -func (api *API) GetPeerServerSubscriptions() map[string][]string { - pstreams := make(map[string][]string) - - api.streamer.peersMu.RLock() - defer api.streamer.peersMu.RUnlock() - - for id, p := range api.streamer.peers { - var streams []string - //every peer has a map of stream servers - //every stream server represents a subscription - p.serverMu.RLock() - for s := range p.servers { - //append the string representation of the stream - //to the list for this peer - streams = append(streams, s.String()) - } - p.serverMu.RUnlock() - //set the array of stream servers to the map - pstreams[id.String()] = streams - } - return pstreams -} diff --git a/swarm/network/stream/streamer_test.go b/swarm/network/stream/streamer_test.go deleted file mode 100644 index 767112b2b4..0000000000 --- a/swarm/network/stream/streamer_test.go +++ /dev/null @@ -1,1214 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "bytes" - "context" - "errors" - "fmt" - "os" - "strconv" - "strings" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - p2ptest "github.com/ethereum/go-ethereum/p2p/testing" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/testutil" - "golang.org/x/crypto/sha3" -) - -func TestStreamerSubscribe(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - stream := NewStream("foo", "", true) - err = streamer.Subscribe(tester.Nodes[0].ID(), stream, NewRange(0, 0), Top) - if err == nil || err.Error() != "stream foo not registered" { - t.Fatalf("Expected error %v, got %v", "stream foo not registered", err) - } -} - -func TestStreamerRequestSubscription(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - stream := NewStream("foo", "", false) - err = streamer.RequestSubscription(tester.Nodes[0].ID(), stream, &Range{}, Top) - if err == nil || err.Error() != "stream foo not registered" { - t.Fatalf("Expected error %v, got %v", "stream foo not registered", err) - } -} - -var ( - hash0 = sha3.Sum256([]byte{0}) - hash1 = sha3.Sum256([]byte{1}) - hash2 = sha3.Sum256([]byte{2}) - hashesTmp = append(hash0[:], hash1[:]...) - hashes = append(hashesTmp, hash2[:]...) - corruptHashes = append(hashes[:40]) -) - -type testClient struct { - t string - wait0 chan bool - wait2 chan bool - batchDone chan bool - receivedHashes map[string][]byte -} - -func newTestClient(t string) *testClient { - return &testClient{ - t: t, - wait0: make(chan bool), - wait2: make(chan bool), - batchDone: make(chan bool), - receivedHashes: make(map[string][]byte), - } -} - -func (self *testClient) NeedData(ctx context.Context, hash []byte) func(context.Context) error { - self.receivedHashes[string(hash)] = hash - if bytes.Equal(hash, hash0[:]) { - return func(context.Context) error { - <-self.wait0 - return nil - } - } else if bytes.Equal(hash, hash2[:]) { - return func(context.Context) error { - <-self.wait2 - return nil - } - } - return nil -} - -func (self *testClient) BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) { - close(self.batchDone) - return nil -} - -func (self *testClient) Close() {} - -type testServer struct { - t string - sessionIndex uint64 -} - -func newTestServer(t string, sessionIndex uint64) *testServer { - return &testServer{ - t: t, - sessionIndex: sessionIndex, - } -} - -func (s *testServer) SessionIndex() (uint64, error) { - return s.sessionIndex, nil -} - -func (self *testServer) SetNextBatch(from uint64, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { - return make([]byte, HashSize), from + 1, to + 1, nil, nil -} - -func (self *testServer) GetData(context.Context, []byte) ([]byte, error) { - return nil, nil -} - -func (self *testServer) Close() { -} - -func TestStreamerDownstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { - return newTestClient(t), nil - }) - - node := tester.Nodes[0] - - stream := NewStream("foo", "", true) - err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - err = tester.TestExchanges( - p2ptest.Exchange{ - Label: "Subscribe message", - Expects: []p2ptest.Expect{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - }, - // trigger OfferedHashesMsg to actually create the client - p2ptest.Exchange{ - Label: "OfferedHashes message", - Triggers: []p2ptest.Trigger{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: hashes, - From: 5, - To: 8, - Stream: stream, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 2, - Msg: &WantedHashesMsg{ - Stream: stream, - Want: []byte{5}, - From: 9, - To: 0, - }, - Peer: node.ID(), - }, - }, - }, - ) - if err != nil { - t.Fatal(err) - } - - err = streamer.Unsubscribe(node.ID(), stream) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Unsubscribe message", - Expects: []p2ptest.Expect{ - { - Code: 0, - Msg: &UnsubscribeMsg{ - Stream: stream, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -func TestStreamerUpstreamSubscribeUnsubscribeMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - stream := NewStream("foo", "", false) - - streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { - return newTestServer(t, 10), nil - }) - - node := tester.Nodes[0] - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: stream, - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: make([]byte, HashSize), - From: 6, - To: 9, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "unsubscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: &UnsubscribeMsg{ - Stream: stream, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -func TestStreamerUpstreamSubscribeUnsubscribeMsgExchangeLive(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - stream := NewStream("foo", "", true) - - streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { - return newTestServer(t, 0), nil - }) - - node := tester.Nodes[0] - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: stream, - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: make([]byte, HashSize), - From: 1, - To: 0, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "unsubscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: &UnsubscribeMsg{ - Stream: stream, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -func TestStreamerUpstreamSubscribeErrorMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { - return newTestServer(t, 0), nil - }) - - stream := NewStream("bar", "", true) - - node := tester.Nodes[0] - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 7, - Msg: &SubscribeErrorMsg{ - Error: "stream bar not registered", - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -func TestStreamerUpstreamSubscribeLiveAndHistory(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - stream := NewStream("foo", "", true) - - streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { - return newTestServer(t, 10), nil - }) - - node := tester.Nodes[0] - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: NewStream("foo", "", false), - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: make([]byte, HashSize), - From: 6, - To: 9, - }, - Peer: node.ID(), - }, - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: stream, - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - From: 11, - To: 0, - Hashes: make([]byte, HashSize), - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -func TestStreamerDownstreamCorruptHashesMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - stream := NewStream("foo", "", true) - - var tc *testClient - - streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { - tc = newTestClient(t) - return tc, nil - }) - - node := tester.Nodes[0] - - err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Expects: []p2ptest.Expect{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - }, - p2ptest.Exchange{ - Label: "Corrupt offered hash message", - Triggers: []p2ptest.Trigger{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: corruptHashes, - From: 5, - To: 8, - Stream: stream, - }, - Peer: node.ID(), - }, - }, - }) - if err != nil { - t.Fatal(err) - } - - expectedError := errors.New("subprotocol error") - if err := tester.TestDisconnected(&p2ptest.Disconnect{Peer: node.ID(), Error: expectedError}); err != nil { - t.Fatal(err) - } -} - -func TestStreamerDownstreamOfferedHashesMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - stream := NewStream("foo", "", true) - - var tc *testClient - - streamer.RegisterClientFunc("foo", func(p *Peer, t string, live bool) (Client, error) { - tc = newTestClient(t) - return tc, nil - }) - - node := tester.Nodes[0] - - err = streamer.Subscribe(node.ID(), stream, NewRange(5, 8), Top) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Expects: []p2ptest.Expect{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - }, - p2ptest.Exchange{ - Label: "WantedHashes message", - Triggers: []p2ptest.Trigger{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: hashes, - From: 5, - To: 8, - Stream: stream, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 2, - Msg: &WantedHashesMsg{ - Stream: stream, - Want: []byte{5}, - From: 9, - To: 0, - }, - Peer: node.ID(), - }, - }, - }) - if err != nil { - t.Fatal(err) - } - - if len(tc.receivedHashes) != 3 { - t.Fatalf("Expected number of received hashes %v, got %v", 3, len(tc.receivedHashes)) - } - - close(tc.wait0) - - timeout := time.NewTimer(100 * time.Millisecond) - defer timeout.Stop() - - select { - case <-tc.batchDone: - t.Fatal("batch done early") - case <-timeout.C: - } - - close(tc.wait2) - - timeout2 := time.NewTimer(10000 * time.Millisecond) - defer timeout2.Stop() - - select { - case <-tc.batchDone: - case <-timeout2.C: - t.Fatal("timeout waiting batchdone call") - } - -} - -func TestStreamerRequestSubscriptionQuitMsgExchange(t *testing.T) { - tester, streamer, _, teardown, err := newStreamerTester(nil) - if err != nil { - t.Fatal(err) - } - defer teardown() - - streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { - return newTestServer(t, 10), nil - }) - - node := tester.Nodes[0] - - stream := NewStream("foo", "", true) - err = streamer.RequestSubscription(node.ID(), stream, NewRange(5, 8), Top) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - err = tester.TestExchanges( - p2ptest.Exchange{ - Label: "RequestSubscription message", - Expects: []p2ptest.Expect{ - { - Code: 8, - Msg: &RequestSubscriptionMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - }, - p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - History: NewRange(5, 8), - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: NewStream("foo", "", false), - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: make([]byte, HashSize), - From: 6, - To: 9, - }, - Peer: node.ID(), - }, - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: stream, - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - From: 11, - To: 0, - Hashes: make([]byte, HashSize), - }, - Peer: node.ID(), - }, - }, - }, - ) - if err != nil { - t.Fatal(err) - } - - err = streamer.Quit(node.ID(), stream) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Quit message", - Expects: []p2ptest.Expect{ - { - Code: 9, - Msg: &QuitMsg{ - Stream: stream, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - - historyStream := getHistoryStream(stream) - - err = streamer.Quit(node.ID(), historyStream) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Quit message", - Expects: []p2ptest.Expect{ - { - Code: 9, - Msg: &QuitMsg{ - Stream: historyStream, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } -} - -// TestMaxPeerServersWithUnsubscribe creates a registry with a limited -// number of stream servers, and performs a test with subscriptions and -// unsubscriptions, checking if unsubscriptions will remove streams, -// leaving place for new streams. -func TestMaxPeerServersWithUnsubscribe(t *testing.T) { - var maxPeerServers = 6 - tester, streamer, _, teardown, err := newStreamerTester(&RegistryOptions{ - Syncing: SyncingDisabled, - MaxPeerServers: maxPeerServers, - }) - if err != nil { - t.Fatal(err) - } - defer teardown() - - streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { - return newTestServer(t, 0), nil - }) - - node := tester.Nodes[0] - - for i := 0; i < maxPeerServers+10; i++ { - stream := NewStream("foo", strconv.Itoa(i), true) - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: stream, - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: make([]byte, HashSize), - From: 1, - To: 0, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "unsubscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 0, - Msg: &UnsubscribeMsg{ - Stream: stream, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - } -} - -// TestMaxPeerServersWithoutUnsubscribe creates a registry with a limited -// number of stream servers, and performs subscriptions to detect subscriptions -// error message exchange. -func TestMaxPeerServersWithoutUnsubscribe(t *testing.T) { - var maxPeerServers = 6 - tester, streamer, _, teardown, err := newStreamerTester(&RegistryOptions{ - MaxPeerServers: maxPeerServers, - }) - if err != nil { - t.Fatal(err) - } - defer teardown() - - streamer.RegisterServerFunc("foo", func(p *Peer, t string, live bool) (Server, error) { - return newTestServer(t, 0), nil - }) - - node := tester.Nodes[0] - - for i := 0; i < maxPeerServers+10; i++ { - stream := NewStream("foo", strconv.Itoa(i), true) - - if i >= maxPeerServers { - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 7, - Msg: &SubscribeErrorMsg{ - Error: ErrMaxPeerServers.Error(), - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - continue - } - - err = tester.TestExchanges(p2ptest.Exchange{ - Label: "Subscribe message", - Triggers: []p2ptest.Trigger{ - { - Code: 4, - Msg: &SubscribeMsg{ - Stream: stream, - Priority: Top, - }, - Peer: node.ID(), - }, - }, - Expects: []p2ptest.Expect{ - { - Code: 1, - Msg: &OfferedHashesMsg{ - Stream: stream, - HandoverProof: &HandoverProof{ - Handover: &Handover{}, - }, - Hashes: make([]byte, HashSize), - From: 1, - To: 0, - }, - Peer: node.ID(), - }, - }, - }) - - if err != nil { - t.Fatal(err) - } - } -} - -//TestHasPriceImplementation is to check that the Registry has a -//`Price` interface implementation -func TestHasPriceImplementation(t *testing.T) { - _, r, _, teardown, err := newStreamerTester(&RegistryOptions{ - Syncing: SyncingDisabled, - }) - if err != nil { - t.Fatal(err) - } - defer teardown() - - if r.prices == nil { - t.Fatal("No prices implementation available for the stream protocol") - } - - pricesInstance, ok := r.prices.(*StreamerPrices) - if !ok { - t.Fatal("`Registry` does not have the expected Prices instance") - } - price := pricesInstance.Price(&ChunkDeliveryMsgRetrieval{}) - if price == nil || price.Value == 0 || price.Value != pricesInstance.getChunkDeliveryMsgRetrievalPrice() { - t.Fatal("No prices set for chunk delivery msg") - } - - price = pricesInstance.Price(&RetrieveRequestMsg{}) - if price == nil || price.Value == 0 || price.Value != pricesInstance.getRetrieveRequestMsgPrice() { - t.Fatal("No prices set for chunk delivery msg") - } -} - -// TestGetServerSubscriptions is a unit test for the api.GetPeerServerSubscriptions() function -func TestGetServerSubscriptions(t *testing.T) { - // create an amount of dummy peers - testPeerCount := 8 - // every peer will have this amount of dummy servers - testServerCount := 4 - // the peerMap which will store this data for the registry - peerMap := make(map[enode.ID]*Peer) - // create the registry - r := &Registry{} - api := NewAPI(r) - // call once, at this point should be empty - regs := api.GetPeerServerSubscriptions() - if len(regs) != 0 { - t.Fatal("Expected subscription count to be 0, but it is not") - } - - // now create a number of dummy servers for each node - for i := 0; i < testPeerCount; i++ { - addr := network.RandomAddr() - id := addr.ID() - p := &Peer{} - p.servers = make(map[Stream]*server) - for k := 0; k < testServerCount; k++ { - s := Stream{ - Name: strconv.Itoa(k), - Key: "", - Live: false, - } - p.servers[s] = &server{} - } - peerMap[id] = p - } - r.peers = peerMap - - // call the subscriptions again - regs = api.GetPeerServerSubscriptions() - // count how many (fake) subscriptions there are - cnt := 0 - for _, reg := range regs { - for range reg { - cnt++ - } - } - // check expected value - expectedCount := testPeerCount * testServerCount - if cnt != expectedCount { - t.Fatalf("Expected %d subscriptions, but got %d", expectedCount, cnt) - } -} - -/* -TestGetServerSubscriptionsRPC sets up a simulation network of `nodeCount` nodes, -starts the simulation, waits for SyncUpdateDelay in order to kick off -stream registration, then tests that there are subscriptions. -*/ -func TestGetServerSubscriptionsRPC(t *testing.T) { - - if testutil.RaceEnabled && os.Getenv("TRAVIS") == "true" { - t.Skip("flaky with -race on Travis") - // Note: related ticket https://github.com/ethersphere/go-ethereum/issues/1234 - } - - // arbitrarily set to 4 - nodeCount := 4 - // set the syncUpdateDelay for sync registrations to start - syncUpdateDelay := 200 * time.Millisecond - // run with more nodes if `longrunning` flag is set - if *longrunning { - nodeCount = 64 - syncUpdateDelay = 10 * time.Second - } - // holds the msg code for SubscribeMsg - var subscribeMsgCode uint64 - var ok bool - var expectedMsgCount counter - - // this channel signalizes that the expected amount of subscriptiosn is done - allSubscriptionsDone := make(chan struct{}) - // after the test, we need to reset the subscriptionFunc to the default - defer func() { subscriptionFunc = doRequestSubscription }() - - // we use this subscriptionFunc for this test: just increases count and calls the actual subscription - subscriptionFunc = func(r *Registry, id enode.ID, bin uint8) error { - // syncing starts after syncUpdateDelay and loops after that Duration; we only want to count at the first iteration - // in the first iteration, subs will be empty (no existing subscriptions), thus we can use this check - // this avoids flakyness - expectedMsgCount.inc() - doRequestSubscription(r, id, bin) - return nil - } - // create a standard sim - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDeliveryWithRequestFunc(ctx, bucket, dummyRequestFromPeers) - if err != nil { - return nil, nil, err - } - - // configure so that sync registrations actually happen - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Syncing: SyncingAutoSubscribe, //enable sync registrations - SyncUpdateDelay: syncUpdateDelay, - }, nil) - - // get the SubscribeMsg code - subscribeMsgCode, ok = r.GetSpec().GetCode(SubscribeMsg{}) - if !ok { - t.Fatal("Message code for SubscribeMsg not found") - } - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, - }) - defer sim.Close() - - ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancelSimRun() - - // setup the filter for SubscribeMsg - msgs := sim.PeerEvents( - context.Background(), - sim.UpNodeIDs(), - simulation.NewPeerEventsFilter().ReceivedMessages().Protocol("stream").MsgCode(subscribeMsgCode), - ) - - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - filename := fmt.Sprintf("testing/snapshot_%d.json", nodeCount) - if err := sim.UploadSnapshot(ctx, filename); err != nil { - t.Fatal(err) - } - - // strategy: listen to all SubscribeMsg events; after every event we wait - // if after `waitDuration` no more messages are being received, we assume the - // subscription phase has terminated! - - // the loop in this go routine will either wait for new message events - // or times out after 1 second, which signals that we are not receiving - // any new subscriptions any more - go func() { - //for long running sims, waiting 1 sec will not be enough - waitDuration := 1 * time.Second - if *longrunning { - waitDuration = 3 * time.Second - } - for { - select { - case <-ctx.Done(): - return - case m := <-msgs: // just reset the loop - if m.Error != nil { - log.Error("stream message", "err", m.Error) - continue - } - log.Trace("stream message", "node", m.NodeID, "peer", m.PeerID) - case <-time.After(waitDuration): - // one second passed, don't assume more subscriptions - allSubscriptionsDone <- struct{}{} - log.Info("All subscriptions received") - return - - } - } - }() - - //run the simulation - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - log.Info("Simulation running") - nodes := sim.Net.Nodes - - //wait until all subscriptions are done - select { - case <-allSubscriptionsDone: - case <-ctx.Done(): - return errors.New("Context timed out") - } - - log.Debug("Expected message count: ", "expectedMsgCount", expectedMsgCount.count()) - //now iterate again, this time we call each node via RPC to get its subscriptions - realCount := 0 - for _, node := range nodes { - //create rpc client - client, err := node.Client() - if err != nil { - return fmt.Errorf("create node 1 rpc client fail: %v", err) - } - - //ask it for subscriptions - pstreams := make(map[string][]string) - err = client.Call(&pstreams, "stream_getPeerServerSubscriptions") - if err != nil { - return fmt.Errorf("client call stream_getPeerSubscriptions: %v", err) - } - //length of the subscriptions can not be smaller than number of peers - log.Debug("node subscriptions", "node", node.String()) - for p, ps := range pstreams { - log.Debug("... with", "peer", p) - for _, s := range ps { - log.Debug(".......", "stream", s) - // each node also has subscriptions to RETRIEVE_REQUEST streams, - // we need to ignore those, we are only counting SYNC streams - if !strings.HasPrefix(s, "RETRIEVE_REQUEST") { - realCount++ - } - } - } - log.Debug("All node streams counted", "realCount", realCount) - } - emc := expectedMsgCount.count() - // after a subscription request, internally a live AND a history stream will be subscribed, - // thus the real count should be half of the actual request subscriptions sent - if realCount/2 != emc { - return fmt.Errorf("Real subscriptions and expected amount don't match; real: %d, expected: %d", realCount/2, emc) - } - return nil - }) - if result.Error != nil { - t.Fatal(result.Error) - } -} - -// counter is used to concurrently increment -// and read an integer value. -type counter struct { - v int - mu sync.RWMutex -} - -// Increment the counter. -func (c *counter) inc() { - c.mu.Lock() - defer c.mu.Unlock() - - c.v++ -} - -// Read the counter value. -func (c *counter) count() int { - c.mu.RLock() - defer c.mu.RUnlock() - - return c.v -} diff --git a/swarm/network/stream/syncer.go b/swarm/network/stream/syncer.go deleted file mode 100644 index 7957a8bf70..0000000000 --- a/swarm/network/stream/syncer.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "fmt" - "strconv" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -const ( - BatchSize = 128 -) - -// SwarmSyncerServer implements an Server for history syncing on bins -// offered streams: -// * live request delivery with or without checkback -// * (live/non-live historical) chunk syncing per proximity bin -type SwarmSyncerServer struct { - correlateId string //used for logging - po uint8 - netStore *storage.NetStore - quit chan struct{} -} - -// NewSwarmSyncerServer is constructor for SwarmSyncerServer -func NewSwarmSyncerServer(po uint8, netStore *storage.NetStore, correlateId string) (*SwarmSyncerServer, error) { - return &SwarmSyncerServer{ - correlateId: correlateId, - po: po, - netStore: netStore, - quit: make(chan struct{}), - }, nil -} - -func RegisterSwarmSyncerServer(streamer *Registry, netStore *storage.NetStore) { - streamer.RegisterServerFunc("SYNC", func(p *Peer, t string, _ bool) (Server, error) { - po, err := ParseSyncBinKey(t) - if err != nil { - return nil, err - } - return NewSwarmSyncerServer(po, netStore, fmt.Sprintf("%s|%d", p.ID(), po)) - }) - // streamer.RegisterServerFunc(stream, func(p *Peer) (Server, error) { - // return NewOutgoingProvableSwarmSyncer(po, db) - // }) -} - -// Close needs to be called on a stream server -func (s *SwarmSyncerServer) Close() { - close(s.quit) -} - -// GetData retrieves the actual chunk from netstore -func (s *SwarmSyncerServer) GetData(ctx context.Context, key []byte) ([]byte, error) { - ch, err := s.netStore.Get(ctx, chunk.ModeGetSync, storage.Address(key)) - if err != nil { - return nil, err - } - return ch.Data(), nil -} - -// SessionIndex returns current storage bin (po) index. -func (s *SwarmSyncerServer) SessionIndex() (uint64, error) { - return s.netStore.LastPullSubscriptionBinID(s.po) -} - -// SetNextBatch retrieves the next batch of hashes from the localstore. -// It expects a range of bin IDs, both ends inclusive in syncing, and returns -// concatenated byte slice of chunk addresses and bin IDs of the first and -// the last one in that slice. The batch may have up to BatchSize number of -// chunk addresses. If at least one chunk is added to the batch and no new chunks -// are added in batchTimeout period, the batch will be returned. This function -// will block until new chunks are received from localstore pull subscription. -func (s *SwarmSyncerServer) SetNextBatch(from, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { - batchStart := time.Now() - descriptors, stop := s.netStore.SubscribePull(context.Background(), s.po, from, to) - defer stop() - - const batchTimeout = 2 * time.Second - - var ( - batch []byte - batchSize int - batchStartID *uint64 - batchEndID uint64 - timer *time.Timer - timerC <-chan time.Time - ) - - defer func(start time.Time) { - metrics.GetOrRegisterResettingTimer("syncer.set-next-batch.total-time", nil).UpdateSince(start) - metrics.GetOrRegisterCounter("syncer.set-next-batch.batch-size", nil).Inc(int64(batchSize)) - if timer != nil { - timer.Stop() - } - }(batchStart) - - for iterate := true; iterate; { - select { - case d, ok := <-descriptors: - if !ok { - iterate = false - break - } - batch = append(batch, d.Address[:]...) - // This is the most naive approach to label the chunk as synced - // allowing it to be garbage collected. A proper way requires - // validating that the chunk is successfully stored by the peer. - err := s.netStore.Set(context.Background(), chunk.ModeSetSync, d.Address) - if err != nil { - metrics.GetOrRegisterCounter("syncer.set-next-batch.set-sync-err", nil).Inc(1) - log.Debug("syncer pull subscription - err setting chunk as synced", "correlateId", s.correlateId, "err", err) - return nil, 0, 0, nil, err - } - batchSize++ - if batchStartID == nil { - // set batch start id only if - // this is the first iteration - batchStartID = &d.BinID - } - batchEndID = d.BinID - if batchSize >= BatchSize { - iterate = false - metrics.GetOrRegisterCounter("syncer.set-next-batch.full-batch", nil).Inc(1) - log.Trace("syncer pull subscription - batch size reached", "correlateId", s.correlateId, "batchSize", batchSize, "batchStartID", batchStartID, "batchEndID", batchEndID) - } - if timer == nil { - timer = time.NewTimer(batchTimeout) - } else { - log.Trace("syncer pull subscription - stopping timer", "correlateId", s.correlateId) - if !timer.Stop() { - <-timer.C - } - log.Trace("syncer pull subscription - channel drained, resetting timer", "correlateId", s.correlateId) - timer.Reset(batchTimeout) - } - timerC = timer.C - case <-timerC: - // return batch if new chunks are not - // received after some time - iterate = false - metrics.GetOrRegisterCounter("syncer.set-next-batch.timer-expire", nil).Inc(1) - log.Trace("syncer pull subscription timer expired", "correlateId", s.correlateId, "batchSize", batchSize, "batchStartID", batchStartID, "batchEndID", batchEndID) - case <-s.quit: - iterate = false - log.Trace("syncer pull subscription - quit received", "correlateId", s.correlateId, "batchSize", batchSize, "batchStartID", batchStartID, "batchEndID", batchEndID) - } - } - if batchStartID == nil { - // if batch start id is not set, return 0 - batchStartID = new(uint64) - } - return batch, *batchStartID, batchEndID, nil, nil -} - -// SwarmSyncerClient -type SwarmSyncerClient struct { - netStore *storage.NetStore - peer *Peer - stream Stream -} - -// NewSwarmSyncerClient is a contructor for provable data exchange syncer -func NewSwarmSyncerClient(p *Peer, netStore *storage.NetStore, stream Stream) (*SwarmSyncerClient, error) { - return &SwarmSyncerClient{ - netStore: netStore, - peer: p, - stream: stream, - }, nil -} - -// RegisterSwarmSyncerClient registers the client constructor function for -// to handle incoming sync streams -func RegisterSwarmSyncerClient(streamer *Registry, netStore *storage.NetStore) { - streamer.RegisterClientFunc("SYNC", func(p *Peer, t string, live bool) (Client, error) { - return NewSwarmSyncerClient(p, netStore, NewStream("SYNC", t, live)) - }) -} - -// NeedData -func (s *SwarmSyncerClient) NeedData(ctx context.Context, key []byte) (wait func(context.Context) error) { - return s.netStore.FetchFunc(ctx, key) -} - -// BatchDone -func (s *SwarmSyncerClient) BatchDone(stream Stream, from uint64, hashes []byte, root []byte) func() (*TakeoverProof, error) { - // TODO: reenable this with putter/getter refactored code - // if s.chunker != nil { - // return func() (*TakeoverProof, error) { return s.TakeoverProof(stream, from, hashes, root) } - // } - return nil -} - -func (s *SwarmSyncerClient) Close() {} - -// base for parsing and formating sync bin key -// it must be 2 <= base <= 36 -const syncBinKeyBase = 36 - -// FormatSyncBinKey returns a string representation of -// Kademlia bin number to be used as key for SYNC stream. -func FormatSyncBinKey(bin uint8) string { - return strconv.FormatUint(uint64(bin), syncBinKeyBase) -} - -// ParseSyncBinKey parses the string representation -// and returns the Kademlia bin number. -func ParseSyncBinKey(s string) (uint8, error) { - bin, err := strconv.ParseUint(s, syncBinKeyBase, 8) - if err != nil { - return 0, err - } - return uint8(bin), nil -} diff --git a/swarm/network/stream/syncer_test.go b/swarm/network/stream/syncer_test.go deleted file mode 100644 index b787c7bb81..0000000000 --- a/swarm/network/stream/syncer_test.go +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package stream - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -const dataChunkCount = 200 - -func TestSyncerSimulation(t *testing.T) { - testSyncBetweenNodes(t, 2, dataChunkCount, true, 1) - // This test uses much more memory when running with - // race detector. Allow it to finish successfully by - // reducing its scope, and still check for data races - // with the smallest number of nodes. - if !testutil.RaceEnabled { - testSyncBetweenNodes(t, 4, dataChunkCount, true, 1) - testSyncBetweenNodes(t, 8, dataChunkCount, true, 1) - testSyncBetweenNodes(t, 16, dataChunkCount, true, 1) - } -} - -func testSyncBetweenNodes(t *testing.T, nodes, chunkCount int, skipCheck bool, po uint8) { - - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr := network.NewAddr(ctx.Config.Node()) - //hack to put addresses in same space - addr.OAddr[0] = byte(0) - - netStore, delivery, clean, err := newNetStoreAndDeliveryWithBzzAddr(ctx, bucket, addr) - if err != nil { - return nil, nil, err - } - - var dir string - var store *state.DBStore - if testutil.RaceEnabled { - // Use on-disk DBStore to reduce memory consumption in race tests. - dir, err = ioutil.TempDir("", "swarm-stream-") - if err != nil { - return nil, nil, err - } - store, err = state.NewDBStore(dir) - if err != nil { - return nil, nil, err - } - } else { - store = state.NewInmemoryStore() - } - - r := NewRegistry(addr.ID(), delivery, netStore, store, &RegistryOptions{ - Syncing: SyncingAutoSubscribe, - SkipCheck: skipCheck, - }, nil) - - cleanup = func() { - r.Close() - clean() - if dir != "" { - os.RemoveAll(dir) - } - } - - return r, cleanup, nil - }, - }) - defer sim.Close() - - // create context for simulation run - timeout := 30 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - // defer cancel should come before defer simulation teardown - defer cancel() - - _, err := sim.AddNodesAndConnectChain(nodes) - if err != nil { - t.Fatal(err) - } - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { - nodeIDs := sim.UpNodeIDs() - - nodeIndex := make(map[enode.ID]int) - for i, id := range nodeIDs { - nodeIndex[id] = i - } - - disconnected := watchDisconnections(ctx, sim) - defer func() { - if err != nil && disconnected.bool() { - err = errors.New("disconnect events received") - } - }() - - // each node Subscribes to each other's swarmChunkServerStreamName - for j := 0; j < nodes-1; j++ { - id := nodeIDs[j] - client, err := sim.Net.GetNode(id).Client() - if err != nil { - return fmt.Errorf("node %s client: %v", id, err) - } - sid := nodeIDs[j+1] - client.CallContext(ctx, nil, "stream_subscribeStream", sid, NewStream("SYNC", FormatSyncBinKey(1), false), NewRange(0, 0), Top) - if err != nil { - return err - } - if j > 0 || nodes == 2 { - item, ok := sim.NodeItem(nodeIDs[j], bucketKeyFileStore) - if !ok { - return fmt.Errorf("No filestore") - } - fileStore := item.(*storage.FileStore) - size := chunkCount * chunkSize - _, wait, err := fileStore.Store(ctx, testutil.RandomReader(j, size), int64(size), false) - if err != nil { - return fmt.Errorf("fileStore.Store: %v", err) - } - wait(ctx) - } - } - // here we distribute chunks of a random file into stores 1...nodes - // collect hashes in po 1 bin for each node - hashes := make([][]storage.Address, nodes) - totalHashes := 0 - hashCounts := make([]int, nodes) - for i := nodes - 1; i >= 0; i-- { - if i < nodes-1 { - hashCounts[i] = hashCounts[i+1] - } - item, ok := sim.NodeItem(nodeIDs[i], bucketKeyStore) - if !ok { - return fmt.Errorf("No DB") - } - store := item.(chunk.Store) - until, err := store.LastPullSubscriptionBinID(po) - if err != nil { - return err - } - if until > 0 { - c, _ := store.SubscribePull(ctx, po, 0, until) - for iterate := true; iterate; { - select { - case cd, ok := <-c: - if !ok { - iterate = false - break - } - hashes[i] = append(hashes[i], cd.Address) - totalHashes++ - hashCounts[i]++ - case <-ctx.Done(): - return ctx.Err() - } - } - } - } - var total, found int - for _, node := range nodeIDs { - i := nodeIndex[node] - - for j := i; j < nodes; j++ { - total += len(hashes[j]) - for _, key := range hashes[j] { - item, ok := sim.NodeItem(nodeIDs[j], bucketKeyStore) - if !ok { - return fmt.Errorf("No DB") - } - db := item.(chunk.Store) - _, err := db.Get(ctx, chunk.ModeGetRequest, key) - if err == nil { - found++ - } - } - } - log.Debug("sync check", "node", node, "index", i, "bin", po, "found", found, "total", total) - } - if total == found && total > 0 { - return nil - } - return fmt.Errorf("Total not equallying found %v: total is %d", found, total) - }) - - if result.Error != nil { - t.Fatal(result.Error) - } -} - -//TestSameVersionID just checks that if the version is not changed, -//then streamer peers see each other -func TestSameVersionID(t *testing.T) { - //test version ID - v := uint(1) - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Syncing: SyncingAutoSubscribe, - }, nil) - bucket.Store(bucketKeyRegistry, r) - - //assign to each node the same version ID - r.spec.Version = v - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, - }) - defer sim.Close() - - //connect just two nodes - log.Info("Adding nodes to simulation") - _, err := sim.AddNodesAndConnectChain(2) - if err != nil { - t.Fatal(err) - } - - log.Info("Starting simulation") - ctx := context.Background() - //make sure they have time to connect - time.Sleep(200 * time.Millisecond) - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - //get the pivot node's filestore - nodes := sim.UpNodeIDs() - - item, ok := sim.NodeItem(nodes[0], bucketKeyRegistry) - if !ok { - return fmt.Errorf("No filestore") - } - registry := item.(*Registry) - - //the peers should connect, thus getting the peer should not return nil - if registry.getPeer(nodes[1]) == nil { - return errors.New("Expected the peer to not be nil, but it is") - } - return nil - }) - if result.Error != nil { - t.Fatal(result.Error) - } - log.Info("Simulation ended") -} - -//TestDifferentVersionID proves that if the streamer protocol version doesn't match, -//then the peers are not connected at streamer level -func TestDifferentVersionID(t *testing.T) { - //create a variable to hold the version ID - v := uint(0) - sim := simulation.New(map[string]simulation.ServiceFunc{ - "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) - if err != nil { - return nil, nil, err - } - - r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ - Syncing: SyncingAutoSubscribe, - }, nil) - bucket.Store(bucketKeyRegistry, r) - - //increase the version ID for each node - v++ - r.spec.Version = v - - cleanup = func() { - r.Close() - clean() - } - - return r, cleanup, nil - }, - }) - defer sim.Close() - - //connect the nodes - log.Info("Adding nodes to simulation") - _, err := sim.AddNodesAndConnectChain(2) - if err != nil { - t.Fatal(err) - } - - log.Info("Starting simulation") - ctx := context.Background() - //make sure they have time to connect - time.Sleep(200 * time.Millisecond) - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - //get the pivot node's filestore - nodes := sim.UpNodeIDs() - - item, ok := sim.NodeItem(nodes[0], bucketKeyRegistry) - if !ok { - return fmt.Errorf("No filestore") - } - registry := item.(*Registry) - - //getting the other peer should fail due to the different version numbers - if registry.getPeer(nodes[1]) != nil { - return errors.New("Expected the peer to be nil, but it is not") - } - return nil - }) - if result.Error != nil { - t.Fatal(result.Error) - } - log.Info("Simulation ended") - -} diff --git a/swarm/network/stream/testing/snapshot_128.json b/swarm/network/stream/testing/snapshot_128.json deleted file mode 100644 index d25fa51c01..0000000000 --- a/swarm/network/stream/testing/snapshot_128.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","name":"node_dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","enode":"enode://dfc47747201ccdd02b200ec672c3884626a10fd4d395d729cd67e3172635873cbb9f20e1a9d402fe058c43705671b2b7b51b4fda33b1c71f67dc48fc8f80c93e@127.0.0.1:0","enr":"0xf88fb840de2ad283128b20ac2fb81c51ce7b4cc5e0fa78eee1fe7f79570a47d850263a8a1aa7e04415d06c9e35cfb89705a7574d3bc05b7881ace913df570dc72bdc27d10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102dfc47747201ccdd02b200ec672c3884626a10fd4d395d729cd67e3172635873c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3ZKz1CQU/V7/XB5MpVxjzXA2Y0BJmVtyogzffKEyGXg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dd92b3\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0f31 5c62 64e6 | 68 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n001 7 b4e2 a9fa a861 957e | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 8 ea3d ed12 ed2e efd6 | 17 efd6 (0) ee2b (0) eceb (0) ed12 (0)\n003 6 c2f9 c0ad cabf ce01 | 8 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n004 3 d125 d18a d23c | 3 d18a (0) d125 (0) d23c (0)\n============ DEPTH: 5 ==========================================\n005 1 d9d3 | 1 d9d3 (0)\n006 1 deec | 1 deec (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","private_key":"009fe52f1950de37f99e7888e92c1d26717ca84232a756701b4a642f2b642869","name":"node_dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","services":["streamer"],"enable_msg_events":true,"port":45169},"up":true}},{"node":{"info":{"id":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","name":"node_fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","enode":"enode://d70fb3399dab49d5d0085dad53fc1383a10fe708bdbc54abcd67fe3207984bcb145ce8859b7576b0a6faa795fdf64eeb6c63759bac66f5c5baba4e6e522cead7@127.0.0.1:0","enr":"0xf88fb840f7f08be963b0a1326da55df415a377468da1b99d0e12583ab97b3af05ea36f930c3913e7e58b6154d71478ccf5836a56140d9ad60b819d94197d4c4892a10b870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d70fb3399dab49d5d0085dad53fc1383a10fe708bdbc54abcd67fe3207984bcb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+sgIt5kjkx/r1U42EbeYEbOXPHd+dQK9VrmAPQxL94U=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fac808\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 3775 4746 4775 4589 | 68 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n001 6 836e a861 a192 b245 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 4 ce01 d18a deec dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 5 eb01 efd6 ee2b eceb | 8 efd6 (0) ee2b (0) eceb (0) ed12 (0)\n004 6 f4a0 f611 f177 f005 | 6 f177 (0) f005 (0) f33c (0) f3d5 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 fa65 | 1 fa65 (0)\n009 1 fa9a | 1 fa9a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","private_key":"59a3d47a5b2fa0f6cff34a3b7923fe5bd5bcd027704761ffaa4d22752484fe79","name":"node_fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","services":["streamer"],"enable_msg_events":true,"port":34267},"up":true}},{"node":{"info":{"id":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","name":"node_b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","enode":"enode://f9fa2390fdb8807909e77cb819962e0e99aff947653d98f8214cd66694386f1ddb1902f61be1598592f66184534da5b7519cf7eacbdcde753ff8e9359f1ad7cd@127.0.0.1:0","enr":"0xf88fb8407259bd30798ce82b8b4d9dd309e5fa69a46bc8d320221016d5cc98922b865e5968fbe4704097f55dee037fe7f3638efec032c6fb00f2e850035a729c1407bd850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f9fa2390fdb8807909e77cb819962e0e99aff947653d98f8214cd66694386f1d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uGlb7GyOHmeUu5Q7g2Kc0skQBn5uF49vjjPE8PotdPQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8695b\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3e19 4d75 72a5 | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 7 cabf ee2b ed2e f611 | 31 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n002 2 8012 8330 | 9 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n003 4 a9fa a861 acf8 a192 | 6 aedc (0) acf8 (0) aba7 (0) a861 (0)\n004 4 b5fc b4e2 b355 b245 | 5 b245 (0) b355 (0) b60e (0) b5fc (0)\n============ DEPTH: 5 ==========================================\n005 7 be0f bc71 bc29 bd48 | 7 be0f (0) bd48 (0) bd96 (0) bddb (0)\n006 0 | 0\n007 1 b9d9 | 1 b9d9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","private_key":"097a05bf51118f924f1adb26e6a452bb90533346ba3a28a13f3d0d984eccf2b6","name":"node_b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","services":["streamer"],"enable_msg_events":true,"port":44203},"up":true}},{"node":{"info":{"id":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","name":"node_72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","enode":"enode://05e3a75ccb0d9a1554a071d18873ceef4aec0d0ecb15840824ce3826f6c07e9e3fc43284c66bcbc0a57268a6efef655d7cf4cd12d9052f071e8c8374907716ef@127.0.0.1:0","enr":"0xf88fb840c57b532df76cb5be5b002107b74ba9b52855af33fe4d5233521e04bd89496c5472f49ace6d880f2d12d87c4e9296883a61ed286682e8e4cebe6a0092268f49770183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10305e3a75ccb0d9a1554a071d18873ceef4aec0d0ecb15840824ce3826f6c07e9e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cqU/D7G1GFXLQFSjnL0TCadqhi024Yr5ugRWpgMlwG4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 72a53f\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 c0ad eb01 ee2b fac8 | 60 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n001 4 0807 0a21 27b5 3e19 | 30 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n002 9 4a37 4bc8 4efa 4746 | 20 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n003 5 6975 68a6 62f0 672a | 9 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n004 3 7a68 7bcb 7bee | 3 7a68 (0) 7bcb (0) 7bee (0)\n005 3 75e2 772a 77ee | 3 772a (0) 77ee (0) 75e2 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 73d0 | 1 73d0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 1 72a7 | 1 72a7 (0)\n015 0 | 0\n========================================================================="}},"config":{"id":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","private_key":"b43306b3e3a12c45a24bacbc053382c7c985c642252fd778f0397ba9b30bfb78","name":"node_72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","services":["streamer"],"enable_msg_events":true,"port":40757},"up":true}},{"node":{"info":{"id":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","name":"node_f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","enode":"enode://935e2d2fb4ec2899b4a4fae26ea6325ff296a698da7c81b5a67870eba307c1869c91558f7b8835a8d6e78ff772a4330447bc3a1e94298a2e15733bc0272b4ad0@127.0.0.1:0","enr":"0xf88fb8406b3720141a112476eb8640a2b4253f2f73929aca065cf93cb76e6b04cc2e2b890c1657f0755ff355ad24af42636fcd866c96e5431800daa692711baa906569e20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102935e2d2fb4ec2899b4a4fae26ea6325ff296a698da7c81b5a67870eba307c186","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"89UIEe8QZh0++ZeAd81xgThymPMGgzq24n8ly7d0Nc0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f3d508\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3e19 72a5 | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 9 957e 8330 8012 a9fa | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 2 d23c cabf | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 6 ea3d eb01 ed2e ee2b | 8 e06f (0) efd6 (0) ee2b (0) eceb (0)\n004 2 fa65 fac8 | 3 fa9a (0) fac8 (0) fa65 (0)\n005 2 f4a0 f611 | 2 f611 (0) f4a0 (0)\n============ DEPTH: 6 ==========================================\n006 2 f177 f005 | 2 f177 (0) f005 (0)\n007 0 | 0\n008 1 f33c | 1 f33c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","private_key":"1400f36ad2ebedcf9c8897f84d4c1145757c0b829eeead178385d6e58b8af6d2","name":"node_f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","services":["streamer"],"enable_msg_events":true,"port":44709},"up":true}},{"node":{"info":{"id":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","name":"node_3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","enode":"enode://7dd2bef04deecdcb459658589d12dd5ccd1e8946309bac3a44e77161a25762e2eca61c3f151d0502c1d87a6617b91e39007101f5b9cad7b3c72ec216f566f436@127.0.0.1:0","enr":"0xf88fb840ff54e5bf97acf0f558d8bdda0e66ded18a9a0147bb097d7e18a3107d9b0720f13117a5b72582ebb9c81320b0ed489e15b31d85ae5c31684331caefd43e3173a00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027dd2bef04deecdcb459658589d12dd5ccd1e8946309bac3a44e77161a25762e2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PhlZspu6yzzn3M+kHD5RuH8a/HAKPG5HE8OMwP43kN8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3e1959\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b355 b869 d23c e06f | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 9 4589 4775 52b4 62f0 | 38 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n002 7 184e 1929 1740 127c | 13 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n003 5 27b5 2471 2354 2803 | 11 2803 (0) 2dd4 (0) 2d53 (0) 21dc (0)\n004 3 36d5 3775 3590 | 3 3590 (0) 3775 (0) 36d5 (0)\n============ DEPTH: 5 ==========================================\n005 2 3871 3b83 | 2 3871 (0) 3b83 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","private_key":"79b77704fc404ea988a22902c0829368cc662928cff0a0cd1da58204d8798187","name":"node_3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","services":["streamer"],"enable_msg_events":true,"port":45515},"up":true}},{"node":{"info":{"id":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","name":"node_fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","enode":"enode://1bd15b81ce9c254be30f589cb832521a921c02c85d2816b7908cac8f0087244fb472c89900fdd6295768deef48504061995e3912039a46881d149fd5f38eebe0@127.0.0.1:0","enr":"0xf88fb84006acad544c50bd08be034b2ed91454d521ae949b4a8420cac9aa8a44849871fc14b06caa330bfc823a926ae6b2af2ec87c9d78a9ddd222cf1f35ef26518baf300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021bd15b81ce9c254be30f589cb832521a921c02c85d2816b7908cac8f0087244f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+mVbSIJXnmWTehSrHGvLoCFYDwpevATEhCT1rnK31bQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fa655b\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 7bcb 4a3c 4589 27b5 | 68 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n001 4 836e a192 b245 bc71 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 5 d18a d125 cc9f cabf | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 7 e06f eb01 ee2b efd6 | 8 e06f (0) efd6 (0) ee2b (0) eceb (0)\n004 6 f177 f005 f33c f3d5 | 6 f611 (0) f4a0 (0) f177 (0) f005 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 2 fa9a fac8 | 2 fa9a (0) fac8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","private_key":"57a4b89b8685312b36e106e0ad52cb8ee76e8ded6c198f02a1ec38b354c211e5","name":"node_fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","services":["streamer"],"enable_msg_events":true,"port":42203},"up":true}},{"node":{"info":{"id":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","name":"node_2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","enode":"enode://782260bab233d14554e8f786b5415ffd70ac89c7c221556fdb89ffb4e8f6977ab28d8918a8255aecfcc50ac131dd44231c431d6bf85229f36f8f095b62a91bbe@127.0.0.1:0","enr":"0xf88fb84089e932678501d708a5f4b9ffb2523f4716179e653f829dc22d15905cea0441b67ab9de8d2d9e91914f5ff28e37867036b36714fa1ea6e017dd084e64029850c50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102782260bab233d14554e8f786b5415ffd70ac89c7c221556fdb89ffb4e8f6977a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JHF3YDfVWgXfKxW87+UssfTJQunhUROrwqDB/Lql1iY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 247177\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 a192 acf8 a9fa a861 | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 5 4775 5c62 62f0 64e6 | 38 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n002 5 0e34 0a21 127c 1929 | 13 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n003 3 36d5 3871 3e19 | 6 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n004 3 2803 2dd4 2d53 | 3 2803 (0) 2dd4 (0) 2d53 (0)\n005 5 216e 21dc 221c 22bb | 5 216e (0) 21dc (0) 22bb (0) 221c (0)\n============ DEPTH: 6 ==========================================\n006 2 27db 27b5 | 2 27db (0) 27b5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","private_key":"4fb235ecc4c97edf33736a85d3641e652e3713b0c77d9870ab993eb9d10afcc2","name":"node_2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","services":["streamer"],"enable_msg_events":true,"port":41591},"up":true}},{"node":{"info":{"id":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","name":"node_27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","enode":"enode://2c8d76747698073fd7707081b9c643e9bd58242098e91b191f417fbbcc60dc236b8df6bb2011488880af007b77f3f826285fb2ce1ff1bcbe04c21d6fb373c111@127.0.0.1:0","enr":"0xf88fb8400b8f821da1310d4ecd5caff36e8ddaa69544654cd1241aa92aae063aac2a9f9472aa9f4b065c3a29a54feff65021b136e635a9379f9af99e57923535df10c73c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032c8d76747698073fd7707081b9c643e9bd58242098e91b191f417fbbcc60dc23","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J7VjAqiWBag1Y7p7ZtSR7CXt+tDqEBCTf8req0065YI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 27b563\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 fa65 ea3d | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 8 7bee 72a5 64e6 672a | 38 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n002 5 184e 127c 0e34 0807 | 13 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n003 2 3e19 36d5 | 6 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n004 2 2803 2d53 | 3 2803 (0) 2dd4 (0) 2d53 (0)\n005 5 216e 21dc 2354 221c | 5 216e (0) 21dc (0) 221c (0) 22bb (0)\n============ DEPTH: 6 ==========================================\n006 1 2471 | 1 2471 (0)\n007 0 | 0\n008 0 | 0\n009 1 27db | 1 27db (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","private_key":"e230f8ba6e49724537db8be23422f340405faa744171eda44d4414b8841f8d65","name":"node_27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","services":["streamer"],"enable_msg_events":true,"port":37611},"up":true}},{"node":{"info":{"id":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","name":"node_ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","enode":"enode://e3382fa3db3fda2f1f3729fc5eab5747a80c97abf5536b24fe20890ac988d61c0e3df2f91553c2768db16fdd48bfa36ec3c3e2ac4696137162859d238e4d8509@127.0.0.1:0","enr":"0xf88fb8409cf06d414b5b67bcf1e38e69f509a14cb0dcbb61db09fab4ce36203ef99b5a287b96c3febcbc9686f75736cdc30446d392ac7ad1e3cae7afece3d609b3c964f00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e3382fa3db3fda2f1f3729fc5eab5747a80c97abf5536b24fe20890ac988d61c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6j1qpQrVodVkfSE/m1z+Zxgznux+74ZESH6zwiPHvN4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ea3d6a\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 4d75 4775 4746 4589 | 68 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n001 4 a9fa a192 8330 8012 | 29 9472 (0) 957e (0) 8fb8 (0) 8d3e (0)\n002 7 c52a c2f9 d9d3 dd92 | 14 d18a (0) d125 (0) d23c (0) d9d3 (0)\n003 5 fa9a f3d5 f33c f177 | 9 fa9a (0) fac8 (0) fa65 (0) f33c (0)\n004 1 e06f | 1 e06f (0)\n============ DEPTH: 5 ==========================================\n005 5 eceb ed12 ed2e efd6 | 5 eceb (0) ed12 (0) ed2e (0) efd6 (0)\n006 0 | 0\n007 1 eb01 | 1 eb01 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","private_key":"7c2c7b1ed36aa7347eb5dd1069e933f2226e857d909980a5d78571de6aeb6867","name":"node_ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","services":["streamer"],"enable_msg_events":true,"port":46599},"up":true}},{"node":{"info":{"id":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","name":"node_f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","enode":"enode://71e720933310fdd429e11130816957617b45fd95d2e8bb1ac6e70b351c3bf2e1ad4934cef5497f766939836952bc939d6c4d694db17ee23aa22e687f7e4f1e61@127.0.0.1:0","enr":"0xf88fb840f9c7fe83c3c9fd5157e8e3320ab57aa3c67f6e1c4330581593214ef13e34ec42370db0c4aeed95c3133bf33247f122a93905351c98c5558e6d7274dd63258c0a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10371e720933310fdd429e11130816957617b45fd95d2e8bb1ac6e70b351c3bf2e1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9KD3azC89Zh8+j9PSwqjRF851gofUVGfpmDCe12DPd4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4a0f7\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 72a5 4efa 4bc8 4a37 | 68 55fd (0) 52b4 (0) 51c2 (0) 5008 (0)\n001 4 b245 a192 836e 8330 | 29 9472 (0) 957e (0) 8fb8 (0) 8d3e (0)\n002 5 cc5f c2f9 c0ad d23c | 14 d18a (0) d125 (0) d23c (0) d9d3 (0)\n003 4 efd6 ee2b eb01 ea3d | 8 e06f (0) eceb (0) ed12 (0) ed2e (0)\n004 3 fac8 fa9a fa65 | 3 fa9a (0) fac8 (0) fa65 (0)\n============ DEPTH: 5 ==========================================\n005 4 f005 f177 f33c f3d5 | 4 f005 (0) f177 (0) f33c (0) f3d5 (0)\n006 1 f611 | 1 f611 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","private_key":"ea1b57ee39036543e929539274921246c082c626d3338b562352e1570697b380","name":"node_f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","services":["streamer"],"enable_msg_events":true,"port":36907},"up":true}},{"node":{"info":{"id":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","name":"node_184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","enode":"enode://e7521d45b3c81db4b1bfc556f89dbdbc47fc7ac609fe1eafc0a7e830bee2b50f8b128616da05f3eeed91033d64402dbec46238c619da3c159c67c715fcc42c96@127.0.0.1:0","enr":"0xf88fb84045617828d5c7c09265f7dd67603ac0e5cb3e13bfd1aa995f4fa2f933c1257a6476590491ceb0211c9174c55e57d0a600bc20d608f2b1ced80363254101b91a290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e7521d45b3c81db4b1bfc556f89dbdbc47fc7ac609fe1eafc0a7e830bee2b50f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GE6eAKtP4WadTZn7M9QY0z7/kn2jjMmX9pZ5RDwksgs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 184e9e\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b355 a192 d23c e06f | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 9 5c62 52b4 4746 4d75 | 38 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n002 8 2354 27b5 2471 2803 | 17 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n003 7 0639 034d 03eb 01a6 | 8 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n============ DEPTH: 4 ==========================================\n004 3 1740 1385 127c | 3 1740 (0) 1385 (0) 127c (0)\n005 0 | 0\n006 0 | 0\n007 1 1929 | 1 1929 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","private_key":"3d7c42c0ee77391c165bc551bc1353809a10a3dc98a861729720d549f7b63386","name":"node_184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","services":["streamer"],"enable_msg_events":true,"port":43977},"up":true}},{"node":{"info":{"id":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","name":"node_64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","enode":"enode://78910b44088439d364d5486fd9eee45c43f910ad4e7a1fa7bd925bef18455f7f3e21397047344aa0abca519d7f19211c5998fb9d1977c9eb0c3586a7f3cd6c9a@127.0.0.1:0","enr":"0xf88fb8402ae44f0913233c76e5590653b9801497737a50b397a877f4bf3e49c453aa41f57cbc4a5fc6a128aa2726ea9f4bac6411fd90ef86c39ad02424c4842187c11ce30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10278910b44088439d364d5486fd9eee45c43f910ad4e7a1fa7bd925bef18455f7f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZOZC3iZnp1Y8d0BQ02iFjZmv9DPvvRy2g2Hj4kRimwM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 64e642\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ee2b dd92 bc71 | 60 d23c (0) d18a (0) d125 (0) d9d3 (0)\n001 9 2354 2471 27b5 2d53 | 30 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n002 2 4746 4a3c | 20 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n003 3 7bee 75e2 72a5 | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 2 68a6 6975 | 3 6daa (0) 6975 (0) 68a6 (0)\n005 2 62f0 6379 | 2 6379 (0) 62f0 (0)\n006 1 672a | 1 672a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 6450 641a | 2 6450 (0) 641a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","private_key":"01c1a76aef076f97db9bf60e66af44d4d529abe0f71f0b856c4508431e1792c9","name":"node_64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","services":["streamer"],"enable_msg_events":true,"port":41283},"up":true}},{"node":{"info":{"id":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","name":"node_bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","enode":"enode://0f1575d3b450347bb3500ed09bb0e0ff0fbf252b802e2a0e8e1ede7fedf7f6b64e2326928de87bb45800a8498d20b6bdfdd80fbd0041d7bbed546c86cbe8953e@127.0.0.1:0","enr":"0xf88fb840a158d2da63bc36da645177c654f2ca0a6cec837921556ecb04a65d57509dc46f66b7c4edfbefc8233e72992e4a8a3e41523af33e57ccd3966ae53be8491f3d3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f1575d3b450347bb3500ed09bb0e0ff0fbf252b802e2a0e8e1ede7fedf7f6b6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vHHz5AntuYniZgdEhJFTDFRRBTtYLqZNiCUlRRrJQLs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bc71f3\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 64e6 75e2 | 68 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n001 3 cabf f3d5 fa65 | 31 f33c (0) f3d5 (0) f177 (0) f005 (0)\n002 7 957e 9472 8fb8 8284 | 9 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n003 3 a861 a9fa a192 | 6 aedc (0) acf8 (0) aba7 (0) a9fa (0)\n004 3 b4e2 b355 b245 | 5 b60e (0) b5fc (0) b4e2 (0) b355 (0)\n005 2 b869 b9d9 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n============ DEPTH: 7 ==========================================\n007 4 bd48 bd96 bddb bde9 | 4 bd48 (0) bd96 (0) bddb (0) bde9 (0)\n008 0 | 0\n009 1 bc29 | 1 bc29 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","private_key":"6dccee837e7d946fc35f7afeb74d1977abaa3488cdf673d9e8a0a0d9d6ed0c21","name":"node_bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","services":["streamer"],"enable_msg_events":true,"port":36167},"up":true}},{"node":{"info":{"id":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","name":"node_75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","enode":"enode://0929c1d89eedea4cba85836dfc498319bbc4fa3a811ad84aef807af863b80365d86fc93e87d85f44822c9930d62eb6668cc64ad0fab431c7afe2824529e934f7@127.0.0.1:0","enr":"0xf88fb840d80d8a682e3360189c74b617f133ec7585e50d9dbed3329e8625c30c1d7471353fdf1a49ca51ca63b7c0dff86d48c2bd2d19f6c45fae4b5587fe23c6781bee3f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030929c1d89eedea4cba85836dfc498319bbc4fa3a811ad84aef807af863b80365","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"deKCwPPTVaQFc+ZXjFqsmOcmKXCpI59Nzv0m1vAItVM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 75e282\npopulation: 42 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 ee2b eb01 c0ad cc5f | 60 f33c (0) f3d5 (0) f005 (0) f177 (0)\n001 5 0807 0a21 3e19 2d53 | 30 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n002 12 5008 52b4 5a8b 5c62 | 20 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n003 9 64e6 6450 641a 672a | 9 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n004 3 7a68 7bcb 7bee | 3 7a68 (0) 7bcb (0) 7bee (0)\n005 3 73d0 72a5 72a7 | 3 73d0 (0) 72a7 (0) 72a5 (0)\n============ DEPTH: 6 ==========================================\n006 2 772a 77ee | 2 772a (0) 77ee (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","private_key":"cdafa79406c7b344d079038e1495604987c7c5cb47cc80bb494dc78d10085474","name":"node_75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","services":["streamer"],"enable_msg_events":true,"port":39125},"up":true}},{"node":{"info":{"id":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","name":"node_cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","enode":"enode://1a24350591770da447d5dbf6fba74dd85dd27050cc1a68603b8cb89e76b2eb77b4022b9d2cfbadc9d4a727b883104cc0b56287d9675b33d8c4d0f4f32f75e4e4@127.0.0.1:0","enr":"0xf88fb840b98c3132ab4d278a63670e3ae4432632206c358799c769ff7083d4b91cbad7d65f7b5fd6d79c96d8841b3e81ce9c3e58d82837512f7cfdd3619ddebea6e926e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021a24350591770da447d5dbf6fba74dd85dd27050cc1a68603b8cb89e76b2eb77","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zF+i1JIQ4kCYOwhT/xUAPw02bwXLH2SGuuKGLMqFLMU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc5fa2\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0f31 01a6 68a6 75e2 | 68 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n001 4 be0f b4e2 a9fa 8012 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 6 eceb ed12 ed2e f177 | 17 f33c (0) f3d5 (0) f177 (0) f005 (0)\n003 6 deec dd92 d9d3 d23c | 6 d18a (0) d125 (0) d23c (0) d9d3 (0)\n004 3 c52a c0ad c2f9 | 3 c52a (0) c2f9 (0) c0ad (0)\n005 2 c9ef cabf | 2 c9ef (0) cabf (0)\n============ DEPTH: 6 ==========================================\n006 1 ce01 | 1 ce01 (0)\n007 0 | 0\n008 1 cc9f | 1 cc9f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","private_key":"e1260778d751d38a387d4a88c5e115edf9e5478423866b27485a2292dc8e8c5a","name":"node_cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","services":["streamer"],"enable_msg_events":true,"port":35235},"up":true}},{"node":{"info":{"id":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","name":"node_68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","enode":"enode://45b4b209ea27a1478d3439b7b1c5e07f0f8021590ce28e6e498788ffc5a97d2372743f9b838796df1a3784a7e7d36abacf6f765e69941f4735b52eeab4bbcac5@127.0.0.1:0","enr":"0xf88fb840adb223ccf956ef0b48ac44f1fb4955cd78f315fae65a8a26fe14a6b0516b68982cd7f7c163fd51357a9c9f8cf8b7d7a8b002b933909fa33e717cb15e8a9e5bbb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10345b4b209ea27a1478d3439b7b1c5e07f0f8021590ce28e6e498788ffc5a97d23","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aKY+vEgz3t/bbVNEOP/MzQQvYENL7g459Ms3JudBPno=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 68a63e\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 b9d9 a192 a861 a9fa | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 4 0807 03eb 27b5 3e19 | 30 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n002 4 52b4 5a8b 4bc8 4a3c | 20 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n003 3 7bee 75e2 72a5 | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 6 6379 62f0 672a 6450 | 6 6379 (0) 62f0 (0) 672a (0) 6450 (0)\n============ DEPTH: 5 ==========================================\n005 1 6daa | 1 6daa (0)\n006 0 | 0\n007 1 6975 | 1 6975 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","private_key":"5b70dd7e5dac1e6c7338aa2968162aec253e332ea3599bec657be6d04f612da6","name":"node_68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","services":["streamer"],"enable_msg_events":true,"port":33311},"up":true}},{"node":{"info":{"id":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","name":"node_4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","enode":"enode://4ab4e0bfbba774d3dff10d02b4464d3a06ef1a9c14fd4084ec4c239a398653aa3e6c1a58462ffd6fe0d0d27c3dc284999c3560886891b362e8e99ad385747b84@127.0.0.1:0","enr":"0xf88fb840b36e6eecac0592d08346ad3d82fd3b0879b1b73d47026222ac4afb89289daf5504012dd22594a354b108a7396d8c509bc3b373adcd376aa441dc778d6c2c72ea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024ab4e0bfbba774d3dff10d02b4464d3a06ef1a9c14fd4084ec4c239a398653aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Sjw58ETEJcFT1JANsw+DnXhmyOD09NONkgXmf7VAmI4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a3c39\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 e06f eb01 fa65 fac8 | 60 f3d5 (0) f33c (0) f177 (0) f005 (0)\n001 2 184e 27b5 | 30 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n002 3 75e2 64e6 68a6 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 5008 52b4 5a8b 5c62 | 9 55fd (0) 51c2 (0) 5008 (0) 52b4 (0)\n004 3 4746 459b 4589 | 4 459b (0) 4589 (0) 4746 (0) 4775 (0)\n005 2 4d75 4efa | 4 4c21 (0) 4cc2 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4bc8 | 1 4bc8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 4a37 | 1 4a37 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","private_key":"1dfd38b15db0c055f13b2e98bdef34c32d745b817c9f37516af52c78e2ba2a3e","name":"node_4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","services":["streamer"],"enable_msg_events":true,"port":34469},"up":true}},{"node":{"info":{"id":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","name":"node_8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","enode":"enode://3fc2da9e04199b0c080846d5f56ed8ab73bed014a03c242832e9be303880d706f671d59b5e15d134f4da9410d101204d0567afcde9ab261c83461744ce520751@127.0.0.1:0","enr":"0xf88fb84072d464b640b8c4621eea600036ab5b62f29ca3e9b26135a37947d95f54e9890f6559c3a84ea0b623de61d0d0ad41f9b85abe44906f2bf8e22df934c061fe6cd90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033fc2da9e04199b0c080846d5f56ed8ab73bed014a03c242832e9be303880d706","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gzDiuK4vGEu43F4VP6+k2v6G+E7GktPukUE8wHsc2eI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8330e2\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 2471 127c 0e34 0807 | 68 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n001 10 d125 dd92 c2f9 cabf | 31 f177 (0) f005 (0) f33c (0) f3d5 (0)\n002 12 a861 acf8 a192 bc71 | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 3 8fb8 8d3e 8b35 | 3 8b35 (0) 8d3e (0) 8fb8 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 8012 | 1 8012 (0)\n007 1 8284 | 1 8284 (0)\n008 0 | 0\n009 1 836e | 1 836e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","private_key":"655f2ae9378e87cd580544c9cb99036bcfb2795b603d200b06e0df9f41438877","name":"node_8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","services":["streamer"],"enable_msg_events":true,"port":46233},"up":true}},{"node":{"info":{"id":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","name":"node_b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","enode":"enode://d3a39529d6f6310edfbbecde895c8a3024336ed33e9904646e9e3e86718ed5248faaa14fd06beb2acbc38689cef3d1d7235845d431d25deb99ca91471a529092@127.0.0.1:0","enr":"0xf88fb840f566ab01e80bef9b69c5c6341ef1ee20605368864011471a8ae8bb9a47a27b434331d6c7e2b361e2766764ed97aacb871ec2912f49c7f45f1e90f321c4c9c02a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d3a39529d6f6310edfbbecde895c8a3024336ed33e9904646e9e3e86718ed524","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"skU8bnVaMO+5EZT6YHszUtdbaQXESLCa9K6t86RFtjM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2453c\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 672a 75e2 72a5 5c62 | 68 58a9 (0) 5a8b (0) 5be6 (0) 5cc1 (0)\n001 8 e06f fa65 fac8 f4a0 | 31 f005 (0) f177 (0) f3d5 (0) f33c (0)\n002 4 8d3e 8012 836e 8330 | 9 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n003 4 a192 acf8 a9fa a861 | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 5 b9d9 b869 bc71 bde9 | 9 b9d9 (0) b869 (0) be0f (0) bd48 (0)\n============ DEPTH: 5 ==========================================\n005 3 b60e b5fc b4e2 | 3 b60e (0) b5fc (0) b4e2 (0)\n006 0 | 0\n007 1 b355 | 1 b355 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","private_key":"34a8d5008ee38c02fa2deffed8ac1eb5e4238f26925bba625642248ee6f4b502","name":"node_b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","services":["streamer"],"enable_msg_events":true,"port":44445},"up":true}},{"node":{"info":{"id":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","name":"node_c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","enode":"enode://e8139ca6fd25a63ec0226a7e0d1b3e24dd4a64e28de32b96e967dce072e64ca1eda7974197edb2b54bce2bff0c78543b0d9b29eb6ea9610bad964a9177b0f40a@127.0.0.1:0","enr":"0xf88fb840ea7ff8e5655a5641139c8258f6ea2d2fcaf6b7e83105a5a3489aa0c3611a21c5763a5b6a12671c24fd597686f485cdcc17d168e4ec02458d74c3be1cf0455d480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8139ca6fd25a63ec0226a7e0d1b3e24dd4a64e28de32b96e967dce072e64ca1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wK3zlK99VnDBzoxr6ikvvAPFauK2NuLzAzEaRVuzUA8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c0adf3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 62f0 672a 7bee 75e2 | 68 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n001 5 9472 8b35 a9fa b4e2 | 29 957e (0) 9472 (0) 8fb8 (0) 8d3e (0)\n002 5 f4a0 fa65 ed12 ed2e | 17 f3d5 (0) f33c (0) f177 (0) f005 (0)\n003 5 d23c d18a d125 dd92 | 6 d18a (0) d125 (0) d23c (0) deec (0)\n004 5 ce01 cc5f cc9f c9ef | 5 c9ef (0) cabf (0) ce01 (0) cc5f (0)\n============ DEPTH: 5 ==========================================\n005 1 c52a | 1 c52a (0)\n006 1 c2f9 | 1 c2f9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","private_key":"269f2338eae4174d5d03bcc681f76dc898907e6bcaa160114424dc97aa7307b8","name":"node_c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","services":["streamer"],"enable_msg_events":true,"port":36773},"up":true}},{"node":{"info":{"id":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","name":"node_2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","enode":"enode://3f4db397fc277b2e70200ee0df565958becb600266ad3362cb2fcf934318cca69ae8ac6ecf3040c7bc23192473e12a8828383ac4106878567e97fc0c3ff63339@127.0.0.1:0","enr":"0xf88fb840e7c428cebdf711272fc568f71b015bf4dcf2c02936b88067d975ddf1d00fd52a28c15718e1c7dd0120d9614b4063392c515e52ffdf2c222ea70d6651df4cc9830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033f4db397fc277b2e70200ee0df565958becb600266ad3362cb2fcf934318cca6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LVMcUBg/ARUmmz/q7PRZJ6OsROG+KiY8fl0idNg3mxw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2d531c\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e06f ee2b c0ad | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 7 4775 5c62 64e6 672a | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 6 0639 03eb 0a21 0e34 | 13 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n003 3 36d5 3b83 3e19 | 6 3590 (0) 3775 (0) 36d5 (0) 3871 (0)\n004 7 2471 27db 27b5 216e | 8 216e (0) 21dc (0) 22bb (0) 221c (0)\n============ DEPTH: 5 ==========================================\n005 1 2803 | 1 2803 (0)\n006 0 | 0\n007 0 | 0\n008 1 2dd4 | 1 2dd4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","private_key":"ee9db292a301dd892d1aedca4ef8a90d737b64e572c05b6cca13f334c41ba6dd","name":"node_2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","services":["streamer"],"enable_msg_events":true,"port":45347},"up":true}},{"node":{"info":{"id":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","name":"node_ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","enode":"enode://82b34fd84b01efb9af41bd124c2681e968807afaca2443d11d60658225bdd803500d87c13fa9c5211d1653afd9bf44755a722f01f91e518459780203fad0cd43@127.0.0.1:0","enr":"0xf88fb840f0a7a792a4415787d483eb211eff11116792290e2670e5a0bd87f67c81f5dc54301614339b1960d225318d4f7745e6af895493e42d6c270f429fd4def2e241560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10382b34fd84b01efb9af41bd124c2681e968807afaca2443d11d60658225bdd803","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7isK/2GphG0T3jpycS7wvzykKtjaV+gXWcJCeXJY7+w=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ee2b0a\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 6975 68a6 62f0 672a | 68 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n001 10 bc29 be0f b9d9 b869 | 29 a192 (0) aedc (0) acf8 (0) aba7 (0)\n002 3 d125 d9d3 cc9f | 14 d23c (0) d18a (0) d125 (0) deec (0)\n003 6 f33c f3d5 f611 f4a0 | 9 f3d5 (0) f33c (0) f177 (0) f005 (0)\n004 1 e06f | 1 e06f (0)\n005 2 ea3d eb01 | 2 ea3d (0) eb01 (0)\n============ DEPTH: 6 ==========================================\n006 3 eceb ed12 ed2e | 3 ed12 (0) ed2e (0) eceb (0)\n007 1 efd6 | 1 efd6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","private_key":"51ff90bcd8f1d150186f82b07c3bf74723a2111416020b1205876876d1456e91","name":"node_ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","services":["streamer"],"enable_msg_events":true,"port":34721},"up":true}},{"node":{"info":{"id":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","name":"node_8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","enode":"enode://638906e18d86b361cea53902fae144fb0a7bbe1c7f674a34e10247c074d176f58a797837069d5a21666ffb9476348fb394b80ecc0b1023d2111a85eb5c1952fb@127.0.0.1:0","enr":"0xf88fb84024f9e170931c28fb70978c7ce403865edd91dde7ffbb04e68f03512bf8ed726d5db895185177805ad4e5c9c73717ea1e97430505269dd32916cc5949aa72e7410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103638906e18d86b361cea53902fae144fb0a7bbe1c7f674a34e10247c074d176f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gBKnr3HXbYgiAs+TclI0eMzr6iNEMAbH8pwqgxBs0bM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8012a7\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 2471 0a21 4775 | 68 21dc (0) 216e (0) 221c (0) 22bb (0)\n001 14 dd92 d23c d125 c2f9 | 31 d23c (0) d18a (0) d125 (0) deec (0)\n002 12 acf8 a861 a9fa a192 | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 3 8b35 8d3e 8fb8 | 3 8b35 (0) 8d3e (0) 8fb8 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 8284 836e 8330 | 3 8284 (0) 836e (0) 8330 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","private_key":"9a9f5d8e07fc393a86b48129afcd4aa66dda3b5ff3498c7239e89572c4f218a1","name":"node_8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","services":["streamer"],"enable_msg_events":true,"port":33055},"up":true}},{"node":{"info":{"id":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","name":"node_47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","enode":"enode://ea98a4cc6d36e0a9e09061c40743fd14032109b1a0d8d20d2e20b419275c526f99c5c19b6123a6e78d21c5497e16fb49ca279795954f2ceac05ea01c772c83a4@127.0.0.1:0","enr":"0xf88fb8403249a6dba1fd864f716568258f1c1c1044871b1ab897dfccb42a89c5ad14ee743a196a92533717f40d4e17de9d9a9cd2cd14cc87855f4c270ac5407a6c8e0e530183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ea98a4cc6d36e0a9e09061c40743fd14032109b1a0d8d20d2e20b419275c526f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R3U/3KhV6nmr9me1CqnJChMtRL3RVyw+PEEcjufltfQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 47753f\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 fac8 f4a0 ea3d efd6 | 60 d23c (0) d18a (0) d125 (0) deec (0)\n001 9 27b5 2471 2354 2d53 | 30 3b83 (0) 3871 (0) 3e19 (0) 3590 (0)\n002 4 672a 62f0 72a5 75e2 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 3 5c62 5a8b 5008 | 9 58a9 (0) 5be6 (0) 5a8b (0) 5cc1 (0)\n004 5 4a37 4bc8 4d75 4c21 | 7 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 459b 4589 | 2 459b (0) 4589 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 4746 | 1 4746 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","private_key":"3f946790db720a1aff2dcaef0a931c26359587ade7dbbd5611d6e4e4c48b45a7","name":"node_47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","services":["streamer"],"enable_msg_events":true,"port":39017},"up":true}},{"node":{"info":{"id":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","name":"node_efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","enode":"enode://36e15237c01d8907bd512448e053510123d7742258fc18294dd99bc2dd171d87f1f14fd30584dff7196d37ab49ee7eb689238aeb159e0162efb3c35ba47d4723@127.0.0.1:0","enr":"0xf88fb84010215926d38f4b9af18d9d9e2831fd468800ada49bcdf6dcf9254373c72e00187ee5495c9979f3684cd5ee9750204e55dd9154ae90f78e9775578a2a221c8fd20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10336e15237c01d8907bd512448e053510123d7742258fc18294dd99bc2dd171d87","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"79aNLJk0bKCFye+Ja+5hJa2GOEEylRCPOpKyR6Qcpik=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: efd68d\npopulation: 22 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 127c 4775 | 68 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n001 2 8012 8330 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 5 c9ef cabf d23c d9d3 | 14 d18a (0) d125 (0) d23c (0) deec (0)\n003 6 f3d5 f4a0 f611 fac8 | 9 f177 (0) f005 (0) f33c (0) f3d5 (0)\n004 1 e06f | 1 e06f (0)\n005 2 ea3d eb01 | 2 ea3d (0) eb01 (0)\n============ DEPTH: 6 ==========================================\n006 3 eceb ed12 ed2e | 3 eceb (0) ed12 (0) ed2e (0)\n007 1 ee2b | 1 ee2b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","private_key":"245b148ec129e7a6491d45cc5c65217870ae2de275e5b688021b636011178055","name":"node_efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","services":["streamer"],"enable_msg_events":true,"port":34239},"up":true}},{"node":{"info":{"id":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","name":"node_127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","enode":"enode://7db629e8af234327ae65a632ab973188f8d44b4dc9336cc42246df45a87caa6a64c3a3b41a68f623e284a4bf0462a85ab81b0a51c28dedf1cb3357451a56d5c6@127.0.0.1:0","enr":"0xf88fb840acbb379c02f6b49e0fcc45220b6ed91e7e13bfc2beaf4a0ef7644b445216a379260871c4d3b022edab98a8cd70bbc4ca98623ea4c3b365840e157dd64c2147470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027db629e8af234327ae65a632ab973188f8d44b4dc9336cc42246df45a87caa6a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EnyJ6ulLGV3y6163tE9jSttzwRTSCJzZBLVpiMhnThE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 127c89\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b355 8d3e 836e 8330 | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 5 4d75 4746 5008 7bcb | 38 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n002 6 36d5 3e19 2d53 2471 | 17 3e19 (0) 3871 (0) 3b83 (0) 3590 (0)\n003 6 01a6 03eb 0a21 0807 | 8 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n004 2 1929 184e | 2 1929 (0) 184e (0)\n============ DEPTH: 5 ==========================================\n005 1 1740 | 1 1740 (0)\n006 0 | 0\n007 1 1385 | 1 1385 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","private_key":"54a20d22b4654e13d2547690e34e3de3cae15187e8034f587fe718896fa946f7","name":"node_127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","services":["streamer"],"enable_msg_events":true,"port":45857},"up":true}},{"node":{"info":{"id":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","name":"node_69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","enode":"enode://08a249844dec3d48a57ec53c79310b2f24cc27fedf91464cc30bd2213ec844437a00e3cc7d5e2f97b99516b21901ffe2e2a451340f594023bfac4463750c1ccf@127.0.0.1:0","enr":"0xf88fb84026ec31c1451ae3cc1ab533f52d87c62368080c439aff174f1f0a67fe50b956cc31c5260e382dcee5546e815dfa2dc26802922227f77d4bb25e5b47975222653a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10308a249844dec3d48a57ec53c79310b2f24cc27fedf91464cc30bd2213ec84443","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aXU4ZarKr3LZv20mXIhdP3BYBP9LJnX3qoYGQdrKsqA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 697538\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ee2b cc9f 836e bd96 | 60 f177 (0) f005 (0) f3d5 (0) f33c (0)\n001 6 2d53 03eb 0e34 0807 | 30 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n002 5 5a8b 52b4 5008 4bc8 | 20 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n003 3 72a5 77ee 75e2 | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 6 6379 62f0 672a 641a | 6 672a (0) 641a (0) 6450 (0) 64e6 (0)\n============ DEPTH: 5 ==========================================\n005 1 6daa | 1 6daa (0)\n006 0 | 0\n007 1 68a6 | 1 68a6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","private_key":"ce7b2f3ec596e7541804d73b0233cf93b061d33437fded3aae42df7d2fed2431","name":"node_69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","services":["streamer"],"enable_msg_events":true,"port":42103},"up":true}},{"node":{"info":{"id":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","name":"node_bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","enode":"enode://6ff77126c9946af5efe7c6850f8e59fa25bf6b808b00fade65d30e736f8eae7cc9fa35eb0f4382f95e5408b1cb030919d4f43e911ad1019ea5908d31ace54fb0@127.0.0.1:0","enr":"0xf88fb84047976194f9b1bbc1d405c1f0db707474b3b32a9a96750e1efcc39c5af51fa41213297557f076cbdd35bde4e8f909eeafe16d9694c5ce304ebcec675c7b7e11ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ff77126c9946af5efe7c6850f8e59fa25bf6b808b00fade65d30e736f8eae7c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vZYH1fV/e2909K2YG+NomI70i18x4/2WyrO7eQ1WgVA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bd9607\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4589 6975 | 68 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n001 5 cabf f611 f33c f005 | 31 f177 (0) f005 (0) f3d5 (0) f33c (0)\n002 4 8d3e 8012 836e 8330 | 9 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n003 4 a192 a9fa a861 acf8 | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 5 b4e2 b5fc b60e b355 | 5 b60e (0) b5fc (0) b4e2 (0) b355 (0)\n005 2 b9d9 b869 | 2 b869 (0) b9d9 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc29 bc71 | 2 bc29 (0) bc71 (0)\n008 1 bd48 | 1 bd48 (0)\n============ DEPTH: 9 ==========================================\n009 2 bddb bde9 | 2 bddb (0) bde9 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","private_key":"cbe3758f2717e1a3a9e53818d435eee8edc340e4e3d507cee9efdab8eddab838","name":"node_bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","services":["streamer"],"enable_msg_events":true,"port":40601},"up":true}},{"node":{"info":{"id":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","name":"node_45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","enode":"enode://99d33a9f9eebfa22c429478e4a0a01fa06d35e27b162331e8e4464a87d2adf5ec35e26697560f760cc58c5afd36ced8e1be393168089020b5881a44264fe609d@127.0.0.1:0","enr":"0xf88fb840b358458a817fa640619f1d3a7f3aaa81f7de7b7830255d88d70eb1aaf9b3c921433aea9123e9756df8724646634423960203427b8ff8e7f8929a6a501a51c6740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10399d33a9f9eebfa22c429478e4a0a01fa06d35e27b162331e8e4464a87d2adf5e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RYla/2dAefa+AuTMdJFNYxJcP+SLtpBWwHDHExn+ofo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 45895a\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 ed2e eceb ea3d e06f | 60 f3d5 (0) f33c (0) f177 (0) f005 (0)\n001 9 2dd4 2803 36d5 3e19 | 30 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n002 4 75e2 72a5 672a 6975 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 55fd 5008 5c62 5a8b | 9 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n004 4 4d75 4efa 4bc8 4a3c | 7 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 4775 4746 | 2 4746 (0) 4775 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 459b | 1 459b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","private_key":"4be326b4bad9ec6d897672d72f86d7c21742af31459c61ff9d29a7c4f2b87288","name":"node_45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","services":["streamer"],"enable_msg_events":true,"port":35991},"up":true}},{"node":{"info":{"id":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","name":"node_0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","enode":"enode://55140e8f1873f8006a1e1a309e31669c0442eb381ea30f7e4261c7979760b5b10030ca2c72d35492c2c3d456c560f898249944dfbd3d408c456b3ded66c13e5d@127.0.0.1:0","enr":"0xf88fb840a3583d99fad5b4703c5847493453e0b451c4d555d6ee5a8833671be976378a823cf88dd213ebdd319ff433e569d46dd3d19c6e06e909f79ce6d847f6145a430b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10355140e8f1873f8006a1e1a309e31669c0442eb381ea30f7e4261c7979760b5b1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CiFcd2W+LK6/dq0+gBe7wqqt+ODdSFmveBlToFZMXVk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0a215c\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d23c fa9a e06f 8d3e | 60 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n001 7 672a 64e6 75e2 72a7 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 7 3e19 3871 36d5 2d53 | 17 3871 (0) 3b83 (0) 3e19 (0) 3590 (0)\n003 5 1385 127c 1740 1929 | 5 1929 (0) 184e (0) 1740 (0) 1385 (0)\n004 4 0639 01a6 034d 03eb | 4 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n============ DEPTH: 5 ==========================================\n005 2 0f31 0e34 | 2 0f31 (0) 0e34 (0)\n006 1 0807 | 1 0807 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","private_key":"48398a9192cbe71d3dae01f8cd736bd6fa81f40d86363732910ab557934ac32a","name":"node_0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","services":["streamer"],"enable_msg_events":true,"port":32803},"up":true}},{"node":{"info":{"id":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","name":"node_0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","enode":"enode://a657bea94ef83334a2eb69fa819e389faa047abb53fdce1ada5de9f2ad8577331fc88094fd258ff4dfb4ecc38e37cc65b0807dc8c13d0f933d0975b4930a152a@127.0.0.1:0","enr":"0xf88fb840e7a038b940736e411d390aa7ac6e0d5380fb096ac5b06fb69e561038d33eece64602defd9da5012d991e93b78ce269e66ae7083c78fa635400a7941b55511bd50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a657bea94ef83334a2eb69fa819e389faa047abb53fdce1ada5de9f2ad857733","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DjRMbifCO9Nr3T3c76Tld/3JRh5Sx84gE1czoIuYe4I=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e344c\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 d23c e06f b355 8330 | 60 f3d5 (0) f33c (0) f177 (0) f005 (0)\n001 4 7bcb 6975 4746 4775 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 6 36d5 3e19 2d53 2471 | 17 3590 (0) 3775 (0) 36d5 (0) 3b83 (0)\n003 4 1929 184e 1740 127c | 5 1929 (0) 184e (0) 1740 (0) 1385 (0)\n004 3 034d 03eb 01a6 | 4 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n============ DEPTH: 5 ==========================================\n005 2 0807 0a21 | 2 0807 (0) 0a21 (0)\n006 0 | 0\n007 1 0f31 | 1 0f31 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","private_key":"bd217ea07881a97e7c8d265ab1ea058cd33f23e29d61169327cafa40e7eb7e35","name":"node_0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","services":["streamer"],"enable_msg_events":true,"port":32907},"up":true}},{"node":{"info":{"id":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","name":"node_836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","enode":"enode://7955513f0867be5484a68700771fab5ed2bcaff4c5fe81e88b07b95e273742fe920d733d44b7b187d1d5ddca6eccb92921a69f1a5f1874d9eee4d61f4e849f3d@127.0.0.1:0","enr":"0xf88fb840e3fdd157b8d17ad9462935700437f5e3379cc6b910e447979420623db2209a132159463905a57dace86b0516654cfb2e39b3e9c5a376652fd559309c05dcf4410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037955513f0867be5484a68700771fab5ed2bcaff4c5fe81e88b07b95e273742fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g25l3+bwHh0pNGVcGEbLhv7W5B6pUaEJ16ILsUy0wQo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 836e65\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 4589 6975 68a6 62f0 | 68 7bcb (0) 7bee (0) 7a68 (0) 73d0 (0)\n001 8 fac8 fa9a fa65 f4a0 | 31 f177 (0) f005 (0) f3d5 (0) f33c (0)\n002 6 b9d9 bc71 bd96 b245 | 20 be0f (0) bc29 (0) bc71 (0) bd48 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 3 8b35 8fb8 8d3e | 3 8b35 (0) 8fb8 (0) 8d3e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 8012 | 1 8012 (0)\n007 1 8284 | 1 8284 (0)\n008 0 | 0\n009 1 8330 | 1 8330 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","private_key":"828792ee935c8a9739d8fffdccb73fdb38a998850e0a4e5f3a67fad91701cc2c","name":"node_836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","services":["streamer"],"enable_msg_events":true,"port":46599},"up":true}},{"node":{"info":{"id":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","name":"node_cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","enode":"enode://fcd2ab0c2237f9a09130eef63262c5dbe407ec25a8ff88d55dae0c65c7352a829f879f303aebfdc8d979b2843b7b61933608d4f89ebe778995455c135371ba78@127.0.0.1:0","enr":"0xf88fb840ebf4dbd2665552b22575e2991f43e3d416eff9488c23d9f3580a78a225117d891a35ec6b32c752922b70470cc162564533cd54db06d6b9cf023e19932ef864e10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fcd2ab0c2237f9a09130eef63262c5dbe407ec25a8ff88d55dae0c65c7352a82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zJ9l1zTxo7vGAZ4Wb+NVvX/DO7SIcEOlzPUyqbo1Y3k=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc9f65\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6975 62f0 0f31 01a6 | 68 7a68 (0) 7bcb (0) 7bee (0) 772a (0)\n001 2 acf8 836e | 29 b4e2 (0) b5fc (0) b60e (0) b355 (0)\n002 6 f33c fa65 eceb ed2e | 17 f177 (0) f005 (0) f3d5 (0) f33c (0)\n003 5 d125 d23c deec dd92 | 6 d23c (0) d18a (0) d125 (0) deec (0)\n004 3 c0ad c2f9 c52a | 3 c52a (0) c2f9 (0) c0ad (0)\n005 2 cabf c9ef | 2 c9ef (0) cabf (0)\n============ DEPTH: 6 ==========================================\n006 1 ce01 | 1 ce01 (0)\n007 0 | 0\n008 1 cc5f | 1 cc5f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","private_key":"4a1901aae6d17a696581fa1df5fb404606b4894884e5ce2ae52f014c1f7ab1ec","name":"node_cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","services":["streamer"],"enable_msg_events":true,"port":45379},"up":true}},{"node":{"info":{"id":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","name":"node_eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","enode":"enode://6570b12362a67ae69eb59bbb7ef187f002e9d8c189bc44e7a66d49e48442754fb3c332e796a34094a0c32ca763a56bf77272b15090ea404f1fde0f8f02f69d9a@127.0.0.1:0","enr":"0xf88fb840a0eb32cba24198285bd35892feb415dc76bca095952a0b36d8b453aadb7c61fc63195b1956ee0ca78f7e50df142ed78fea1741090dc0988605592bd8b167af1a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026570b12362a67ae69eb59bbb7ef187f002e9d8c189bc44e7a66d49e48442754f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6wH/gDB6+/x0V8lllM1LpNAKy3/SWnVx0SIxaL1m/wk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb01ff\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4a3c 7bee 72a7 72a5 | 68 7a68 (0) 7bcb (0) 7bee (0) 772a (0)\n001 3 8012 a861 bd96 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 4 c52a c0ad c9ef cc9f | 14 d18a (0) d125 (0) d23c (0) deec (0)\n003 7 f4a0 f611 f3d5 f33c | 9 f177 (0) f005 (0) f3d5 (0) f33c (0)\n004 1 e06f | 1 e06f (0)\n============ DEPTH: 5 ==========================================\n005 5 ed12 ed2e eceb efd6 | 5 efd6 (0) ee2b (0) ed12 (0) ed2e (0)\n006 0 | 0\n007 1 ea3d | 1 ea3d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","private_key":"e5be2c35a1499c508166c81de8a45fd1cda4bea223164bf47ba8c974725fdf75","name":"node_eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","services":["streamer"],"enable_msg_events":true,"port":33263},"up":true}},{"node":{"info":{"id":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","name":"node_08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","enode":"enode://7d4f4b1f1c3dc1f6418391214afa500757d43f64aea2f11d7694de79d243af3e1c1c1662233b71306cc1c060ddf7e21dbdbbac53d0bcfe2fd3b6f29c7656e69f@127.0.0.1:0","enr":"0xf88fb840da1dfdefbe43711df3887e5825a698e2931b2e4fda60051803d6402f11fe21a14ee3b5bac8cf9543cad98736a88ae0734609ac9b8ba3d04815d21c44e5c2551e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037d4f4b1f1c3dc1f6418391214afa500757d43f64aea2f11d7694de79d243af3e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CAd8DOjUEwwURkST6RZKi65htGRrHsSImedfL2+bjGY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08077c\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eb01 8d3e 8330 a861 | 60 c52a (0) c2f9 (0) c0ad (0) cabf (0)\n001 10 4589 4775 4746 7bcb | 38 7bee (0) 7bcb (0) 7a68 (0) 73d0 (0)\n002 5 3e19 3871 3b83 27b5 | 17 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n003 4 1740 1385 127c 184e | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0639 01a6 034d 03eb | 4 0639 (0) 01a6 (0) 034d (0) 03eb (0)\n============ DEPTH: 5 ==========================================\n005 2 0f31 0e34 | 2 0e34 (0) 0f31 (0)\n006 1 0a21 | 1 0a21 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","private_key":"97f4ac0685f5a566c69307b57852116db766c3319995e5a30c98d0b770d9ebf8","name":"node_08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","services":["streamer"],"enable_msg_events":true,"port":34207},"up":true}},{"node":{"info":{"id":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","name":"node_a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","enode":"enode://288eb859b2b3db8e349860a6324c65887218b6162fb33a09fc8b18ae24bfc20a7f490f036a7c5b889d68f8eb9efe590b77d3983019b8f8ef4d3cfa76dafc655e@127.0.0.1:0","enr":"0xf88fb8404a25f16978fe1fb9671930db81e544e0cff37050b6c6325193d7feccf29e22c45e8bef40ecda5b29e9cea5d10e7e70ee0a8a02744a915a78858248804e87186e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102288eb859b2b3db8e349860a6324c65887218b6162fb33a09fc8b18ae24bfc20a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qGEXFHt48gptiD03cV2oUXjK2J7/ZQp0qonnvBG8Rac=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a86117\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 73d0 68a6 5008 2471 | 68 7bee (0) 7bcb (0) 7a68 (0) 73d0 (0)\n001 8 dd92 c2f9 f3d5 f611 | 31 f611 (0) f4a0 (0) f177 (0) f005 (0)\n002 4 8d3e 8012 8330 836e | 9 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n003 9 b9d9 b869 bd48 bde9 | 14 b355 (0) b245 (0) b5fc (0) b4e2 (0)\n004 1 a192 | 1 a192 (0)\n005 2 aedc acf8 | 2 aedc (0) acf8 (0)\n============ DEPTH: 6 ==========================================\n006 1 aba7 | 1 aba7 (0)\n007 1 a9fa | 1 a9fa (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","private_key":"e91c4e7ef86a9d2c9e2d4949d79f0188a6fe4c317a21ff93d7517b08b03a84ad","name":"node_a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","services":["streamer"],"enable_msg_events":true,"port":42373},"up":true}},{"node":{"info":{"id":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","name":"node_5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","enode":"enode://4352662356e5f6fed37ae1e0853e8f9d1d52e8c8291718bd69f73ff06f3a3904f070a2ee34d6b3c4ce86429317a48c1aae1ee3a95565f2164240c1289d49d409@127.0.0.1:0","enr":"0xf88fb84075269349b759660c79167f80db6ab17f351f923baab541b3fc9a2b78dd6577a7610b64e2d804fe4670d11df5a743a6d4e2c73b726a72c4539f380470c2795c300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034352662356e5f6fed37ae1e0853e8f9d1d52e8c8291718bd69f73ff06f3a3904","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UAjvVa2AiPcGQ7D5O8tHlTG8sK/o4BshXb+Fl+yGY2k=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5008ef\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ea3d f4a0 d9d3 b245 | 60 f611 (0) f4a0 (0) f177 (0) f005 (0)\n001 5 1740 127c 03eb 01a6 | 30 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n002 3 75e2 62f0 6975 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 4a3c 459b 4589 4775 | 11 4efa (0) 4c21 (0) 4cc2 (0) 4d75 (0)\n004 4 5c62 5cc1 58a9 5a8b | 5 5cc1 (0) 5c62 (0) 58a9 (0) 5be6 (0)\n005 1 55fd | 1 55fd (0)\n============ DEPTH: 6 ==========================================\n006 1 52b4 | 1 52b4 (0)\n007 1 51c2 | 1 51c2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","private_key":"40ffe414c67c7872869542bbaf010af4e063dbc9e734ec01ebc6ffe7f09a289b","name":"node_5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","services":["streamer"],"enable_msg_events":true,"port":42611},"up":true}},{"node":{"info":{"id":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","name":"node_d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","enode":"enode://10520254bae35bd2c92f66f483de02b78d1753df0d2969aa22382c5dfb51a967e47e6189437e2326a96b6f902faa6ae5cf59af59f3b0cd4021dc6ecb0dbe0ed7@127.0.0.1:0","enr":"0xf88fb8406d769c006c5ed31a452a2a90135f9d37fea25bd1eff0888fcf8d995e9994b13437c02d2f21b826af8f36fff78e9f23b13e1af4851c0df81af662729cd81cccb40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10310520254bae35bd2c92f66f483de02b78d1753df0d2969aa22382c5dfb51a967","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2dMLmyEr1IEaROvjBLo5NerTq+Mkf5mJP69lZkExwp0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d9d30b\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0f31 01a6 03eb 5008 | 68 3775 (0) 36d5 (0) 3590 (0) 3e19 (0)\n001 2 acf8 b9d9 | 29 957e (0) 9472 (0) 8b35 (0) 8fb8 (0)\n002 6 ea3d eceb efd6 ee2b | 17 f611 (0) f4a0 (0) f177 (0) f005 (0)\n003 6 c9ef cc5f cc9f c52a | 8 c52a (0) c0ad (0) c2f9 (0) cabf (0)\n004 3 d125 d18a d23c | 3 d125 (0) d18a (0) d23c (0)\n============ DEPTH: 5 ==========================================\n005 2 dd92 deec | 2 dd92 (0) deec (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","private_key":"70b8e572ba811ae79bbcaffd1421381dc00b020737f2e6f4c1311ebe984fa426","name":"node_d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","services":["streamer"],"enable_msg_events":true,"port":36959},"up":true}},{"node":{"info":{"id":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","name":"node_03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","enode":"enode://118cbd671c6e8b583a18aa14af1eeddb499047376ff5e84c160f3eec13f5b5d33f390b65cf2428621ced70ec419935c37ef4236a8f63f7b5cf81f58a0dfb59f3@127.0.0.1:0","enr":"0xf88fb840c91599a2365e987a7355bef1ad535065e3c907887c577bfbf22416ec8c60a63e28c13dfc44d51262f3a3514757c2ff8c315eb57f44ce1c58397816c8e8bd2fea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103118cbd671c6e8b583a18aa14af1eeddb499047376ff5e84c160f3eec13f5b5d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A+suku0JI/aWJp56A/7HMdjD+N8ngCOpywCGe1M6PKM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 03eb2e\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fa9a c9ef c2f9 d9d3 | 60 957e (0) 9472 (0) 8b35 (0) 8fb8 (0)\n001 11 62f0 6975 68a6 72a7 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 4 2dd4 2d53 22bb 2354 | 17 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n003 3 184e 1740 127c | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0e34 0f31 0807 0a21 | 4 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n005 1 0639 | 1 0639 (0)\n============ DEPTH: 6 ==========================================\n006 1 01a6 | 1 01a6 (0)\n007 0 | 0\n008 1 034d | 1 034d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","private_key":"bb068a5ae255ce7c42cb5928785a16dd2b717db214b975dc7af82a56d1465fa4","name":"node_03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","services":["streamer"],"enable_msg_events":true,"port":41317},"up":true}},{"node":{"info":{"id":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","name":"node_5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","enode":"enode://1e7d80f4aab757649946e09a942ec9dc561f7fab556def6e20e6449f154eddd1d6acc7d2e24db2f0951152d4ccd3eaa9ad32b54b1dedc60eb4c15078f2281cc6@127.0.0.1:0","enr":"0xf88fb8404b1fe1c4ca1bb536ead1b7c7fa4e49b2514aaa26ad2076329d9316b78adc03db18a0e3c270a9cfd2e61e06f850436d2bd103ae39b7c61106619bef3f3fdfb8a90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021e7d80f4aab757649946e09a942ec9dc561f7fab556def6e20e6449f154eddd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WoukBHxEVuglvRs0yWH1x/N798J7xIvucbhDDH0TVIY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a8ba4\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c9ef c2f9 | 60 d23c (0) d18a (0) d125 (0) deec (0)\n001 3 1740 03eb 2354 | 30 1929 (0) 184e (0) 1385 (0) 127c (0)\n002 7 62f0 6975 68a6 73d0 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 4 4bc8 4a3c 4775 4589 | 11 4efa (0) 4c21 (0) 4cc2 (0) 4d75 (0)\n004 3 55fd 52b4 5008 | 4 55fd (0) 52b4 (0) 51c2 (0) 5008 (0)\n005 2 5cc1 5c62 | 2 5cc1 (0) 5c62 (0)\n============ DEPTH: 6 ==========================================\n006 1 58a9 | 1 58a9 (0)\n007 1 5be6 | 1 5be6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","private_key":"dbec70bb9a08cabd1e7f19877731d486591fa448c65d8e48175658b5a46d7708","name":"node_5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","services":["streamer"],"enable_msg_events":true,"port":35767},"up":true}},{"node":{"info":{"id":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","name":"node_2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","enode":"enode://5f6d6715804fb0fa79d11569c038c51fdb2c154b06f8403d57d7362c87b361147a3bbf7d990c650a857a7aed53df21bc7a6d08540b1d0894db1cd83e1e69d0bd@127.0.0.1:0","enr":"0xf88fb8400295eb2dd56032a5f0ef15321413956120d8ea0924e56ebba770b064f823e42c015ddb67c6964e293c937f596999883d7a6d3c8b1fd7364e6afe36b4c0ca679f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035f6d6715804fb0fa79d11569c038c51fdb2c154b06f8403d57d7362c87b36114","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"I1TTr1xtygXX3CErEAES83qyn7iz9DGYhyMKTUIPXZ0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2354d3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c9ef cc9f | 60 d23c (0) d18a (0) d125 (0) deec (0)\n001 5 64e6 4d75 4775 5008 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 7 0e34 0807 01a6 03eb | 13 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n003 4 36d5 3e19 3871 3b83 | 6 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n004 3 2803 2dd4 2d53 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 27b5 27db 2471 | 3 27db (0) 27b5 (0) 2471 (0)\n006 2 21dc 216e | 2 21dc (0) 216e (0)\n============ DEPTH: 7 ==========================================\n007 2 221c 22bb | 2 221c (0) 22bb (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","private_key":"33f99c8fc27af3dfbab6afb6eca5cf61ff93788a211883b10a12d2696ebc18a5","name":"node_2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","services":["streamer"],"enable_msg_events":true,"port":37965},"up":true}},{"node":{"info":{"id":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","name":"node_17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","enode":"enode://0163c2caaad749b2a1877dee27794e363304a8dfa3af56d253c7021217545cd1f31f24a821594b340e18ef78a6498656b65c7a12ba99a7e1a2ef34ef9da4c04d@127.0.0.1:0","enr":"0xf88fb840737226882bb1d943eb2e9cd4dfcfa63deca2a52dc312ea55f2cb29cf6f44704976ad5889976d9d00a3e0b745a7870999b20eb3a8f915f0c0b797c878cbe77fdf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030163c2caaad749b2a1877dee27794e363304a8dfa3af56d253c7021217545cd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F0Bt6lBG8A4n6vdOFmqUXJSFE51u3N/NhPWwP1Du3Qo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 17406d\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 be0f 8d3e fa9a c2f9 | 60 d23c (0) d125 (0) d18a (0) dd92 (0)\n001 6 6975 73d0 77ee 5a8b | 38 4a37 (0) 4a3c (0) 4bc8 (0) 4efa (0)\n002 7 3e19 3b83 3871 2dd4 | 17 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n003 7 0a21 0807 0e34 0f31 | 8 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n004 2 1929 184e | 2 184e (0) 1929 (0)\n============ DEPTH: 5 ==========================================\n005 2 1385 127c | 2 1385 (0) 127c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","private_key":"96f0245c4b78bbf5a569ca11e55db6399d83ce08e6ec692e63acaebac837a9ea","name":"node_17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","services":["streamer"],"enable_msg_events":true,"port":33857},"up":true}},{"node":{"info":{"id":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","name":"node_01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","enode":"enode://946ba7faf16b78557ada55aa61d2ce4df1f255db899d3719d93c2005e88fd20aba59f9cdb4bc62d86b4b405a24bd310a8af3f1e4baf9cf5dbd548cf4e8d35557@127.0.0.1:0","enr":"0xf88fb8403960e3e45dce252d35faa9910dff31d41ef445f18ea2ff3d8fdeffb2716ef6fe40bdf310ee963cc581fc397dcd35c02571b7ff73bad2e0f63fde62678c392aa50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103946ba7faf16b78557ada55aa61d2ce4df1f255db899d3719d93c2005e88fd20a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AaY1dcOE9oblc54b0HnkpMVUIc1tiblE4sYd0XT6K/Y=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 01a635\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 fa9a c9ef cc9f cc5f | 60 d18a (0) d125 (0) d23c (0) dd92 (0)\n001 4 6450 4d75 5008 55fd | 38 4a37 (0) 4a3c (0) 4bc8 (0) 4efa (0)\n002 7 2dd4 22bb 2354 216e | 17 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n003 4 184e 1385 127c 1740 | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0a21 0807 0f31 0e34 | 4 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n005 1 0639 | 1 0639 (0)\n============ DEPTH: 6 ==========================================\n006 2 034d 03eb | 2 034d (0) 03eb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","private_key":"cc2f52f2da8baa58e999a96ec31dc946b081f0fc546742bfe885a4d65048f0ba","name":"node_01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","services":["streamer"],"enable_msg_events":true,"port":32789},"up":true}},{"node":{"info":{"id":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","name":"node_acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","enode":"enode://2051ad3d9ecac3a9242bc33d92f20eb0265d19c75f91c5541715e4125dbc793b8cbbfaae8f549e0526d334b28142f61dd82fef168e2078e10046d42de98a8d84@127.0.0.1:0","enr":"0xf88fb840633de8fb5d405d72f5575e854e513bca5fa24ec6fb1e75838c27118b118fc3334af4ce9f07c4717bcd139c61925a6ad329754aad8fc5a3a441bbbe120d6386270183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022051ad3d9ecac3a9242bc33d92f20eb0265d19c75f91c5541715e4125dbc793b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rPiI7XgfU1hJPi5QSGkazDnqwyQMqekJO7QFKx9iQyU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: acf888\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 73d0 68a6 2471 0f31 | 68 4a37 (0) 4a3c (0) 4bc8 (0) 4efa (0)\n001 6 ee2b f33c d9d3 c2f9 | 31 d23c (0) d125 (0) d18a (0) dd92 (0)\n002 4 8012 8330 836e 8d3e | 9 957e (0) 9472 (0) 8284 (0) 8330 (0)\n003 7 b869 b9d9 bd48 bd96 | 14 b355 (0) b245 (0) b60e (0) b4e2 (0)\n004 1 a192 | 1 a192 (0)\n============ DEPTH: 5 ==========================================\n005 3 aba7 a9fa a861 | 3 aba7 (0) a9fa (0) a861 (0)\n006 1 aedc | 1 aedc (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","private_key":"e3da942e1ebba4519becee21a2285ae952467d7639501faab88c017ed66d238e","name":"node_acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","services":["streamer"],"enable_msg_events":true,"port":35297},"up":true}},{"node":{"info":{"id":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","name":"node_0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","enode":"enode://5c476e3ae360f530756888a27af18afcec729c3d9485832d85b55f4910e22be32fe20aff65f08973bdb22a46239654a0b9ff97c4d3dbef485d21d6fbf2d21a25@127.0.0.1:0","enr":"0xf88fb8402d28c83dbd79c5e95b11079daad1069cecc4337f35abae0ff0a87d06300a14aa33ea3dde14e4082892622446978b18063fe5621c543b4392139e8066ebf634b50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035c476e3ae360f530756888a27af18afcec729c3d9485832d85b55f4910e22be3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DzEGrf5wrvtHTEqYqVkyMHOR3iy3D70uEd0xyeaV7YM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0f3106\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 cc9f cc5f d23c d9d3 | 60 d23c (0) d125 (0) d18a (0) dd92 (0)\n001 5 459b 7bcb 6daa 6450 | 38 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n002 5 3b83 3871 2dd4 221c | 17 36d5 (0) 3775 (0) 3590 (0) 3e19 (0)\n003 3 1385 127c 1740 | 5 1929 (0) 184e (0) 1385 (0) 127c (0)\n004 4 0639 01a6 034d 03eb | 4 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n============ DEPTH: 5 ==========================================\n005 2 0807 0a21 | 2 0a21 (0) 0807 (0)\n006 0 | 0\n007 1 0e34 | 1 0e34 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","private_key":"6241837c865bfdb4b5200d2c76fbd45a87b9de82bb790d1ac679ceb517449a82","name":"node_0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","services":["streamer"],"enable_msg_events":true,"port":37821},"up":true}},{"node":{"info":{"id":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","name":"node_62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","enode":"enode://6a42ebbfda57a4727b4f686c785b5030992d3a2ecba2aa780527153ed432dc4a779c1a0c496e6503ec67f7063c21eaf924c996c37a2eb1dd29b86afddc735518@127.0.0.1:0","enr":"0xf88fb840844c5f5293365e47b6ea31282d2a2bcab345eb98290e20d878c868cf51faef74771a2271eef6d5e86d681144a1b449acbea967e03cc390b2d2472e714054391a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a42ebbfda57a4727b4f686c785b5030992d3a2ecba2aa780527153ed432dc4a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YvAHySqK9GbpDtCx5ecalVrSc+x5OUjd/AOXfxMe0tE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 62f007\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ee2b c0ad cc9f 836e | 60 d23c (0) d18a (0) d125 (0) dd92 (0)\n001 8 2471 2dd4 3e19 3b83 | 30 3590 (0) 3775 (0) 36d5 (0) 3e19 (0)\n002 4 4775 5a8b 55fd 5008 | 20 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n003 5 75e2 77ee 72a7 72a5 | 9 7a68 (0) 7bee (0) 7bcb (0) 72a5 (0)\n004 3 6daa 68a6 6975 | 3 6daa (0) 6975 (0) 68a6 (0)\n============ DEPTH: 5 ==========================================\n005 4 6450 641a 64e6 672a | 4 672a (0) 64e6 (0) 6450 (0) 641a (0)\n006 0 | 0\n007 1 6379 | 1 6379 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","private_key":"ebf64acc962af28b6b8ed56078a7ae4726b851e322cebb1c852e24267f1c4a1d","name":"node_62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","services":["streamer"],"enable_msg_events":true,"port":43977},"up":true}},{"node":{"info":{"id":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","name":"node_b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","enode":"enode://d97b0fcc83cc71942a961140d70fbed0f9819f50795a64dce5d018ea28bcc04486d39682cb07a8f2084f401a987298d2a5385a1068133929a838255afd71df1b@127.0.0.1:0","enr":"0xf88fb84000536ff0e44a6e9ea1b978d39a2b2b4c28b4c30d63cc253d1996f9c000c0cee949b1904a5eee67b25704fbb2ba12b15f995cc6b9ac5717d610cc101ed5e3e75a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d97b0fcc83cc71942a961140d70fbed0f9819f50795a64dce5d018ea28bcc044","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"udkG5Aaw/GB4wiu8FzBD3x91gQYbT2zNdpvFaNlLQzk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b9d906\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 22bb 55fd 73d0 68a6 | 68 3775 (0) 36d5 (0) 3590 (0) 3e19 (0)\n001 4 c52a d9d3 ee2b eceb | 31 d23c (0) d125 (0) d18a (0) dd92 (0)\n002 4 8012 8330 836e 8d3e | 9 957e (0) 9472 (0) 8012 (0) 8284 (0)\n003 5 a861 a9fa aba7 acf8 | 6 a192 (0) aba7 (0) a9fa (0) a861 (0)\n004 5 b355 b245 b4e2 b5fc | 5 b355 (0) b245 (0) b4e2 (0) b5fc (0)\n============ DEPTH: 5 ==========================================\n005 7 be0f bd48 bddb bde9 | 7 be0f (0) bc29 (0) bc71 (0) bd48 (0)\n006 0 | 0\n007 1 b869 | 1 b869 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","private_key":"908ebb48b37c8f9239e22db00fb7161ba4a14b3f5857a1142bcaf9d46586ad23","name":"node_b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","services":["streamer"],"enable_msg_events":true,"port":34371},"up":true}},{"node":{"info":{"id":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","name":"node_eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","enode":"enode://3419c9288c2eff070d8db3ecdf0c5675a6978ff0ca5e459886f451fb7c6a1c79f40f74557de8e513ea6e3db67a52a99933260c4838d0c88e1329e8c23f8e367b@127.0.0.1:0","enr":"0xf88fb840d19d680dca990e3894d8e63f0c7e053bb4beccc2b28b26e2156c3de7cfd0293637e634f6f398e2c52a3767d0f82b356f5387e7cbd65eb778d17d253d500eb9f00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033419c9288c2eff070d8db3ecdf0c5675a6978ff0ca5e459886f451fb7c6a1c79","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7Ot9xTJZbotoB0ET25YF49FcsV4ugPdfGmbZWhIhx9w=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eceb7d\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 772a 4589 58a9 216e | 68 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n001 7 8d3e 8012 836e aba7 | 29 9472 (0) 957e (0) 8284 (0) 8330 (0)\n002 7 deec d9d3 cc9f cc5f | 14 d23c (0) d18a (0) d125 (0) dd92 (0)\n003 6 f33c f177 f005 fa9a | 9 f4a0 (0) f611 (0) f177 (0) f005 (0)\n004 1 e06f | 1 e06f (0)\n005 2 ea3d eb01 | 2 ea3d (0) eb01 (0)\n006 2 efd6 ee2b | 2 efd6 (0) ee2b (0)\n============ DEPTH: 7 ==========================================\n007 2 ed2e ed12 | 2 ed2e (0) ed12 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","private_key":"ebb9302277d87e1d7ead59e5bcd7f4c125c61b0d09ede9e8a3a87f788b8cb3ab","name":"node_eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","services":["streamer"],"enable_msg_events":true,"port":39661},"up":true}},{"node":{"info":{"id":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","name":"node_c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","enode":"enode://3e0ee81dad3d6e6b7e146766e689ca44b20c076cd0dac90a0b937c80ffe51e87a731bb789fe07f1e3781e5aa25ea70150eb3b053fe0b179e7f7d94fbc180ed2a@127.0.0.1:0","enr":"0xf88fb84019f7283cf95d09b72f63e06b3411e0b049c15d2b86dfd18369f70d4ee944372e5c12e658b704f83f4482400458b31a516d5604fa0469210d467fe77d8e64f7dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023e0ee81dad3d6e6b7e146766e689ca44b20c076cd0dac90a0b937c80ffe51e87","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wvm0q+2caoOf5MA6gL05b9GHqHhLpHqDaH06VLfi7d8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c2f9b4\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0639 03eb 1740 772a | 68 1929 (0) 184e (0) 127c (0) 1385 (0)\n001 6 acf8 aba7 a861 8330 | 29 957e (0) 9472 (0) 8284 (0) 836e (0)\n002 4 f33c f4a0 ea3d eceb | 17 f611 (0) f4a0 (0) f005 (0) f177 (0)\n003 4 d23c d9d3 dd92 deec | 6 d18a (0) d125 (0) d23c (0) dd92 (0)\n004 4 cc5f cc9f cabf c9ef | 5 ce01 (0) cc5f (0) cc9f (0) cabf (0)\n============ DEPTH: 5 ==========================================\n005 1 c52a | 1 c52a (0)\n006 1 c0ad | 1 c0ad (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","private_key":"f980e9ba4f79f9f79e3659e3ba6dd1900868076a78a0cb0390b5c13fdfc2e105","name":"node_c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","services":["streamer"],"enable_msg_events":true,"port":37679},"up":true}},{"node":{"info":{"id":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","name":"node_c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","enode":"enode://b88aef73e2d38fb6fd1c0be8112453bc96dac9df272e9366494bb266ab6591c01482a93613d919a26bf6a4f62920343fe26b4dd5b8f13c4642fccd588d1b6407@127.0.0.1:0","enr":"0xf88fb8403c2ce4e2ffb11a365ec4903ac72a546b354de5dceec18acb0ce931dfdf593c9364716fab2b08ab7d23681b95c4ea160944780a2fb5eda9a5186c40196ed6fd350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b88aef73e2d38fb6fd1c0be8112453bc96dac9df272e9366494bb266ab6591c0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ye9Wr+0tQNs5atOdb19fOPQFi2sNHgK3HWqpLb6vffc=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c9ef56\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 772a 72a7 4cc2 58a9 | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 2 b60e acf8 | 29 b869 (0) b9d9 (0) be0f (0) bc71 (0)\n002 5 eb01 efd6 eceb f33c | 17 e06f (0) ee2b (0) efd6 (0) ed2e (0)\n003 2 deec d9d3 | 6 d23c (0) d125 (0) d18a (0) dd92 (0)\n004 3 c52a c0ad c2f9 | 3 c52a (0) c0ad (0) c2f9 (0)\n============ DEPTH: 5 ==========================================\n005 3 ce01 cc9f cc5f | 3 ce01 (0) cc5f (0) cc9f (0)\n006 1 cabf | 1 cabf (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","private_key":"e39438d65893f9aa29c4f0b62c56230930d90dcaab3cbb07ea3c19d0cad5136e","name":"node_c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","services":["streamer"],"enable_msg_events":true,"port":36083},"up":true}},{"node":{"info":{"id":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","name":"node_fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","enode":"enode://d27fa62643cd7eea1b635af3b3ce578baf185fffc47830a4c13ec296f90c46d2663dc1789046b5a79d796c57546e1ef68a15dbc440d08cc6644a8fa0ae887549@127.0.0.1:0","enr":"0xf88fb840f341ded7be4fe1c85a832c0eebf0214215e6fa10536fb974fad93566458010b2239adb66b6817d8493b1ec12ac407bb97cb2b1fbf6c36bb8809e809809df05c10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d27fa62643cd7eea1b635af3b3ce578baf185fffc47830a4c13ec296f90c46d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+pqAnwFgl9lJ+hRjocjwiHHH045gt99tPiirBMzToUM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fa9a80\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 0a21 01a6 03eb 034d | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 5 836e be0f b60e aba7 | 29 be0f (0) bc71 (0) bc29 (0) bde9 (0)\n002 4 deec d9d3 c52a c9ef | 14 d23c (0) d125 (0) d18a (0) dd92 (0)\n003 5 eceb ed2e efd6 ea3d | 8 e06f (0) ee2b (0) efd6 (0) ed12 (0)\n004 4 f4a0 f611 f177 f33c | 6 f611 (0) f4a0 (0) f005 (0) f177 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 fa65 | 1 fa65 (0)\n009 1 fac8 | 1 fac8 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","private_key":"d7298e7ba76d8700d47fe74a50ac92478020ce786a9d1c343e118f94dd564864","name":"node_fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","services":["streamer"],"enable_msg_events":true,"port":41357},"up":true}},{"node":{"info":{"id":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","name":"node_55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","enode":"enode://3eae4ff354105cae615e8ed7499a263aab368017815886ccf3875219dfb6ae72174bc5241ef3c91c0c7baa54a3e833da1c27f41b8861dbb86b34351780ce8b18@127.0.0.1:0","enr":"0xf88fb8403c706e742e24e2e3e8bfcc48604544f9b4593b9fac94f97664fe76d2d9a02a183b24baf1ebfac2e908c29886fb61952983d054555cc677f2b4795e38cf5768dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023eae4ff354105cae615e8ed7499a263aab368017815886ccf3875219dfb6ae72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Vf2tAzA6dGkgdzIXxWijfSAEhp/zQJb75FGX9x66K2M=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 55fdad\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b5fc b245 bd48 b9d9 | 60 be0f (0) bc71 (0) bc29 (0) bde9 (0)\n001 6 1740 03eb 01a6 3b83 | 30 184e (0) 1929 (0) 127c (0) 1385 (0)\n002 4 6daa 62f0 73d0 77ee | 18 672a (0) 64e6 (0) 6450 (0) 641a (0)\n003 4 4c21 4cc2 4589 459b | 11 4bc8 (0) 4a3c (0) 4a37 (0) 4efa (0)\n004 5 5be6 5a8b 58a9 5c62 | 5 58a9 (0) 5be6 (0) 5a8b (0) 5c62 (0)\n============ DEPTH: 5 ==========================================\n005 3 5008 51c2 52b4 | 3 52b4 (0) 51c2 (0) 5008 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","private_key":"9ffae4eb3efdf717dce58938868a5816422239bac33c7d104cae4e18b73feaa8","name":"node_55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","services":["streamer"],"enable_msg_events":true,"port":37795},"up":true}},{"node":{"info":{"id":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","name":"node_22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","enode":"enode://0fcdb40b9980223ca221f90fca68efae8db086998c519d8725f451e9e351346836103fb5aa037e39188b71cb4b3f0625b313e7aee625e297edb036c44566f728@127.0.0.1:0","enr":"0xf88fb840d0cc3284ff4f87d20c3a83d7047fd8ab950c8bda00565839b26d7c9d24e7abf205c14a5d4714dbea74bf7a6de1731a8f80b41519fdf01063bbf6ed3322b874be0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020fcdb40b9980223ca221f90fca68efae8db086998c519d8725f451e9e3513468","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IruzI2peChlHocRzWqrPkSIXN4mgKgbnZTEDvcri+CM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 22bbb3\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b5fc b60e b9d9 | 60 be0f (0) bc71 (0) bc29 (0) bde9 (0)\n001 2 77ee 55fd | 38 6975 (0) 68a6 (0) 6daa (0) 672a (0)\n002 8 1385 1740 0639 01a6 | 13 1929 (0) 184e (0) 127c (0) 1385 (0)\n003 2 3871 3b83 | 6 36d5 (0) 3775 (0) 3590 (0) 3e19 (0)\n004 3 2803 2d53 2dd4 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27db 27b5 | 3 2471 (0) 27b5 (0) 27db (0)\n006 2 216e 21dc | 2 21dc (0) 216e (0)\n============ DEPTH: 7 ==========================================\n007 1 2354 | 1 2354 (0)\n008 1 221c | 1 221c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","private_key":"cce6899e27a53e544f7f5b8aad86ab94d88cb44d56c3990527df6186741b5448","name":"node_22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","services":["streamer"],"enable_msg_events":true,"port":46859},"up":true}},{"node":{"info":{"id":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","name":"node_77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","enode":"enode://30c18cf67d3de082cf0bf79b9f1722fa4816434fd18609381488df512c8f3759e7c9bbccea6cd0e592c81ac1169d277e6b45beb59dec2f4678ba549b19370751@127.0.0.1:0","enr":"0xf88fb840054a553fdf6785422e9ba595a831b259bb7cc62c4c3a41861f937338904e08c1117e88ce97c436f3ea15af9cd139711452a589831e746d9b174c404df5b9b6130183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10330c18cf67d3de082cf0bf79b9f1722fa4816434fd18609381488df512c8f3759","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d+7crAyEex1pPd/wfFhor7HCAIsty0igKZFDqxRhGWk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 77eedc\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 eb01 f33c 8d3e | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 7 0807 0639 034d 03eb | 30 1929 (0) 184e (0) 127c (0) 1385 (0)\n002 3 459b 5a8b 55fd | 20 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n003 5 6450 641a 62f0 6975 | 9 6379 (0) 62f0 (0) 672a (0) 64e6 (0)\n004 3 7bcb 7bee 7a68 | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 72a5 72a7 73d0 | 3 72a5 (0) 72a7 (0) 73d0 (0)\n============ DEPTH: 6 ==========================================\n006 1 75e2 | 1 75e2 (0)\n007 0 | 0\n008 1 772a | 1 772a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","private_key":"e1e6b3e6225cad6b1df7fc028cf8a745346a7c26d5dea6825108ae2f483d8c04","name":"node_77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","services":["streamer"],"enable_msg_events":true,"port":44643},"up":true}},{"node":{"info":{"id":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","name":"node_8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","enode":"enode://ba544e97e0b245ef40d6515136e3b0b9af76a2d9f7eadfb8fde90b979079abcf9c60d1c43f5ab07731dc0d72a59a501b9cb7c951d9f5da576f16e19c5b1fdfbc@127.0.0.1:0","enr":"0xf88fb8400a1d7ba92c3ca031f366592c2d92fdb57881f30a2584f776614e94451218ba5a10ece049d25fcc363f9f3f26915edc173410d3a2393d5b83e18893e89e6a074f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ba544e97e0b245ef40d6515136e3b0b9af76a2d9f7eadfb8fde90b979079abcf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jT4NnGky00IgJDlJmOlDMJtnnWZzlNDrYi8OII5/zwo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8d3e0d\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0f31 0807 0a21 127c | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 4 eceb f33c c2f9 c52a | 31 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n002 12 a9fa a861 aba7 acf8 | 20 b869 (0) b9d9 (0) be0f (0) bc29 (0)\n003 2 957e 9472 | 2 957e (0) 9472 (0)\n004 3 8012 8330 836e | 4 8012 (0) 8284 (0) 836e (0) 8330 (0)\n============ DEPTH: 5 ==========================================\n005 1 8b35 | 1 8b35 (0)\n006 1 8fb8 | 1 8fb8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","private_key":"f2b2db3ab3bb25ad92063630dd8898f4437d0af687073abd25e341b1649e41cf","name":"node_8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","services":["streamer"],"enable_msg_events":true,"port":35799},"up":true}},{"node":{"info":{"id":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","name":"node_c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","enode":"enode://d0cbe2c3073b8e2da7f2d750d97719714b354e4a823141560a5c7e6bcc460dfe7a1fbab94d94d8bf48a64cb16c59489ef1d6b9a47d6f9e7e96bce190cc7f8d4d@127.0.0.1:0","enr":"0xf88fb8403bf91f39e315b53cdc4b2dbbf4b41e95542ff5660d7a2916fe2ee858ecc2c5723462999e9c22d592f05fe322d42caddf25eee3e855d5d9599b6f438f7627589c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d0cbe2c3073b8e2da7f2d750d97719714b354e4a823141560a5c7e6bcc460dfe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xSpo2DiKIQE+Tuzvnqhm2x9esWu+DsyCuL+v0z5OAU8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c52a68\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 7bcb 72a7 641a 58a9 | 68 184e (0) 1929 (0) 127c (0) 1385 (0)\n001 3 b9d9 b5fc 8d3e | 29 b869 (0) b9d9 (0) bc71 (0) bc29 (0)\n002 6 ea3d eb01 eceb fa9a | 17 e06f (0) ea3d (0) eb01 (0) ee2b (0)\n003 4 d18a d125 deec d9d3 | 6 d23c (0) d125 (0) d18a (0) d9d3 (0)\n004 5 ce01 cc5f cc9f cabf | 5 ce01 (0) cc5f (0) cc9f (0) cabf (0)\n============ DEPTH: 5 ==========================================\n005 2 c0ad c2f9 | 2 c0ad (0) c2f9 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","private_key":"f49dc248179df01ec6c8b426228f64aaa30b16ea7f8e9e9bf4f933d061d58bb6","name":"node_c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","services":["streamer"],"enable_msg_events":true,"port":42373},"up":true}},{"node":{"info":{"id":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","name":"node_3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","enode":"enode://8d83c109e42a329f480a3a51a9dde5516d6731233ddd28de467ff3ef255a8e5342765c79c446fdb28e14ead4c4c590b2ba5ba740b3f96be1eee5bbc837ee5963@127.0.0.1:0","enr":"0xf88fb84031a328c351d984beccbc346fa806f81c52b5e33a6ca23e3c378b6ce2cf71e60f7936466c5c8ef78d0cbbef2c09fa6b3fc77fafb99cdb8bcbf90a26a50dc0d0580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038d83c109e42a329f480a3a51a9dde5516d6731233ddd28de467ff3ef255a8e53","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OHFJLIxizXTL5lqZNmnkl4zGQYeaUiPda55ofwUKHEA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 387149\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eceb c52a 8b35 aedc | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 8 6daa 62f0 7bcb 772a | 38 4bc8 (0) 4a37 (0) 4a3c (0) 4efa (0)\n002 8 1929 1385 1740 034d | 13 184e (0) 1929 (0) 127c (0) 1385 (0)\n003 8 2dd4 2471 27db 21dc | 11 2803 (0) 2d53 (0) 2dd4 (0) 27b5 (0)\n004 3 36d5 3775 3590 | 3 36d5 (0) 3775 (0) 3590 (0)\n============ DEPTH: 5 ==========================================\n005 1 3e19 | 1 3e19 (0)\n006 1 3b83 | 1 3b83 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","private_key":"834f76d47474f2c89e8e0405186442df99beaa572593e766307382a90766efae","name":"node_3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","services":["streamer"],"enable_msg_events":true,"port":44349},"up":true}},{"node":{"info":{"id":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","name":"node_aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","enode":"enode://de0a47f289a5e5d540db8adc0ef05baf590d55abad62f68a25d5262181ce611b0a3aa703cdf027fc666dd62e66ce6be0ebc78179e341b06fa407ffee34176330@127.0.0.1:0","enr":"0xf88fb840870ed3339b049cab40a19dacd5afe7e4f8139c5f9da6053b795be3d6ac9447070011c7efbcdf83ab755f08ffcd03df0cabffa76734712b57822864e8514bce850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102de0a47f289a5e5d540db8adc0ef05baf590d55abad62f68a25d5262181ce611b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rtybR4IE7/3LrRqJIzPxXAYfvRQjs3D4pQ+SmyovaVI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aedc9b\npopulation: 21 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 73d0 216e 3871 | 68 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n001 3 deec f33c fa9a | 31 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n002 4 9472 8284 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 836e (0)\n003 6 b60e b5fc b9d9 bc29 | 14 b869 (0) b9d9 (0) bc71 (0) bc29 (0)\n004 1 a192 | 1 a192 (0)\n============ DEPTH: 5 ==========================================\n005 3 a9fa a861 aba7 | 3 a9fa (0) a861 (0) aba7 (0)\n006 1 acf8 | 1 acf8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","private_key":"d0b21651e7458eb9235717900d45d5d655a60530764fcc4ca99ade40d39e4f0c","name":"node_aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","services":["streamer"],"enable_msg_events":true,"port":34417},"up":true}},{"node":{"info":{"id":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","name":"node_216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","enode":"enode://683e4c5a8d928aee37c2f41441e3d7550c42d486625db97883eb2046e9bafc9713f50ee269f4801f3a3c6220af6b097c4100ae92a1970333d9253f86d23c8a0c@127.0.0.1:0","enr":"0xf88fb8401dfe814edc9bad85208abd4a89df104f3d8a58386eb8a593a97d41fa5b72ae395106fc13f4897da7efe6c140ffef9097cd2f468a4920b060d8ea5bc13a46c2940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102683e4c5a8d928aee37c2f41441e3d7550c42d486625db97883eb2046e9bafc97","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IW4DcBEeLgOSe4A654j5lH3o4kHUHb9qcJg88OzWivE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 216e03\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eceb aedc | 60 d23c (0) d18a (0) d125 (0) d9d3 (0)\n001 8 4d75 4c21 4efa 4bc8 | 38 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n002 4 1929 1385 01a6 0639 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 5 3590 36d5 3775 3871 | 6 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n004 3 2803 2d53 2dd4 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27b5 27db | 3 2471 (0) 27b5 (0) 27db (0)\n============ DEPTH: 6 ==========================================\n006 3 2354 221c 22bb | 3 2354 (0) 22bb (0) 221c (0)\n007 0 | 0\n008 1 21dc | 1 21dc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","private_key":"03956bb84d1d10be6b5626b2c0175cefa443ca6cafbff149baba36309c2be8fd","name":"node_216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","services":["streamer"],"enable_msg_events":true,"port":44971},"up":true}},{"node":{"info":{"id":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","name":"node_73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","enode":"enode://9ac8ba21114f8c40f21f83d7747cd65cc99c986ab59bb477956d068c8cd04001712f8a843e0101b065abbcb2c3b2bd5472dc79345af64d86af2442b35eb0fb68@127.0.0.1:0","enr":"0xf88fb8405197213d021e7a00219b2701909e28eea2507aacb71f2ac2ead5dca945e66d7d1ba4dfa641f44981ca3e8b71b479abb37209113213d5e81f5fb709dead3663300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029ac8ba21114f8c40f21f83d7747cd65cc99c986ab59bb477956d068c8cd04001","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c9DR1KK3JQ9R5XwTzEi8ayBoIyDOEu6OV2Wv7vfZ3kI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 73d0d1\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 b60e b5fc be0f bd48 | 60 957e (0) 9472 (0) 8012 (0) 8330 (0)\n001 2 1740 216e | 30 1929 (0) 184e (0) 1740 (0) 127c (0)\n002 7 4a37 4cc2 459b 5cc1 | 20 4bc8 (0) 4a3c (0) 4a37 (0) 4efa (0)\n003 4 6450 6379 62f0 6daa | 9 672a (0) 64e6 (0) 6450 (0) 641a (0)\n004 3 7bee 7bcb 7a68 | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 75e2 772a 77ee | 3 75e2 (0) 77ee (0) 772a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 72a5 72a7 | 2 72a5 (0) 72a7 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","private_key":"5c8a42c979ee0b2447144c7dd26b2c6e8a98d27f055aa74c3e8e5559e2cb46bf","name":"node_73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","services":["streamer"],"enable_msg_events":true,"port":39577},"up":true}},{"node":{"info":{"id":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","name":"node_f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","enode":"enode://bb701e37ec5c4eb7faf97cc3aeb366de572c8d5d69e00eb267fecf7d1057eae9b583d3c64a9c0cd2374c0386113db63a61c256ab2b7cf358a6d90a7e9794260d@127.0.0.1:0","enr":"0xf88fb8406c2273c5e5619bccbf0c95225591124b18297b1ae02303095104b37745795d1b4b1d98f175c9198c719d3e2039226b02017e0d5a579e852f53ab0abcbb6a63c30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bb701e37ec5c4eb7faf97cc3aeb366de572c8d5d69e00eb267fecf7d1057eae9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8zwHqBiGOjWDWJiexxUEq608oKfIG1Sq1ZB1p2b61QE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f33c07\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 034d 27db 221c 2dd4 | 68 184e (0) 1929 (0) 1740 (0) 127c (0)\n001 8 9472 8d3e b245 be0f | 29 957e (0) 9472 (0) 8012 (0) 8284 (0)\n002 6 deec d9d3 c9ef cc9f | 14 d23c (0) d18a (0) d125 (0) d9d3 (0)\n003 6 eceb ed2e ed12 ee2b | 8 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n004 3 fa65 fac8 fa9a | 3 fa65 (0) fac8 (0) fa9a (0)\n005 2 f4a0 f611 | 2 f4a0 (0) f611 (0)\n============ DEPTH: 6 ==========================================\n006 2 f005 f177 | 2 f005 (0) f177 (0)\n007 0 | 0\n008 1 f3d5 | 1 f3d5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","private_key":"cc252064f7892875bcbb546a3d781327da4ab0042adaa0dd77dda609e9dbeacc","name":"node_f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","services":["streamer"],"enable_msg_events":true,"port":40171},"up":true}},{"node":{"info":{"id":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","name":"node_3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","enode":"enode://0009f6f563c6452d012e984f5cbe5de59f3838507fa83b32de8e12fc72d7abc3722c4b2b439eb90ccb5268e246b24cd30b2f317e7d1c855c25ef4d429d5b867b@127.0.0.1:0","enr":"0xf88fb8400938dcfa0fa11e741c028a9b8cbcb9e6b12b58464a8c5d0b8581f6103d56571352e10574431842737cf1f8e857b861b51a7b4094d046eac4cc42a317b5fbcd260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030009f6f563c6452d012e984f5cbe5de59f3838507fa83b32de8e12fc72d7abc3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O4MMKuVGPKLyJgF2t3uN2iMEgleqeAJVxpzxu7xvtkw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b830c\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b60e f33c | 60 957e (0) 9472 (0) 8330 (0) 836e (0)\n001 7 7bcb 6daa 62f0 4589 | 38 52b4 (0) 5008 (0) 51c2 (0) 55fd (0)\n002 6 0f31 0807 034d 01a6 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 8 2d53 2dd4 27db 21dc | 11 2803 (0) 2d53 (0) 2dd4 (0) 2471 (0)\n004 3 36d5 3775 3590 | 3 36d5 (0) 3775 (0) 3590 (0)\n============ DEPTH: 5 ==========================================\n005 1 3e19 | 1 3e19 (0)\n006 1 3871 | 1 3871 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","private_key":"a26abbb5971ae2f14bf7f9cf3604375ed01076a0a5f87bdb169a057aba393510","name":"node_3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","services":["streamer"],"enable_msg_events":true,"port":44047},"up":true}},{"node":{"info":{"id":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","name":"node_b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","enode":"enode://8056da3baf80eb4e505b24fa85d6983cd0c08e57ff29de4fcd7cc5265957b4b951f2c346254e6476b70b57f3d47a2acd98577851778d4f96c6cf16f3cbcef6bd@127.0.0.1:0","enr":"0xf88fb840dc084998ced183bd31314071c4467df4b73013e165b0d232050ea6a34da27200541f9558182b77822222c499c6e0dac4fce02d7e39368547197e7f396dbcc66d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038056da3baf80eb4e505b24fa85d6983cd0c08e57ff29de4fcd7cc5265957b4b9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tg53xA3cnceKStNGrdN+YPEPKZneg2YV21NSRIfR7ek=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b60e77\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 73d0 6daa 22bb 3b83 | 68 52b4 (0) 5008 (0) 51c2 (0) 55fd (0)\n001 3 fa9a c9ef deec | 31 d23c (0) d125 (0) d18a (0) d9d3 (0)\n002 3 9472 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 8330 (0)\n003 5 acf8 aedc a9fa a861 | 6 a192 (0) acf8 (0) aedc (0) a9fa (0)\n004 4 b9d9 bd96 bd48 be0f | 9 b869 (0) b9d9 (0) bc29 (0) bc71 (0)\n005 2 b355 b245 | 2 b355 (0) b245 (0)\n============ DEPTH: 6 ==========================================\n006 2 b4e2 b5fc | 2 b4e2 (0) b5fc (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","private_key":"a9b81b86acde80334419f584fa1f17b478272a646091fd3c7250f8b10ba99c10","name":"node_b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","services":["streamer"],"enable_msg_events":true,"port":36265},"up":true}},{"node":{"info":{"id":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","name":"node_b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","enode":"enode://ad94d5da30a8e6fa7eed9bdffb921e1092d69a95a807d03810dc03bc57ead17b20c03d139f43048113b82ef53df5e92169655c100e4f408de936364aa731dda4@127.0.0.1:0","enr":"0xf88fb840ee7e922aec199035d2d62046ea3b1a19143ec54359003e49b68d8cbd84b539f27d0e7caf904f7f220035c6210d38e15b618abecbfb9c4db3d503b741aa37f6dc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ad94d5da30a8e6fa7eed9bdffb921e1092d69a95a807d03810dc03bc57ead17b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tfxD6MDfMnnWoSzYsDASy40iBSCDJAGMeucldFqZovM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5fc43\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 55fd 73d0 6450 22bb | 68 52b4 (0) 51c2 (0) 5008 (0) 55fd (0)\n001 2 c52a deec | 31 d23c (0) d18a (0) d125 (0) d9d3 (0)\n002 3 9472 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 8330 (0)\n003 3 aedc acf8 aba7 | 6 a192 (0) acf8 (0) aedc (0) a9fa (0)\n004 7 b869 b9d9 bc29 bd96 | 9 b869 (0) b9d9 (0) bc71 (0) bc29 (0)\n005 2 b355 b245 | 2 b245 (0) b355 (0)\n============ DEPTH: 6 ==========================================\n006 1 b60e | 1 b60e (0)\n007 1 b4e2 | 1 b4e2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","private_key":"0134c954441986806c11920e8f351540b3c6bdd309245a07f647cc4e169a81da","name":"node_b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","services":["streamer"],"enable_msg_events":true,"port":38321},"up":true}},{"node":{"info":{"id":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","name":"node_0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","enode":"enode://2d6b0e5f0d91f9894a0dabb941a7d6dc48de6b6554cfb6d7a8a9cec18c826ee0e655dae74f3e10a713ab5f85c916b579dddf8520a9921fab3f12b73a87e6f701@127.0.0.1:0","enr":"0xf88fb840dfa210d668f3a2c36acd290f3d30342b0e7d83f74443a6c6a50ea14f016dc5ec5ecf5395805d6322a9ff4fe28ee4f0d3b5cca2fc3be0fe8ac43f39650231ef750183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032d6b0e5f0d91f9894a0dabb941a7d6dc48de6b6554cfb6d7a8a9cec18c826ee0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BjnwEINPW8SXeY8tJ1u8YL+81TyD44mGtyYDEMYAFCA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0639f0\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 fa9a c2f9 c9ef 8b35 | 60 cc9f (0) cc5f (0) ce01 (0) cabf (0)\n001 7 5be6 6daa 6450 77ee | 38 6975 (0) 68a6 (0) 6daa (0) 62f0 (0)\n002 8 3775 3590 2d53 2dd4 | 17 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n003 4 184e 1929 1740 1385 | 5 184e (0) 1929 (0) 1740 (0) 127c (0)\n004 3 0f31 0807 0a21 | 4 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n============ DEPTH: 5 ==========================================\n005 3 01a6 03eb 034d | 3 01a6 (0) 03eb (0) 034d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","private_key":"77308f10c71498c40a49e4aeb7c93c863895a490407505b02a488c452abf01e9","name":"node_0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","services":["streamer"],"enable_msg_events":true,"port":38359},"up":true}},{"node":{"info":{"id":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","name":"node_221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","enode":"enode://4c0f14e6659005f725d17c49e95e9bba43b97f7a4c2cec6f8ae665dca6f9113e7a8b8f561014b4b2f850b5f135e0f0189d7efb4e74795d3dee5848cf6d07e6aa@127.0.0.1:0","enr":"0xf88fb840aa25c219ac37cc27c5582211fa9de0891c9aab80d7e185863532cc15a1c8eda84507ccbc3f09570329c6d2c0eacb3910cf2c29d9299eef9ce1a8ceffbeb4b0880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c0f14e6659005f725d17c49e95e9bba43b97f7a4c2cec6f8ae665dca6f9113e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IhzY6gom8NP4H3gvHeOQKCQV7NnPQCJLSUWgCJeJW04=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 221cd8\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c52a f33c | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 3 5cc1 7a68 772a | 38 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n002 5 1385 1740 1929 0f31 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 4 3590 3775 3871 3b83 | 6 3590 (0) 36d5 (0) 3775 (0) 3e19 (0)\n004 3 2803 2d53 2dd4 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27b5 27db | 3 2471 (0) 27b5 (0) 27db (0)\n006 2 216e 21dc | 2 21dc (0) 216e (0)\n============ DEPTH: 7 ==========================================\n007 1 2354 | 1 2354 (0)\n008 1 22bb | 1 22bb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","private_key":"c103c3cd8b3ec73103ecffab8a4778ba17c4ef1c7764c4edae06bb253bb4a1c7","name":"node_221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","services":["streamer"],"enable_msg_events":true,"port":34123},"up":true}},{"node":{"info":{"id":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","name":"node_2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","enode":"enode://2185c184311e0733ef3b385df4a2aaa3999aff53d34d3eef8fd026b46623c06a22c8ed8af0ec2827ea684193eb59cf3f6983f8c15a76b59a1fd8f2ee927f7070@127.0.0.1:0","enr":"0xf88fb8407c20d1f26dca6179ace9bc2df0f2e49e8ce46a9ab6ffc3ebc4b70f5448c300b604be2f148e16830139c9afb09d266af5fee0f6826901a4fcb31a79a39a3e48f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022185c184311e0733ef3b385df4a2aaa3999aff53d34d3eef8fd026b46623c06a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LdStg+/8O6c+cvVllYPlmHJBvaVjVjIAtQxGzOAKHZs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2dd4ad\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c52a f33c | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 62f0 5cc1 4589 459b | 38 6379 (0) 62f0 (0) 672a (0) 64e6 (0)\n002 7 1385 1740 0639 01a6 | 13 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n003 5 36d5 3775 3590 3b83 | 6 36d5 (0) 3775 (0) 3590 (0) 3e19 (0)\n004 7 2471 27db 21dc 216e | 8 2471 (0) 27b5 (0) 27db (0) 21dc (0)\n============ DEPTH: 5 ==========================================\n005 1 2803 | 1 2803 (0)\n006 0 | 0\n007 0 | 0\n008 1 2d53 | 1 2d53 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","private_key":"7780b155f127c1e2df9bd24187ab68f6bcfbc96c9ef1d8e6bfb2453180d4d177","name":"node_2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","services":["streamer"],"enable_msg_events":true,"port":41059},"up":true}},{"node":{"info":{"id":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","name":"node_459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","enode":"enode://596d8f8a3f115e739480cfc90bc3ed52bd3c6db976e8b44dd13b7c598ae1592b213998fcd92d010932001f405ea0d17a35cf0ee9dbd4d27cf7f5a665cec3dc63@127.0.0.1:0","enr":"0xf88fb8409cc2805d0639562a229301ca59a539f4a081f7b38ac8f293061de8340bca1d2645d0c65b2fc1170fff5f9386d3ab9f0357bfab057f46159767025ca2d20a0cf70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103596d8f8a3f115e739480cfc90bc3ed52bd3c6db976e8b44dd13b7c598ae1592b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RZufsrf045bejPh0CmgEyOW5bKEf+itRBsFN+7q2XJU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 459b9f\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c52a f33c | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 4 03eb 0f31 3871 2dd4 | 30 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n002 8 6daa 6450 641a 7a68 | 18 6379 (0) 62f0 (0) 672a (0) 64e6 (0)\n003 3 5008 55fd 58a9 | 9 52b4 (0) 5008 (0) 51c2 (0) 55fd (0)\n004 5 4a3c 4efa 4d75 4c21 | 7 4bc8 (0) 4a37 (0) 4a3c (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 4775 4746 | 2 4775 (0) 4746 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 4589 | 1 4589 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","private_key":"a5637f6dfe5f01c6cc2f881f665ff337c05147527c551e16933839046d2f0402","name":"node_459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","services":["streamer"],"enable_msg_events":true,"port":43667},"up":true}},{"node":{"info":{"id":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","name":"node_58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","enode":"enode://a316c9e7d1d346e81a1fec594ce6e35c607b9c61382ae1d43ee823bff44691073f86d5d9c0855bc150802216453072291e4fcf13a75b9e7c24f4c050c5b8f383@127.0.0.1:0","enr":"0xf88fb840989fd084c3dc88c500954c17cbe02ddeb37aec1afd002fbec87e88f3efa1758b10901f9c502b0e252254124e32464db5744f524bf2e090d035e4cb986373579c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a316c9e7d1d346e81a1fec594ce6e35c607b9c61382ae1d43ee823bff4469107","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WKkLWIWEF6TpcmJkIe2OeLGz5axp/O3SLFioq0xhR98=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 58a90b\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 deec c9ef c52a c2f9 | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 3 1385 034d 3b83 | 30 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n002 5 73d0 6379 6450 641a | 18 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n003 3 4a37 4c21 459b | 11 4a3c (0) 4a37 (0) 4bc8 (0) 4efa (0)\n004 3 5008 51c2 55fd | 4 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n005 2 5c62 5cc1 | 2 5c62 (0) 5cc1 (0)\n============ DEPTH: 6 ==========================================\n006 2 5a8b 5be6 | 2 5a8b (0) 5be6 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","private_key":"f76a3f3cb8f63a53ab4db362f8c406b8b64c653bfeb32a8e730eb9386f52f057","name":"node_58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","services":["streamer"],"enable_msg_events":true,"port":43195},"up":true}},{"node":{"info":{"id":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","name":"node_be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","enode":"enode://eeded07e99fa4ff2d426439e42dc4604dd4b1b48d79b02496e61ff86d21658dc4ece7ba599e544ef99d326c12c01c70509c8cfd486228c14db2d8c2b15648571@127.0.0.1:0","enr":"0xf88fb840bf0cf1c25f6277811da44fc4d073295fcffa375500de088bd154cff1aa9770737b9e677865a1873a4a10103f43db1289382f15e37cebe4e4d8cc60b013ff2a1c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eeded07e99fa4ff2d426439e42dc4604dd4b1b48d79b02496e61ff86d21658dc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vg+ytEC5HnGcIPUbZz658vZsevd7CwreMSmYzf/MUEU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be0fb2\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 3775 1740 1385 034d | 68 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n001 12 f611 f177 f33c f3d5 | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 3 9472 8b35 8d3e | 9 957e (0) 9472 (0) 8012 (0) 836e (0)\n003 2 aedc aba7 | 6 a192 (0) acf8 (0) aedc (0) a861 (0)\n004 3 b355 b60e b5fc | 5 b245 (0) b355 (0) b4e2 (0) b5fc (0)\n005 2 b869 b9d9 | 2 b869 (0) b9d9 (0)\n============ DEPTH: 6 ==========================================\n006 6 bc71 bc29 bd96 bde9 | 6 bc71 (0) bc29 (0) bd96 (0) bde9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","private_key":"38ca3287eddd306f53a09e7f411c72cd416a6fea9372c3be4307ffa2b66a5e84","name":"node_be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","services":["streamer"],"enable_msg_events":true,"port":33661},"up":true}},{"node":{"info":{"id":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","name":"node_deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","enode":"enode://f76349ec766de9d4431151d18ef460cbf69350f3bfa572661117e66b942e7c43605b02eb8805192c15a2c6a5fa47fefe5f4faf57cff643dffd13cfe84d80dcd2@127.0.0.1:0","enr":"0xf88fb840a8e8b269bcf4e00811769f0b731ba2d12904fea4ba28727d8c02b71eb17799531e0b15265ed663ef981c53c77bcbd0a2bb3e8607ade87aef661238ac26892bfb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f76349ec766de9d4431151d18ef460cbf69350f3bfa572661117e66b942e7c43","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3uxqi+tOXkQd1CMRNUGUw775RI6IWbTM1AFkW2khfRI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: deec6a\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 58a9 5cc1 4c21 7bcb | 68 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n001 7 9472 aedc aba7 b60e | 29 957e (0) 9472 (0) 8012 (0) 836e (0)\n002 8 eceb ed12 ed2e fa9a | 17 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n003 6 c52a c2f9 c9ef ce01 | 8 cc5f (0) cc9f (0) ce01 (0) cabf (0)\n004 3 d23c d18a d125 | 3 d23c (0) d18a (0) d125 (0)\n============ DEPTH: 5 ==========================================\n005 1 d9d3 | 1 d9d3 (0)\n006 1 dd92 | 1 dd92 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","private_key":"e937ad3db719737f604c22bd1bc3702c56cab3b5ef6aeddadad798027099af81","name":"node_deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","services":["streamer"],"enable_msg_events":true,"port":42029},"up":true}},{"node":{"info":{"id":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","name":"node_13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","enode":"enode://233f1ef8d53ba1f2f35253d6fd30975d21193041f84c41e99efa3680301dbd2dc630d0ac490193182b8f32036c6cc7fd56f8396c42f02d6797074cabfec0aa1c@127.0.0.1:0","enr":"0xf88fb8404cb34513bd8303f7d3bf75384dd785ab45af5e1ddb4087f14b97cb418a03dcac17b596bc11aec73cbf0795c77a2d1b84f895a76f54d0ee90d842fc74759bace40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102233f1ef8d53ba1f2f35253d6fd30975d21193041f84c41e99efa3680301dbd2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E4U0B9J4pF4V1LFI/Djrs1xPWO5VLuDkQBxsmMRbjj4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 138534\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 8b35 8d3e b355 be0f | 60 8012 (0) 8284 (0) 836e (0) 8330 (0)\n001 10 6450 6daa 7bcb 77ee | 38 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n002 10 3775 3590 3871 3b83 | 17 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n003 6 0f31 0a21 0807 01a6 | 8 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n004 2 184e 1929 | 2 184e (0) 1929 (0)\n============ DEPTH: 5 ==========================================\n005 1 1740 | 1 1740 (0)\n006 0 | 0\n007 1 127c | 1 127c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","private_key":"7da06589109c392355e1be112c5b857ab81263c8a0d024f4bb9a295c1e7e7835","name":"node_13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","services":["streamer"],"enable_msg_events":true,"port":46227},"up":true}},{"node":{"info":{"id":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","name":"node_aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","enode":"enode://682bf60eaccc8c0ea6b95167841aee6e412a1d544017d3a9a894ed557cf576fb38146ddd775e94eedff062a3ef8030515beeea9982f8904c148790d6ff5ca40b@127.0.0.1:0","enr":"0xf88fb840ca36c7659c737b8ebbb2cf6ae6954a5dc378e4a3ba74cdf832186b307b46ab6942e82c3c7562eb653e7dc998e912f2a78935d1573fd6f2faa4e0366888622e0e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103682bf60eaccc8c0ea6b95167841aee6e412a1d544017d3a9a894ed557cf576fb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"q6eT5jX3EWkQWtBzIlzI25FN5rcR/p8ixdlKyMuF4us=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aba793\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 73d0 772a 1385 | 68 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n001 8 ee2b eceb fa9a f611 | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 2 8d3e 9472 | 9 8012 (0) 8284 (0) 836e (0) 8330 (0)\n003 7 b5fc b60e b9d9 bc29 | 14 b245 (0) b355 (0) b4e2 (0) b5fc (0)\n004 1 a192 | 1 a192 (0)\n005 2 acf8 aedc | 2 acf8 (0) aedc (0)\n============ DEPTH: 6 ==========================================\n006 2 a861 a9fa | 2 a861 (0) a9fa (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","private_key":"2fedc92f155f2df9c7680e003208e896d4afe676f8d42a34e9c052876a8eba05","name":"node_aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","services":["streamer"],"enable_msg_events":true,"port":44069},"up":true}},{"node":{"info":{"id":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","name":"node_772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","enode":"enode://705fa39aa2e54e3cf627d29d6b986190ac5c50c3ef5702ebf41f048db0b691596ce6cf281898420112ed749a1dbeb4ad5160a62cb8cac2fc23aafc9eeeeaab54@127.0.0.1:0","enr":"0xf88fb8404f14a1ec789a7e2c007912c3209baae1e1b9bdb005a66efc25bcf1e48324aab522e9eddebd99b287bc2240719d578f848243a42d5e6ed9b0db297261eceb6fde0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102705fa39aa2e54e3cf627d29d6b986190ac5c50c3ef5702ebf41f048db0b69159","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dyp5MCUo/c5qIWyYyV4oEzMpLIHf5JCuqkp4v+sZgMg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 772a79\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 c2f9 c9ef ce01 f33c | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 3871 3590 221c 0639 | 30 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n002 8 5cc1 51c2 459b 4bc8 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 4 6daa 6379 641a 6450 | 9 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n004 3 7bee 7bcb 7a68 | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 72a7 72a5 73d0 | 3 73d0 (0) 72a5 (0) 72a7 (0)\n============ DEPTH: 6 ==========================================\n006 1 75e2 | 1 75e2 (0)\n007 0 | 0\n008 1 77ee | 1 77ee (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","private_key":"20f8e29f129c023ce09631a3c2b173e7f73cf8040aa372de1eca8d2b5d6aa3f6","name":"node_772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","services":["streamer"],"enable_msg_events":true,"port":34307},"up":true}},{"node":{"info":{"id":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","name":"node_7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","enode":"enode://3c14067242581a41318e20b5bf461a2010c6163ce865664c0846d3c020ec076876b38593cb72579d5e5d1c5eda4182195bbacda4a6cd6f75246d0dac4b348f88@127.0.0.1:0","enr":"0xf88fb84015230ae1b2f1e7e93185930792b34197809d010451d124ef701f64630aec586a16d0a8cd37cdeaeef002bef58bd34243cf3c0a97216cb08ec2e4937ed48313b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c14067242581a41318e20b5bf461a2010c6163ce865664c0846d3c020ec0768","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"emj6RLvsGHJy4tXfvW7YrzGho2WqcqpQ2wI1Dr6YyFk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7a68fa\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8284 9472 f33c deec | 60 e06f (0) ea3d (0) eb01 (0) efd6 (0)\n001 3 221c 0639 034d | 30 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n002 5 5cc1 459b 4a37 4cc2 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 4 6daa 6379 641a 6450 | 9 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n004 6 72a5 72a7 73d0 75e2 | 6 73d0 (0) 72a5 (0) 72a7 (0) 75e2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 2 7bee 7bcb | 2 7bee (0) 7bcb (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","private_key":"55bb3e30ef20d49d0cfe74562140bde2e178fe9c68c22a323aee1342c262a374","name":"node_7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","services":["streamer"],"enable_msg_events":true,"port":33619},"up":true}},{"node":{"info":{"id":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","name":"node_034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","enode":"enode://e6424d57236a8e78654448dbacf849545ea5f8d8963a1839bda9e7e2ed7b9f75235ce65da8cd8658f6907052e5ff7500aab3d5bf41e7ef55cf6a0c51d0531da1@127.0.0.1:0","enr":"0xf88fb84031fe742fa635670041f5fe96872983f924cd30e5949074833ecf42feafa3d792135e91a69af260875cb6b8e0b99148175b0570494dc64dfed550c4b594b2be780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e6424d57236a8e78654448dbacf849545ea5f8d8963a1839bda9e7e2ed7b9f75","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A03mZ3TtomuT40LJuUud6util2UMgZsUSlgyvr/msC8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 034de6\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 b355 be0f 8b35 957e | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 10 58a9 4d75 4cc2 6daa | 38 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n002 9 2803 2dd4 27db 22bb | 17 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n003 3 1385 184e 1929 | 5 184e (0) 1929 (0) 1740 (0) 127c (0)\n004 4 0807 0a21 0e34 0f31 | 4 0e34 (0) 0f31 (0) 0807 (0) 0a21 (0)\n005 1 0639 | 1 0639 (0)\n============ DEPTH: 6 ==========================================\n006 1 01a6 | 1 01a6 (0)\n007 0 | 0\n008 1 03eb | 1 03eb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","private_key":"85899df9a7c186468ac564ef2a386b2657c6d63c3f0751f128882d292dbda09a","name":"node_034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","services":["streamer"],"enable_msg_events":true,"port":37491},"up":true}},{"node":{"info":{"id":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","name":"node_72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","enode":"enode://f0232c32322d105dcc559017d690018c44958df27f400c2da47688421eb9446788c84dc8f1295f282f2af16f62dcb6cc6e25d06c58031bbe1179d859904b568a@127.0.0.1:0","enr":"0xf88fb840d8f5c3b3a865e6fb673db1e14223e95eebbf821ed0ebedb85ca36ed6d7b8e8b810af20b72f1321af49040b9636f9f653b88821f970089c882da2faf5ae94cb590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0232c32322d105dcc559017d690018c44958df27f400c2da47688421eb94467","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cqdvZo2bkjkUhg60+Fd7yYwVP23SIs02oLve8rq38Gg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 72a76f\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 d125 c52a ce01 c9ef | 60 e06f (0) ea3d (0) eb01 (0) ee2b (0)\n001 4 3e19 0a21 03eb 034d | 30 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n002 8 459b 4bc8 4a37 4cc2 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 6 6daa 62f0 6379 672a | 9 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n004 3 7a68 7bee 7bcb | 3 7bee (0) 7bcb (0) 7a68 (0)\n005 3 75e2 772a 77ee | 3 75e2 (0) 77ee (0) 772a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 73d0 | 1 73d0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 1 72a5 | 1 72a5 (0)\n015 0 | 0\n========================================================================="}},"config":{"id":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","private_key":"2dbcb1f5dc3a4230a4b221acbcb0ddd1e7178bd47ef73c82eed7ffecc7740e8f","name":"node_72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","services":["streamer"],"enable_msg_events":true,"port":36137},"up":true}},{"node":{"info":{"id":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","name":"node_bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","enode":"enode://d1614db3ef30a1d4e4082531616f3fe131a586eacc407b1d4041e9714d0dc98600467eaa2d408b5686dbb3cace24919099715a04a8e829bc0a0eac80f3d8fda5@127.0.0.1:0","enr":"0xf88fb8409b8ce0903002c146be1f872e039e3a98a5226c19fa7fab111327cc0f7d31fa6f0abde0b02ff8f05e228e94511987c311a2c0a577eb3196f305e3a5ed95b97bc60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d1614db3ef30a1d4e4082531616f3fe131a586eacc407b1d4041e9714d0dc986","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vUhuHhXfTHU5sa1bVPdWbdSDakMOn301A4gfp54ljZs=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bd486e\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 55fd 4c21 73d0 72a7 | 68 3e19 (0) 3871 (0) 3b83 (0) 36d5 (0)\n001 2 f177 deec | 31 e06f (0) eb01 (0) ea3d (0) ee2b (0)\n002 4 9472 8b35 8d3e 8fb8 | 9 8012 (0) 836e (0) 8330 (0) 8284 (0)\n003 5 a861 a9fa aba7 acf8 | 6 a192 (0) acf8 (0) aedc (0) a861 (0)\n004 4 b355 b60e b4e2 b5fc | 5 b355 (0) b245 (0) b4e2 (0) b5fc (0)\n005 2 b869 b9d9 | 2 b869 (0) b9d9 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc71 bc29 | 2 bc71 (0) bc29 (0)\n============ DEPTH: 8 ==========================================\n008 3 bd96 bde9 bddb | 3 bd96 (0) bde9 (0) bddb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","private_key":"7caa80d81addc9906ff055f89b4f28d67c666b90d9fd0030cf4a4a9e2372f478","name":"node_bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","services":["streamer"],"enable_msg_events":true,"port":45371},"up":true}},{"node":{"info":{"id":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","name":"node_4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","enode":"enode://6fbec307bce183850f96a0e0401fe05f26abb60c34295c692aecaaf353766314ccece95987b85ab3cf2c43c4fc8090823c86539f548ba5727d9030c99f049180@127.0.0.1:0","enr":"0xf88fb840a324b4bf2450128b22b8e99d9e7863140c8d4deab6e51d53891a5eab787249f45bbd942c8a73aa78acd0d87997764ddee5241040c712f0633281cbc5bb2dca790183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026fbec307bce183850f96a0e0401fe05f26abb60c34295c692aecaaf353766314","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TCEcEX5VXCrIMdVohhW2tMXjHx18eQazTwy828RUgrQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c211c\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 deec 8fb8 bd48 | 60 e06f (0) ea3d (0) eb01 (0) ee2b (0)\n001 3 1385 216e 21dc | 30 184e (0) 1929 (0) 1740 (0) 127c (0)\n002 3 772a 7a68 6450 | 18 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n003 6 5cc1 58a9 5be6 55fd | 9 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n004 3 4775 4746 459b | 4 4775 (0) 4746 (0) 4589 (0) 459b (0)\n005 2 4bc8 4a37 | 3 4a3c (0) 4a37 (0) 4bc8 (0)\n006 1 4efa | 1 4efa (0)\n============ DEPTH: 7 ==========================================\n007 1 4d75 | 1 4d75 (0)\n008 1 4cc2 | 1 4cc2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","private_key":"7534963388dc983ea5464538eec56a62b0acd0fc995c8549f2679755d385c2e8","name":"node_4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","services":["streamer"],"enable_msg_events":true,"port":45341},"up":true}},{"node":{"info":{"id":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","name":"node_21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","enode":"enode://88a1d0469479ab5a39001ece4f2c99ead3dc557053ca176ac22316ff7ed86ae4388683a54c38ba0f1bd78859cce8e650171fff2fa49006461c4c0d3ccff806fa@127.0.0.1:0","enr":"0xf88fb84056e42be02ea67947908fe9561498acbc10dddbec310fabfefb996e2eea72b4572e347aa61c0cab4658f9d6e382d08411d5da74a9f076c5a9f9d79e4242a9678e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10288a1d0469479ab5a39001ece4f2c99ead3dc557053ca176ac22316ff7ed86ae4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Idz7iTpUy1bSE1X8VkWDBX/FGzJQOoYn51dWYHJadic=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 21dcfb\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 deec f177 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 6daa 5cc1 4d75 4c21 | 38 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n002 4 01a6 034d 1929 1385 | 13 184e (0) 1929 (0) 1740 (0) 127c (0)\n003 5 3871 3b83 3590 36d5 | 6 3e19 (0) 3b83 (0) 3871 (0) 36d5 (0)\n004 2 2dd4 2803 | 3 2803 (0) 2d53 (0) 2dd4 (0)\n005 3 2471 27b5 27db | 3 2471 (0) 27b5 (0) 27db (0)\n============ DEPTH: 6 ==========================================\n006 3 2354 221c 22bb | 3 2354 (0) 22bb (0) 221c (0)\n007 0 | 0\n008 1 216e | 1 216e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","private_key":"f08efc99ef01728ff510e5f92b7180a1367519e8326761e78161233efa455123","name":"node_21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","services":["streamer"],"enable_msg_events":true,"port":42527},"up":true}},{"node":{"info":{"id":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","name":"node_6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","enode":"enode://9a9ce2e0b9a084ec93e5bf364d61450a6f630e3fcaf89692e6c084ef927d2c6acb1d0f5c3f0df97fd53807055774ed027dff214b337e644f766673ee959d6691@127.0.0.1:0","enr":"0xf88fb84044d9d55ee6ab6484a0a3ddabbc5227af358b46ebb1f61eb0155d882e31e9cd2010a81e6d888667b79f2121cd96793570539b6ec00410f3e171a61bef9431fb480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039a9ce2e0b9a084ec93e5bf364d61450a6f630e3fcaf89692e6c084ef927d2c6a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bar1FZmcmjSRyWP3a+gu1gBWFr97qYJHsB1qiamvHXE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6daaf5\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b60e f177 deec | 60 cabf (0) c9ef (0) cc9f (0) cc5f (0)\n001 9 0f31 0639 034d 1385 | 30 184e (0) 1929 (0) 1740 (0) 127c (0)\n002 4 459b 55fd 58a9 5cc1 | 20 4775 (0) 4746 (0) 4589 (0) 459b (0)\n003 8 7a68 7bee 7bcb 75e2 | 9 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n004 5 6379 62f0 672a 6450 | 6 62f0 (0) 6379 (0) 672a (0) 64e6 (0)\n============ DEPTH: 5 ==========================================\n005 2 6975 68a6 | 2 68a6 (0) 6975 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","private_key":"cddadd9acb99e1d405844e54f8c99b3b8971ab5210eafaba25db3fe4f8fcd91d","name":"node_6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","services":["streamer"],"enable_msg_events":true,"port":44965},"up":true}},{"node":{"info":{"id":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","name":"node_5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","enode":"enode://c734583d55ba85edc61b6e6737e43bce10a56dba57f05d4fc8bd3ade2e47a0eefabac7e83bda748a41c8b90a8a4bd965aa9da73b25b50b2ae9b57dfdd330ae7a@127.0.0.1:0","enr":"0xf88fb8403795468f0460cb1e3426dae834bdf0a6407814c00628447ad37ea9cdd7ad51535c32b9ef97d29a71a3958d034f6a01527a5b2c6230934e8f27c513f758b3d58e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c734583d55ba85edc61b6e6737e43bce10a56dba57f05d4fc8bd3ade2e47a0ee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XMHCjq/ZdY6AeigVmhp6bqMT+n6Hj95dR/zI9aXCUXI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5cc1c2\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8fb8 ce01 deec f177 | 60 c0ad (0) c2f9 (0) c52a (0) cabf (0)\n001 7 3871 3b83 27db 216e | 30 2803 (0) 2d53 (0) 2dd4 (0) 2354 (0)\n002 7 72a7 73d0 772a 7a68 | 18 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n003 4 4a37 4efa 4c21 4cc2 | 11 4775 (0) 4746 (0) 4589 (0) 459b (0)\n004 4 51c2 5008 52b4 55fd | 4 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n============ DEPTH: 5 ==========================================\n005 3 58a9 5a8b 5be6 | 3 58a9 (0) 5a8b (0) 5be6 (0)\n006 0 | 0\n007 0 | 0\n008 1 5c62 | 1 5c62 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","private_key":"e9b5e89040faaac07a9024be985c1b6a79cda66a0910b7a2ffa0a5c78b9afe61","name":"node_5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","services":["streamer"],"enable_msg_events":true,"port":45281},"up":true}},{"node":{"info":{"id":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","name":"node_4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","enode":"enode://d7ef3fd82861a99d09be17b9ed57768a386d22fbde25e097e376cb18f34b8b8e0bee1e3478fbd5fe0910f2306d0b0fa4df665e27e5a12611abc392c179d239e9@127.0.0.1:0","enr":"0xf88fb840289078a8d405c68188e3f1a163789ae0179de25d0af8223e4979d2ae17c304985bc8f4d436fab339c12b3f5ef00c5a2fda52f8622285df4f76335f4402dcf9170183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d7ef3fd82861a99d09be17b9ed57768a386d22fbde25e097e376cb18f34b8b8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TMI4aob9IQv2mcbZMXOwh5wyENRvVypiuxVMtgp9LLE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4cc238\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c9ef c2f9 c52a 9472 | 60 c0ad (0) c2f9 (0) c52a (0) cabf (0)\n001 2 1385 034d | 30 184e (0) 1929 (0) 1740 (0) 127c (0)\n002 7 6450 6379 72a7 73d0 | 18 7bee (0) 7bcb (0) 7a68 (0) 75e2 (0)\n003 3 51c2 55fd 5cc1 | 9 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n004 2 4746 459b | 4 4775 (0) 4746 (0) 4589 (0) 459b (0)\n005 2 4bc8 4a37 | 3 4bc8 (0) 4a3c (0) 4a37 (0)\n006 1 4efa | 1 4efa (0)\n============ DEPTH: 7 ==========================================\n007 1 4d75 | 1 4d75 (0)\n008 1 4c21 | 1 4c21 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","private_key":"ab042a555a4b63b145f4de3bbfccdf1f9b84b6cb627f349b61aa1180b6fe933f","name":"node_4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","services":["streamer"],"enable_msg_events":true,"port":36183},"up":true}},{"node":{"info":{"id":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","name":"node_947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","enode":"enode://3ca90095f93c4f83cffc3cf6da5e155328580ae3f82119872f3088143f19bcc006916f2dddcf8f4325de936f67e88f96446e448c4a59def92228dfade44c5901@127.0.0.1:0","enr":"0xf88fb84036ea2f3f5156386eb2d22329ca9cb82df354d2411a505c41eb3cd0455f9f4e706903cbbe26ecebe77942a1650c5475a289f05cbeaca4a648322982b30b84a2a60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033ca90095f93c4f83cffc3cf6da5e155328580ae3f82119872f3088143f19bcc0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lHIF/YWhczCm1cUaZlSMX2l3nHarEkCPj8bTPXxrjp0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 947205\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 034d 5be6 4cc2 73d0 | 68 184e (0) 1929 (0) 1740 (0) 127c (0)\n001 6 c0ad ce01 d18a deec | 31 c2f9 (0) c0ad (0) c52a (0) c9ef (0)\n002 12 b60e b5fc b4e2 be0f | 20 a192 (0) acf8 (0) aedc (0) aba7 (0)\n============ DEPTH: 3 ==========================================\n003 7 8fb8 8d3e 8b35 8012 | 7 8012 (0) 836e (0) 8330 (0) 8284 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 957e | 1 957e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","private_key":"eaf46b142d5bbbd82ca1980c2bf40b52e6c63c995e5e99fb80517e644adea556","name":"node_947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","services":["streamer"],"enable_msg_events":true,"port":33771},"up":true}},{"node":{"info":{"id":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","name":"node_641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","enode":"enode://97de2f10991b84b4170cadcc248b4222bd846e91b5212930b3a721cb99af24894df3ba5ba33a7b6cc18dd6cbfba935526b69cb0a5e6b93dec26a696f32c580ea@127.0.0.1:0","enr":"0xf88fb840dd1c643add167311c80939c5d5ff43fac27e87b7bff2726cb3d5e156638744383d3370833f2730acccd609cd6d0813ed5993951c83b59cc7b51fe835f7a457d10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10297de2f10991b84b4170cadcc248b4222bd846e91b5212930b3a721cb99af2489","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZBoWX4vg7uNvU8Erro4qNKcJrbjR3NZn6I5OkMnuJAE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 641a16\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 ed12 f611 ce01 c52a | 60 d23c (0) d125 (0) d18a (0) d9d3 (0)\n001 2 1929 034d | 30 1740 (0) 127c (0) 1385 (0) 184e (0)\n002 4 4bc8 459b 58a9 51c2 | 20 5c62 (0) 5cc1 (0) 58a9 (0) 5a8b (0)\n003 6 75e2 772a 77ee 72a7 | 9 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n004 3 6975 68a6 6daa | 3 6975 (0) 68a6 (0) 6daa (0)\n005 2 62f0 6379 | 2 62f0 (0) 6379 (0)\n006 1 672a | 1 672a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 64e6 | 1 64e6 (0)\n009 1 6450 | 1 6450 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","private_key":"f38953abdf59b216747d7c22e600d0f55aa03853782359e4f1d890ee6ccd3795","name":"node_641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","services":["streamer"],"enable_msg_events":true,"port":45833},"up":true}},{"node":{"info":{"id":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","name":"node_51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","enode":"enode://19c4efcab79f59b42b632f546d5075b30aebe0cf70b190e194aa53b3cb07a57e054266625288519f7f1ec51933e8a173ee31de9ae1c3ed7a3e52e881e1320bc2@127.0.0.1:0","enr":"0xf88fb840a924d32fa5c0500800c3babdaeff831b1c13855d864a74e91f06b59765c5112f7d5587255be9743f22305b6b734594f50af53545f49998d89400accb44da1a7c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10219c4efcab79f59b42b632f546d5075b30aebe0cf70b190e194aa53b3cb07a57e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UcKFSJ/xRigmiuiGlF4c0tpkxqCoyxhKramFZ6tCm24=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 51c285\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ce01 8fb8 957e bddb | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 3 1385 1929 3590 | 30 1740 (0) 127c (0) 1385 (0) 184e (0)\n002 5 7bee 772a 72a7 6379 | 18 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n003 7 4746 4efa 4d75 4cc2 | 11 4589 (0) 459b (0) 4775 (0) 4746 (0)\n004 4 5cc1 5c62 58a9 5be6 | 5 5c62 (0) 5cc1 (0) 58a9 (0) 5a8b (0)\n005 1 55fd | 1 55fd (0)\n============ DEPTH: 6 ==========================================\n006 1 52b4 | 1 52b4 (0)\n007 1 5008 | 1 5008 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","private_key":"21aeef42b1bca1386305b8a2618ef22c9d57c0a69e14dacf5e9b23b4bd23b510","name":"node_51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","services":["streamer"],"enable_msg_events":true,"port":34421},"up":true}},{"node":{"info":{"id":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","name":"node_3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","enode":"enode://dd24910cfba19349898ab2b4cf2312f77e8c9cbaecebe966a4a599e93acd4ab317c4f64219c14c87eff8676c5f7fba8c5077c9bab707839809585cf3c19e6128@127.0.0.1:0","enr":"0xf88fb8402ed923c581464c45b4e676ff07c79106b7ceff7a57d96353d044e4d884c8a90116f8ec71e379e0311d071f53601855786da347a3d69d1aae9b1d3a07292ecd090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102dd24910cfba19349898ab2b4cf2312f77e8c9cbaecebe966a4a599e93acd4ab3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NZCvzRD7j1jDn3IGhmHZp3K3fg79V7vWAwZjL7BI+jo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3590af\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 8b35 957e a9fa bddb | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 7 7bcb 7bee 772a 6379 | 38 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n002 4 0639 034d 1385 1929 | 13 1740 (0) 127c (0) 1385 (0) 184e (0)\n003 6 2dd4 2803 221c 216e | 11 2dd4 (0) 2d53 (0) 2803 (0) 2354 (0)\n004 3 3e19 3871 3b83 | 3 3e19 (0) 3b83 (0) 3871 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 36d5 3775 | 2 36d5 (0) 3775 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","private_key":"1835770333937be27e295723616d36666fa8de13a77c315e3b4697160def434c","name":"node_3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","services":["streamer"],"enable_msg_events":true,"port":32919},"up":true}},{"node":{"info":{"id":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","name":"node_6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","enode":"enode://6d3336dba794e0658e4fcbecdb6aa6751876ce7d97023c4c68f1c6cf7fa19f6df34069acfdbbd0df6374dad95a86536fa70adefe67496703bc6cc0ca00bc0d6b@127.0.0.1:0","enr":"0xf88fb840a5c366f1069400f50edc7a3dcf5ced0b5f36fc8ac4add80658a7ae4e069e242d0e234a304d1f3f0906667c9331ecc0ea06215873ca2359615ea2539b09849b710183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036d3336dba794e0658e4fcbecdb6aa6751876ce7d97023c4c68f1c6cf7fa19f6d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZFC7XogEEavLYCWNhWCUn29w2Sunv6mk14RUY8SNqzA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6450bb\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b355 b4e2 b5fc a9fa | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 9 1929 1385 0f31 01a6 | 30 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n002 6 58a9 459b 4bc8 4d75 | 20 4746 (0) 4775 (0) 4589 (0) 459b (0)\n003 7 75e2 77ee 772a 73d0 | 9 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n004 3 6daa 68a6 6975 | 3 68a6 (0) 6975 (0) 6daa (0)\n005 2 62f0 6379 | 2 62f0 (0) 6379 (0)\n006 1 672a | 1 672a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 64e6 | 1 64e6 (0)\n009 1 641a | 1 641a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","private_key":"d9d71e00271234db6e058d9dd56ff836e602ba475c91f715471e599e1bed5a5c","name":"node_6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","services":["streamer"],"enable_msg_events":true,"port":40239},"up":true}},{"node":{"info":{"id":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","name":"node_f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","enode":"enode://29ba5c4d8b75150f0c292d475cbafdcad1c6083b68404ea2c937aff1d74a2c8a718c535eaa698de476e4023d6a8dff115d7a6a18d4ef2df8919f5c0af5369179@127.0.0.1:0","enr":"0xf88fb840c816b422b2f4e87c16b25211009de1d65a9e678d98a60bf481a498341d8bf07f11c27a00cac462bf811b306a3b6f7178df60428c1069862f6eba19f0827d7e8c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329ba5c4d8b75150f0c292d475cbafdcad1c6083b68404ea2c937aff1d74a2c8a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8XfuZ2enile3JdvmfsN39Qf1d300WiiJKw+/uADcRDo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f177ee\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 3775 27db 21dc 5cc1 | 68 0807 (0) 0a21 (0) 0f31 (0) 0e34 (0)\n001 5 aba7 be0f bd48 bddb | 29 a192 (0) acf8 (0) aedc (0) aba7 (0)\n002 6 c52a cc5f ce01 deec | 14 d9d3 (0) dd92 (0) deec (0) d23c (0)\n003 5 eceb ed12 ed2e ea3d | 8 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n004 3 fa9a fac8 fa65 | 3 fa65 (0) fa9a (0) fac8 (0)\n005 2 f611 f4a0 | 2 f4a0 (0) f611 (0)\n============ DEPTH: 6 ==========================================\n006 2 f3d5 f33c | 2 f33c (0) f3d5 (0)\n007 1 f005 | 1 f005 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","private_key":"025f98a103e82b260c7f1e0786cc7c7b322ecac23e4bf433a8c3b6ca3c0a7ce1","name":"node_f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","services":["streamer"],"enable_msg_events":true,"port":40657},"up":true}},{"node":{"info":{"id":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","name":"node_5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","enode":"enode://0411dc978683dba8f21f9b8342e621825888fc4937c3657235a2544564af2cf596f918e981af49789225b6548f0476ddcb2c478c561a7ccf2de5cf175b2bd667@127.0.0.1:0","enr":"0xf88fb8402bd016128d16428094936d2baa4cea722a02b856589d60f027fb7ea3cf0d2d312ea4efc1fb1cc49b83d8d28e225fc859c87d2d63e94977820e53d6c4793e95850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030411dc978683dba8f21f9b8342e621825888fc4937c3657235a2544564af2cf5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W+bfIyAfxcAL5lCEnIv+VYHkQDPvGQEoNvl8mPOVRHE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5be6df\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 957e 9472 bc29 bddb | 60 a192 (0) acf8 (0) aedc (0) aba7 (0)\n001 3 0639 1385 3775 | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 2 72a7 7bcb | 18 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n003 4 4a37 4efa 4c21 4d75 | 11 4775 (0) 4746 (0) 459b (0) 4589 (0)\n004 3 55fd 52b4 51c2 | 4 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n005 2 5c62 5cc1 | 2 5c62 (0) 5cc1 (0)\n============ DEPTH: 6 ==========================================\n006 1 58a9 | 1 58a9 (0)\n007 1 5a8b | 1 5a8b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","private_key":"b70a8c0d588327194e8b81c1f09b2403aa37aa56914bbfd6ef7e9b7c383a61f7","name":"node_5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","services":["streamer"],"enable_msg_events":true,"port":39601},"up":true}},{"node":{"info":{"id":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","name":"node_37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","enode":"enode://9a0c7c70a6abc8d8d6312e26526241fbaac88e2599c2e8ddc70a0d82155c8a19e306a320af2a0b0ba2a91333c804b1d9aaf1ff34059e1560391b141ec0195be3@127.0.0.1:0","enr":"0xf88fb840299e881f43f4d0b0fc892936f7f58feda81693023bf5890163c50e85520efc40047960a98b178845a87a28261d6fd072ea58cc313c5caa59e80ba89e01ca917c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039a0c7c70a6abc8d8d6312e26526241fbaac88e2599c2e8ddc70a0d82155c8a19","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"N3UfJ5ST3FzltcPFWm7C5BGe7e/hBpsoP2/4x7ydFBE=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 37751f\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 ed2e fac8 f611 f177 | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 6 6daa 7bcb 7bee 4d75 | 38 6975 (0) 68a6 (0) 6daa (0) 62f0 (0)\n002 5 0639 034d 1385 184e | 13 0e34 (0) 0f31 (0) 0807 (0) 0a21 (0)\n003 6 2803 2dd4 27db 221c | 11 2dd4 (0) 2d53 (0) 2803 (0) 2354 (0)\n004 3 3e19 3871 3b83 | 3 3e19 (0) 3b83 (0) 3871 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 3590 | 1 3590 (0)\n007 1 36d5 | 1 36d5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","private_key":"bbe213c9c2af2fb4cf312a148364ca68ebecd37b64368e153ea9e51c67042ad5","name":"node_37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","services":["streamer"],"enable_msg_events":true,"port":35275},"up":true}},{"node":{"info":{"id":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","name":"node_8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","enode":"enode://d73cda92a018755888f77a3e564e7551c42f9b0293dce5f7926ad51f152e0608a98f76043b29a2ccee8b56829e6abb11f11bcc8f37138dcff09a22e9883b5da0@127.0.0.1:0","enr":"0xf88fb8406aaa1bd0ce40aedb00ca17a8b54f37666e5fda8c5fd73f70cb28d4f94789bbdd28ccfa1a85414025663af2b020c3b3d80b719d4163d059196efeb1c35caf0e8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d73cda92a018755888f77a3e564e7551c42f9b0293dce5f7926ad51f152e0608","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"j7ggi3Fn3QbMCHeLUHzNhWdR099t+66sGLn1J7ZihSM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8fb820\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 51c2 5cc1 5c62 4efa | 68 4589 (0) 459b (0) 4746 (0) 4775 (0)\n001 5 f005 f611 ed12 d18a | 31 fa9a (0) fac8 (0) fa65 (0) f4a0 (0)\n002 7 b4e2 bc71 bc29 bde9 | 20 a192 (0) acf8 (0) aedc (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 4 8012 836e 8330 8284 | 4 8012 (0) 8330 (0) 836e (0) 8284 (0)\n============ DEPTH: 5 ==========================================\n005 1 8b35 | 1 8b35 (0)\n006 1 8d3e | 1 8d3e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","private_key":"278f3a6445da6b4d5dace451a1c2a3561bdef9784b8326ca0bcae3a8028ed69f","name":"node_8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","services":["streamer"],"enable_msg_events":true,"port":36235},"up":true}},{"node":{"info":{"id":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","name":"node_8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","enode":"enode://5e607646d00042ef14c4f21aea45ea5bd505be570b97f2b1b4ef73a22adf25cde1a8964defec14140b92ef5121092f391b5f2dff5345edd747ebff330059a77f@127.0.0.1:0","enr":"0xf88fb8400a07d6729478c8bd73bee4a5c31564b940112b25c41614e61d55d98ef2e09178170274aae5097d373ef2e01384f6b60f630c75a3185e1254b5a02193b3a74aa90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035e607646d00042ef14c4f21aea45ea5bd505be570b97f2b1b4ef73a22adf25cd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"izUjbamZML+PXvbHVVuxi4DOLjQ2G7v9a69Vpkg+VP8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8b3523\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3590 3871 1929 1385 | 68 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n001 3 ed12 c0ad ce01 | 31 fa9a (0) fac8 (0) fa65 (0) f4a0 (0)\n002 11 aedc a9fa b60e b5fc | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n003 2 957e 9472 | 2 9472 (0) 957e (0)\n004 4 8012 836e 8330 8284 | 4 8012 (0) 836e (0) 8330 (0) 8284 (0)\n============ DEPTH: 5 ==========================================\n005 2 8d3e 8fb8 | 2 8d3e (0) 8fb8 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","private_key":"3322d061eb98b1819a131c74f1241090bf160874985ca4e58cc11e1286ac0c3a","name":"node_8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","services":["streamer"],"enable_msg_events":true,"port":40641},"up":true}},{"node":{"info":{"id":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","name":"node_7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","enode":"enode://466c01046515dee738d0579e73a747c68ced8223155312c012c3f51c97298abc594772c6662ce7511bc515aac473d52bb9bbcf8e44b04576ed927cdcc214dab9@127.0.0.1:0","enr":"0xf88fb840fe0d278bd98464c794a3d0874a16b75432ba8b26f9011bfccc1461bc081260dc5b2fad42936698153126bd2792daec579d9481ecf3c53f7a9efaf80cb867b9240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103466c01046515dee738d0579e73a747c68ced8223155312c012c3f51c97298abc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e8sNe5+ErtQTz5sqeFG6bRE42FOCqiDmyTmkPI5ZwDQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7bcb0d\npopulation: 46 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 c52a ce01 d18a d125 | 60 fac8 (0) fa9a (0) fa65 (0) f4a0 (0)\n001 14 1929 127c 1385 034d | 30 0a21 (0) 0807 (0) 0e34 (0) 0f31 (0)\n002 6 4a37 4bc8 4efa 4cc2 | 20 459b (0) 4589 (0) 4775 (0) 4746 (0)\n003 4 6daa 672a 6450 641a | 9 6975 (0) 68a6 (0) 6daa (0) 672a (0)\n004 6 73d0 72a5 72a7 75e2 | 6 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 7a68 | 1 7a68 (0)\n008 0 | 0\n009 0 | 0\n010 1 7bee | 1 7bee (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","private_key":"a18a91aea9caebd371fccc6f16fbdbae7309ab0a75d82690d6762dfbf43e8237","name":"node_7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","services":["streamer"],"enable_msg_events":true,"port":34329},"up":true}},{"node":{"info":{"id":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","name":"node_27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","enode":"enode://81447592a9952d8e82cbde99d9a3a804c8251313e257587d4fd1441ccab4589209ef2eca6be2a90dd162a15afa8fa1c46112377c94317e710a692ebf3ecab3f5@127.0.0.1:0","enr":"0xf88fb84050691fa1ed8df80d90662ae933a8efbb5e3a89c1e11702c156c0c4d86c410f626a9409a01ad627a3bf48c1f787d9e70306cb6bc2068a36b1d5a6fb5c814b171b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10381447592a9952d8e82cbde99d9a3a804c8251313e257587d4fd1441ccab45892","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J9tm0T7oForKiXhv69aXHdHWxVS8qFAQUgZctHYxVg0=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 27db66\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f611 f177 f33c 957e | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 6 4d75 4efa 4bc8 4a37 | 38 459b (0) 4589 (0) 4775 (0) 4746 (0)\n002 4 034d 0639 1385 1929 | 13 0807 (0) 0a21 (0) 0e34 (0) 0f31 (0)\n003 5 3871 3b83 3775 36d5 | 6 3e19 (0) 3b83 (0) 3871 (0) 3590 (0)\n004 3 2d53 2dd4 2803 | 3 2dd4 (0) 2d53 (0) 2803 (0)\n005 5 2354 22bb 221c 216e | 5 2354 (0) 22bb (0) 221c (0) 216e (0)\n============ DEPTH: 6 ==========================================\n006 1 2471 | 1 2471 (0)\n007 0 | 0\n008 0 | 0\n009 1 27b5 | 1 27b5 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","private_key":"0a5ec02539f87d3f1bbe5e084133ad7fc6656fcc73cc18afb174f48e0bf9d670","name":"node_27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","services":["streamer"],"enable_msg_events":true,"port":35267},"up":true}},{"node":{"info":{"id":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","name":"node_bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","enode":"enode://838a4d55191548d17c665566c483b72340302b64549e2745f5e0d48c4e0e76359349919ae4cd0afacd5a4d9da24aebb15ca6d9bf5a028223df52d12f3aa2b77e@127.0.0.1:0","enr":"0xf88fb840ed735da037c65b1531755f40ecb8315e80fed6331af749996e684fbbf86560aa2ffdad12f343a38edb1feefc8de2de8de90416ea256ed794d06e29aa212e9cf00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102838a4d55191548d17c665566c483b72340302b64549e2745f5e0d48c4e0e7635","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vCmg2bYPPiw0IkzsGHz0Tq3EYoCG1VlGZu0CXacefno=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bc29a0\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 4d75 5be6 51c2 1929 | 68 4589 (0) 459b (0) 4775 (0) 4746 (0)\n001 6 cabf d18a f005 f611 | 31 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n002 6 8330 8284 8b35 8fb8 | 9 9472 (0) 957e (0) 8012 (0) 836e (0)\n003 4 aedc aba7 a9fa a192 | 6 a192 (0) acf8 (0) aedc (0) aba7 (0)\n004 3 b355 b5fc b4e2 | 5 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n005 2 b9d9 b869 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n============ DEPTH: 7 ==========================================\n007 4 bd48 bd96 bde9 bddb | 4 bd48 (0) bd96 (0) bde9 (0) bddb (0)\n008 0 | 0\n009 1 bc71 | 1 bc71 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","private_key":"2cf6d0e467db44e155c5ad07c701eba3784d380456d0bd1e248e88e4bd50db52","name":"node_bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","services":["streamer"],"enable_msg_events":true,"port":43139},"up":true}},{"node":{"info":{"id":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","name":"node_1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","enode":"enode://faa781fe46eab677d200731251f2be1aede682a047df2f555335072653b2cf1ad6b90a43c223c2567e8eb00b40a89e31b5d22ddd20563a80e01232f1ba4e151b@127.0.0.1:0","enr":"0xf88fb84098c7e67161c619f0c3c62c007544d6ea9adb3dbc6b48de51b49786232388fca74a3c88c994b07222dfcbba9fb8dbdd2711d9aa0c33c94ecef3d10b9e0e9ab7e20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103faa781fe46eab677d200731251f2be1aede682a047df2f555335072653b2cf1a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GSmwHA+Fr3RSoPNYtU9rNmQKGWs2aQkXKvWUoWSP5kw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1929b0\npopulation: 39 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f005 d23c ce01 8b35 | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 13 4746 4d75 4efa 4a37 | 38 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n002 11 3871 3e19 3590 36d5 | 17 3b83 (0) 3871 (0) 3e19 (0) 3590 (0)\n003 4 0e34 0a21 0639 034d | 8 0f31 (0) 0e34 (0) 0807 (0) 0a21 (0)\n============ DEPTH: 4 ==========================================\n004 3 1740 127c 1385 | 3 1740 (0) 127c (0) 1385 (0)\n005 0 | 0\n006 0 | 0\n007 1 184e | 1 184e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","private_key":"f3de60891a8eef22fd764c76d7b6d43b2af723a9731661df6e11020da0718b7c","name":"node_1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","services":["streamer"],"enable_msg_events":true,"port":41623},"up":true}},{"node":{"info":{"id":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","name":"node_ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","enode":"enode://1c368e379ede78380a9710e4d82c88489f66cbc28792aff7702313c087a47b0289a9c8db20c4181b75184f84aac33116cb707ffe2e01e033f014f7f14a082ef1@127.0.0.1:0","enr":"0xf88fb84077b68fee63a81bffa263efd74f643a807ceacce488968c34836eeedf7883e9da6c52dcd816863207878248ea60ba2d67c99473148fe275966dad15341798430d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031c368e379ede78380a9710e4d82c88489f66cbc28792aff7702313c087a47b02","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zgEjRmEwkSe7hy1p043Fvxm8TeLgoLUEHNNi0HPfT/g=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ce0123\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 7bcb 772a 72a7 641a | 68 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n001 6 b4e2 a9fa 8fb8 8b35 | 29 a192 (0) acf8 (0) aedc (0) aba7 (0)\n002 6 fac8 f611 f177 f005 | 17 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n003 5 deec dd92 d23c d18a | 6 d9d3 (0) dd92 (0) deec (0) d23c (0)\n004 2 c52a c0ad | 3 c52a (0) c2f9 (0) c0ad (0)\n005 2 c9ef cabf | 2 c9ef (0) cabf (0)\n============ DEPTH: 6 ==========================================\n006 2 cc9f cc5f | 2 cc5f (0) cc9f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","private_key":"95cc1ce48219ce51e9d9520f9ed3968f753d9bce3da5e3bd7ea9362f1f51a509","name":"node_ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","services":["streamer"],"enable_msg_events":true,"port":45409},"up":true}},{"node":{"info":{"id":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","name":"node_957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","enode":"enode://8b3a82a0b62bf9f4fe01d9c72712b70dd78140dfd808de3b5d4e2daa6d1e0bc78137035a1c4888ca82d1ae29cd2ed1e42db6210f629a415080082cacbcf3bf48@127.0.0.1:0","enr":"0xf88fb84018ff9330c436aa3ccef762f9c9a9d020113f1b7b955b454631d5bcc2c441ce99132e51acf27ba2589be6a6d018a52f3110342b94391caa43e26f3ba790a0248f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028b3a82a0b62bf9f4fe01d9c72712b70dd78140dfd808de3b5d4e2daa6d1e0bc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lX7WGU5u9W6Wlr5DoaAljyuk9I9W15DkK9BmPD/Gqq4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 957ed6\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 1929 034d 2803 2471 | 68 3e19 (0) 3b83 (0) 3871 (0) 3590 (0)\n001 7 f005 f3d5 f611 dd92 | 31 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n002 7 a9fa b4e2 b355 bc71 | 20 a192 (0) aedc (0) acf8 (0) aba7 (0)\n============ DEPTH: 3 ==========================================\n003 7 8b35 8d3e 8fb8 8012 | 7 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 9472 | 1 9472 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","private_key":"c249537590c459e98e22f7a70786699bfd3c23aef26288b9f589ee97574d33cc","name":"node_957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","services":["streamer"],"enable_msg_events":true,"port":42809},"up":true}},{"node":{"info":{"id":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","name":"node_6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","enode":"enode://9b66200ba83d63d75740082432f6c3831ad635f6d3fe228458bd67d7e49cbaa1df293dffbf9406b165a041c7d284b6979057355ab46f925a4ae75a21e35fdf2e@127.0.0.1:0","enr":"0xf88fb8403156b1191369fe50cd749c6aac2c8795c35461c3f5bcc76313ab9a54c9248041081d5084353de2c4357294d870533e298b6954e3d9ca93644323f9cbaefb2a5b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029b66200ba83d63d75740082432f6c3831ad635f6d3fe228458bd67d7e49cbaa1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Y3m01hHN1uNgSAwUs/Z4Q2Dyj3ArWm83XtpO873n7zM=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6379b4\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bddb 957e | 60 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n001 2 3590 1929 | 30 0807 (0) 0a21 (0) 0f31 (0) 0e34 (0)\n002 6 4cc2 58a9 5cc1 5c62 | 20 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n003 5 7a68 75e2 772a 73d0 | 9 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n004 3 6daa 68a6 6975 | 3 6975 (0) 68a6 (0) 6daa (0)\n============ DEPTH: 5 ==========================================\n005 4 672a 64e6 6450 641a | 4 672a (0) 64e6 (0) 641a (0) 6450 (0)\n006 0 | 0\n007 1 62f0 | 1 62f0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","private_key":"024d0a70b86bc13cf4efc5e5bd5144a351300f43a58a6e6b95684a79ddd6fa69","name":"node_6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","services":["streamer"],"enable_msg_events":true,"port":38231},"up":true}},{"node":{"info":{"id":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","name":"node_bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","enode":"enode://fee39a564023c233a4363d4b025275561497b7b7c8e82b20160ec71631ec4adebe8afa63a77c3eb4a2d29f8c5038d08cc1ae180ea5bc95ed479297b2eaf84354@127.0.0.1:0","enr":"0xf88fb8408b6f5d1b485209e0c27b986c8f1f4356f21252247a203ff1e10fe4d511299bb01096acece8f2bf01e7674f4a3b9f315ecced47e671df32ae11bc7dcde6c0636d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fee39a564023c233a4363d4b025275561497b7b7c8e82b20160ec71631ec4ade","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vdvf88vSL87d3AfeJxJYGarHK+csMSa6iYYhxJbLlaI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bddbdf\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3590 4d75 5be6 51c2 | 68 0f31 (0) 0e34 (0) 0807 (0) 0a21 (0)\n001 2 f177 ed12 | 31 d9d3 (0) dd92 (0) deec (0) d23c (0)\n002 5 9472 957e 8fb8 8b35 | 9 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n003 3 a192 aba7 a9fa | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 3 b5fc b4e2 b355 | 5 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n005 2 b9d9 b869 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc71 bc29 | 2 bc71 (0) bc29 (0)\n008 1 bd48 | 1 bd48 (0)\n============ DEPTH: 9 ==========================================\n009 1 bd96 | 1 bd96 (0)\n010 1 bde9 | 1 bde9 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","private_key":"4d7f0353e69c74cd0ffd1788c11c34ed5bf024705a9d91fcc91364dcc0170d44","name":"node_bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","services":["streamer"],"enable_msg_events":true,"port":40129},"up":true}},{"node":{"info":{"id":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","name":"node_82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","enode":"enode://e2446d4ba20cf04f7587b21f065505bf06a0b763ad10228db7fac2f3d0ce85b065c6ae7856d0cf0de33e54f769d982a19db0166690996d05cfe8789eefcd061c@127.0.0.1:0","enr":"0xf88fb840390e501e8aea6582161ebc4735fea5ea709f34fdce68c3bea1d8ac01a9bee38b1f74f6c9802e7101930fa56f8379569b9e68aeca2f58c3af3f64fc0346e8bf000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e2446d4ba20cf04f7587b21f065505bf06a0b763ad10228db7fac2f3d0ce85b0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"goR6SvT1BiJlDQNfaRUbICvM1fySMCphdgLJdGA+2Zc=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82847a\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 72a7 75e2 772a 7a68 | 68 6975 (0) 68a6 (0) 6daa (0) 62f0 (0)\n001 7 dd92 d23c d18a d125 | 31 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n002 8 aedc a9fa b355 b4e2 | 20 a192 (0) acf8 (0) aedc (0) aba7 (0)\n003 2 9472 957e | 2 9472 (0) 957e (0)\n004 2 8b35 8fb8 | 3 8b35 (0) 8d3e (0) 8fb8 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 8012 | 1 8012 (0)\n007 2 836e 8330 | 2 8330 (0) 836e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","private_key":"8ad165530adf15657647eec0c9ad139e69f7656f1deca7792c1fc0de289a1add","name":"node_82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","services":["streamer"],"enable_msg_events":true,"port":45695},"up":true}},{"node":{"info":{"id":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","name":"node_2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","enode":"enode://89fa1305c12aff15670cc1bd8b563b83fe9f1674d1001a07b9603e7da4f267a84dfb81b00c1b2a8b6515fa90ad36b8790ed0d0bca1509e9bf434327d50ff6375@127.0.0.1:0","enr":"0xf88fb840f7c3b1530907dfcb9ba22825a0bac829dd204d31f686d97d7f4481599308bb0536112276a86c5ce46f913fb6817457bd19a2b684046c47fcbd14827391e52f080183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10389fa1305c12aff15670cc1bd8b563b83fe9f1674d1001a07b9603e7da4f267a8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KAPyEutKpPSSJLFrLeiLqGUq0RUyHuHmDNvZJuza04o=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2803f2\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 957e 8284 f005 e06f | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 9 6450 64e6 672a 7bee | 38 6daa (0) 68a6 (0) 6975 (0) 62f0 (0)\n002 3 034d 184e 1929 | 13 0f31 (0) 0e34 (0) 0a21 (0) 0807 (0)\n003 4 3e19 3590 3775 36d5 | 6 3e19 (0) 3871 (0) 3b83 (0) 3590 (0)\n004 8 22bb 221c 2354 216e | 8 2471 (0) 27b5 (0) 27db (0) 2354 (0)\n============ DEPTH: 5 ==========================================\n005 2 2dd4 2d53 | 2 2dd4 (0) 2d53 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","private_key":"b37365e96591f61ba1f1f4c9438ef43bd78f2207737972de4ecc9bc85640c7c5","name":"node_2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","services":["streamer"],"enable_msg_events":true,"port":46045},"up":true}},{"node":{"info":{"id":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","name":"node_ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","enode":"enode://0b74c99f74b309c85f91b8ac4c7ebd527e900a0e3ec1355dfbfcc3f9e3bdeba8f75f27696f1412ccfa6d1580c769641f74289f5ac39347e2af880b54dbe1bdb4@127.0.0.1:0","enr":"0xf88fb840d82da58cd4d87e8a9a7bc9fa59302a31d713ec01ba8a8a0f3c989a2975ed12a41cec56ba3214c6dff113d27ed34285dd89654def2164131e72eb4d7fa553aacb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020b74c99f74b309c85f91b8ac4c7ebd527e900a0e3ec1355dfbfcc3f9e3bdeba8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7RLHjnAL+AVmnEil1i8eVnkSY8SyzlvTRYfqm8kxo+U=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed12c7\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 641a 72a7 7bcb 4d75 | 68 6daa (0) 68a6 (0) 6975 (0) 6379 (0)\n001 6 be0f bc29 bddb 8fb8 | 29 a192 (0) aedc (0) acf8 (0) aba7 (0)\n002 9 d23c d125 d18a dd92 | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 5 fa65 f33c f177 f005 | 9 fa65 (0) fa9a (0) fac8 (0) f4a0 (0)\n004 1 e06f | 1 e06f (0)\n005 2 eb01 ea3d | 2 eb01 (0) ea3d (0)\n006 2 efd6 ee2b | 2 efd6 (0) ee2b (0)\n============ DEPTH: 7 ==========================================\n007 1 eceb | 1 eceb (0)\n008 0 | 0\n009 0 | 0\n010 1 ed2e | 1 ed2e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","private_key":"f54883fc517f0e3c2eddab9bdc23da7263abbb18620926ea60fdc8e1c54f341e","name":"node_ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","services":["streamer"],"enable_msg_events":true,"port":41603},"up":true}},{"node":{"info":{"id":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","name":"node_4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","enode":"enode://ed37ba950278a3c20524b27d1e9a25e94d01f5fa944c8c34d28feea810dc7c9ff037e34daa95ad6d532439949b2f4ce551f3e01eb652ca662e40b561560bf690@127.0.0.1:0","enr":"0xf88fb84074cdf17f902a07b1fe1cf0d4977a986ae645bb8d982f6feeae2a955a91b8eb3b25a8c65e204fbb42b090a2ca073f7de07f6fe8bb3ae3dc993c9f193ce5f800930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ed37ba950278a3c20524b27d1e9a25e94d01f5fa944c8c34d28feea810dc7c9f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TXUGZtwOniwkTENJKAHB1+xiCJVKDLX4u3k7kSRAdTo=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d7506\npopulation: 45 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 957e 8fb8 b869 bddb | 60 a192 (0) aedc (0) acf8 (0) aba7 (0)\n001 14 127c 1385 1929 184e | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 4 672a 6450 75e2 7bee | 18 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n003 4 52b4 51c2 5c62 5be6 | 9 55fd (0) 52b4 (0) 5008 (0) 51c2 (0)\n004 4 4589 459b 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 3 4bc8 4a3c 4a37 | 3 4a3c (0) 4a37 (0) 4bc8 (0)\n006 1 4efa | 1 4efa (0)\n============ DEPTH: 7 ==========================================\n007 2 4c21 4cc2 | 2 4cc2 (0) 4c21 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","private_key":"86b527d54feaa68feaa47006bfdddb5ed3db2af4f2d2c66c08442c78bfddeb4a","name":"node_4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","services":["streamer"],"enable_msg_events":true,"port":43481},"up":true}},{"node":{"info":{"id":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","name":"node_7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","enode":"enode://ee6f1a851bbd2d48a78f56ee08516649226a2b2c490ecede0f8144fd1bd0c94113ed85d0f117ed7d577e6ca4fc62f21ff3f1bc4fda1504ef8f9120b7836fa78b@127.0.0.1:0","enr":"0xf88fb840d7c73ae301629d49e06baa43aba331e7eabb685bf4c4d420b746acdbf05acb7b2468e5c944470383ac2d8aeb608a478c483b1d7fd866cec2f9b38244934394260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ee6f1a851bbd2d48a78f56ee08516649226a2b2c490ecede0f8144fd1bd0c941","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e+55Z/97ByQ77VW20GDV7CofKLUw7WXNBV3FtGig+Hg=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7bee79\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 b4e2 8284 8fb8 9472 | 60 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n001 7 184e 1929 3590 3775 | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 5 51c2 52b4 4bc8 4efa | 20 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n003 4 6daa 68a6 64e6 672a | 9 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n004 6 77ee 772a 75e2 73d0 | 6 77ee (0) 772a (0) 75e2 (0) 73d0 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 7a68 | 1 7a68 (0)\n008 0 | 0\n009 0 | 0\n010 1 7bcb | 1 7bcb (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","private_key":"2ba96f376fb0ff9f7f829af5f4ac836ee1973e1a0198f5e9fcdfd002aa55f7db","name":"node_7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","services":["streamer"],"enable_msg_events":true,"port":45185},"up":true}},{"node":{"info":{"id":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","name":"node_d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","enode":"enode://111a2f319dc9db157c329c910ac39ad991b4a51e524947cdef3771765b1de028196a000955e727277027e2120a5fc6a1ad482b9b905988222c43895d74b496da@127.0.0.1:0","enr":"0xf88fb8404522aa5ddd38e1612c0c481686380332cc9624a872608456ad811feebe30a98e417d969aa10b1db80af028c334406d20531319decbc1dc63339222303e8379a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102111a2f319dc9db157c329c910ac39ad991b4a51e524947cdef3771765b1de028","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0Yoe3SZmEGn7QB/uiqhalhSjGI4uBma/6TB/kdKarUk=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d18a1e\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4a37 641a 7bcb 7bee | 68 0e34 (0) 0f31 (0) 0a21 (0) 0807 (0)\n001 7 a9fa b4e2 bc29 8284 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 9 e06f ed2e ed12 ea3d | 17 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n003 5 c52a c0ad cabf cc5f | 8 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n004 3 d9d3 deec dd92 | 3 d9d3 (0) deec (0) dd92 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 d23c | 1 d23c (0)\n007 0 | 0\n008 1 d125 | 1 d125 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","private_key":"1254e1b68ce774b5f389113becbac1ac48e7cd670611899a781849e45f626f93","name":"node_d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","services":["streamer"],"enable_msg_events":true,"port":36067},"up":true}},{"node":{"info":{"id":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","name":"node_f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","enode":"enode://44c0501c60e75da3cff66ec0cc1f38a048f0236760ae5a715e180477166acef0f3861d57d16ece9860e9ab79f1d0c0d8d2e72d224b7b2efeaef3851ee781dd2c@127.0.0.1:0","enr":"0xf88fb840c322770a94cf0d299ed2c66f6698f6cc8cf2c1297f7f1f0f4db86c08c7eb44b2451dc9ee8f9f0e2a30068eb28c80097b8413bfb5bbbb41ec8bb3f2b3d9a384e30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10244c0501c60e75da3cff66ec0cc1f38a048f0236760ae5a715e180477166acef0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8AWk00U9UkNPK1vkAG5lO1C1KtMZJtZUci/D3wDxaJw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f005a4\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 2803 3775 36d5 034d | 68 0807 (0) 0a21 (0) 0f31 (0) 0e34 (0)\n001 12 8fb8 8012 8330 8284 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 2 ce01 d18a | 14 c52a (0) c2f9 (0) c0ad (0) c9ef (0)\n003 3 eceb ed12 ed2e | 8 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n004 2 fa65 fac8 | 3 fa65 (0) fa9a (0) fac8 (0)\n005 2 f4a0 f611 | 2 f4a0 (0) f611 (0)\n============ DEPTH: 6 ==========================================\n006 2 f33c f3d5 | 2 f33c (0) f3d5 (0)\n007 1 f177 | 1 f177 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","private_key":"22efd63c6544702dc87aeb332bfd579220f67ee8aeb6de7e8d074f5c0bc7406d","name":"node_f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","services":["streamer"],"enable_msg_events":true,"port":35571},"up":true}},{"node":{"info":{"id":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","name":"node_4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","enode":"enode://8932a57b3a5d0667185be53dfc1c53a171fb4ed6de334b49c24440e48bd85288cb827ff2141fedab03949eaaac6340211b64e434f80dc83e4c21b24e907b54aa@127.0.0.1:0","enr":"0xf88fb84026d7e9844328cc3aead03b756a7922f94121db28001850d34df1b7f2513ec69e30437cc7a321d10338c447945422db8b68c70409fd74fb560da1a45823fa40840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028932a57b3a5d0667185be53dfc1c53a171fb4ed6de334b49c24440e48bd85288","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Sjc1cUdeK0woDS1LIvEKJJ7gn8+Qf1IIHsA5iotepvI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a3735\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8fb8 a9fa d18a fac8 | 60 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n001 5 216e 27db 36d5 3775 | 30 0e34 (0) 0f31 (0) 0807 (0) 0a21 (0)\n002 7 7bcb 7a68 73d0 72a7 | 18 75e2 (0) 77ee (0) 772a (0) 73d0 (0)\n003 6 5cc1 5c62 58a9 5be6 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 2 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 4 4efa 4cc2 4c21 4d75 | 4 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4bc8 | 1 4bc8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 4a3c | 1 4a3c (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","private_key":"01b16147c78c71594879cbc9eace48bccf5f46f6c50604ec8fee98e1e91914b2","name":"node_4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","services":["streamer"],"enable_msg_events":true,"port":43203},"up":true}},{"node":{"info":{"id":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","name":"node_a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","enode":"enode://37b1fbaed8a69d74dcb79c7269e934ef02b048bc42b77b82e5e62866160ba5cad476950f99f99285f882b0a904a19b9cc97400347dd8913ebdbf6698e62f4490@127.0.0.1:0","enr":"0xf88fb840651a030a5371bc567448dc8f7027e7e4d9aca1dffba13e9503cbd1be66c51de02e5ee41bbc0d27c11c4d68d95ed088f1108e358ae435ebb57803627f6d7712ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10237b1fbaed8a69d74dcb79c7269e934ef02b048bc42b77b82e5e62866160ba5ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qfooEXpLaQa1zjkxVz4KGe7Dy0/NkUG+LSWKK+BvO2E=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a9fa28\npopulation: 46 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 2471 3590 68a6 6450 | 68 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n001 14 d18a d125 d23c dd92 | 31 c52a (0) c2f9 (0) c0ad (0) cc9f (0)\n002 7 9472 957e 8b35 8d3e | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 12 b245 b355 b60e b4e2 | 14 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n004 1 a192 | 1 a192 (0)\n005 2 aedc acf8 | 2 aedc (0) acf8 (0)\n============ DEPTH: 6 ==========================================\n006 1 aba7 | 1 aba7 (0)\n007 1 a861 | 1 a861 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","private_key":"eea6155ca80745d78b3a9c8c63fc2618254022771e70abd50cc80a7bcee4129c","name":"node_a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","services":["streamer"],"enable_msg_events":true,"port":35285},"up":true}},{"node":{"info":{"id":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","name":"node_4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","enode":"enode://83716365bf8c5748254c76a38079e43293468d4a67d489df3092fc33447390a566e18708a5ef396134e35ca5f2ff58e96ea27ed6941bc20dc6c3d1be57960d9b@127.0.0.1:0","enr":"0xf88fb840beee55803b074f7f9ec59bf2276feeb7849256026ecb0b230f47905554a0b7721dc5f36ac09fcad8662a9da7962463ba1c8380d27ebc363edf966b1b4fffd7970183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10383716365bf8c5748254c76a38079e43293468d4a67d489df3092fc33447390a5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Tvqrqw1dxZ8Jiu5NujhoJjQRpVYVosR0pz5u7CIR3sw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4efaab\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f4a0 fac8 8fb8 bde9 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 1929 216e 27db 2803 | 30 0a21 (0) 0807 (0) 0f31 (0) 0e34 (0)\n002 6 7bee 7bcb 72a7 72a5 | 18 73d0 (0) 72a7 (0) 72a5 (0) 77ee (0)\n003 5 52b4 51c2 5cc1 5c62 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 4 459b 4589 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 3 4bc8 4a37 4a3c | 3 4a3c (0) 4a37 (0) 4bc8 (0)\n============ DEPTH: 6 ==========================================\n006 3 4cc2 4c21 4d75 | 3 4cc2 (0) 4c21 (0) 4d75 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","private_key":"9adb7214565c62d93b6daada5fb947a4aa641f07396dc29def6a399d06534b3f","name":"node_4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","services":["streamer"],"enable_msg_events":true,"port":41679},"up":true}},{"node":{"info":{"id":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","name":"node_bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","enode":"enode://18c5769fcc3cebeb0f8151e2f4b84902c268fe8db07c01b90e0992abf123891768735738fa07913a22d143ae1b0852d830f7b49fd9b022b48765b518bccf8166@127.0.0.1:0","enr":"0xf88fb84006231adc86baddad575a6b04c656320bf5c226c2f4907c98a80d09ffd30a9c5e5f4ef4e17a92c907e3fa90a57634dec8277905a2298a73fea645bf359a400e910183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10218c5769fcc3cebeb0f8151e2f4b84902c268fe8db07c01b90e0992abf1238917","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vekKqg8fen65Zf8whxjSm1WoCxyoTfuhbBaeq+Kw1d4=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bde90a\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5be6 4bc8 4d75 4efa | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 2 e06f ed2e | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 6 957e 8fb8 8b35 8012 | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 3 a9fa a861 a192 | 6 a192 (0) aedc (0) acf8 (0) aba7 (0)\n004 3 b4e2 b245 b355 | 5 b60e (0) b5fc (0) b4e2 (0) b245 (0)\n005 2 b9d9 b869 | 2 b9d9 (0) b869 (0)\n006 1 be0f | 1 be0f (0)\n007 2 bc71 bc29 | 2 bc71 (0) bc29 (0)\n008 1 bd48 | 1 bd48 (0)\n============ DEPTH: 9 ==========================================\n009 1 bd96 | 1 bd96 (0)\n010 1 bddb | 1 bddb (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","private_key":"5c9ecf07c02ad229e4278ffee6d3f401fd8e6605ec8cda65cd1de164bdb2c4c9","name":"node_bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","services":["streamer"],"enable_msg_events":true,"port":37049},"up":true}},{"node":{"info":{"id":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","name":"node_b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","enode":"enode://05ec349b77cce593afc87d277f22c4664825e5cda0f4685461bf1161b262a3c29837580c1f80a96fd1953be71e7083284fbb28a7cbd63df5ceea63f89d1c429d@127.0.0.1:0","enr":"0xf88fb8403b39c4a274c55d5fda8b8b8e52dfdb970bff69c0055370a4553ff68fd90d149f41ff2b874b4b9c2258a91d1256de830ec8c0ea3cf7881acab5e8dce0fff835bb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10305ec349b77cce593afc87d277f22c4664825e5cda0f4685461bf1161b262a3c2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s1VbqnZMRWKTW5NTPubFpt9jHoRsOrUS/bHWuQGmjGA=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b3555b\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 3775 3e19 184e 1929 | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 3 f005 e06f ed2e | 31 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n002 5 957e 8b35 8012 8284 | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 3 a9fa a861 a192 | 6 a192 (0) acf8 (0) aedc (0) aba7 (0)\n004 9 b9d9 b869 be0f bc29 | 9 b9d9 (0) b869 (0) be0f (0) bc71 (0)\n============ DEPTH: 5 ==========================================\n005 3 b60e b4e2 b5fc | 3 b60e (0) b5fc (0) b4e2 (0)\n006 0 | 0\n007 1 b245 | 1 b245 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","private_key":"590969da498fe95b0a99340a0c185e65d4cc9eb3ee04b3629e91bdc6b8ce18c6","name":"node_b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","services":["streamer"],"enable_msg_events":true,"port":39871},"up":true}},{"node":{"info":{"id":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","name":"node_4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","enode":"enode://29d89497ada4c78fa702d02812539dddff2d5b2a38b2eabf3ccca262ca18d8a7781a78b87287b1d2e204171814e04a54d268c692c64f9da0079ff9b143f8b386@127.0.0.1:0","enr":"0xf88fb840933154156e40944b295ca276bd44fdccde6fa8f9ca5ec52169c14e3d609078a3554a271fdcc0e539e728506b39331131141632c216ce5728688f16aa2367a0590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10229d89497ada4c78fa702d02812539dddff2d5b2a38b2eabf3ccca262ca18d8a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"S8jfv4R5TSbXpXPJ2JiXTqo6IWfhnLeoqkYIB6YDrNQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4bc8df\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f4a0 fac8 d125 bde9 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 4 184e 216e 27db 36d5 | 30 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n002 10 6450 641a 6975 68a6 | 18 73d0 (0) 72a7 (0) 72a5 (0) 77ee (0)\n003 4 5a8b 5c62 52b4 51c2 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 3 4589 4775 4746 | 4 459b (0) 4589 (0) 4775 (0) 4746 (0)\n005 4 4efa 4d75 4cc2 4c21 | 4 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 4a37 4a3c | 2 4a3c (0) 4a37 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","private_key":"2b3a544890fa52405c7779653a8a4e5269283d9f341ab7aa99823d9135a96263","name":"node_4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","services":["streamer"],"enable_msg_events":true,"port":44129},"up":true}},{"node":{"info":{"id":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","name":"node_d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","enode":"enode://d2dec9507d007942f28636ef9f81f1a1a872649603fd6a91663cd0130f4cda18defe6e621a84a16b090128c8f34cb74030ccb6da91c4d4f738ef2fc72fa7a14a@127.0.0.1:0","enr":"0xf88fb840625c10b99f412c5021f6b462a097936033b6ce377281de62adfcf031f36be69c099ffbd4039c05d2c01fd4020579a384db855daf9ddae3b84112d2ba0fd359000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d2dec9507d007942f28636ef9f81f1a1a872649603fd6a91663cd0130f4cda18","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0SUxe0kt9Gp91JbTDG0Hg57Wv6GWq95Ihs57yPm1wB8=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d12531\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 72a7 7bcb 641a 672a | 68 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n001 6 8012 8330 8284 b4e2 | 29 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n002 7 ea3d ed12 ed2e ee2b | 17 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n003 6 c52a c0ad cabf cc5f | 8 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n004 3 d9d3 deec dd92 | 3 d9d3 (0) deec (0) dd92 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 d23c | 1 d23c (0)\n007 0 | 0\n008 1 d18a | 1 d18a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","private_key":"f481929f9772f78b97a8f3aec412d8fcce1c6413a74f05ae88a2a1f966ac73ea","name":"node_d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","services":["streamer"],"enable_msg_events":true,"port":35019},"up":true}},{"node":{"info":{"id":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","name":"node_672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","enode":"enode://7b6be04d1749751b5092a9e161b023476c969249f8f813aaa7d55bb11ea59589a48186fdbd5669729d96c2e6aa36e602be0dd2affbb4f9b746cffe9d6ce980c6@127.0.0.1:0","enr":"0xf88fb840a265ed80e2605099ff7573c1400c1e72f63aeba4a2ab3fa32bcd5983f0f0bd89046d176ca64735155279f50bfabb42326955276866cdb505549743cee3f0e7190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027b6be04d1749751b5092a9e161b023476c969249f8f813aaa7d55bb11ea59589","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZypWbHwq6x2R5u5OQ5hAUN+LlWDZI9YNwfsj+3OxoEY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 672a56\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ee2b c0ad d125 8284 | 60 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n001 6 27b5 2d53 2803 0a21 | 30 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n002 6 4d75 4589 4746 4775 | 20 459b (0) 4589 (0) 4775 (0) 4746 (0)\n003 5 75e2 72a7 72a5 7bcb | 9 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n004 3 6daa 6975 68a6 | 3 6daa (0) 6975 (0) 68a6 (0)\n005 2 62f0 6379 | 2 6379 (0) 62f0 (0)\n============ DEPTH: 6 ==========================================\n006 3 64e6 641a 6450 | 3 641a (0) 6450 (0) 64e6 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","private_key":"310d5355dc6d53293d04e7e253fbbc07b4f8990b7da8ed4a43b288b8091dae9a","name":"node_672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","services":["streamer"],"enable_msg_events":true,"port":38621},"up":true}},{"node":{"info":{"id":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","name":"node_b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","enode":"enode://34eec1960cf31fc2dbdcebf909d70107e4589b1136173b360bd9428e5403683b9cbf3d075784c2059942ece65d262f429c184c07f0ca0b3e9cf609484e99b01f@127.0.0.1:0","enr":"0xf88fb840328330bce745f0a6aecebf965760649d16f77adfe7dc13e07094a7d3d2238d1304692cb5d4fbbac1caf45e4c5ca08e54fcfd1a30d2a8e9d6fefe7108a3355d010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10334eec1960cf31fc2dbdcebf909d70107e4589b1136173b360bd9428e5403683b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tOKd5L1XUfMRlerYqhVI0wWlP7T5m+mTGFDmJz3o81k=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b4e29d\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 4d75 5be6 5c62 7bee | 68 01a6 (0) 03eb (0) 034d (0) 0639 (0)\n001 11 d125 d18a d23c dd92 | 31 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n002 7 957e 9472 8b35 8fb8 | 9 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n003 2 a192 a9fa | 6 aedc (0) acf8 (0) aba7 (0) a861 (0)\n004 8 b9d9 b869 bc29 bc71 | 9 b9d9 (0) b869 (0) be0f (0) bc29 (0)\n005 2 b355 b245 | 2 b245 (0) b355 (0)\n============ DEPTH: 6 ==========================================\n006 1 b60e | 1 b60e (0)\n007 1 b5fc | 1 b5fc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","private_key":"91d529071d81ab2bdb9e196080d3e71c4e0b1489d32f062fed6384af3da301ba","name":"node_b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","services":["streamer"],"enable_msg_events":true,"port":43795},"up":true}},{"node":{"info":{"id":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","name":"node_f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","enode":"enode://7c45bf66c718bd1786d40d630447ad12d162cab1cda004e9cda42d46e902793a21486f69dc05cbdf2668185e67b050e7a0201cb4795acf046008819e31bf0b3a@127.0.0.1:0","enr":"0xf88fb840ecb85cd88a5e53a505d6f8fc3bfba676551879609d7600f44cf989c3954b6b295b9001b005ec206366f0e2e2b4568301bdd7800a4931e26d253ea68cb93da85a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027c45bf66c718bd1786d40d630447ad12d162cab1cda004e9cda42d46e902793a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9hHYA5OFrVYmCrORdj42J6rdJ1ZWX+3D7JX3YSTaDvw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f611d8\npopulation: 45 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 27db 3775 641a 7bcb | 68 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n001 16 8fb8 8330 836e 8284 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 7 d18a d23c deec dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 6 e06f eb01 efd6 ee2b | 8 e06f (0) eb01 (0) ea3d (0) efd6 (0)\n004 3 fac8 fa9a fa65 | 3 fa65 (0) fa9a (0) fac8 (0)\n============ DEPTH: 5 ==========================================\n005 4 f33c f3d5 f177 f005 | 4 f177 (0) f005 (0) f33c (0) f3d5 (0)\n006 1 f4a0 | 1 f4a0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","private_key":"7ab918155f49b16772c29096b650cf6baa603a51b6d2bde3aa338c699ac4bcff","name":"node_f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","services":["streamer"],"enable_msg_events":true,"port":40431},"up":true}},{"node":{"info":{"id":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","name":"node_5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","enode":"enode://233c4654af0c29a6d9f1fd643f00e4c77b24df2f4a388dc96f185a6492c67af3875580e0e3df923cfc1857baf0933fcfc451fd1af522d0ae636212c787ac549a@127.0.0.1:0","enr":"0xf88fb8409ba9b9726a6f75d6349a441f7afacdfcd153e89635e530e301aba363979b95be152ab2b042540762f8e738257928ed7cb0e1dcc276af3f5a178dc3cdf78733c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102233c4654af0c29a6d9f1fd643f00e4c77b24df2f4a388dc96f185a6492c67af3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XGI/oBAxCNCx4k5tAaZiTOO1mp58QixF38EhFnZ4VUI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5c623f\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 8fb8 957e b245 b4e2 | 60 8b35 (0) 8d3e (0) 8fb8 (0) 8012 (0)\n001 7 1929 184e 2471 27b5 | 30 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n002 4 75e2 72a5 6379 672a | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 8 4bc8 4a37 4a3c 4efa | 11 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n004 4 55fd 5008 51c2 52b4 | 4 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n============ DEPTH: 5 ==========================================\n005 3 58a9 5a8b 5be6 | 3 58a9 (0) 5a8b (0) 5be6 (0)\n006 0 | 0\n007 0 | 0\n008 1 5cc1 | 1 5cc1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","private_key":"59601d5a451dc893a0eacd7c9a58064f127f7a6006cb91d3ce285e840eba9ccb","name":"node_5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","services":["streamer"],"enable_msg_events":true,"port":44553},"up":true}},{"node":{"info":{"id":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","name":"node_4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","enode":"enode://da0cf3977228d65352ccef3b882334d901b72fbb167e3f5b4c45f62e52526ed3eb3d50ec8227e9d6b8c14a9d43a769265337e2a228575b810b885e3db5eb2f49@127.0.0.1:0","enr":"0xf88fb84051a2a5e0e8760be8f291be6f24a97796a1aee5a826d1d5b7b7736aba877749a15622871be3c2e8363c03a126114650ad0459f143f01b34abc25b3c1c909a34d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103da0cf3977228d65352ccef3b882334d901b72fbb167e3f5b4c45f62e52526ed3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R0Y3khK5HuHBPBM26POnOoRAi3Y2wiLBG9J859ck5sY=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 474637\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b245 ce01 fac8 f4a0 | 60 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n001 7 184e 1929 127c 0e34 | 30 0639 (0) 01a6 (0) 03eb (0) 034d (0)\n002 4 672a 64e6 72a5 75e2 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 2 51c2 5c62 | 9 55fd (0) 5008 (0) 51c2 (0) 52b4 (0)\n004 7 4bc8 4a37 4a3c 4efa | 7 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 459b 4589 | 2 459b (0) 4589 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 4775 | 1 4775 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","private_key":"7f51642b5475141f99f5c1b1ae83d37f562df9bc05930b615f2d9e36c631eb09","name":"node_4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","services":["streamer"],"enable_msg_events":true,"port":42479},"up":true}},{"node":{"info":{"id":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","name":"node_ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","enode":"enode://69f46f822ed108a3341c1b99942e66e6fdcd74e0d37a20ab54831a0ef22b1686782dd6547d34e038a8402a5d39fca494365e445c5e24646340677ee07478b1d1@127.0.0.1:0","enr":"0xf88fb8403cf3999ab1acccd527ca14d5712142e6de9dbe055b041c09ed9a97c8c904c3615dd568f79fba4871ebba52e4d28fc8645c9db1fe5fa6bcb3534dc7ed8079b5d80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10369f46f822ed108a3341c1b99942e66e6fdcd74e0d37a20ab54831a0ef22b1686","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7S7GaBvzJYh3aHA3eczzpieHMRGM0+yJBJCj3lD2iaw=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed2ec6\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3775 36d5 72a7 4589 | 68 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n001 4 b355 b869 be0f bde9 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 10 d23c d18a d125 dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 8 fa65 fa9a fac8 f33c | 9 fa65 (0) fa9a (0) fac8 (0) f177 (0)\n004 1 e06f | 1 e06f (0)\n005 2 eb01 ea3d | 2 eb01 (0) ea3d (0)\n006 2 efd6 ee2b | 2 efd6 (0) ee2b (0)\n============ DEPTH: 7 ==========================================\n007 1 eceb | 1 eceb (0)\n008 0 | 0\n009 0 | 0\n010 1 ed12 | 1 ed12 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","private_key":"1f0f2deaf715e265a0dc7e04ebce7f7ab8f71ce370739dbb27f3a69c46cf5ed5","name":"node_ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","services":["streamer"],"enable_msg_events":true,"port":36339},"up":true}},{"node":{"info":{"id":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","name":"node_36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","enode":"enode://ece93da9ec83a6c37b2bd0240c13c80cf1a175d1883e1881c7cc9122756be72dc17964a01f72b5e570f8948296665c11f34a28691feb337825be71830dd71aa4@127.0.0.1:0","enr":"0xf88fb8400bb1875a3bb9340c4f3442f8cb86cc57892d5c1f6f6149b97ce85a88fe97d6bf3fcef5348de2c000530c8320f52890fd28a31a6393aa7f7d304e3574646bf6ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ece93da9ec83a6c37b2bd0240c13c80cf1a175d1883e1881c7cc9122756be72d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NtWVJoXJXkK+8U93tjcFiXynHSTSHk6e/HctnKvSESI=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 36d595\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f005 e06f ed2e d23c | 60 9472 (0) 957e (0) 8d3e (0) 8fb8 (0)\n001 10 64e6 7bee 4d75 4a37 | 38 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n002 5 0e34 0a21 127c 1929 | 13 01a6 (0) 03eb (0) 034d (0) 0639 (0)\n003 9 21dc 216e 2354 2471 | 11 2dd4 (0) 2d53 (0) 2803 (0) 21dc (0)\n004 3 3e19 3871 3b83 | 3 3871 (0) 3b83 (0) 3e19 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 3590 | 1 3590 (0)\n007 1 3775 | 1 3775 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","private_key":"6f7f6fa8cf239e96150cce6db5caa458629888f8f5f726b8cc6bbcbe09dfcb2c","name":"node_36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","services":["streamer"],"enable_msg_events":true,"port":34495},"up":true}},{"node":{"info":{"id":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","name":"node_cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","enode":"enode://49eae8779e617a7104cbd74223738ff9b987295433994660ab89955cd4e1fb8bbce3608ed7e0acb995c78f652e038d6b6ae87a9ce968bd82de552f8b86994ff2@127.0.0.1:0","enr":"0xf88fb840c2b4c4f501dbf7f98654d927a7fb975ad27786b3cbc874c1994dfc8cd97b89522e882d0fc4258d3d6c928f131df7e96aff65485d5b56a5f54d0e0938ea80751f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10249eae8779e617a7104cbd74223738ff9b987295433994660ab89955cd4e1fb8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yr/ft4nMIJYuq6Hb5o1twEZuaZ0i3Fsp8npc1VU5h5U=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cabfdf\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 52b4 36d5 | 68 6daa (0) 6975 (0) 68a6 (0) 6379 (0)\n001 9 8012 8330 b4e2 bd96 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 6 fa65 f611 f3d5 efd6 | 17 fa65 (0) fa9a (0) fac8 (0) f177 (0)\n003 4 dd92 d125 d18a d23c | 6 d9d3 (0) deec (0) dd92 (0) d18a (0)\n004 3 c52a c2f9 c0ad | 3 c52a (0) c2f9 (0) c0ad (0)\n============ DEPTH: 5 ==========================================\n005 3 ce01 cc9f cc5f | 3 ce01 (0) cc9f (0) cc5f (0)\n006 1 c9ef | 1 c9ef (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","private_key":"50c1b7e67b07c5e3e977aa0690b20a2bcc1ffea472bef560311f987eda352d1d","name":"node_cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","services":["streamer"],"enable_msg_events":true,"port":32801},"up":true}},{"node":{"info":{"id":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","name":"node_d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","enode":"enode://59e6798c8baabbf319576e50e1a709538aa094df1468e5a787b1593fc175622fdb8c56a5b1fea1b6ddfdb8099c602aa7d542cfcc0736b0f8e90761c1672a0057@127.0.0.1:0","enr":"0xf88fb8406107c3f070686e09872ca8a041ab9bbb404d2aca874e09f6dc628aa7efcfe23f671b20e5d229ff36fce675f9954b02e453337d800619251a0ffa0a997c4604ed0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10359e6798c8baabbf319576e50e1a709538aa094df1468e5a787b1593fc175622f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0jyXvrzeJvXjUcS5dcdqr2BP0gb5uQY+y9pTjnpS9RQ=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d23c97\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 3e19 36d5 184e 1929 | 68 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n001 6 8284 8012 957e b4e2 | 29 9472 (0) 957e (0) 8b35 (0) 8fb8 (0)\n002 7 ea3d ed12 ed2e efd6 | 17 f177 (0) f005 (0) f33c (0) f3d5 (0)\n003 6 c2f9 c0ad ce01 cc5f | 8 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n004 3 d9d3 deec dd92 | 3 d9d3 (0) deec (0) dd92 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 d18a d125 | 2 d18a (0) d125 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","private_key":"7ef7bc7466fca587aab3f839ece8ec307619523af4dc22ab14b3129c81978144","name":"node_d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","services":["streamer"],"enable_msg_events":true,"port":39477},"up":true}},{"node":{"info":{"id":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","name":"node_a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","enode":"enode://3c5d51d426ffa9069eae24c2f0c108b2f543255bbef13b8ddf2a2dfdd34bf1fee87505e6163e90fa9f7432ec9865f90490aefc0bbd8049fddf18d8eecd8bb076@127.0.0.1:0","enr":"0xf88fb840c935263f2fe7bcceed68a1f97aa98b1f4898056415975bfe6af3a937a3e8afbc664cfe541a801aa79c8a84efac3ec10512e3c34b32d5fa16b9383f850a5ca9bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c5d51d426ffa9069eae24c2f0c108b2f543255bbef13b8ddf2a2dfdd34bf1fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oZKfcEZkyoXYKaw7q2LmiGR6fP3LyfA8YbASTPkJNQU=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a1929f\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 2471 184e 68a6 6450 | 68 0639 (0) 034d (0) 03eb (0) 01a6 (0)\n001 11 ee2b ea3d e06f f611 | 31 f177 (0) f005 (0) f33c (0) f3d5 (0)\n002 3 9472 8012 8330 | 9 957e (0) 9472 (0) 8b35 (0) 8d3e (0)\n003 9 b355 b245 b4e2 bde9 | 14 b245 (0) b355 (0) b60e (0) b5fc (0)\n============ DEPTH: 4 ==========================================\n004 5 aba7 a9fa a861 aedc | 5 aedc (0) acf8 (0) aba7 (0) a861 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","private_key":"9037f029de76f869c02e95928a58d061068ff690b7a5ce42fe021987910ec074","name":"node_a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","services":["streamer"],"enable_msg_events":true,"port":42239},"up":true}},{"node":{"info":{"id":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","name":"node_52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","enode":"enode://fc05173b55aa81517b3ac06d2d7c2c6a7f3ce4a2b37780ab5111f90a2d537c3081147d82c05d274eee69f1576a40da8d1065dd9f951547cb1c072f2748bae488@127.0.0.1:0","enr":"0xf88fb840b0c717a2ac8079ccf35009302f2fdb71fc7d427791e0db68bd05457b484f738c6c8cba664f215e4772f08a743818e428827b0dbb2e2b213bd427367bd64659900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fc05173b55aa81517b3ac06d2d7c2c6a7f3ce4a2b37780ab5111f90a2d537c30","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UrR9Ur9KGv2hYEt5QgGcjSrEx2DF60WX4c4t16jhz00=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 52b47d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 cabf d23c fac8 ea3d | 60 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n001 4 2803 36d5 3e19 184e | 30 03eb (0) 034d (0) 01a6 (0) 0639 (0)\n002 7 7bee 75e2 72a5 68a6 | 18 7a68 (0) 7bcb (0) 7bee (0) 73d0 (0)\n003 6 4efa 4c21 4d75 4bc8 | 11 4cc2 (0) 4c21 (0) 4d75 (0) 4efa (0)\n004 4 5be6 5a8b 5cc1 5c62 | 5 58a9 (0) 5be6 (0) 5a8b (0) 5cc1 (0)\n005 1 55fd | 1 55fd (0)\n============ DEPTH: 6 ==========================================\n006 2 5008 51c2 | 2 5008 (0) 51c2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","private_key":"a160ffd0d147d08006e444e85b70fb9e8f982c3e0a7ad72f8005d6a040a65682","name":"node_52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","services":["streamer"],"enable_msg_events":true,"port":37611},"up":true}},{"node":{"info":{"id":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","name":"node_e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","enode":"enode://c527957ba9cb7743e768b25580478414c9740bf57540523a69f55a7e40c6e1d5f2f53b2d72c9e017219e008e4c68cc9f6f9209d12dbe5e617557b73b0c465cab@127.0.0.1:0","enr":"0xf88fb84055bcf73035487cb5632f8ed4d3f298da2d47da173342acd58a537bec7b17f1981d6d0060dff9891b4f3b79168a713b0ea134bf4a724cea40a0a0a20e9df661980183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c527957ba9cb7743e768b25580478414c9740bf57540523a69f55a7e40c6e1d5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4G9YsUT6plD5ZGWCXSU7Y9fgYeOjxCKK1eG2Za+8zDc=","hive":"\n=========================================================================\nThu Feb 28 18:08:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e06f58\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 2d53 2803 3e19 36d5 | 68 0639 (0) 03eb (0) 034d (0) 01a6 (0)\n001 7 836e bde9 b4e2 b245 | 29 9472 (0) 957e (0) 8b35 (0) 8d3e (0)\n002 3 d18a d125 dd92 | 14 c52a (0) c2f9 (0) c0ad (0) ce01 (0)\n003 4 fa65 f611 f177 f3d5 | 9 f177 (0) f005 (0) f33c (0) f3d5 (0)\n============ DEPTH: 4 ==========================================\n004 7 ea3d eb01 efd6 ee2b | 7 efd6 (0) ee2b (0) eceb (0) ed12 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","private_key":"1fb267b5c56dc43486cd338b223dbdd81bbe0d2ca10ce150e87fafd8ea7fb55d","name":"node_e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","services":["streamer"],"enable_msg_events":true,"port":36611},"up":true}}],"conns":[{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","up":true},{"one":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","up":true},{"one":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","other":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","other":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"4a373571475e2b4c280d2d4b22f10a249ee09fcf907f52081ec0398a8b5ea6f2","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","up":true},{"one":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"4bc8dfbf84794d26d7a573c9d898974eaa3a2167e19cb7a8aa460807a603acd4","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","up":true},{"one":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","up":true},{"one":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"c0adf394af7d5670c1ce8c6bea292fbc03c56ae2b636e2f303311a455bb3500f","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"ea3d6aa50ad5a1d5647d213f9b5cfe6718339eec7eef8644487eb3c223c7bcde","up":true},{"one":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"672a566c7c2aeb1d91e6ee4e43984050df8b9560d923d60dc1fb23fb73b1a046","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"eb01ff80307afbfc7457c96594cd4ba4d00acb7fd25a7571d1223168bd66ff09","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"0f3106adfe70aefb474c4a98a95932307391de2cb70fbd2e11dd31c9e695ed83","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"cc9f65d734f1a3bbc6019e166fe355bd7fc33bb4887043a5ccf532a9ba356379","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"acf888ed781f5358493e2e5048691acc39eac3240ca9e9093bb4052b1f624325","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"4efaabab0d5dc59f098aee4dba3868263411a55615a2c474a73e6eec2211decc","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"fac808b79923931febd54e3611b79811b3973c777e7502bd56b9803d0c4bf785","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"a86117147b78f20a6d883d37715da85178cad89eff650a74aa89e7bc11bc45a7","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"efd68d2c99346ca085c9ef896bee6125ad8638413295108f3a92b247a41ca629","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"fa655b4882579e65937a14ab1c6bcba021580f0a5ebc04c48424f5ae72b7d5b4","up":true},{"one":"4cc2386a86fd210bf699c6d93173b0879c3210d46f572a62bb154cb60a7d2cb1","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"52b47d52bf4a1afda1604b7942019c8d2ac4c760c5eb4597e1ce2dd7a8e1cf4d","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","other":"0a215c7765be2caebf76ad3e8017bbc2aaadf8e0dd4859af781953a0564c5d59","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"221cd8ea0a26f0d3f81f782f1de390282415ecd9cf40224b4945a00897895b4e","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"bde90aaa0f1f7a7eb965ff308718d29b55a80b1ca84dfba16c169eabe2b0d5de","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"4a3c39f044c425c153d4900db30f839d7866c8e0f4f4d38d9205e67fb540988e","other":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","other":"e06f58b144faa650f96465825d253b63d7e061e3a3c4228ad5e1b665afbccc37","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"5be6df23201fc5c00be650849c8bfe5581e44033ef19012836f97c98f3954471","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"127c89eae94b195df2eb5eb7b44f634adb73c114d2089cd904b56988c8674e11","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","other":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b8695bec6c8e1e6794bb943b83629cd2c910067e6e178f6f8e33c4f0fa2d74f4","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"08077c0ce8d4130c14464493e9164a8bae61b4646b1ec48899e75f2f6f9b8c66","other":"0639f010834f5bc497798f2d275bbc60bfbcd53c83e38986b7260310c6001420","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"aba793e635f71169105ad073225cc8db914de6b711fe9f22c5d94ac8cb85e2eb","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","other":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","other":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"ed12c78e700bf805669c48a5d62f1e56791263c4b2ce5bd34587ea9bc931a3e5","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"27b56302a89605a83563ba7b66d491ec25edfad0ea1010937fcadeab4d3ae582","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"cc5fa2d49210e240983b0853ff15003f0d366f05cb1f6486bae2862cca852cc5","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","other":"3e1959b29bbacb3ce7dccfa41c3e51b87f1afc700a3c6e4713c38cc0fe3790df","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"957ed6194e6ef56e9696be43a1a0258f2ba4f48f56d790e42bd0663c3fc6aaae","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"3b830c2ae5463ca2f2260176b77b8dda23048257aa780255c69cf1bbbc6fb64c","up":true},{"one":"2dd4ad83effc3ba73e72f5659583e5987241bda563563200b50c46cce00a1d9b","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"f177ee6767a78a57b725dbe67ec377f507f5777d345a28892b0fbfb800dc443a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","other":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"ce01234661309127bb872d69d38dc5bf19bc4de2e0a0b5041cd362d073df4ff8","up":true},{"one":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","up":true},{"one":"01a63575c384f686e5739e1bd079e4a4c55421cd6d89b944e2c61dd174fa2bf6","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"37751f279493dc5ce5b5c3c55a6ec2e4119eedefe1069b283f6ff8c7bc9d1411","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"d9d30b9b212bd4811a44ebe304ba3935ead3abe3247f99893faf65664131c29d","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"bc29a0d9b60f3e2c34224cec187cf44eadc4628086d5594666ed025da71e7e7a","other":"ee2b0aff61a9846d13de3a72712ef0bf3ca42ad8da57e81759c242797258efec","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"3590afcd10fb8f58c39f72068661d9a772b77e0efd57bbd60306632fb048fa3a","up":true},{"one":"641a165f8be0eee36f53c12bae8e2a34a709adb8d1dcd667e88e4e90c9ee2401","other":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"03eb2e92ed0923f696269e7a03fec731d8c3f8df278023a9cb00867b533a3ca3","other":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","up":true},{"one":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","other":"13853407d278a45e15d4b148fc38ebb35c4f58ee552ee0e4401c6c98c45b8e3e","up":true},{"one":"459b9fb2b7f4e396de8cf8740a6804c8e5b96ca11ffa2b5106c14dfbbab65c95","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"51c285489ff14628268ae886945e1cd2da64c6a0a8cb184aada98567ab429b6e","other":"55fdad03303a746920773217c568a37d2004869ff34096fbe45197f71eba2b63","up":true},{"one":"45895aff674079f6be02e4cc74914d63125c3fe48bb69056c070c71319fea1fa","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"c9ef56afed2d40db396ad39d6f5f5f38f4058b6b0d1e02b71d6aa92dbeaf7df7","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"5a8ba4047c4456e825bd1b34c961f5c7f37bf7c27bc48bee71b8430c7d135486","other":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"b4e29de4bd5751f31195ead8aa1548d305a53fb4f99be9931850e6273de8f359","other":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"21dcfb893a54cb56d21355fc564583057fc51b32503a8627e7575660725a7627","other":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","up":true},{"one":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"2354d3af5c6dca05d7dc212b100112f37ab29fb8b3f4319887230a4d420f5d9d","other":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"aedc9b478204effdcbad1a892333f15c061fbd1423b370f8a50f929b2a2f6952","other":"a1929f704664ca85d829ac3bab62e688647a7cfdcbc9f03c61b0124cf9093505","up":true},{"one":"5cc1c28eafd9758e807a28159a1a7a6ea313fa7e878fde5d47fcc8f5a5c25172","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"772a79302528fdce6a216c98c95e281333292c81dfe490aeaa4a78bfeb1980c8","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"5008ef55ad8088f70643b0f93bcb479531bcb0afe8e01b215dbf8597ec866369","up":true},{"one":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","other":"b2453c6e755a30efb91194fa607b3352d75b6905c448b09af4aeadf3a445b633","up":true},{"one":"eceb7dc532596e8b68074113db9605e3d15cb15e2e80f75f1a66d95a1221c7dc","other":"ed2ec6681bf325887768703779ccf3a6278731118cd3ec890490a3de50f689ac","up":true},{"one":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","up":true},{"one":"b9d906e406b0fc6078c22bbc173043df1f7581061b4f6ccd769bc568d94b4339","other":"a9fa28117a4b6906b5ce3931573e0a19eec3cb4fcd9141be2d258a2be06f3b61","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"8d3e0d9c6932d3422024394998e943309b679d667394d0eb622f0e208e7fcf0a","other":"8012a7af71d76d882202cf9372523478ccebea23443006c7f29c2a83106cd1b3","up":true},{"one":"62f007c92a8af466e90ed0b1e5e71a955ad273ec793948ddfc03977f131ed2d1","other":"6379b4d611cdd6e360480c14b3f6784360f28f702b5a6f375eda4ef3bde7ef33","up":true},{"one":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","other":"22bbb3236a5e0a1947a1c4735aaacf9122173789a02a06e7653103bdcae2f823","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"d125317b492df46a7dd496d30c6d07839ed6bfa196abde4886ce7bc8f9b5c01f","up":true},{"one":"c52a68d8388a21013e4eecef9ea866db1f5eb16bbe0ecc82b8bfafd33e4e014f","other":"d18a1edd26661069fb401fee8aa85a9614a3188e2e0666bfe9307f91d29aad49","up":true},{"one":"bddbdff3cbd22fcedddc07de27125819aac72be72c3126ba898621c496cb95a2","other":"bd9607d5f57f7b6f74f4ad981be368988ef48b5f31e3fd96cab3bb790d568150","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"4746379212b91ee1c13c1336e8f3a73a84408b7636c222c11bd27ce7d724e6c6","up":true},{"one":"77eedcac0c847b1d693ddff07c5868afb1c2008b2dcb48a0299143ab14611969","other":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","up":true},{"one":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","other":"72a76f668d9b923914860eb4f8577bc98c153f6dd222cd36a0bbdef2bab7f068","up":true},{"one":"17406dea5046f00e27eaf74e166a945c9485139d6edcdfcd84f5b03f50eedd0a","other":"1929b01c0f85af7452a0f358b54f6b36640a196b366909172af594a1648fe64c","up":true},{"one":"184e9e00ab4fe1669d4d99fb33d418d33eff927da38cc997f69679443c24b20b","other":"034de66774eda26b93e342c9b94b9deaeb6297650c819b144a5832bebfe6b02f","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"8330e2b8ae2f184bb8dc5e153fafa4dafe86f84ec692d3ee91413cc07b1cd9e2","up":true},{"one":"c2f9b4abed9c6a839fe4c03a80bd396fd187a8784ba47a83687d3a54b7e2eddf","other":"cabfdfb789cc20962eaba1dbe68d6dc0466e699d22dc5b29f27a5cd555398795","up":true},{"one":"dd92b3d42414fd5eff5c1e4ca55c63cd7036634049995b72a20cdf7ca1321978","other":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","up":true},{"one":"6450bb5e880411abcb60258d8560949f6f70d92ba7bfa9a4d7845463c48dab30","other":"64e642de2667a7563c774050d368858d99aff433efbd1cb68361e3e244629b03","up":true},{"one":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"5c623fa0103108d0b1e24e6d01a6624ce3b59a9e7c422c45dfc1211676785542","other":"58a90b58858417a4e972626421ed8e78b1b3e5ac69fcedd22c58a8ab4c6147df","up":true},{"one":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"68a63ebc4833dedfdb6d534438ffcccd042f60434bee0e39f4cb3726e7413e7a","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2803f212eb4aa4f49224b16b2de88ba8652ad115321ee1e60cdbd926ecdad38a","up":true},{"one":"216e0370111e2e03927b803ae788f9947de8e241d41dbf6a70983cf0ecd68af1","other":"2d531c50183f0115269b3feaecf45927a3ac44e1be2a263c7e5d2274d8379b1c","up":true},{"one":"4c211c117e555c2ac831d5688615b6b4c5e31f1d7c7906b34f0cbcdbc45482b4","other":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","up":true},{"one":"69753865aacaaf72d9bf6d265c885d3f705804ff4b2675f7aa860641dacab2a0","other":"6daaf515999c9a3491c963f76be82ed6005616bf7ba98247b01d6a89a9af1d71","up":true},{"one":"f005a4d3453d52434f2b5be4006e653b50b52ad31926d654722fc3df00f1689c","other":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","up":true},{"one":"f33c07a818863a358358989ec71504abad3ca0a7c81b54aad59075a766fad501","other":"f3d50811ef10661d3ef9978077cd7181387298f306833ab6e27f25cbb77435cd","up":true},{"one":"27db66d13ee8168aca89786febd6971dd1d6c554bca8501052065cb47631560d","other":"2471776037d55a05df2b15bcefe52cb1f4c942e9e15113abc2a0c1fcbaa5d626","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b60e77c40ddc9dc78a4ad346add37e60f10f2999de836615db53524487d1ede9","up":true},{"one":"7bcb0d7b9f84aed413cf9b2a7851ba6d1138d85382aa20e6c939a43c8e59c034","other":"0e344c6e27c23bd36bdd3ddcefa4e577fdc9461e52c7ce20135733a08b987b82","up":true},{"one":"f4a0f76b30bcf5987cfa3f4f4b0aa3445f39d60a1f51519fa660c27b5d833dde","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"bc71f3e409edb989e26607448491530c5451053b582ea64d882525451ac940bb","other":"be0fb2b440b91e719c20f51b673eb9f2f66c7af77b0b0ade312998cdffcc5045","up":true},{"one":"7a68fa44bbec187272e2d5dfbd6ed8af31a1a365aa72aa50db02350ebe98c859","other":"72a53f0fb1b51855cb4054a39cbd1309a76a862d36e18af9ba0456a60325c06e","up":true},{"one":"36d5952685c95e42bef14f77b63705897ca71d24d21e4e9efc772d9cabd21122","other":"3871492c8c62cd74cbe65a993669e4978cc641879a5223dd6b9e687f050a1c40","up":true},{"one":"deec6a8beb4e5e441dd42311354194c3bef9448e8859b4ccd401645b69217d12","other":"d23c97bebcde26f5e351c4b975c76aaf604fd206f9b9063ecbda538e7a52f514","up":true},{"one":"bd486e1e15df4c7539b1ad5b54f7566dd4836a430e9f7d3503881fa79e258d9b","other":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","up":true},{"one":"82847a4af4f50622650d035f69151b202bccd5fc92302a617602c974603ed997","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"7bee7967ff7b07243bed55b6d060d5ec2a1f28b530ed65cd055dc5b468a0f878","other":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","up":true},{"one":"73d0d1d4a2b7250f51e57c13cc48bc6b20682320ce12ee8e5765afeef7d9de42","other":"75e282c0f3d355a40573e6578c5aac98e7262970a9239f4dcefd26d6f008b553","up":true},{"one":"47753fdca855ea79abf667b50aa9c90a132d44bdd1572c3e3c411c8ee7e5b5f4","other":"4d750666dc0e9e2c244c43492801c1d7ec6208954a0cb5f8bb793b912440753a","up":true},{"one":"b3555baa764c4562935b93533ee6c5a6df631e846c3ab512fdb1d6b901a68c60","other":"b5fc43e8c0df3279d6a12cd8b03012cb8d2205208324018c7ae725745a99a2f3","up":true},{"one":"f611d8039385ad56260ab391763e3627aadd2756565fedc3ec95f76124da0efc","other":"fa9a809f016097d949fa1463a1c8f08871c7d38e60b7df6d3e28ab04ccd3a143","up":true},{"one":"947205fd85a17330a6d5c51a66548c5f69779c76ab12408f8fc6d33d7c6b8e9d","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"8b35236da99930bf8f5ef6c7555bb18b80ce2e34361bbbfd6baf55a6483e54ff","other":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","up":true},{"one":"836e65dfe6f01e1d2934655c1846cb86fed6e41ea951a109d7a20bb14cb4c10a","other":"8fb8208b7167dd06cc08778b507ccd856751d3df6dfbaeac18b9f527b6628523","up":true}]} \ No newline at end of file diff --git a/swarm/network/stream/testing/snapshot_16.json b/swarm/network/stream/testing/snapshot_16.json deleted file mode 100644 index e209f568f6..0000000000 --- a/swarm/network/stream/testing/snapshot_16.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","name":"node_427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","enode":"enode://7f2eecc4ffd81993f1f7f961ca00f52eacd77fb52f215cea32246a5742deb627c6b2be0a2112d7114b5d26a898de7c6dcfe18595458e0f50181497fe5631ba8a@127.0.0.1:0","enr":"0xf88fb8408e4b56b8de4863c72f40c38f16925319181e8079bc13b5b14c5ac1626070b4670ff42821d18b044558b1a6e81c4e6afacbcd917915b9c26b325e1775ec15fea00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027f2eecc4ffd81993f1f7f961ca00f52eacd77fb52f215cea32246a5742deb627","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Qn4CiLWkdNlwTfR78uuXuK+Xm9oZn4a3vViCSTOVgSc=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 427e02\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a010 c55a | 9 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n003 1 5942 | 1 5942 (0)\n============ DEPTH: 4 ==========================================\n004 2 4ebd 4c14 | 2 4ebd (0) 4c14 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","private_key":"2939b9a1fe2ce1f27e9d22f9f00cb77563507ca8b5a62bb93fe2a7e1dd5daf4b","name":"node_427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","services":["streamer"],"enable_msg_events":true,"port":39289},"up":true}},{"node":{"info":{"id":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","name":"node_c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","enode":"enode://0e17a602ec55b9499390093d13ef045635eb8b755783f80b0bd57c784cc2a6d52901b4170ec9202ce13084de51eafb9ab6d225f9e83266f280649eecbe332b47@127.0.0.1:0","enr":"0xf88fb8408658caccb6f16b440efbf35061f2e13adc4b3b4469df310a00d8801f752ceed24190e9a75879b496bb999add5be68c8d03127351456f69a3e45a6810f3f1e2900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030e17a602ec55b9499390093d13ef045635eb8b755783f80b0bd57c784cc2a6d5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xVoXaxwYXlJuF9KsJVbll5a8HTprgU7s2wypUZyMUWM=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c55a17\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2653 427e | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 bdf0 a010 | 4 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 d6f7 dd12 | 2 dd12 (0) d6f7 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 c5bf | 1 c5bf (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","private_key":"0cb4fe0b34f942bcabc5485300829a5110c4ed6571e8064f63c88fcd1669485f","name":"node_c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","services":["streamer"],"enable_msg_events":true,"port":46727},"up":true}},{"node":{"info":{"id":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","name":"node_2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","enode":"enode://fd7a5476ddb69019642a906aa79f22a853228df3bc57104c329683b8dd0c70f2a329ef7ec24ef92baa6a39c8abac12cf16a916cc605aecc84e4ab1fc52bbd87b@127.0.0.1:0","enr":"0xf88fb840b9c3ae42b41ec15fee9985def0ab98f7ddf14501eb0963671e974ced1c9f4ad963ed4466ac5d767f55188b6ab91097e0848f8d7a65d532f5d31bd1d78f36c2570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fd7a5476ddb69019642a906aa79f22a853228df3bc57104c329683b8dd0c70f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JlPD140cEf06noBDrlx3A3sB4F3dKj1PYoSETQmKI+U=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2653c3\npopulation: 11 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 95b4 edd7 dd12 c5bf | 9 bdf0 (0) a010 (0) a61c (0) 95b4 (0)\n============ DEPTH: 1 ==========================================\n001 5 427e 4c14 4ebd 5942 | 5 6ff9 (0) 5942 (0) 4ebd (0) 4c14 (0)\n002 1 0d52 | 1 0d52 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","private_key":"35e97c6f9bf750dbe7d8d2c5bb9c3021af68e2d9143010fabf1934073a446c5d","name":"node_2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","services":["streamer"],"enable_msg_events":true,"port":36223},"up":true}},{"node":{"info":{"id":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","name":"node_95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","enode":"enode://3903c8019e85c8d7fe4bca9363b929984a2dcda6c45c42bd8deb02e8128dc87b22db7eb84d96815d349e4cc6e7aeebca10fcf2303783e19b4601e36970874caf@127.0.0.1:0","enr":"0xf88fb8407a344f969c3c14d7152c36b0e5fff71c51a514bbb1725b08f74462b88f3e9d197e473c1d43512ee405d57c7a77b17f38e61e96315f31afa03ec6d07390a839c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033903c8019e85c8d7fe4bca9363b929984a2dcda6c45c42bd8deb02e8128dc87b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lbSKnRlPQrjxnvjM3jN80iFSXgSEhDGm2EP/lopfTfU=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 95b48a\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5942 2653 | 7 6ff9 (0) 4c14 (0) 4ebd (0) 427e (0)\n001 3 dd12 c5bf edd7 | 5 edd7 (0) dd12 (0) d6f7 (0) c5bf (0)\n============ DEPTH: 2 ==========================================\n002 3 bdf0 a010 a61c | 3 bdf0 (0) a010 (0) a61c (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","private_key":"d3b3aee83368bb48feefe0e7782a19a55e4d210864402337e2117313dcd5b189","name":"node_95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","services":["streamer"],"enable_msg_events":true,"port":38325},"up":true}},{"node":{"info":{"id":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","name":"node_594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","enode":"enode://6718e290bc219c921b7b7fa26a7c29176e3175c6eaf273a80bb13b4edc560ff829385aba50dd0171f098716ad83eece60222801b9a074f9c926980dd93813aa3@127.0.0.1:0","enr":"0xf88fb84035a56b10844271058e2d9ca9b3e3c67de90a8c8323d7e5f8531f02952e855a5c0aa53aeb41b6de4638cf94d7301476ccd46e9bdea86f61ef61d97d22957a23a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036718e290bc219c921b7b7fa26a7c29176e3175c6eaf273a80bb13b4edc560ff8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WUIDyPoXC+zh6xKsVpsXMbhqYD0H9QIqfXsr8gX8YVE=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 594203\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 edd7 95b4 | 9 edd7 (0) dd12 (0) d6f7 (0) c5bf (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n============ DEPTH: 3 ==========================================\n003 3 427e 4c14 4ebd | 3 427e (0) 4c14 (0) 4ebd (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","private_key":"fefef9454f2f776b9e1f7baffba1b6008e32ec48486a4183819a5d611d5a4928","name":"node_594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","services":["streamer"],"enable_msg_events":true,"port":37077},"up":true}},{"node":{"info":{"id":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","name":"node_4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","enode":"enode://4d2df1c9d3ed42f561416caf0af60ff21b68e7a24e706595f10893a5cad5c13f5f4f0fe27897ed3eb1717b4e3444574b129900211652b85a56bd9c7bd13cc460@127.0.0.1:0","enr":"0xf88fb840633f9b9c1dce11bb4eb9f00b99b7f31aecc61374fc1ed19ceb3bd40f45a3ba4236f7623af2e69b74ca218e371d317023ae589c23ca11949cb431bfe36defd40f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024d2df1c9d3ed42f561416caf0af60ff21b68e7a24e706595f10893a5cad5c13f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Tr2hznl2ESnOhy9QvqmuLfOdR+TNeh2PG7mIyCuGZ6k=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4ebda1\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 edd7 a61c | 9 edd7 (0) d6f7 (0) dd12 (0) c5bf (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n003 1 5942 | 1 5942 (0)\n============ DEPTH: 4 ==========================================\n004 1 427e | 1 427e (0)\n005 0 | 0\n006 1 4c14 | 1 4c14 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","private_key":"1f13487aa3f685a730149f567e1e95ab7ea53d54717151390b1bf8d236ac93c1","name":"node_4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","services":["streamer"],"enable_msg_events":true,"port":45609},"up":true}},{"node":{"info":{"id":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","name":"node_a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","enode":"enode://16e487d4bc68f28f54477a9bf864b80c62a2802f4f902e69be114c51e8c756ee5e4cda3d522050beb554d731c791ca777cf2a0db1612513434577336ce2f6a16@127.0.0.1:0","enr":"0xf88fb8404beea9a3e5a8fddfbb54ee788fd2b1c2908f9d0c50c1807416315024e491dc9702a1a7a778d302e03937e2bde114fb8d8246f39b32e8e5785147f7eb15f988d30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10216e487d4bc68f28f54477a9bf864b80c62a2802f4f902e69be114c51e8c756ee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"phwP5UGlYrCNkvq9ZDpIaU+/uvcE0ceCWVrQ6Td6BrY=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a61c0f\npopulation: 7 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0d52 4ebd | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 d6f7 edd7 | 5 edd7 (0) d6f7 (0) dd12 (0) c5bf (0)\n002 1 95b4 | 1 95b4 (0)\n============ DEPTH: 3 ==========================================\n003 1 bdf0 | 1 bdf0 (0)\n004 0 | 0\n005 1 a010 | 1 a010 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","private_key":"aca753870ec0d4820df685f13895e1e883e0c533dd949d7957b54a7278e2fa2f","name":"node_a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","services":["streamer"],"enable_msg_events":true,"port":36847},"up":true}},{"node":{"info":{"id":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","name":"node_a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","enode":"enode://da90e12ec1d6737b50a34a3ee3e75fa3e164a4c510506bad503721813291f09bad6b8f3008810a6e738d31e6365ca2a56a278477d23fd18e86e258dce44ab378@127.0.0.1:0","enr":"0xf88fb8404256771ae0b0cd6d23b73a6df956fef179cccc697e78699e807513021fa9c80a4ddd2398cd82f160a433345b7ca8f651ef08d43e87416be27744f146f325e7c10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102da90e12ec1d6737b50a34a3ee3e75fa3e164a4c510506bad503721813291f09b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oBCdbEGjF+hX8ynzCJj3Mo3TgS0fxwCKaP445tgEt6I=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a0109d\npopulation: 11 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6ff9 4c14 427e 0d52 | 7 6ff9 (0) 5942 (0) 427e (0) 4c14 (0)\n001 4 dd12 d6f7 c5bf c55a | 5 c5bf (0) c55a (0) d6f7 (0) dd12 (0)\n002 1 95b4 | 1 95b4 (0)\n============ DEPTH: 3 ==========================================\n003 1 bdf0 | 1 bdf0 (0)\n004 0 | 0\n005 1 a61c | 1 a61c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","private_key":"2def6be33926ceb95119b6eef9b225e963b37378a26743dd6dea6f52e6b188ed","name":"node_a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","services":["streamer"],"enable_msg_events":true,"port":46777},"up":true}},{"node":{"info":{"id":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","name":"node_0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","enode":"enode://3c12b2884039d0d47926d5fe5fe932ed2231c1df1e29c39ec02452bdfd172fee3db62b4568adc560ddbf71cce469b473e124fff10b3f083910526d18b33c42b2@127.0.0.1:0","enr":"0xf88fb84051550b2edf140f46ee64c9c9fad39caafba3103379cfc9b363025cdafb9002d0665ba3a2c0f0701f0e80299e78c9ab7930d8e19fb5251a0406408d5d5bf95cae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c12b2884039d0d47926d5fe5fe932ed2231c1df1e29c39ec02452bdfd172fee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DVKdFGR0NnXZH8QEnXD0KLMm84TojqFMU/8jouRaZb4=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d529d\npopulation: 12 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d6f7 dd12 edd7 bdf0 | 9 c55a (0) c5bf (0) d6f7 (0) dd12 (0)\n============ DEPTH: 1 ==========================================\n001 5 6ff9 5942 4ebd 4c14 | 5 5942 (0) 427e (0) 4c14 (0) 4ebd (0)\n002 1 2653 | 1 2653 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","private_key":"be1de243c5450fb51af634ada17a96c06515fbca77202cdd848c126934749c1b","name":"node_0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","services":["streamer"],"enable_msg_events":true,"port":34387},"up":true}},{"node":{"info":{"id":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","name":"node_bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","enode":"enode://4410ea88db94cde9ffbf85ead5e867e226979f908d82cb1f3d8583ead0e2ca4a3ba5a2f016df89ec0f0d76c3dccddc0b68a9df33783ed942d3df6f138e8169d8@127.0.0.1:0","enr":"0xf88fb8406f933c472c99bd51a9e066d03732148e70013d2eadb5a57bf1ca3d7f0c2266140e8626ff05a46e283a22ff5e16c10fecd00ae7bcbd2e746440733bbeca6c78940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024410ea88db94cde9ffbf85ead5e867e226979f908d82cb1f3d8583ead0e2ca4a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vfASJpjJ2jE3QNLJhUrFwXfGPNzJXjq0Fe7W7r1mFLY=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bdf012\npopulation: 7 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6ff9 0d52 | 7 5942 (0) 427e (0) 4c14 (0) 4ebd (0)\n001 2 c5bf c55a | 5 c55a (0) c5bf (0) d6f7 (0) dd12 (0)\n002 1 95b4 | 1 95b4 (0)\n============ DEPTH: 3 ==========================================\n003 2 a61c a010 | 2 a61c (0) a010 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","private_key":"f89bc000169f6a15dd6881cb70ec8f841a60aceddbde85af267a2515c91e394b","name":"node_bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","services":["streamer"],"enable_msg_events":true,"port":40993},"up":true}},{"node":{"info":{"id":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","name":"node_6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","enode":"enode://6936d2429208f3e456ef654a7a0511e310ec4fb728a62d03861c0a4a8e9d22f5f0f3a90b8bf03d3654afb675e371e2bb5f7065f2662292078a5e3c73a0c9ee04@127.0.0.1:0","enr":"0xf88fb840f98c7122fa9802971ba1acc50caa9e447e49b0dbe4372fc40405128ca954f4dd07b794976a20880bfdd2a586adc2438ddd9e35fc93e6106371af5363ede39d2b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026936d2429208f3e456ef654a7a0511e310ec4fb728a62d03861c0a4a8e9d22f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"b/mj9vH4AZ42a1nM4H43N7Hm5LorTtkBLN0raDkIsAQ=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ff9a3\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a010 bdf0 c5bf | 9 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n001 2 0d52 2653 | 2 2653 (0) 0d52 (0)\n============ DEPTH: 2 ==========================================\n002 4 5942 427e 4c14 4ebd | 4 5942 (0) 427e (0) 4c14 (0) 4ebd (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","private_key":"1dd45d1d581cf612c3b51e58a8a76daac07d6c3e6060e9ebed1d697999257945","name":"node_6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","services":["streamer"],"enable_msg_events":true,"port":33543},"up":true}},{"node":{"info":{"id":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","name":"node_c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","enode":"enode://939e9a819895e0193947e390c9d561c3b1bca8eb6e19eaaef503a49b811b4e436932430dec5d7e01184cc7c7f4680964ccd2d7d1f31e6284148cb65190aea8fc@127.0.0.1:0","enr":"0xf88fb840aa054cfdc1388722d83c8026d2d2c4a9a79187fbcfef0e7cd0454597a55ce9e3129ffec027b96b03efabc975a4461caa27973336fd65caeb105a861e825e72b20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102939e9a819895e0193947e390c9d561c3b1bca8eb6e19eaaef503a49b811b4e43","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xb+GfJ7g24MVBDlbREp79sX2xtjQtsdBKW/KsDIISR8=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c5bf86\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2653 6ff9 | 7 2653 (0) 0d52 (0) 5942 (0) 427e (0)\n001 3 95b4 bdf0 a010 | 4 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 dd12 d6f7 | 2 d6f7 (0) dd12 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 c55a | 1 c55a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","private_key":"f55426e1ac52ab19cd155aeec3bf75415a3c75bfe89987b9747b3bb5cfe2ab54","name":"node_c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","services":["streamer"],"enable_msg_events":true,"port":38361},"up":true}},{"node":{"info":{"id":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","name":"node_edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","enode":"enode://4db77ce0656ae19063ee88a21dab483fc39b82eab3ce8a5a60287a32acd7585f163ee6ec724f66bcf40f40fec9cdb9e4e4c28ec4b7342960eeb505ac8de2d14a@127.0.0.1:0","enr":"0xf88fb840a6875960f8077f6e6a7f474110885c3e4748b3cf61e6348bd9b42efb3def651d35ab2bf6b780587204f2ae2b56019cbbe01464e2b2e221a3bc50d27052b963bd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024db77ce0656ae19063ee88a21dab483fc39b82eab3ce8a5a60287a32acd7585f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7deyKhf+w4JNd9uIK1+06CsIvsqNWeDy3Ikk971vjO4=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: edd7b2\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4ebd 5942 2653 0d52 | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 a61c 95b4 | 4 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n============ DEPTH: 2 ==========================================\n002 4 d6f7 dd12 c55a c5bf | 4 d6f7 (0) dd12 (0) c55a (0) c5bf (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","private_key":"e9fb7f15ab0c529f7fbd15c7fead7762c5ff8563f928d0c77e5fac982a5c6cb3","name":"node_edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","services":["streamer"],"enable_msg_events":true,"port":41753},"up":true}},{"node":{"info":{"id":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","name":"node_dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","enode":"enode://57d7341b933399ef218e3b4e9155299740435d8f39d51bcd55eb0e0206cf3872b5d8edeabcb29fc52a10fb13b2332945895992ed536818ae3d5ca724da435216@127.0.0.1:0","enr":"0xf88fb840be4d387446799bfc72ee406a3f5bff45cefff30cb27b353e2b5d804cffcf842f47af74326db8059b3f239b4aed3f7aaf70e88870dacc93c7700ecde11e125b2d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10257d7341b933399ef218e3b4e9155299740435d8f39d51bcd55eb0e0206cf3872","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3RID4AYNsanC1ABSB4dWrf227EhVlOQRapl7nbyvkAI=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dd1203\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2653 0d52 | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 a010 95b4 | 4 95b4 (0) a010 (0) a61c (0) bdf0 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 c5bf c55a | 2 c5bf (0) c55a (0)\n004 1 d6f7 | 1 d6f7 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","private_key":"1d61966a5bf6ace65cb3663c40fcf26e51904e8ac267f799ba3804f58bc2515b","name":"node_dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","services":["streamer"],"enable_msg_events":true,"port":36287},"up":true}},{"node":{"info":{"id":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","name":"node_d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","enode":"enode://ccca2d21c63669239abca558b432ffda2abd413d3b4564be1c878d3ef8658697d42ef55b3c5fd79afd363a5d60e776e162371e6f50f49b2d78005d54d1212ed7@127.0.0.1:0","enr":"0xf88fb840be7cf77f4591f92fcdb31616f1dd8a29cb45f576ab0ac5ca1336aa394c6c9aad15013911a39a06cf43a096dd158fe05af68f9b36e3e68ab1ffe4663d5519ce730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ccca2d21c63669239abca558b432ffda2abd413d3b4564be1c878d3ef8658697","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1ver1O99kUTidqW6P8QIfsoRBt6tMz86IZyhjirElCI=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d6f7ab\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0d52 4c14 | 7 0d52 (0) 2653 (0) 6ff9 (0) 5942 (0)\n001 2 a61c a010 | 4 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n002 1 edd7 | 1 edd7 (0)\n============ DEPTH: 3 ==========================================\n003 2 c55a c5bf | 2 c5bf (0) c55a (0)\n004 1 dd12 | 1 dd12 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","private_key":"689c424f352a14e065158f6edd016775422abd2ca2e3b67121797457f8cb6b57","name":"node_d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","services":["streamer"],"enable_msg_events":true,"port":45859},"up":true}},{"node":{"info":{"id":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","name":"node_4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","enode":"enode://55b49fb5af1798f20da9536cf2b6b9be5f8660d6def0b5ab2031ed6ae8e4041f0a8787aa1e58f5b493fcb8839bf95058e4955790e5723c6c088ae104d10b42c5@127.0.0.1:0","enr":"0xf88fb840b116a8086d357c160f4515a7f567b528bd41cbf6da84bc00623ea30cd4d4cf052ada52dcb295f404c509d1319cd51139b0d12e9ad279da4a31483922e11a73730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10355b49fb5af1798f20da9536cf2b6b9be5f8660d6def0b5ab2031ed6ae8e4041f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TBRKwvTuSoZTo2Bc7CAWA4TPRxof369pSnIXcKKSVDQ=","hive":"\n=========================================================================\nThu Feb 28 18:00:04 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c144a\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a010 d6f7 | 9 a010 (0) a61c (0) bdf0 (0) 95b4 (0)\n001 2 2653 0d52 | 2 0d52 (0) 2653 (0)\n002 1 6ff9 | 1 6ff9 (0)\n003 1 5942 | 1 5942 (0)\n============ DEPTH: 4 ==========================================\n004 1 427e | 1 427e (0)\n005 0 | 0\n006 1 4ebd | 1 4ebd (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","private_key":"20caf36455148590aefee286656630f80eaf3452f0e12a90d0bec13e3319653b","name":"node_4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","services":["streamer"],"enable_msg_events":true,"port":43573},"up":true}}],"conns":[{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","other":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"95b48a9d194f42b8f19ef8ccde337cd221525e04848431a6d843ff968a5f4df5","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","up":true},{"one":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","other":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","up":true},{"one":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"594203c8fa170bece1eb12ac569b1731b86a603d07f5022a7d7b2bf205fc6151","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","other":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","up":true},{"one":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","other":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","up":true},{"one":"c55a176b1c185e526e17d2ac2556e59796bc1d3a6b814eecdb0ca9519c8c5163","other":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","up":true},{"one":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"d6f7abd4ef7d9144e276a5ba3fc4087eca1106dead333f3a219ca18e2ac49422","other":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","up":true},{"one":"bdf0122698c9da313740d2c9854ac5c177c63cdcc95e3ab415eed6eebd6614b6","other":"c5bf867c9ee0db831504395b444a7bf6c5f6c6d8d0b6c741296fcab03208491f","up":true},{"one":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","other":"6ff9a3f6f1f8019e366b59cce07e3737b1e6e4ba2b4ed9012cdd2b683908b004","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"a61c0fe541a562b08d92fabd643a48694fbfbaf704d1c782595ad0e9377a06b6","other":"0d529d1464743675d91fc4049d70f428b326f384e88ea14c53ff23a2e45a65be","up":true},{"one":"427e0288b5a474d9704df47bf2eb97b8af979bda199f86b7bd58824933958127","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"2653c3d78d1c11fd3a9e8043ae5c77037b01e05ddd2a3d4f6284844d098a23e5","up":true},{"one":"edd7b22a17fec3824d77db882b5fb4e82b08beca8d59e0f2dc8924f7bd6f8cee","other":"4ebda1ce79761129ce872f50bea9ae2df39d47e4cd7a1d8f1bb988c82b8667a9","up":true},{"one":"dd1203e0060db1a9c2d40052078756adfdb6ec485594e4116a997b9dbcaf9002","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true},{"one":"4c144ac2f4ee4a8653a3605cec20160384cf471a1fdfaf694a721770a2925434","other":"a0109d6c41a317e857f329f30898f7328dd3812d1fc7008a68fe38e6d804b7a2","up":true}]} \ No newline at end of file diff --git a/swarm/network/stream/testing/snapshot_256.json b/swarm/network/stream/testing/snapshot_256.json deleted file mode 100644 index 5e400d9245..0000000000 --- a/swarm/network/stream/testing/snapshot_256.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","name":"node_a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","enode":"enode://e70237456671b100c2341a568d85185f57c09cd699045f8c51f5a7bd09217bbf764379a2ad51b60e5671b978ee72cd33416e17520c75e471b4722f59533e3a4d@127.0.0.1:0","enr":"0xf88fb840ea2e2964e4c4bac440d5d5167638da0163abb3df513fa17601c4b04def5883ec78df971cc20ed10c00a8e9b5ba290305181507c49589c3c9026d28161f7dbe080183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e70237456671b100c2341a568d85185f57c09cd699045f8c51f5a7bd09217bbf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pG3VNeO8jxEaiyzlWUti6HdBw5Xoorj7rjPt0py4yvg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a46dd5\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 605a 00c6 0ff2 154b | 146 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n001 6 eb98 e775 fbc8 fbf5 | 63 e027 (0) e5ad (0) e5d7 (0) e547 (0)\n002 6 8505 8f21 88a1 9076 | 20 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n003 6 b2a5 b02b bcc6 bb90 | 17 bcc6 (0) baf2 (0) badd (0) ba88 (0)\n004 4 ad98 af02 ae2b aeb4 | 5 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n005 2 a369 a34e | 2 a369 (0) a34e (0)\n============ DEPTH: 6 ==========================================\n006 2 a653 a6fb | 2 a653 (0) a6fb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","private_key":"1e57a9344381e01bf32e09a979ec63d899dde10dd84d70ecb6404de10ff2fae7","name":"node_a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","services":["streamer"],"enable_msg_events":true,"port":43161},"up":true}},{"node":{"info":{"id":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","name":"node_13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","enode":"enode://101db8d36d797326a36adc76ff41e54a39cfe68b7948bd87bab4e7658bd81db7a962be72ffe4d52e15e65a5605b4fd7b3c5faba7fbeffcf6ce906951a9c4c520@127.0.0.1:0","enr":"0xf88fb84015cb00dd3c456518171748d8926d78335c0854b346464bf9bded32abbcc19aef5852275615470f0fe25130dd8ee37eff80afaa0ef7c7d14ea0f4f60e98b56ce20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102101db8d36d797326a36adc76ff41e54a39cfe68b7948bd87bab4e7658bd81db7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E9bLkxbiiZI+LR3n88lm0MurzjrNuAFxIpRPSrsUCRI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 13d6cb\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 cc20 d3b0 a46d | 110 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n001 4 53fe 4e5a 6e68 605a | 70 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n002 3 2f32 2c79 33b5 | 32 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n003 5 0b72 0af9 0ff2 0fc5 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n004 4 19fa 1e2a 1c8a 1c9c | 10 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n005 8 17db 179f 1672 165f | 9 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 6 ==========================================\n006 2 11d4 103b | 2 11d4 (0) 103b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","private_key":"37ebe30b2c356984a7e460228a022af51a6d955b24fb5e602226fc9b7cda2062","name":"node_13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","services":["streamer"],"enable_msg_events":true,"port":39877},"up":true}},{"node":{"info":{"id":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","name":"node_d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","enode":"enode://05700e757f48449baa479d9e9476883768725b33e1fc661afe18f3974b21d96fe414ceb6c1b7d6e501532e17c7ff740237837c2c812daabed849b5e7797917fe@127.0.0.1:0","enr":"0xf88fb840fac5d8d078a46572c426af0322faba829283795e739c471fc3d33d0395f8e49c52370fb9373e1c6299bc9c5b3716e5af57a39614e8848375d97a3687d2ee89480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10205700e757f48449baa479d9e9476883768725b33e1fc661afe18f3974b21d96f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"07Deod06xx5+SjCUFjLuxTy5gKp8ts2slQQqVACoeMM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3b0de\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 53fe 7dd3 605a 13d6 | 146 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n001 5 9076 a46d a34e b911 | 47 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n002 10 e54b e775 eb98 e883 | 37 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n003 6 c1f9 c6cf c620 c832 | 15 c26f (0) c1f9 (0) c49c (0) c441 (0)\n004 3 daec db6a d887 | 6 df1e (0) d863 (0) d887 (0) db6a (0)\n005 2 d7ac d640 | 2 d7ac (0) d640 (0)\n============ DEPTH: 6 ==========================================\n006 1 d1d7 | 1 d1d7 (0)\n007 1 d299 | 1 d299 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","private_key":"ca03d9ece7d38bee50629933e237f3019a21e19182e1bd49826c89f10e625121","name":"node_d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","services":["streamer"],"enable_msg_events":true,"port":42617},"up":true}},{"node":{"info":{"id":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","name":"node_605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","enode":"enode://a621f4d598855f913a837abe294df8a44fde676e99ed3976972afa30e977462ef16b40a84fb8f439031420d103f4021f5540aa0936b9d4d1e466aa23cae18e32@127.0.0.1:0","enr":"0xf88fb840ed422154098e8b2ec11a4d63bf0da7d8edd6aec4b81b5e574a6a95562ed8c0656a0983ebe8fba7fd52f8a50a73f3e705730466a0881af12efe9e510ad718fd680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a621f4d598855f913a837abe294df8a44fde676e99ed3976972afa30e977462e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YFpGmRrxXNYOZ0E8cSuZ/48hFzyWp5kPJyitbKwrudg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 605a46\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a46d d3b0 | 110 8f21 (0) 898d (0) 886a (0) 88fe (0)\n001 7 0ff2 154b 103b 13d6 | 76 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n002 12 5efb 5cd2 5823 5308 | 38 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n003 3 7125 7920 7dd3 | 12 77d2 (0) 775e (0) 7290 (0) 738c (0)\n004 2 6c73 6e68 | 11 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n005 2 67dc 66e7 | 3 67aa (0) 67dc (0) 66e7 (0)\n006 3 6337 6251 628e | 3 6337 (0) 6251 (0) 628e (0)\n============ DEPTH: 7 ==========================================\n007 1 6103 | 1 6103 (0)\n008 1 60d7 | 1 60d7 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","private_key":"09e7ba543ec6e7608729d561d0dfecef5bd8e50c9849d1baedfbf09f6be28e97","name":"node_605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","services":["streamer"],"enable_msg_events":true,"port":40563},"up":true}},{"node":{"info":{"id":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","name":"node_2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","enode":"enode://09caa0d3176bb2ab29defcb47bc43b066d3f667c2b923fcec05025ee44028c3c8f8151181b4715a567bfe6442b1696c1b5d4436e2673dae648713c1ced646d9d@127.0.0.1:0","enr":"0xf88fb8407cecec0b472dc2d08e251d9584eb234456d972c76227ef38539f0041d03df5e22e4ba13445b3e93db9a066c6c96db30cee8dc4ded48f5cd06f2161f2c21a1fc80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10309caa0d3176bb2ab29defcb47bc43b066d3f667c2b923fcec05025ee44028c3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LHmvfqhfltt4l8+M200AKtIwgZTgOYGHbtuNkE72UTc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c79af\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c620 cc20 b911 | 110 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n001 5 4e5a 53fe 6c73 6e68 | 70 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n002 8 00c6 0fc5 0ff2 1c9c | 44 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n003 9 3e8e 39d1 3b78 3630 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n004 2 2101 21a0 | 6 256e (0) 24b8 (0) 20ae (0) 217f (0)\n005 3 2995 2abb 2a97 | 4 2995 (0) 2a0a (0) 2a97 (0) 2abb (0)\n006 1 2f32 | 1 2f32 (0)\n007 1 2d36 | 1 2d36 (0)\n============ DEPTH: 8 ==========================================\n008 1 2ccf | 1 2ccf (0)\n009 1 2c38 | 1 2c38 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","private_key":"3721498524efb06914a5509b27d864ad186f58e36aab5c7593d0e9cd263282a7","name":"node_2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","services":["streamer"],"enable_msg_events":true,"port":43339},"up":true}},{"node":{"info":{"id":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","name":"node_33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","enode":"enode://7bd8d32df25aaea11952de45f43b3067ec805d9e5c021d0f3ef3ec8916a479dd7ecbfee5a23baed4b751b218c345dd7c9670b8838660d0f010cd1389511e67d5@127.0.0.1:0","enr":"0xf88fb840a37a97fe62ec10c3a463048f5dcaa531e72b6859a704ec6633378ca65afe843a02afe1d4678cd54a8f60a67f20f71a50363415c56c3e3107b4b11d493015e53e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037bd8d32df25aaea11952de45f43b3067ec805d9e5c021d0f3ef3ec8916a479dd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"M7XFIbQgjiZBTbLgXJqMzAAaUk2ShXnUTS500UpWWT4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 33b5c5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b02b b911 | 110 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n001 7 6e68 6c73 605a 7dd3 | 70 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n002 6 00c6 0ff2 0fc5 1c9c | 44 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n003 3 21a0 2f32 2c79 | 15 256e (0) 24b8 (0) 20ae (0) 217f (0)\n004 7 39d1 3b88 3b78 3f94 | 7 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n005 3 3630 378e 35e6 | 4 35e6 (0) 3780 (0) 378e (0) 3630 (0)\n006 3 314a 30be 3089 | 3 30be (0) 3089 (0) 314a (0)\n============ DEPTH: 7 ==========================================\n007 1 3237 | 1 3237 (0)\n008 1 3373 | 1 3373 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","private_key":"fa8a4740b23a1fa3955c662fee2883cc8d1a1e26853b72c3acc66583d6aa2898","name":"node_33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","services":["streamer"],"enable_msg_events":true,"port":39497},"up":true}},{"node":{"info":{"id":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","name":"node_b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","enode":"enode://f909dfa9cf0586fa20c170d7affbef6b9b835d1603c91ed04c0854b16fa42c4eff293cff2e695634d99bdd6ec5a61f219637eb7d885c25b232685d17bd3572b2@127.0.0.1:0","enr":"0xf88fb84004bc964ea8b933d6a3b0265d90808e3f4109cca5b450a732ab97fedfaa6a55b245cab741804fbe671adca5d7a5ad32223302e2908db90622ca8acdba2f84920b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f909dfa9cf0586fa20c170d7affbef6b9b835d1603c91ed04c0854b16fa42c4e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uRG44tclMrfGb/X3v/pw9d2+6mkDqG+TMzmfDEtfD+g=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b911b8\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4990 53fe 2c79 33b5 | 146 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n001 4 fbf5 d887 d3b0 cc20 | 63 e027 (0) e5d7 (0) e5ad (0) e547 (0)\n002 5 9852 9076 90a8 8f21 | 20 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n003 2 a34e a46d | 10 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n004 3 b7ca b2a5 b02b | 8 b5b2 (0) b502 (0) b626 (0) b65e (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 baf2 badd ba88 bb90 | 4 baf2 (0) badd (0) ba88 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b820 b897 | 2 b897 (0) b820 (0)\n008 0 | 0\n009 1 b95d | 1 b95d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","private_key":"2cb79ca016623c39541a82f657e334cd812977188909b562564102890d58ec54","name":"node_b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","services":["streamer"],"enable_msg_events":true,"port":45307},"up":true}},{"node":{"info":{"id":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","name":"node_53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","enode":"enode://b3104e6e79d026630bfe72e7d9efdb57be3f806110418652fb6840c1361f7d1e0e8521b82a7cf884571ce3b7bedf9787826e57b92e334766c65f24eb470f23ed@127.0.0.1:0","enr":"0xf88fb84015b01d0b7cd1ab6245a7bc8d8bb6c97f6032ed9a1ecc96eb5da3cbc3a3aa79f52a326ea510a5735c19c69a5ee802c07098946041df153aab94dad596c2bc21f50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b3104e6e79d026630bfe72e7d9efdb57be3f806110418652fb6840c1361f7d1e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U/4sE5JlB6emwn0PswosNYxMe/pA34tfqOyJhsJFBRk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 53fe2c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 cc20 d3b0 b02b b911 | 110 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n001 5 33b5 2c79 0ff2 103b | 76 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n002 5 6c73 628e 605a 7125 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 6 41d9 4109 4646 4c9e | 23 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n004 4 5efb 5cd2 58ed 5823 | 7 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n005 1 574f | 1 574f (0)\n006 2 512e 51db | 2 512e (0) 51db (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 5308 534b | 2 5308 (0) 534b (0)\n009 1 53a8 | 1 53a8 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","private_key":"70c31ba2f1ff647ffa877b174d1fe7441de6f4ed5e17bbd9857812f35ab10cba","name":"node_53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","services":["streamer"],"enable_msg_events":true,"port":46299},"up":true}},{"node":{"info":{"id":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","name":"node_4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","enode":"enode://2065647ff3dd80dc4e4ebc9a2a8be828f0efaefbb62e2d2b4ccd246f0cc30aa51459e66d352c9ed8b5126ea9e76aeab74cdf95dcad19c9c9cc2fc3706e83d12b@127.0.0.1:0","enr":"0xf88fb840822110c309aaded4c3d0d3c1fca5a0910e094971e98cd41b5225e201d8a965831ec1d234aeb2560ed5dd98a3db6a230653d4e43c14afb51e34bfbf8de69341d90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032065647ff3dd80dc4e4ebc9a2a8be828f0efaefbb62e2d2b4ccd246f0cc30aa5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TlpGwAToXPhqAv378iQwGIJdAV3r+5oHehKD0wIpOzo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4e5a46\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b02b cc20 | 110 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n001 5 154b 103b 13d6 2c79 | 76 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n002 6 7920 7dd3 7125 6c73 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 5 5823 5cd2 5308 534b | 15 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n004 4 4646 461c 4109 41d9 | 12 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n005 4 4bcf 49cd 49ea 4990 | 6 4ac7 (0) 4a8b (0) 4bcf (0) 4990 (0)\n============ DEPTH: 6 ==========================================\n006 4 4c9e 4d10 4d6b 4d59 | 4 4c9e (0) 4d10 (0) 4d6b (0) 4d59 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","private_key":"cd1095af24a2b4f0a0fa3730f681b7d6c26b93a51081cc8f382764a83a73fb86","name":"node_4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","services":["streamer"],"enable_msg_events":true,"port":39501},"up":true}},{"node":{"info":{"id":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","name":"node_cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","enode":"enode://502433c8d1cf2f8fd7b92aefbf87918e268ee26b2850e20aeb3c4ce61c1cb2049af306124476e27a64b98fe49f9261b104ac5bc18643219c3718fd8c03296707@127.0.0.1:0","enr":"0xf88fb8404a286e1fcc023da2601459dc781096bc67a869b3de88ab00755589aa44b0389e18638b7526b4bb40b059179c918c417acbde016bb95edc6c9eefd89121cc42990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103502433c8d1cf2f8fd7b92aefbf87918e268ee26b2850e20aeb3c4ce61c1cb204","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zCA3wIlCoJTfEvRYMfKOABX8OsBNW48k/+qb86CwLDk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc2037\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 00c6 13d6 2c79 7dd3 | 146 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n001 5 9076 aeb4 a46d b911 | 47 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n002 9 e775 e883 e854 eb98 | 37 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n003 3 d887 daec d3b0 | 11 df1e (0) d863 (0) d887 (0) db6a (0)\n004 4 c1f9 c26f c6cf c620 | 9 c26f (0) c1f9 (0) c59e (0) c49c (0)\n============ DEPTH: 5 ==========================================\n005 5 ca04 caf6 c9f5 c832 | 5 ca04 (0) caf6 (0) c9f5 (0) c832 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","private_key":"d23c0a28f40bce284a142b72daad5397f586194601126aedc3df40587d9d45f6","name":"node_cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","services":["streamer"],"enable_msg_events":true,"port":35445},"up":true}},{"node":{"info":{"id":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","name":"node_b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","enode":"enode://08f5b135b35456f2574282474266d863656df0ef0eb157876e12d53c7d6e01e0260e147f6ba3f2b2a1119697aeb464cf61f20f648990b075b98572cb11685c0d@127.0.0.1:0","enr":"0xf88fb8406c19c1ab095388f46d4d6ef2da794ca56fc16daaece67a7e979009f62b74daee01fd0cea0017acf50b872bb9015ad225678c2ca166e45f0d74a1a305d7ded0110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10308f5b135b35456f2574282474266d863656df0ef0eb157876e12d53c7d6e01e0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sCsBpcN8sFwoej3H0E4wXeJvjWLcOIVC7rQ+l9t7QoI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b02b01\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 33b5 6e68 53fe 4990 | 146 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n001 8 e854 eb98 f925 fbf5 | 63 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n002 9 90a8 9076 9fa0 9852 | 20 8f21 (0) 898d (0) 886a (0) 88fe (0)\n003 5 aeb4 ae2b a6fb a46d | 10 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n004 7 bcc6 badd ba88 bb90 | 9 bcc6 (0) baf2 (0) badd (0) ba88 (0)\n005 4 b5b2 b626 b65e b7ca | 5 b5b2 (0) b502 (0) b626 (0) b65e (0)\n============ DEPTH: 6 ==========================================\n006 2 b2b5 b2a5 | 2 b2b5 (0) b2a5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","private_key":"473b45c9196c27d9ae4135ac8cbc2ea31c3a7f7c0b77117fe484b2a4ecd3913e","name":"node_b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","services":["streamer"],"enable_msg_events":true,"port":38045},"up":true}},{"node":{"info":{"id":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","name":"node_a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","enode":"enode://340c7a971a97f9d8f8868b1336bacbe73503e3e1088ac108d216a23c970b04c677ff52e704844600618f76887b06e7083345056961f77a396e2366191ae76f87@127.0.0.1:0","enr":"0xf88fb840f67e5492b185e03ad9fba3676256587139f92c1a0395454a66d28eab0ddfcd3f02717c57b13697f286929dc5ec9737a829e17a8632a202512d46dd89a8406a2c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103340c7a971a97f9d8f8868b1336bacbe73503e3e1088ac108d216a23c970b04c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"o06i6H1MEq2yfWbCyVMAYD/1BBWXTgALvMaaWuBZ2/E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a34ea2\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0ff2 1c9c 6e68 7dd3 | 146 1400 (0) 1436 (0) 14df (0) 154b (0)\n001 6 c620 daec d3b0 e775 | 63 df1e (0) d863 (0) d887 (0) db6a (0)\n002 6 82dd 8505 9076 9fa0 | 20 898d (0) 886a (0) 88fe (0) 88a1 (0)\n003 7 bcc6 b897 b820 b95d | 17 bcc6 (0) ba88 (0) baf2 (0) badd (0)\n004 3 ae2b aeb4 af02 | 5 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n============ DEPTH: 5 ==========================================\n005 3 a653 a6fb a46d | 3 a653 (0) a6fb (0) a46d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 a369 | 1 a369 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","private_key":"68b17ea93b738afd30952707cc7ba1bcc7dbb9a01631477f8d2b2a7f76a83fb5","name":"node_a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","services":["streamer"],"enable_msg_events":true,"port":44293},"up":true}},{"node":{"info":{"id":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","name":"node_7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","enode":"enode://60f4239fd937907e183edf421b9d1df38ea30f43d5bee23ed23f4b7e9e7b801d14006d4e11987b57cd00d7470c31b17e35e6534bdb642b68fcb9f6becdbc4a41@127.0.0.1:0","enr":"0xf88fb84086961ac0d94caace96d4805f4c5c2470e4da31be8b2a85bde0d3ca0b156472865a13c690728f4e37c1986d173045b80d817727c2ebe0a139bffcdde97847468c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10360f4239fd937907e183edf421b9d1df38ea30f43d5bee23ed23f4b7e9e7b801d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fdMHjHEIeriNTSapYoILy3m4zjDpHB+aadS/jTgIaWA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dd307\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d3b0 daec c620 cc20 | 110 df1e (0) d863 (0) d887 (0) db6a (0)\n001 6 39d1 33b5 2f32 11d4 | 76 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n002 12 49ea 4990 4d59 4e5a | 38 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n003 8 66e7 628e 6337 6103 | 20 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n004 5 7125 7290 738c 77d2 | 5 77d2 (0) 775e (0) 7290 (0) 738c (0)\n005 3 7b90 7a60 7920 | 3 7b90 (0) 7a60 (0) 7920 (0)\n006 1 7e04 | 1 7e04 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 7dbb | 1 7dbb (0)\n010 0 | 0\n011 1 7dc2 | 1 7dc2 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","private_key":"02f0e74d872f0a512a39d40801b92a40eb0a1e27e97da040a97c75e0af22af6f","name":"node_7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","services":["streamer"],"enable_msg_events":true,"port":35881},"up":true}},{"node":{"info":{"id":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","name":"node_6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","enode":"enode://6076aa2f272b91cbd2e5db03c497a76d92991b2fb747c5f3aeaef27c702b0e65edaea0879b23d0e37e2812ff67bc7a92c4131c69a912819fd4d2627fade5427a@127.0.0.1:0","enr":"0xf88fb8400138d5775c80387427a7dff700a0cc533dba63b5a23dd02a7fb85988266d0ce64206c9dc261a206b4784a306a82fe5f001cab02a87039a50c4ed1fec2a1f41250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026076aa2f272b91cbd2e5db03c497a76d92991b2fb747c5f3aeaef27c702b0e65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bmjqhkQHBqDXOpUI8iR0klQxY/j6fi3CqmK3TVAmG4s=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e68ea\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b02b a34e fbf5 | 110 898d (0) 886a (0) 88fe (0) 88a1 (0)\n001 9 0ff2 1c9c 13d6 165f | 76 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n002 9 5efb 5cd2 5823 4646 | 38 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n003 2 7125 7dd3 | 12 77d2 (0) 775e (0) 7290 (0) 738c (0)\n004 6 67dc 66e7 628e 6251 | 9 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n005 2 6831 6967 | 2 6831 (0) 6967 (0)\n006 2 6c4d 6c73 | 2 6c4d (0) 6c73 (0)\n007 3 6fe9 6f2d 6f5f | 3 6fe9 (0) 6f2d (0) 6f5f (0)\n============ DEPTH: 8 ==========================================\n008 2 6ecb 6ea5 | 2 6ecb (0) 6ea5 (0)\n009 1 6e05 | 1 6e05 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","private_key":"b20c8d0606ea1db41eabd7ee0f74574539d2cb45d6d4241b6f259b11ac5c2d24","name":"node_6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","services":["streamer"],"enable_msg_events":true,"port":35593},"up":true}},{"node":{"info":{"id":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","name":"node_7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","enode":"enode://e0da25d10aa370ec66f23c45b05eb96ffd8c7378b53214086b29b8e7800cecdc291eb7be7c52ae40f148f79cc7f7417d37617a7dc017b52b4e7692cd22d59b94@127.0.0.1:0","enr":"0xf88fb8409127cf3b56541dad915db116d184cbf4b62a37124cc76bc88b18b2861040ba7f76dca86df9a3fd341069ce7f7e319d900b1fb1f423bfe91145a0347aceb60f3b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e0da25d10aa370ec66f23c45b05eb96ffd8c7378b53214086b29b8e7800cecdc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cSXgW/G/5t+UjJJ2tivHVfxrDsjUrHckth6klZGtzyU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7125e0\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9076 8505 82dd fbf5 | 110 886a (0) 88fe (0) 88a1 (0) 898d (0)\n001 4 39d1 33b5 2f32 1c9c | 76 3b88 (0) 3b78 (0) 39d1 (0) 3f94 (0)\n002 11 5efb 5cd2 53fe 534b | 38 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n003 6 66e7 628e 6103 605a | 20 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n004 5 7920 7e04 7dd3 7dc2 | 7 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n005 2 77d2 775e | 2 77d2 (0) 775e (0)\n============ DEPTH: 6 ==========================================\n006 2 7290 738c | 2 7290 (0) 738c (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","private_key":"0320cf6d59b1fdfd3bd90c7b0e801cb9f574b5bda4809f6842e344263d8a9c4c","name":"node_7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","services":["streamer"],"enable_msg_events":true,"port":34651},"up":true}},{"node":{"info":{"id":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","name":"node_fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","enode":"enode://044552ed8018a3d7a6edcd78b62c7b776f3ea64af85049a170539a9353c32990f61afd5aed5a849eebb4c541418048952b2a969128241782caf66fff588c5576@127.0.0.1:0","enr":"0xf88fb840fb8c98615b2fd9a6ce30296aa151456746d7ff6f93f25567ad09135e11d5912567e796ddb7e02868851acd52d94dabe5f73d7421af7f4e91cb511b49744b23710183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102044552ed8018a3d7a6edcd78b62c7b776f3ea64af85049a170539a9353c32990","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+/XpF75F6QlpepOTxHeCBjM88d2aEDl46NcWIso7HMg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fbf5e9\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 154b 1c9c 0ff2 0fc5 | 146 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n001 7 8f21 9076 9852 b911 | 47 898d (0) 886a (0) 88fe (0) 88a1 (0)\n002 2 d3b0 cc20 | 26 c26f (0) c1f9 (0) c59e (0) c49c (0)\n003 5 e883 e854 eb98 e54b | 18 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n004 12 f27f f31c f629 f7fa | 13 f629 (0) f7fa (0) f7ba (0) f773 (0)\n005 3 ff36 fe21 fe31 | 3 ff36 (0) fe31 (0) fe21 (0)\n============ DEPTH: 6 ==========================================\n006 1 f925 | 1 f925 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 fbc8 | 1 fbc8 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","private_key":"abe3a2c3b4d87e1896b5eeb333bb2fae65888f42d5708e88df6eec9d4d6f2a89","name":"node_fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","services":["streamer"],"enable_msg_events":true,"port":42599},"up":true}},{"node":{"info":{"id":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","name":"node_0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","enode":"enode://22e0f016453557931968739b1927c6a2a96b3b3ef0720b9f574365f821ff4afa7d162aced052618c51e939baeec49bbda090ea6f2a5b14b3ced028e3587b4d51@127.0.0.1:0","enr":"0xf88fb8402397168cccae2be13f6646db7bd1f2d478d9124f8397e08ceae0045ca8baa3242f68f4c83fd1744b397234b474e6f46b048fd0d74acb55d3f44dc78d0dfede6b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10322e0f016453557931968739b1927c6a2a96b3b3ef0720b9f574365f821ff4afa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D8Wb0ErJ3jGV48nQ61c5UqWAXdLn5XIHi26ZZ3it7HM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0fc59b\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 90a8 9076 82dd 8505 | 110 898d (0) 886a (0) 88fe (0) 88a1 (0)\n001 2 7dd3 41d9 | 70 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n002 4 3e8e 33b5 2c79 2f32 | 32 3b78 (0) 3b88 (0) 39d1 (0) 3f94 (0)\n003 4 165f 154b 13d6 1c9c | 22 14df (0) 1400 (0) 1436 (0) 154b (0)\n004 4 0328 00c6 045b 0661 | 11 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n005 3 0b72 0a00 0af9 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 5 0d8a 0de3 0cf5 0c64 | 5 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 7 ==========================================\n007 1 0e5e | 1 0e5e (0)\n008 0 | 0\n009 0 | 0\n010 1 0ff2 | 1 0ff2 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","private_key":"ab99d1389adc583c136dfe3f4569fbb9ce9ea477cc13a503e1a4aa3f557edffc","name":"node_0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","services":["streamer"],"enable_msg_events":true,"port":44559},"up":true}},{"node":{"info":{"id":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","name":"node_0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","enode":"enode://e62b09e34b132f4e59783ab65b9fb191398665c73b314a5fb36715728f869e8e608b374a91e22c4de5eae4fdff9ec4d2e9509c8e1a9c32e675fcf6fee76714f2@127.0.0.1:0","enr":"0xf88fb8409dc12163f250583e65c4c1bb7a368c6d27bbf9a62a49b5b3e99603fa802b0e227379f85879f46521bb12306b9d59b270796787b4da47ad4e0a1a688a4a5ac66c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e62b09e34b132f4e59783ab65b9fb191398665c73b314a5fb36715728f869e8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D/LSxJVH7ryWZ14LiAc96l6Qkb7hhD/+VnEn40SGw0g=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ff2d2\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a34e a46d 9076 9852 | 110 88fe (0) 88a1 (0) 886a (0) 898d (0)\n001 7 6e68 6c73 66e7 605a | 70 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n002 4 3e8e 33b5 2f32 2c79 | 32 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n003 5 154b 179f 165f 13d6 | 22 11d4 (0) 103b (0) 13d6 (0) 1400 (0)\n004 5 0661 045b 0328 0067 | 11 0438 (0) 0451 (0) 045b (0) 0743 (0)\n005 3 0b72 0af9 0a00 | 3 0b72 (0) 0af9 (0) 0a00 (0)\n006 4 0d8a 0de3 0cf5 0c28 | 5 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 7 ==========================================\n007 1 0e5e | 1 0e5e (0)\n008 0 | 0\n009 0 | 0\n010 1 0fc5 | 1 0fc5 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","private_key":"b07ba37d3566d0d06613c70c3b970828a35c02d35d3ef97c26f1e431564cbc71","name":"node_0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","services":["streamer"],"enable_msg_events":true,"port":36663},"up":true}},{"node":{"info":{"id":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","name":"node_582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","enode":"enode://e1459426b83f1c65c5a4dac403ae9a8773d1fadf7f57014afe1f5632b40de446b925e309ac581a098f0a8597f54b231887ddef9fb033832546b7b1c438536514@127.0.0.1:0","enr":"0xf88fb84034a6c607747bfdaaddea35634f841a275979e6eb07a13c4806c7988076977d676c9cbe2a8b59da6776cf329633bf937933eebe202770e6b4cd1dc70b794785850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e1459426b83f1c65c5a4dac403ae9a8773d1fadf7f57014afe1f5632b40de446","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WCMw2LjEkzGyrseQ3HMluc1IP8gSkyPTHsQp1UUEKWQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 582330\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eb98 fbf5 | 110 8f21 (0) 898d (0) 886a (0) 88fe (0)\n001 2 1c9c 0ff2 | 76 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n002 5 7920 7dd3 605a 6e68 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 7 4c9e 4d6b 4d59 4e5a | 23 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n004 7 574f 51db 524d 5308 | 8 574f (0) 512e (0) 51db (0) 524d (0)\n005 3 5cd2 5db0 5efb | 4 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n============ DEPTH: 6 ==========================================\n006 1 5b63 | 1 5b63 (0)\n007 0 | 0\n008 1 58ed | 1 58ed (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","private_key":"e0e4076ce60393be8ae8f561ab3bbb784e5d4b9cf9044cbea245608f94062e9f","name":"node_582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","services":["streamer"],"enable_msg_events":true,"port":44383},"up":true}},{"node":{"info":{"id":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","name":"node_41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","enode":"enode://f68ed6030af61743ebafe811b9833a5cc29e35d00e6e0181d06feef9ca714898bed30f326a49a3c145cd1002a24d9c5ae79c2787464e58cd24dcf59fd0760bc1@127.0.0.1:0","enr":"0xf88fb8408b71d88c0475a30d0141a21ead67266d6a40391c609d4fbb1c376e0f05e920160e6dbbc8db17d82a85e5121346b02f6c670e28e88acba5d763a1986cea5bedf90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f68ed6030af61743ebafe811b9833a5cc29e35d00e6e0181d06feef9ca714898","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QdnAPkS+w/hKYTnOQO8eOQUw847RGGBXWs+tA6SdsJU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 41d9c0\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 daec eb98 fbf5 | 110 ad98 (0) ac4d (0) af02 (0) ae2b (0)\n001 3 314a 0fc5 1c9c | 76 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n002 8 7125 7920 7dd3 66e7 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 5 534b 53fe 5efb 5cd2 | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 7 4990 49ea 4bcf 4c9e | 11 49cd (0) 49ea (0) 4990 (0) 4a8b (0)\n============ DEPTH: 5 ==========================================\n005 10 47bf 4782 46fe 4646 | 10 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n006 0 | 0\n007 0 | 0\n008 1 4109 | 1 4109 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","private_key":"1165ce19cad30464dac1767d11f8462ee17a275b99240f7757f516575dae8bd3","name":"node_41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","services":["streamer"],"enable_msg_events":true,"port":39051},"up":true}},{"node":{"info":{"id":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","name":"node_1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","enode":"enode://27e2579492f09c50dbc56b6542114d27789897327092c0ddacbabe5f3916be86362afe3b61ec3ea54eb7d39401f7a9307901cacc84a5cb54ab868b4b8c28cbe0@127.0.0.1:0","enr":"0xf88fb840a0df68e76ebed32c21b033b1570b6dcdb45783053022b12bc2763acfd7929fbe3ac0306848c56ad630845f8c05dfc0b47d2976e01c8e1f91cc270fd9f6846edf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10227e2579492f09c50dbc56b6542114d27789897327092c0ddacbabe5f3916be86","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HJyvAo3zFoGxRXpU1LOrIACfn6W9EkF6G6fv4MZg5r0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1c9caf\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a34e 9852 daec fbf5 | 110 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n001 7 66e7 6e68 7125 534b | 70 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n002 5 314a 33b5 3e8e 2c79 | 32 39d1 (0) 3b88 (0) 3b78 (0) 3f94 (0)\n003 5 0661 00c6 0af9 0fc5 | 22 0438 (0) 0451 (0) 045b (0) 07a8 (0)\n004 10 154b 1400 1436 14df | 12 11d4 (0) 103b (0) 13d6 (0) 1400 (0)\n005 3 1a2a 18f6 19fa | 4 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n006 3 1f85 1f67 1e2a | 3 1f67 (0) 1f85 (0) 1e2a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 1c47 | 1 1c47 (0)\n009 0 | 0\n010 0 | 0\n011 1 1c8a | 1 1c8a (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","private_key":"67941e3130de030151f98c59f040e588508b299893d26eede53fbfd0400f76a6","name":"node_1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","services":["streamer"],"enable_msg_events":true,"port":40355},"up":true}},{"node":{"info":{"id":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","name":"node_4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","enode":"enode://eb61dee424d25e9ca5147121a89b8dfc8e186fd83ad973d590fe6f050e5ad71094b18d539d127b7699769bd08e722bf1d253c42d9dcd7bd744efb8d90b7517bc@127.0.0.1:0","enr":"0xf88fb8409303866ac69b06db6e9cd2c5bf37b2046d4ba9be08473191181141ebc1a822e37088c33aaa9d396ad7398756422d234de878117f2cce3bd9477b23860a9bcea00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102eb61dee424d25e9ca5147121a89b8dfc8e186fd83ad973d590fe6f050e5ad710","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TVnPGu7PNw6Up6IxiHRQzvlwU7nIin/RHiEIQK8HDik=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d59cf\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9852 c898 eb98 | 110 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n001 2 1c9c 2f32 | 76 02d8 (0) 03cc (0) 0328 (0) 0067 (0)\n002 6 7125 7dd3 7920 605a | 32 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n003 4 5823 5cd2 534b 53fe | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 3 4646 4109 41d9 | 12 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n005 3 4990 49ea 4bcf | 6 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n006 1 4e5a | 1 4e5a (0)\n007 1 4c9e | 1 4c9e (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 4d10 | 1 4d10 (0)\n010 1 4d6b | 1 4d6b (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","private_key":"37294667aa7ef5913f670784ca64ca2422b73d30730798e5ba9d0dce067d5f04","name":"node_4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","services":["streamer"],"enable_msg_events":true,"port":41171},"up":true}},{"node":{"info":{"id":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","name":"node_2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","enode":"enode://27ddb367d5d4a30ad5888523d743494926b5a27942077719cc6c537b73f04bb87f65cddfb3cfc09a733c1691c43c7a9afe8b9e268ee323af1f8d8a85beea4cb5@127.0.0.1:0","enr":"0xf88fb840772057c835ac9c84a2eaa07977982bbc77cdb5dbc67b095e1b64eba4bd7364362a8286caab1fac316b5f9c128103397f945e78d6d1f10dbe310fb1a21a5657680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10327ddb367d5d4a30ad5888523d743494926b5a27942077719cc6c537b73f04bb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LzLVTwaYnvtspUMbdM11n7oF2+827P+P1QbmYgJq+YM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2f32d5\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9852 c620 daec eb98 | 110 ad98 (0) ac4d (0) af02 (0) ae2b (0)\n001 5 6e68 7125 7dd3 534b | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 6 0661 0ff2 0fc5 13d6 | 44 02d8 (0) 03cc (0) 0328 (0) 0067 (0)\n003 6 314a 33b5 3b78 3efc | 17 3780 (0) 378e (0) 3630 (0) 35e6 (0)\n004 4 256e 24b8 2101 21a0 | 6 24b8 (0) 256e (0) 20ae (0) 217f (0)\n005 2 2a97 2abb | 4 2995 (0) 2a0a (0) 2a97 (0) 2abb (0)\n============ DEPTH: 6 ==========================================\n006 4 2d36 2ccf 2c38 2c79 | 4 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","private_key":"fb9c0c109d964d1f2840834912ab8fb4d275c821c47cbacf4865721f774ad246","name":"node_2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","services":["streamer"],"enable_msg_events":true,"port":37983},"up":true}},{"node":{"info":{"id":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","name":"node_eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","enode":"enode://e478db1e6ae924395ba7c3eed4a3c1161fed7757938dbc6e802fca7e8daac58d16f9cf87017d684499f9aa2c5ea3ebbf74805e24b5454661a4f12af2bd9b4e69@127.0.0.1:0","enr":"0xf88fb84083fabf1c86dbfb7ea406905cb02c1a05b4cd8e41ee010679b981abb41d7ef8ba1e5f916713c12c739fd237f35952c0e01b65faf2bdffe581e53b602ef397cd470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e478db1e6ae924395ba7c3eed4a3c1161fed7757938dbc6e802fca7e8daac58d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"65j7Rd1XVPJPnfDJ7LuTky49nXc1zW0N3UqGdbtO9VQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb98fb\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5823 41d9 4d59 103b | 146 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n001 5 b820 b02b a46d a34e | 47 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n002 6 d3b0 d887 daec c898 | 26 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n003 9 fbc8 fbf5 f925 f773 | 19 f629 (0) f7fa (0) f7ba (0) f773 (0)\n004 5 e027 e775 e7fa e514 | 8 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n005 5 ed2d ee5e ef1b ef07 | 6 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n============ DEPTH: 6 ==========================================\n006 3 e8ef e883 e854 | 3 e8ef (0) e883 (0) e854 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","private_key":"ab86a41209d246a5d6b5c8bf86ba8d32901ffa817d143a63719c1189703ae84f","name":"node_eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","services":["streamer"],"enable_msg_events":true,"port":43213},"up":true}},{"node":{"info":{"id":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","name":"node_9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","enode":"enode://e78bf7b14baa9f968a1eab4abb0ffcc6aaf7f6a3152a59d6b404ef00232ff35cf55fa13f6190c6cb6bcfa4394bb912d7dab1d491f2d39ed7b43029d0f99319d0@127.0.0.1:0","enr":"0xf88fb84029d6cf3fe0d8101f62b9bf17bad9b25f903639962d22b9643a3a6216b8946f00593519afbe56588bbd1e0e52d3a0339778deb5c4c780a818db4c44140fd7bd930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e78bf7b14baa9f968a1eab4abb0ffcc6aaf7f6a3152a59d6b404ef00232ff35c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mFLOJn1TEGpuWE1u3bCOAGLrSkItKo05rW3MrrrFUv8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9852ce\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0ff2 165f 1c9c 2f32 | 146 3780 (0) 378e (0) 3630 (0) 35e6 (0)\n001 4 daec fbc8 fbf5 eb98 | 63 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n002 9 b02b b2a5 bcc6 b911 | 27 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n003 5 8f21 88a1 8505 849b | 10 898d (0) 886a (0) 88fe (0) 88a1 (0)\n004 4 9076 90a8 976e 96fc | 6 959f (0) 976e (0) 96fc (0) 915d (0)\n============ DEPTH: 5 ==========================================\n005 2 9d0f 9fa0 | 2 9d0f (0) 9fa0 (0)\n006 0 | 0\n007 0 | 0\n008 1 9890 | 1 9890 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","private_key":"ce304c9eade55eb825a72feda5a3d11f9ae9261aadf2bdd54ccd8f3e963dc251","name":"node_9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","services":["streamer"],"enable_msg_events":true,"port":43037},"up":true}},{"node":{"info":{"id":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","name":"node_daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","enode":"enode://8a808e57c6bcbab9333ebbeb571f922303b1bb3197db84c5ff936033294f12429f7b8b06da61e7c04ad7f7c039e2b765b324069428cf86ad8a2d4bddca8d9948@127.0.0.1:0","enr":"0xf88fb84027da20f74a296f9b64d09eb538af5e462aececd8a624e3ac95423f168b062f7c4c6368ee7acf0f9bed1ce235bef0b932517a9ff281c24a84ab5bb5a307b560fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028a808e57c6bcbab9333ebbeb571f922303b1bb3197db84c5ff936033294f1242","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2uxF7KQPSIQ7QfcCZ8B+lJls7YKfAnEPFTVPvibhd+c=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: daec45\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 7dd3 6c73 6251 41d9 | 146 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n001 6 a34e b02b b2a5 b820 | 47 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n002 11 f456 f45f f773 f31c | 37 f629 (0) f7ba (0) f7fa (0) f773 (0)\n003 5 cc20 c9f5 c898 c1f9 | 15 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n004 3 d1d7 d3b0 d299 | 5 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n005 1 df1e | 1 df1e (0)\n006 2 d887 d863 | 2 d887 (0) d863 (0)\n============ DEPTH: 7 ==========================================\n007 1 db6a | 1 db6a (0)\n008 1 da67 | 1 da67 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","private_key":"56866cfeb6cabc6b29d13eb7d3d7f08b4638fcf8f8d6c84303c8af5fa371a1a5","name":"node_daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","services":["streamer"],"enable_msg_events":true,"port":41737},"up":true}},{"node":{"info":{"id":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","name":"node_c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","enode":"enode://87345615c0805d99ec1ea2d9a2524323283810eec32d47fb14165619987edcb9c7d0cc052960238c4beda0cb4692412848cf083744f4287c1d3e3d3549ec8a17@127.0.0.1:0","enr":"0xf88fb84019bfcc1148e643a0381e48afe5c5e9d093b752843123d526ed1df4f62f0c9bdc3ccdc2c80c5be269b4a5674da87b07f2bfea41b969d01926921086864a6914940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10387345615c0805d99ec1ea2d9a2524323283810eec32d47fb14165619987edcb9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xiB1Kgg8of8DmJNyNc+WQTOTlFLCk8eZzgf/iqK95CA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c62075\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2c79 2f32 7dd3 6c73 | 146 24b8 (0) 256e (0) 20ae (0) 2101 (0)\n001 6 b2a5 b02b b820 a34e | 47 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n002 11 fbc8 f925 f31c f773 | 37 f629 (0) f7ba (0) f7fa (0) f773 (0)\n003 3 d3b0 d887 daec | 11 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n004 4 cc20 c9f5 c832 c898 | 6 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n005 2 c26f c1f9 | 2 c26f (0) c1f9 (0)\n006 3 c59e c43f c441 | 4 c59e (0) c49c (0) c43f (0) c441 (0)\n============ DEPTH: 7 ==========================================\n007 1 c786 | 1 c786 (0)\n008 1 c6cf | 1 c6cf (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","private_key":"6819c930fa19b056e7757bb4f0b87d2eba8bbd661c6bec9f68594559199669e9","name":"node_c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","services":["streamer"],"enable_msg_events":true,"port":39637},"up":true}},{"node":{"info":{"id":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","name":"node_6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","enode":"enode://80cc5420bd8d38bbd9b86077f10f27e11ac8ba32e9faa57dae75f0ebd5b605deaba207fc0912b1b93cbd29ad868bdcb0ecfc77c35f8d02e63729e09e8ccf1050@127.0.0.1:0","enr":"0xf88fb840f9be773757b0f5b1b3eecf7c1e53f23d4c24f84948d5fa49b2024cafcd7e7fce1dde3a795a557af1919771bb29869e79054b383ecb6413dbd5a7ad5637552c130183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10280cc5420bd8d38bbd9b86077f10f27e11ac8ba32e9faa57dae75f0ebd5b605de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bHMVBJDovpZ3xACG3grv7Rk5WBBI4m9Kk/XKJlcaGo8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c7315\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9076 e854 daec c620 | 110 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n001 6 21a0 2c79 3e8e 33b5 | 76 24b8 (0) 256e (0) 20ae (0) 217f (0)\n002 9 53fe 534b 5823 4646 | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 6 7125 738c 775e 7dbb | 12 77d2 (0) 775e (0) 7290 (0) 738c (0)\n004 6 67dc 66e7 60d7 605a | 9 6103 (0) 60d7 (0) 605a (0) 6337 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n============ DEPTH: 6 ==========================================\n006 7 6fe9 6f5f 6f2d 6ecb | 7 6fe9 (0) 6f5f (0) 6f2d (0) 6ecb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 6c4d | 1 6c4d (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","private_key":"1d02f4867632ec5b85fbb3116d676151cc62887e6c539870ba0c42f929299581","name":"node_6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","services":["streamer"],"enable_msg_events":true,"port":34593},"up":true}},{"node":{"info":{"id":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","name":"node_e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","enode":"enode://427720d085bc2d3fdde2d55df27162448b78a2e49d4d68bd8566b41345c87af64019cab4042a4228010b78ccc0935eb8d1fbbd6e147127d103557cff767e43fe@127.0.0.1:0","enr":"0xf88fb8400983bdd51a44197b57c4edd3528554d739aeb0876d2c50da898b134a951aea4d0045cd49590984531c7ba95e99489cb0155a426655d50bc36483d8da6e90af5b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102427720d085bc2d3fdde2d55df27162448b78a2e49d4d68bd8566b41345c87af6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6FSLXfFa3w8qmX/1cJgnvrXh02uwii8tAXdG1cDoP8o=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8548b\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 103b 165f 7920 6c73 | 146 24b8 (0) 256e (0) 20ae (0) 217f (0)\n001 3 b02b b820 9076 | 47 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n002 5 d3b0 daec c620 cc20 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 7 fbc8 fbf5 f925 f27f | 19 f629 (0) f7fa (0) f7ba (0) f773 (0)\n004 3 e775 e7fa e54b | 8 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n005 6 ec52 ed2d efea ef07 | 6 ec52 (0) ed2d (0) ee5e (0) efea (0)\n006 1 eb98 | 1 eb98 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e8ef e883 | 2 e8ef (0) e883 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","private_key":"a54bb672dc9321d27af926996f1bd8561f767a940f45b2ae7b50641aafc296b2","name":"node_e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","services":["streamer"],"enable_msg_events":true,"port":46437},"up":true}},{"node":{"info":{"id":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","name":"node_165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","enode":"enode://4201b86b495b4d95596ac23ba0cc4d0f467eb4570eae4bb2406f02acd483a0b590572cb93ff3d5e15951430b17eb765cfc57f0dd0f98d54facc4840a2f3c7446@127.0.0.1:0","enr":"0xf88fb8402d57c75cdbe7f54cfca4be2a9df2fd02b13b64e4abe4a8777dfcc5ac11a951a14393317578595f7833b5b2c12b361607c6f94305581f0499823944b40349d6d20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024201b86b495b4d95596ac23ba0cc4d0f467eb4570eae4bb2406f02acd483a0b5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Fl8a9nqh0kVp4L3/YdKbPDnpMlAHHY8ltb5vrOIJrGo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 165f1a\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9852 9076 daec e775 | 110 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n001 5 66e7 6831 6e68 6c73 | 70 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n002 4 2c79 2f32 314a 3e8e | 32 256e (0) 24b8 (0) 20ae (0) 217f (0)\n003 6 0328 0661 045b 0b72 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0d8a (0)\n004 4 1e2a 1c9c 1c8a 19fa | 10 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n005 3 11d4 103b 13d6 | 3 11d4 (0) 103b (0) 13d6 (0)\n006 3 1436 14df 154b | 4 1400 (0) 1436 (0) 14df (0) 154b (0)\n============ DEPTH: 7 ==========================================\n007 3 1704 17db 179f | 3 1704 (0) 17db (0) 179f (0)\n008 0 | 0\n009 0 | 0\n010 1 1672 | 1 1672 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","private_key":"a5255c5dfef55c549d9899c6086c1aa7f58eeab3dae94d863d16c3e8e5e6f308","name":"node_165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","services":["streamer"],"enable_msg_events":true,"port":37147},"up":true}},{"node":{"info":{"id":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","name":"node_7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","enode":"enode://9abcce8e8480c2df00f55c8b10f7cbcc56979a41c870eb9fc81ebf37df92ee56d47d9a3d76b9e87204e7cb20d39b04d584ce00ac702f1328606752cabc70d246@127.0.0.1:0","enr":"0xf88fb840246ddc3f6e34e2c10b5ef70b569b15a2579675614e0994c18a8ebf51041a206f4a5a670c168fed69567e6ce63b8b4308bd28e430a270bf4c36bc8e090a29e4780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029abcce8e8480c2df00f55c8b10f7cbcc56979a41c870eb9fc81ebf37df92ee56","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eSDWnPfkWPzgeB6hpOB3aOGmn2gYCQ7/Cr8LSgwsNfg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7920d6\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b2a5 e854 e775 | 110 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n001 2 3e8e 165f | 76 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n002 6 524d 5823 41d9 4bcf | 38 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n003 9 67dc 66e7 6251 628e | 20 67aa (0) 67dc (0) 66e7 (0) 6103 (0)\n004 3 738c 7125 775e | 5 77d2 (0) 775e (0) 7290 (0) 738c (0)\n005 4 7e04 7dbb 7dc2 7dd3 | 4 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n============ DEPTH: 6 ==========================================\n006 2 7a60 7b90 | 2 7a60 (0) 7b90 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","private_key":"9a81a3bcde96713d5d92389b259485aaaff9b59596864bb8933d09ef5ebb1d41","name":"node_7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","services":["streamer"],"enable_msg_events":true,"port":42903},"up":true}},{"node":{"info":{"id":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","name":"node_e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","enode":"enode://beda928185a8d044cb7303a817ba03b2c76bcf663ef5e852bb6f1f00730bdc445f98b40f8e29f427d9a802c2a3b74ad3403a3d47efb577b555ed87c05ebf83f7@127.0.0.1:0","enr":"0xf88fb840f9fda3d64eba7bad62497dba8a4c99a8e256a8159a4d7b38855bea2e5055a81b7ac9f978137e928e9116c805cca511efdcc58fb9b2473f5c08c4f0d0061cc1e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103beda928185a8d044cb7303a817ba03b2c76bcf663ef5e852bb6f1f00730bdc44","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"53XpdZ1HAb2bQ8IvHRvnPBJisnUrsjyzhXSF2vHcrS0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e775e9\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 103b 165f 7920 | 146 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n001 5 aeb4 af02 a34e a46d | 47 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n002 4 d3b0 c1f9 cc20 c898 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 8 f925 fbf5 fbc8 f773 | 19 f629 (0) f7fa (0) f7ba (0) f773 (0)\n004 6 ee5e ef1b efea eb98 | 10 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n005 1 e027 | 1 e027 (0)\n============ DEPTH: 6 ==========================================\n006 5 e5d7 e5ad e54b e547 | 5 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n007 0 | 0\n008 1 e7fa | 1 e7fa (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","private_key":"6be6c403a2ff471a0099cbeee98c75dbf2d356237b388e44e9620413135bfe37","name":"node_e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","services":["streamer"],"enable_msg_events":true,"port":46777},"up":true}},{"node":{"info":{"id":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","name":"node_90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","enode":"enode://475b303a40b4441c17f91b7ad399fa70524c60f241f66ac9139de672f06daa5b470a82c16372cb24c759bd76074ca5fb3161083dc6e1131d8f5f4de86ee8542e@127.0.0.1:0","enr":"0xf88fb84067ea7594026da51603b1294b65583b247f3a11286470ba680919f1cfd860bdd20a177b4b4dc916ba757482dac7f6f796677756f635eaa61bb8342f18bad700a20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102475b303a40b4441c17f91b7ad399fa70524c60f241f66ac9139de672f06daa5b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kHZbcig/Wb5M+b96npoi/W23AcNgPLwIF7St8vjpzgg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 90765b\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 3e8e 0fc5 0ff2 165f | 146 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n001 9 fbc8 fbf5 f456 e854 | 63 f629 (0) f7ba (0) f7fa (0) f773 (0)\n002 13 a46d a34e ad98 af02 | 27 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n003 5 8f21 88a1 8505 849b | 10 8f21 (0) 898d (0) 886a (0) 88fe (0)\n004 4 9852 9890 9fa0 9d0f | 4 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n005 3 959f 976e 96fc | 3 976e (0) 96fc (0) 959f (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 915d | 1 915d (0)\n008 1 90a8 | 1 90a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","private_key":"e212701e3a46630b79ca2e6bd4d1a4a4abe893d524fc5bb0327380b4c6ab4c0f","name":"node_90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","services":["streamer"],"enable_msg_events":true,"port":41311},"up":true}},{"node":{"info":{"id":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","name":"node_c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","enode":"enode://825fc662eadb1275f9fcd9e791cf12186b5446a81da414669c827c420f43b5550dc05c59267237d34248e57aa77bb1ca04b16a1667f06f1f277e76df0da74bd4@127.0.0.1:0","enr":"0xf88fb8405d639cdcd2181b1bbc1d50557f4ec79e187fddc491c03234d9b07f7968f78a8e49bc2c34d44a6790e07bdf309cb28c8fa1e0fa7ca95b2d5c9c2e34a676f4a9040183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102825fc662eadb1275f9fcd9e791cf12186b5446a81da414669c827c420f43b555","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yJhoceRvAB0V7Ytw8qoP6orjCdXlZxpQD2GeOzSMjBU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c89868\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7dd3 4bcf 4d6b 4d59 | 146 4e5a (0) 4c9e (0) 4d10 (0) 4d6b (0)\n001 4 b820 b2a5 82dd 9076 | 47 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n002 12 fbc8 f773 f5dc f5b2 | 37 f629 (0) f7ba (0) f7fa (0) f773 (0)\n003 3 d3b0 d887 daec | 11 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n004 4 c26f c1f9 c6cf c620 | 9 c26f (0) c1f9 (0) c59e (0) c43f (0)\n005 1 cc20 | 1 cc20 (0)\n006 2 caf6 ca04 | 2 caf6 (0) ca04 (0)\n============ DEPTH: 7 ==========================================\n007 1 c9f5 | 1 c9f5 (0)\n008 1 c832 | 1 c832 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","private_key":"6a52946fb72e66e0da1a45ae5641b7e4bd71cd109d0f8b0bd84c912f21a62a29","name":"node_c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","services":["streamer"],"enable_msg_events":true,"port":42015},"up":true}},{"node":{"info":{"id":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","name":"node_3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","enode":"enode://eb36b8be16b143563e4e6a0d40a3059746dd4073e875a344c54ac9da33c5687b346497f5efcb5b8ae55c7c077ad93fa8ddd69dc4aca6f257f892f8f0535e83bd@127.0.0.1:0","enr":"0xf88fb840606ae288441ca25000384f3327aab7b6a889361a45eed00f010a8711ec569a9304f1c0084e167f0f4f050196deb0d8c3321fe2266446fa5e76b11908918001c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eb36b8be16b143563e4e6a0d40a3059746dd4073e875a344c54ac9da33c5687b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Po78rzACUis5Bl6jDBVCbR61WRZJnv+OtagU451BhTw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3e8efc\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9076 b2a5 fbc8 c898 | 110 a653 (0) a6fb (0) a46d (0) a369 (0)\n001 7 534b 7dbb 7920 6c73 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 6 0661 0328 0ff2 0fc5 | 44 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n003 4 21a0 2abb 2c79 2f32 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 3 3373 33b5 314a | 10 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n005 3 39d1 3b78 3b88 | 3 39d1 (0) 3b78 (0) 3b88 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 3f94 | 1 3f94 (0)\n008 0 | 0\n009 2 3ec5 3efc | 2 3ec5 (0) 3efc (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","private_key":"4de210de6f44b43eebcea0e42a320de5fe4a52ee899ce93696e65018dff1943b","name":"node_3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","services":["streamer"],"enable_msg_events":true,"port":39127},"up":true}},{"node":{"info":{"id":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","name":"node_fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","enode":"enode://a017d5ec65ed0ff2bae902195ea9a509c51eade81c818bc111bd6e344ab51bbdb90239fbef510e247dd4917ee5be1cdee2b4f7206adccc675c6b1ef1ac1b70d6@127.0.0.1:0","enr":"0xf88fb840fb39a6e6bc63eb34afc956930c4bb747b7653c69db586b3e5e8986f527c8d08142c0bbc03752bb77e1109ac8a562274d065fd633c69ea3597394362919a720f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a017d5ec65ed0ff2bae902195ea9a509c51eade81c818bc111bd6e344ab51bbd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+8gIenI8VkygE5MpkC55dIr0Zpnqe+JNV5Cafo6W9oE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fbc808\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 534b 179f 3e8e | 146 7290 (0) 738c (0) 7125 (0) 77d2 (0)\n001 9 8f21 8505 9076 9fa0 | 47 959f (0) 976e (0) 96fc (0) 915d (0)\n002 3 daec c620 c898 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 ef1b eb98 e854 e883 | 18 ed2d (0) ec52 (0) ee5e (0) ef07 (0)\n004 9 f773 f456 f45f f4e0 | 13 f629 (0) f7fa (0) f7ba (0) f773 (0)\n005 3 fe31 fe21 ff36 | 3 fe31 (0) fe21 (0) ff36 (0)\n============ DEPTH: 6 ==========================================\n006 1 f925 | 1 f925 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 fbf5 | 1 fbf5 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","private_key":"459e90cfb3188b5829214e99ecdfdc92c3ca4a8df6a164a5c4c61f79eeefe059","name":"node_fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","services":["streamer"],"enable_msg_events":true,"port":35587},"up":true}},{"node":{"info":{"id":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","name":"node_f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","enode":"enode://ad212ba24b9f1cd7ee7e5431309edc1714e9c5ff6610fc49c63be97528ebacc2013bdd5f987b388cb1d6a6a7645d8ea7c5a98b90c4b0f70f4fca6793eb1f01f4@127.0.0.1:0","enr":"0xf88fb840cdd1cdeb2532d9112faf9bdd13f0ab62954f54b6d55a30181ff5f719725dd1b3761a25fdd94173632cf3aa481a3430b30a1bb5341e26c05b8e0ae738e0ace46c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ad212ba24b9f1cd7ee7e5431309edc1714e9c5ff6610fc49c63be97528ebacc2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8n8QRHd+BfP2AWXQ0vw+dmf+FI4Mp6CXgF1gufYQJfc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f27f10\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0661 534b | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 2 b820 b2a5 | 47 959f (0) 976e (0) 96fc (0) 915d (0)\n002 4 d3b0 daec c1f9 c898 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 e54b e775 ef1b eb98 | 18 ec52 (0) ed2d (0) ee5e (0) ef1b (0)\n004 3 f925 fbf5 fbc8 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 9 f629 f7ba f773 f528 | 10 f629 (0) f7fa (0) f7ba (0) f773 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f31c | 1 f31c (0)\n008 1 f2d5 | 1 f2d5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","private_key":"ce524e315364068c85c93ee7c34cfc6e5532742848a01bf543d213e2cf22f9ee","name":"node_f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","services":["streamer"],"enable_msg_events":true,"port":40031},"up":true}},{"node":{"info":{"id":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","name":"node_b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","enode":"enode://a5a8a40f361adf355086fefe1a9d530ee072ff7dda43026954c2e20dfdcdc445873d72bf613dea981c6fe57941e79af6b837431625892eae841bcecec8fa5ea1@127.0.0.1:0","enr":"0xf88fb840a9cc6dfb9ffae8d02cc4343351e64345b21f117b53ef86ee469eed2d5d3929f67c1084a5e8b4ce788894461222a59beb00152452d61f6acc04724857718931030183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a5a8a40f361adf355086fefe1a9d530ee072ff7dda43026954c2e20dfdcdc445","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sqVjrFm6tN/d97bie4Duev3rLkKVQREHkD9IS8+fxPI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2a563\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0661 3e8e 7920 628e | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 6 daec c620 c898 fbc8 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 6 9fa0 9852 9890 9076 | 20 959f (0) 976e (0) 96fc (0) 915d (0)\n003 5 af02 aeb4 a6fb a46d | 10 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n004 8 bcc6 ba88 badd bb90 | 9 bcc6 (0) baf2 (0) badd (0) ba88 (0)\n005 3 b5b2 b502 b7ca | 5 b5b2 (0) b502 (0) b626 (0) b65e (0)\n============ DEPTH: 6 ==========================================\n006 1 b02b | 1 b02b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 b2b5 | 1 b2b5 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","private_key":"d311ffc3650bc45898ce1480ced3b3fabaed9a8a9877d26a97b2710c9318716f","name":"node_b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","services":["streamer"],"enable_msg_events":true,"port":44537},"up":true}},{"node":{"info":{"id":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","name":"node_b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","enode":"enode://7f841ce185c998f72468ded1e943d2a109a834b4b15c957132af2e5f364df4111c57d1b83651a4b899bf40a3131509505ff6d750e182af6b711511f92bc594a5@127.0.0.1:0","enr":"0xf88fb840c1a87287bf9a406351496453395ee3cc77e00b626375a7e86abedcd951c907f875178719162b1663979a6ec05a5f949286e03f2611eecf13bfb9caca0f670c200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037f841ce185c998f72468ded1e943d2a109a834b4b15c957132af2e5f364df411","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uCDkgDVAAMg3sXgewcST6HdrSDQlLmRTQlrAW5JbWlg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b820e4\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0661 66e7 628e 534b | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 11 c898 c620 daec e883 | 63 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n002 6 9890 9852 9fa0 9076 | 20 959f (0) 976e (0) 96fc (0) 915d (0)\n003 3 a34e a46d af02 | 10 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n004 2 b02b b2a5 | 8 b626 (0) b65e (0) b7ca (0) b5b2 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 badd ba88 bb90 | 4 baf2 (0) badd (0) ba88 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b911 b95d | 2 b95d (0) b911 (0)\n008 1 b897 | 1 b897 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","private_key":"61fe17d5be2ccee74b17d7c47a21cef62eea82042e68eb5bc32139b57bf6ee76","name":"node_b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","services":["streamer"],"enable_msg_events":true,"port":36559},"up":true}},{"node":{"info":{"id":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","name":"node_534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","enode":"enode://b948e96344e56ff7ae61c23f8751d2dcc3cb818bb11e981357d1acc94c3c662987cc236e5ecbac4288b68cac7f704edbd39a158a7ec1477817e6379b9d3f06ac@127.0.0.1:0","enr":"0xf88fb8408d7d8db1b2d8e46e0446181eb4d5f2d93967e8f7c55430e17ce80fa7269dbadc2a24bddd9024c14a94deea3ad1cfa69efd5b3e6156e87d8b0afaac9d3ff4a6680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b948e96344e56ff7ae61c23f8751d2dcc3cb818bb11e981357d1acc94c3c6629","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U0vKqYz5GSs1tgFMZQrgZ+dDMsAV67UW1jYBQn1zdrg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 534bca\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c898 fbc8 f27f b2a5 | 110 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n001 7 1c9c 0661 2abb 2f32 | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 6 7dc2 775e 7125 6c73 | 32 7290 (0) 738c (0) 7125 (0) 77d2 (0)\n003 7 41d9 44a1 4e5a 4c9e | 23 4782 (0) 47bf (0) 46fe (0) 461c (0)\n004 3 5efb 5cd2 5823 | 7 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n005 1 574f | 1 574f (0)\n006 2 51db 512e | 2 512e (0) 51db (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 53a8 53fe | 2 53a8 (0) 53fe (0)\n009 1 5308 | 1 5308 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","private_key":"c7f75190502386c9d3b3434c24956d84b4c9e41c91671f2b28496a7f4fcdc39e","name":"node_534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","services":["streamer"],"enable_msg_events":true,"port":45967},"up":true}},{"node":{"info":{"id":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","name":"node_66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","enode":"enode://71bc46e6ba9589ea0718de84c96b5d58b5d7f0781e021b003f14b1cda7ff7ccbe697f9d910349ec8830341cfc00ce73729b28d91bf6c66989a46e72d3c5853f7@127.0.0.1:0","enr":"0xf88fb8402f952b1b8ee3a0cdd608676ac1b0422c05695038e3da52824da26933ab776cae7a335c51043e1d2c6b35d878ed54ffa2c4acd71f3870c1ac2db03fdda4be24880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10371bc46e6ba9589ea0718de84c96b5d58b5d7f0781e021b003f14b1cda7ff7ccb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Zuf8LfUfXfjXMphR/pNX2JXp1d/cJfjZK9sQqWD34Vo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 66e7fc\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b820 82dd | 110 959f (0) 976e (0) 96fc (0) 915d (0)\n001 8 0ff2 1c9c 165f 1672 | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 6 44a1 4109 41d9 4bcf | 38 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n003 4 7125 7920 7dd3 7dbb | 12 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n004 5 6967 6fe9 6ea5 6e68 | 11 6831 (0) 6967 (0) 6f5f (0) 6f2d (0)\n005 6 6103 60d7 605a 6337 | 6 6103 (0) 60d7 (0) 605a (0) 6337 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 67aa 67dc | 2 67aa (0) 67dc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","private_key":"73edf61ff541e3a6ba465ffea56c19839af7e9bc3782ff09216905843c204e08","name":"node_66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","services":["streamer"],"enable_msg_events":true,"port":46675},"up":true}},{"node":{"info":{"id":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","name":"node_628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","enode":"enode://753579fc0f9683818e057900626e09327d6610fdbc6996be1b4faea9431977b3c78dd63e7e603523b19dd2b55c8a90b6ea21e91edd926513843de5fc1eea9b26@127.0.0.1:0","enr":"0xf88fb8406e4b52980cff25be487a37763583146103d0312687b7183e3dd02233a6f94b387c1b61ccb793d70ea879dedb92e32c45923debbec85a24bd00f68780acc0da170183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102753579fc0f9683818e057900626e09327d6610fdbc6996be1b4faea9431977b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Yo59ozWe1tnc+6/HWBlm5OCSRcMh7HjKdVh8nLtEaX8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 628e7d\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e883 82dd b2a5 b820 | 110 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n001 6 21a0 3e8e 1672 0ff2 | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 6 41d9 4bcf 4d6b 4d59 | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 7 775e 7125 738c 7920 | 12 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n004 4 6967 6e68 6f2d 6c73 | 11 6831 (0) 6967 (0) 6fe9 (0) 6f5f (0)\n005 3 67aa 67dc 66e7 | 3 67aa (0) 67dc (0) 66e7 (0)\n006 3 6103 60d7 605a | 3 6103 (0) 60d7 (0) 605a (0)\n============ DEPTH: 7 ==========================================\n007 1 6337 | 1 6337 (0)\n008 1 6251 | 1 6251 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","private_key":"83ebb4dfd7e07f53a417d7d2d026d506a6d45dc6ec03f3acc64b473cf238454a","name":"node_628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","services":["streamer"],"enable_msg_events":true,"port":39369},"up":true}},{"node":{"info":{"id":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","name":"node_06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","enode":"enode://299e207d28b61a8754f9056b7c66999601d85c166abf2d5e28b58bb9af5d07ae1191a60f6b7daa7f1db158847cf41042bacd8d65caced5aae6b785279c7db9c9@127.0.0.1:0","enr":"0xf88fb8405c00f8abb44fe6724d6ec81f03c33ed424ef532ff6d7f23711109c46205f12793e95b225e5830489b2b439f04128e4ee2e2aa0732db7eb8c69c53030da7f9b2f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103299e207d28b61a8754f9056b7c66999601d85c166abf2d5e28b58bb9af5d07ae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BmGNgpqKcxepjxpA7PiGThyUxOJwqeTACCKdx8+Te34=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 06618d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b820 b2a5 8505 e54b | 110 a653 (0) a6fb (0) a46d (0) a369 (0)\n001 4 534b 4bcf 7dbb 628e | 70 5cd2 (0) 5db0 (0) 5f00 (0) 5efb (0)\n002 5 2abb 2f32 21a0 3e8e | 32 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n003 5 1c9c 19fa 165f 1672 | 22 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n004 5 0af9 0de3 0c28 0ff2 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n005 4 0067 00c6 03cc 0328 | 5 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n006 3 0438 0451 045b | 3 0438 (0) 0451 (0) 045b (0)\n============ DEPTH: 7 ==========================================\n007 2 0743 07a8 | 2 0743 (0) 07a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","private_key":"8d4e48a151d1f68c567c3be3325aab9baa3b0abb8bf08d65ce6cb448cf056f5b","name":"node_06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","services":["streamer"],"enable_msg_events":true,"port":35915},"up":true}},{"node":{"info":{"id":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","name":"node_f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","enode":"enode://5b2117cf5005122b31d4139c5ecffbfb0b3b5b3ccc04122ecee2b65ddc3b5f365fc02b4df864cce4b6b626a9c76bdee3d791ae0dd8acf96c0844b2a6e5641b39@127.0.0.1:0","enr":"0xf88fb840e2d50d151f647dccd99b24b546d0c033602555711b5e9b696b397c56e0301e34144f5201dc6446c2708545baa267d5ab59974b796a1af49a6cde843af933d35e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035b2117cf5005122b31d4139c5ecffbfb0b3b5b3ccc04122ecee2b65ddc3b5f36","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9FZd0sQowD16jV+th6bdX5KucGUp62FS02+lhOfNvk0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4565d\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7dbb 4bcf 0661 | 146 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n001 6 b820 b2a5 9fa0 9076 | 47 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n002 5 daec d3b0 c620 c1f9 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 ed2d eb98 e854 e883 | 18 e027 (0) e7fa (0) e775 (0) e5ad (0)\n004 3 f925 fbc8 fbf5 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 2 f31c f27f | 3 f31c (0) f2d5 (0) f27f (0)\n006 2 f7ba f773 | 4 f629 (0) f7fa (0) f7ba (0) f773 (0)\n007 3 f528 f5b2 f5dc | 3 f528 (0) f5dc (0) f5b2 (0)\n============ DEPTH: 8 ==========================================\n008 1 f4e0 | 1 f4e0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 f45f | 1 f45f (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","private_key":"b9015ed803b33c63a30a8abe7812408ed9cc2ba7efcdb5fcd69f0a681d123675","name":"node_f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","services":["streamer"],"enable_msg_events":true,"port":39127},"up":true}},{"node":{"info":{"id":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","name":"node_4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","enode":"enode://88c7ac31971ce995e22e0820ae73cd53e1bda565f636bea5b3c0472c44d54a66a23d6143ecad625bef9fb09e3e64da6fd629ead736b184981cb9052a1cb0489f@127.0.0.1:0","enr":"0xf88fb840c74ff09f194ac5d818ba51ea9fd29c00ac3ebd753d02ec50dfe7c1438f754d9c794455cf5ee526e53b257971614e8b756a1a4c0da3fbcac597cbf2044a14e7e20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10388c7ac31971ce995e22e0820ae73cd53e1bda565f636bea5b3c0472c44d54a66","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"S89OtTHV7Esx2Z6DVK8D+XZSTHhYoecEPptwVTJvCVI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4bcf4e\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 82dd c898 e883 f456 | 110 a653 (0) a6fb (0) a46d (0) a369 (0)\n001 6 2abb 314a 179f 1672 | 76 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n002 10 6ea5 6c73 628e 67dc | 32 6831 (0) 6967 (0) 6fe9 (0) 6f5f (0)\n003 2 5823 534b | 15 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n004 6 4636 4646 44a1 4559 | 12 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n005 4 4e5a 4d6b 4d59 4c9e | 5 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n006 3 4990 49cd 49ea | 3 4990 (0) 49cd (0) 49ea (0)\n============ DEPTH: 7 ==========================================\n007 2 4ac7 4a8b | 2 4ac7 (0) 4a8b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","private_key":"4cc4751021f2e7e361f1abe34a0ae098305a4d7cfae9fff4e3d9c198f765536c","name":"node_4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","services":["streamer"],"enable_msg_events":true,"port":37843},"up":true}},{"node":{"info":{"id":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","name":"node_82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","enode":"enode://9e0bd5f9048e54e757f441f6e806f675359f125df0759d69c99dfa05b612264f47f2e4ef3b1e8c33ea12203b3539baa8e8f7112a42c09fba13c8088012abf854@127.0.0.1:0","enr":"0xf88fb840ce5cbe31c864fb919be4b8bbaeb4aac9af3baceddb264f0fc41711cfe79eac031fef6d0c4e5186833885990f4fb8bf788dfde9ec3140e53dd617c1a301f7da460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029e0bd5f9048e54e757f441f6e806f675359f125df0759d69c99dfa05b612264f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gt2Dg4y5griVBe8knTU6IOQ0NG3Xi3HNm4CfcdXBEto=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82dd83\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0fc5 66e7 628e 7125 | 146 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n001 8 daec c898 c1f9 f456 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 6 b820 b2a5 b02b af02 | 27 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n003 5 96fc 9076 9852 9890 | 10 959f (0) 976e (0) 96fc (0) 915d (0)\n004 5 8f21 898d 886a 88a1 | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n005 2 849b 8505 | 2 849b (0) 8505 (0)\n============ DEPTH: 6 ==========================================\n006 1 8025 | 1 8025 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 82f9 | 1 82f9 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","private_key":"40b87f812144699438e8ce3203329a31e5e6fd191ccc6d632b53acd2dabf009a","name":"node_82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","services":["streamer"],"enable_msg_events":true,"port":36651},"up":true}},{"node":{"info":{"id":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","name":"node_7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","enode":"enode://c6f41778e207aa191bfcc7583d517dc276591cb6e4ea45a7f640b9e296d6ac32ed466e046bd8e3cd7213d78408c82594ab0d4f91fff4af306e45e91e25568f08@127.0.0.1:0","enr":"0xf88fb840cd11dd01b07641a3cc440cc6247d249d33f4f5f6f8812ff8f209b221f42611e934dd83397f8ce608353435eff2358217cfcee195e78947e92f7f10ae9c8dface0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c6f41778e207aa191bfcc7583d517dc276591cb6e4ea45a7f640b9e296d6ac32","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fbveujcx4f9DBy+MvYbbFHdh4bYXU+6nAkd02/RpFL0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dbbde\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f456 e54b 8505 82dd | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 8 1672 179f 0328 0661 | 76 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n002 3 524d 4d6b 4bcf | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 9 6ea5 6f2d 6c73 6c4d | 20 6831 (0) 6967 (0) 6fe9 (0) 6f5f (0)\n004 3 738c 7125 775e | 5 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n005 3 7920 7b90 7a60 | 3 7a60 (0) 7b90 (0) 7920 (0)\n006 1 7e04 | 1 7e04 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 2 7dd3 7dc2 | 2 7dd3 (0) 7dc2 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","private_key":"30869970089e876f509073901dbe3a34c332d7a6755999e960da313f0d41bdda","name":"node_7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","services":["streamer"],"enable_msg_events":true,"port":42487},"up":true}},{"node":{"info":{"id":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","name":"node_314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","enode":"enode://2ddf028c09516742c8f18d9dc30575448afbf80f0999e2cccc53671e4b12c97af49c3251151d20ff3c38c6e4885805039f3e31e32101cdb9ccb70596e29e6e97@127.0.0.1:0","enr":"0xf88fb84084eb7ae1c3f66517fa8698e26815ca4ddd8d95653248080c4cf1ae2af93c9ae76806cd1ba9bd6bce2079c1762ba8bc13a96e07869d8fc5fde206d61c694ac4010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032ddf028c09516742c8f18d9dc30575448afbf80f0999e2cccc53671e4b12c97a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MUo1MKXgw31WCRSbOunC4HhXM0a9j848dp666zFybsE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 314a35\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 af02 8505 daec e54b | 110 a369 (0) a34e (0) a653 (0) a6fb (0)\n001 7 534b 41d9 4d6b 4bcf | 70 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n002 6 1c9c 19fa 165f 0c28 | 44 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n003 6 2c79 2f32 2abb 256e | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 6 39d1 3b78 3b88 3efc | 7 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n005 4 35e6 378e 3780 3630 | 4 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n006 3 3237 33b5 3373 | 3 3237 (0) 3373 (0) 33b5 (0)\n============ DEPTH: 7 ==========================================\n007 2 3089 30be | 2 3089 (0) 30be (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","private_key":"65cff60a3a02082e25d44b652a89286c56814d6e8a124c9cd481c53d6bfc7d14","name":"node_314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","services":["streamer"],"enable_msg_events":true,"port":34143},"up":true}},{"node":{"info":{"id":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","name":"node_e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","enode":"enode://2ff0f6983a8df852e410db35700f5eb2e9b6626b555eb6a0f46ed3b1039c11d99e30fa7fb8ef8a5e04f6747539a8fa3b422b0e167e3740bfd0dfc6f05b7811c0@127.0.0.1:0","enr":"0xf88fb84073d5865ea6eef52ccbd4fb0579988b8c89f10c04bf0aab24b530bccf20477019412b8e906f69332ba31a2b366d9cf41dc6b91c1c3dbf0201b5c1815aba93e7990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022ff0f6983a8df852e410db35700f5eb2e9b6626b555eb6a0f46ed3b1039c11d9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6IMPKy99CN8VvTP0soQdAdnWLBYhI0vWroZ0PlI2Dz4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8830f\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 628e 4bcf 4d6b 103b | 146 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n001 4 b820 9890 82dd 8505 | 47 a46d (0) a653 (0) a6fb (0) a369 (0)\n002 5 d3b0 daec c1f9 cc20 | 26 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n003 6 fbf5 fbc8 f773 f456 | 19 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n004 4 e027 e7fa e775 e54b | 8 e027 (0) e7fa (0) e775 (0) e5ad (0)\n005 4 ed2d efea ef07 ee5e | 6 ec52 (0) ed2d (0) ee5e (0) ef1b (0)\n006 1 eb98 | 1 eb98 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 e854 | 1 e854 (0)\n009 1 e8ef | 1 e8ef (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","private_key":"300d395f69d29389b4951f1054ccdecbbb0aa4ee4359e0a42916d279feed61b9","name":"node_e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","services":["streamer"],"enable_msg_events":true,"port":44709},"up":true}},{"node":{"info":{"id":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","name":"node_e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","enode":"enode://88d397dae0a821bb3ade7f8b6934b521491617f1f55ce053be63153915a1d422f16ab186007929b0232d9a7fd420cf692a7df1d9f419a191a1e9e57698485728@127.0.0.1:0","enr":"0xf88fb8405030079ea6a64ac5c86f5eb9955181bb9c23d35cbc28ed8a13410b3c9e9a234928490232594c4773176af76896b5283dffb7979ca1082589e48a45d54473d9e70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10288d397dae0a821bb3ade7f8b6934b521491617f1f55ce053be63153915a1d422","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5UtkPLyV2fXSfsN2DYkraAKYG/q/T5l5Jn1mJZ35gsc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e54b64\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4d6b 7dbb 1672 0661 | 146 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n001 5 b820 9890 9fa0 82dd | 47 a653 (0) a6fb (0) a46d (0) a369 (0)\n002 5 daec d3b0 c898 c1f9 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 6 fbf5 fbc8 f31c f27f | 19 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n004 7 ed2d ee5e ef1b efea | 10 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e7fa (0) e775 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e5d7 e5ad | 2 e5d7 (0) e5ad (0)\n009 1 e514 | 1 e514 (0)\n010 0 | 0\n011 0 | 0\n012 1 e547 | 1 e547 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","private_key":"727ffbf99e8a4a3259aa56178cd67759e1efcf9d6a0d1bbc5eced5778195a6bb","name":"node_e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","services":["streamer"],"enable_msg_events":true,"port":35117},"up":true}},{"node":{"info":{"id":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","name":"node_850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","enode":"enode://f96b8378f9a6fdb344b192c08fa716f806c81b10d9ff1be769f2f147f0a3e59be1d63e3458c6bb0be3826901cc82855dcb176ea550580ce3c1353f45411effa8@127.0.0.1:0","enr":"0xf88fb840e608377b110a66c37a6402a52005fab9cbbd1293d2faf8ac2f2d11f21c86074e65803f9af2fd8a4652da5a03c3a8f62c56bedc2b504966b9def8bec4d14aa6f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f96b8378f9a6fdb344b192c08fa716f806c81b10d9ff1be769f2f147f0a3e59b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hQV1V31rQgqHq6OIr0geDARML3XPKf+TTa9WdDGKYbo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 850575\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0fc5 0661 314a 7125 | 146 0a00 (0) 0af9 (0) 0b72 (0) 0e5e (0)\n001 5 c620 fbc8 f456 e883 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 9 af02 aeb4 a46d a6fb | 27 a369 (0) a34e (0) a653 (0) a6fb (0)\n003 6 9fa0 9852 9890 9076 | 10 959f (0) 976e (0) 96fc (0) 915d (0)\n004 5 898d 886a 88a1 88fe | 5 898d (0) 886a (0) 88fe (0) 88a1 (0)\n============ DEPTH: 5 ==========================================\n005 3 8025 82f9 82dd | 3 8025 (0) 82f9 (0) 82dd (0)\n006 0 | 0\n007 1 849b | 1 849b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","private_key":"771aa77f7ed2c88cec05f7d2bbe77ca3b3baed77808bcede79d47430b855ef8c","name":"node_850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","services":["streamer"],"enable_msg_events":true,"port":38191},"up":true}},{"node":{"info":{"id":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","name":"node_4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","enode":"enode://65fe4500b12d8a6300f6dfa00c6053c96a116b98d8c08d706534d0b0cd73def015021b00da0ea48952faaf26fb6860612ae6f05dc69e3152a60467c474513524@127.0.0.1:0","enr":"0xf88fb840e4f68b9d9c982c9d702d4e773ac1559d8ef54db673accfcab9b83cf5f16a0d191460f4acfcad1a8c86b72017692073a6ad12e178800fa4dd5c30f7958acfb4530183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10265fe4500b12d8a6300f6dfa00c6053c96a116b98d8c08d706534d0b0cd73def0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TWuTn7ZzOMSElIq5KyzupNS2Ztfgh3NnPNfI+D9JW4k=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d6b93\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c898 e54b e883 8505 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 4 314a 2abb 0328 179f | 76 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n002 7 67dc 628e 6ea5 775e | 32 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n003 2 5823 534b | 15 5f00 (0) 5efb (0) 5db0 (0) 5cd2 (0)\n004 5 4559 44a1 4646 4636 | 12 47bf (0) 4782 (0) 46fe (0) 4646 (0)\n005 6 4bcf 4ac7 4a8b 4990 | 6 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n006 1 4e5a | 1 4e5a (0)\n007 1 4c9e | 1 4c9e (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 4d10 | 1 4d10 (0)\n010 1 4d59 | 1 4d59 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","private_key":"ec9be85f4525323e3e5fba6d38fddd6e2c490c51f04e40824f612945338ff314","name":"node_4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","services":["streamer"],"enable_msg_events":true,"port":33119},"up":true}},{"node":{"info":{"id":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","name":"node_9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","enode":"enode://74dcd08206970995c262f6fdc36f05eb33b2efd6a76f8dad6d50f4c990fdfff532b14e3a48ae9fdad2e8969bb28c472b5fa4e037266ed8ab1b223d351b00c58c@127.0.0.1:0","enr":"0xf88fb840e8a03ba6a2bd809293a3aa9fc2cd67a032f701eda802d05b9fed7988cd354f6228072d95e1279cfdbb332a0b3f7b6bcc772dd13ef98a3cab034c0beef16d15840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10274dcd08206970995c262f6fdc36f05eb33b2efd6a76f8dad6d50f4c990fdfff5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"n6AhXpgNyQffTMR6tJN/NlJ9ePmDdJMBb9T8UeYXKZw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9fa021\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2abb 21a0 1672 179f | 146 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n001 7 fbc8 f45f f456 f773 | 63 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n002 8 af02 a6fb a34e b2a5 | 27 a369 (0) a34e (0) a46d (0) a653 (0)\n003 5 8505 849b 8025 82f9 | 10 898d (0) 886a (0) 88fe (0) 88a1 (0)\n004 6 9076 90a8 915d 959f | 6 959f (0) 976e (0) 96fc (0) 915d (0)\n============ DEPTH: 5 ==========================================\n005 2 9852 9890 | 2 9852 (0) 9890 (0)\n006 1 9d0f | 1 9d0f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","private_key":"2151ae4bd0c0dbe72d08c6cc2dc2d42d45d5929d158953f98802508bcc7b6abc","name":"node_9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","services":["streamer"],"enable_msg_events":true,"port":42793},"up":true}},{"node":{"info":{"id":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","name":"node_179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","enode":"enode://45316c9ce2f7458c2170694fa0458bb6bc612e0fe7e98d5776eaa2deb243090f2112f86d6378e3fbf2bc3581294561eba34c820855dde3c62fbbd0fb00d464bc@127.0.0.1:0","enr":"0xf88fb840ba7939a13853c684f0fbba8aabd321c8c18392c860e899d661b8ae62334778bc3a1cc6bd039962763203c07b6f86aa8b247af81fb2c72e4b1e9de83cd2f02d3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10245316c9ce2f7458c2170694fa0458bb6bc612e0fe7e98d5776eaa2deb243090f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F58h0uBCG4BW7pomC8CYW/pkpSo20Kj7zk4D8xINHWU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 179f21\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c1f9 c898 daec fbc8 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 3 7dbb 4bcf 4d6b | 70 6fe9 (0) 6f5f (0) 6f2d (0) 6e05 (0)\n002 3 3b88 21a0 2abb | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 6 0ff2 0c28 00c6 0328 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n004 3 19fa 1c9c 1c8a | 10 1f67 (0) 1f85 (0) 1e2a (0) 1c47 (0)\n005 3 13d6 11d4 103b | 3 13d6 (0) 11d4 (0) 103b (0)\n006 4 14df 1400 1436 154b | 4 14df (0) 1400 (0) 1436 (0) 154b (0)\n007 2 165f 1672 | 2 165f (0) 1672 (0)\n============ DEPTH: 8 ==========================================\n008 1 1704 | 1 1704 (0)\n009 1 17db | 1 17db (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","private_key":"6fc4e9abe82ac6f220359e1a24c752a8538ca3d77fa2a44721ec006e4dac96c8","name":"node_179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","services":["streamer"],"enable_msg_events":true,"port":46579},"up":true}},{"node":{"info":{"id":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","name":"node_2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","enode":"enode://079b150d46590810199925ef6914c54c274297aa5ddbaec77e0e1881fb11e67c597e4310d3fa518e919ba3530c7863fb75e67892ba8a3ee5385446aded8bd46c@127.0.0.1:0","enr":"0xf88fb840e4c34bba2889adb60fd7f03da39f9172c73803337915b8a91a787ecd1e15f7ac32b8c5ebc60e9bc30a9f10e582b6c56955e330b874275d8f785b67b3d2b7ad7a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102079b150d46590810199925ef6914c54c274297aa5ddbaec77e0e1881fb11e67c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KruTi4iaLrc1E0RimFpWBWvkjxibW4nSO2U4ZMdkJ/Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2abb93\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e883 c1f9 af02 9fa0 | 110 d7ac (0) d640 (0) d3b0 (0) d299 (0)\n001 6 7dbb 6967 66e7 534b | 70 6c4d (0) 6c73 (0) 6fe9 (0) 6f5f (0)\n002 6 0c28 0661 045b 19fa | 44 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n003 5 3b88 3e8e 3ec5 3efc | 17 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n004 3 256e 24b8 21a0 | 6 24b8 (0) 256e (0) 20ae (0) 2101 (0)\n005 5 2d36 2c79 2c38 2ccf | 5 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n006 1 2995 | 1 2995 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 2a0a | 1 2a0a (0)\n009 0 | 0\n010 1 2a97 | 1 2a97 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","private_key":"5f2d2d97cebeab930620649942a1d9ff3fb18cfdfe20065c115c21fcc1736417","name":"node_2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","services":["streamer"],"enable_msg_events":true,"port":46385},"up":true}},{"node":{"info":{"id":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","name":"node_16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","enode":"enode://e24763610f818132ec0e495f6371f3e94f8822100ee5956998fc7585d7e09a222bbdb9a02937e628ca33f6902fe511b8711405899f5cddfa93a1035ac09af4b8@127.0.0.1:0","enr":"0xf88fb840df13ef5dcc1c0cb21d197b2cdfd5d86b8bec8a3882f2c8ba0166a590276699446bccccceac9b5ccb0bcf42d3f59ee925945d58295588d35de7077b7910c5401f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e24763610f818132ec0e495f6371f3e94f8822100ee5956998fc7585d7e09a22","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FnJeMYMiNTvvwvKroRLwmEvAEYIbsWyY4s2LOc1irqE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 16725e\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e54b c1f9 9fa0 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 8 4bcf 6831 66e7 628e | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 3 3b88 21a0 2abb | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 4 0c28 045b 0661 0328 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n004 2 1c9c 19fa | 10 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n005 3 13d6 103b 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 4 14df 1400 1436 154b | 4 14df (0) 1400 (0) 1436 (0) 154b (0)\n============ DEPTH: 7 ==========================================\n007 3 1704 17db 179f | 3 1704 (0) 17db (0) 179f (0)\n008 0 | 0\n009 0 | 0\n010 1 165f | 1 165f (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","private_key":"0e22a97f0fa9df60515e999107287dd670bbfba6496b95e7419f1ae24ac1430f","name":"node_16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","services":["streamer"],"enable_msg_events":true,"port":42487},"up":true}},{"node":{"info":{"id":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","name":"node_03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","enode":"enode://3960e88898c09e1856391d4ff8b0e413551efaa9d41b29dbe1d131c4c23d0f3debf2451b0019c3cd1a3cced4e5b0ead9dd73ca011cf6f319d3a6440623ce12c3@127.0.0.1:0","enr":"0xf88fb8403059f7dae44ef458aafb69f9b519e35847da261c7fc2415beb3027871fc5f55b0a37db22d9d2e503fae99b8dce9317e0aab1999b6dc73f581ac8fdabbc40cb7e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033960e88898c09e1856391d4ff8b0e413551efaa9d41b29dbe1d131c4c23d0f3d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AyheBmVwMneP7/C0OCjJZNv53mafYxca61h6oaH6zAo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 03285e\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c1f9 f31c | 110 d7ac (0) d640 (0) d3b0 (0) d299 (0)\n001 7 7dbb 7dc2 628e 6251 | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 4 3e8e 3ec5 3b88 21a0 | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 4 19fa 179f 165f 1672 | 22 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n004 6 0a00 0af9 0c28 0de3 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n005 4 045b 0438 07a8 0661 | 6 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n006 2 0067 00c6 | 2 0067 (0) 00c6 (0)\n============ DEPTH: 7 ==========================================\n007 1 02d8 | 1 02d8 (0)\n008 1 03cc | 1 03cc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","private_key":"eb65890ae3df82c2a8355c7b7a50e258abb0c833e93aacc2a5dbd51ee15664d4","name":"node_03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","services":["streamer"],"enable_msg_events":true,"port":37579},"up":true}},{"node":{"info":{"id":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","name":"node_21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","enode":"enode://af8cb83192683c7397ab76929a7a6ebd42a34f250c74baa77449624ec14ff1014486c342f70c70454d60192f7a52ad16cab58958b752e01feea05491ad7b7915@127.0.0.1:0","enr":"0xf88fb84060c1ac919d32f84d9c226ded0dc92ed0cb32034912167e68663f93a3644a8e6b1235368600a6006c4a63078fec8299adecdc0afc9a016fa9eace65a141581d610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103af8cb83192683c7397ab76929a7a6ebd42a34f250c74baa77449624ec14ff101","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IaBE53K3yVX+Sm+3w6miDpXUi3/WuVGHQXgvBPXx9cI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 21a044\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 af02 9fa0 c1f9 ed2d | 110 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n001 10 534b 6967 6c73 6ea5 | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 8 19fa 1436 179f 1672 | 44 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n003 6 3ec5 3efc 3e8e 3b88 | 17 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n004 3 2f32 2c79 2abb | 9 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 20ae | 1 20ae (0)\n008 2 217f 2101 | 2 217f (0) 2101 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","private_key":"e8c622b14e0b37df0fd9611ed22903fd62f8b8823866163156b933c17f3fc9b3","name":"node_21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","services":["streamer"],"enable_msg_events":true,"port":40127},"up":true}},{"node":{"info":{"id":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","name":"node_f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","enode":"enode://2d511a834e682276a6f3a8650f3728bec644ab1efd34d504e37aeb317f3a3ee4c0ee0db1c4fa4fd0db73a1da15fef34b527a2587be73d68b35da971c09e6ad5e@127.0.0.1:0","enr":"0xf88fb840d947ce6d973f74d7e2c06e2aa7b0511cf2a30fb7f6565a76dd01220c3071d124635ae79845e4bf315d6a2e0e07acaf661c378ed6998c33219c8cf3158949cc840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022d511a834e682276a6f3a8650f3728bec644ab1efd34d504e37aeb317f3a3ee4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8xzHROqSH+6DZMUmmxzn7GtfDAy7aIXvv2At5bNvYWk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f31cc7\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 775e 0328 21a0 | 146 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n001 6 b95d af02 82dd 849b | 47 b65e (0) b626 (0) b7ca (0) b5b2 (0)\n002 6 d1d7 daec c898 cc20 | 26 d640 (0) d7ac (0) d3b0 (0) d299 (0)\n003 8 e027 e54b e7fa ee5e | 18 ec52 (0) ed2d (0) ee5e (0) ef07 (0)\n004 5 f925 fbc8 fbf5 ff36 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 9 f4e0 f45f f456 f528 | 10 f528 (0) f5b2 (0) f5dc (0) f4e0 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 f2d5 f27f | 2 f2d5 (0) f27f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","private_key":"7b96931ae2b82181dbbf1ce714ef7dcd8a73ee4ba37b6cd3e5a38c185179b50a","name":"node_f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","services":["streamer"],"enable_msg_events":true,"port":43987},"up":true}},{"node":{"info":{"id":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","name":"node_c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","enode":"enode://3e653640cb83949eb33046e1f53f3cea2dfc41dda2b5b820f8f519198a9ef5be60bb4feb02bcab43abc24d6283d318be1d4e79ff8530dfe9c9a0cd3b0583460f@127.0.0.1:0","enr":"0xf88fb84070b2190039d9877fc8133fa67fa8c4ce0339ca41fe322a61637d2f6a0501d7d41dfbf0f867138735e708a26fcc2df5419d72eb535ba75a4ab36df55305b825e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033e653640cb83949eb33046e1f53f3cea2dfc41dda2b5b820f8f519198a9ef5be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wfno4dUJ/r3x8me7IndB5RNCAEii5mmsnu9LBaKc8Qs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c1f9e8\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 738c 6251 179f 1672 | 146 5b63 (0) 58ed (0) 5823 (0) 5db0 (0)\n001 6 b95d af02 82dd 849b | 47 b65e (0) b626 (0) b7ca (0) b5b2 (0)\n002 14 e883 efea ee5e ed2d | 37 ec52 (0) ed2d (0) ef07 (0) ef1b (0)\n003 4 d1d7 d3b0 d887 daec | 11 df1e (0) d863 (0) d887 (0) db6a (0)\n004 3 cc20 ca04 c898 | 6 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n============ DEPTH: 5 ==========================================\n005 7 c59e c49c c441 c43f | 7 c59e (0) c49c (0) c441 (0) c43f (0)\n006 1 c26f | 1 c26f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","private_key":"d1af3c939ccb6fbd80b3e800e90fc304fe1a95e5093d4b8a8014d2c2bcc614ef","name":"node_c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","services":["streamer"],"enable_msg_events":true,"port":38941},"up":true}},{"node":{"info":{"id":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","name":"node_f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","enode":"enode://ebdf19a2508ec342f90a571ea57e25d9fe086842827fb7122f9040f247be1782a6f73e3830e0d4a6d15fb9ba45deaefdd93c4c7ff95d9062fc9fa64149f98e39@127.0.0.1:0","enr":"0xf88fb84074708297591a962a8f10e1c5023c61300d115facd722246df478257dcb61eab468084b00d42034c7472dc28fa7dd04a6e8c31f4478bfb790e7d6a45f9a011a6f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ebdf19a2508ec342f90a571ea57e25d9fe086842827fb7122f9040f247be1782","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"93O4Pxod4qtmYO2wt2XPzOxneAYe4lxahPloYlaG72A=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f773b8\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3ec5 045b 7dc2 | 146 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n001 5 b95d af02 849b 9fa0 | 47 b626 (0) b65e (0) b7ca (0) b5b2 (0)\n002 7 daec d299 d1d7 c898 | 26 d7ac (0) d640 (0) d3b0 (0) d299 (0)\n003 8 ed2d ee5e eb98 e854 | 18 ec52 (0) ed2d (0) ef07 (0) ef1b (0)\n004 4 fe21 f925 fbf5 fbc8 | 6 fe31 (0) fe21 (0) ff36 (0) f925 (0)\n005 3 f2d5 f27f f31c | 3 f2d5 (0) f27f (0) f31c (0)\n006 6 f528 f5b2 f5dc f4e0 | 6 f528 (0) f5b2 (0) f5dc (0) f4e0 (0)\n007 1 f629 | 1 f629 (0)\n============ DEPTH: 8 ==========================================\n008 2 f7fa f7ba | 2 f7fa (0) f7ba (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","private_key":"e898408c6a69bdbbb2b3d144d09beeb11db724b09c3b43d166192d7af9c168a9","name":"node_f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","services":["streamer"],"enable_msg_events":true,"port":37133},"up":true}},{"node":{"info":{"id":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","name":"node_7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","enode":"enode://ce63a767ab6f112649325e6862410a7e4788fec965925e83abcbc055deca8a04c3beb8619a415ae9a767691bbec01ec218ee44b8a1afd11a06ccbdd63e64d135@127.0.0.1:0","enr":"0xf88fb8400698b27f1b516079af94fb615edaac2e5afe70b2961bcf8525534071441b3b0409021a48a66ad2e700e4d9d46ee752d9aebb9a55dbcac1c6aa072024a7139b260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ce63a767ab6f112649325e6862410a7e4788fec965925e83abcbc055deca8a04","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fcKpVz8lPzYu8bIbv8wUSxGm/rxYqjxEMCJBYOn6c4w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dc2a9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9890 f45f f773 | 110 b502 (0) b5b2 (0) b7ca (0) b65e (0)\n001 3 1672 0328 045b | 76 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n002 7 524d 534b 44a1 4559 | 38 58ed (0) 5823 (0) 5b63 (0) 5f00 (0)\n003 8 6c4d 6ea5 6f2d 6831 | 20 6c73 (0) 6c4d (0) 6fe9 (0) 6f5f (0)\n004 5 775e 77d2 7125 7290 | 5 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n005 3 7a60 7b90 7920 | 3 7a60 (0) 7b90 (0) 7920 (0)\n006 1 7e04 | 1 7e04 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 7dbb | 1 7dbb (0)\n010 0 | 0\n011 1 7dd3 | 1 7dd3 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","private_key":"202bed44b0e5747d57db0077e83d62aa8814b4a640a338a0b0e200d4231f69dc","name":"node_7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","services":["streamer"],"enable_msg_events":true,"port":38091},"up":true}},{"node":{"info":{"id":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","name":"node_045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","enode":"enode://a8da5558c682d2a891ea880bbed34a14cb1087c5fe6ee20c66210ab1eac9fd69dc13a6fc924f84bb35b5dfb838f499895a1226efd887e3e0ac1e76b92ea358b8@127.0.0.1:0","enr":"0xf88fb840e00bd27f128a7ceab96f9085ff60dba7842de4f23816bc8e957a96a3d4807a3b209f5c0675fe420cd322fe7bcc131344e5aae695d4a6b95c0224634bcf102c0c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a8da5558c682d2a891ea880bbed34a14cb1087c5fe6ee20c66210ab1eac9fd69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BFuo2kZB2j8LgFi7DZ2Kr7uBSW3ByuKj/ZwDmn4cr7Y=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 045ba8\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c1f9 f773 9890 | 110 ec52 (0) ed2d (0) ef1b (0) ef07 (0)\n001 2 775e 7dc2 | 70 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n002 6 3b88 3efc 3ec5 314a | 32 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n003 4 1672 165f 179f 19fa | 22 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n004 4 0ff2 0fc5 0de3 0c28 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n005 4 0328 02d8 0067 00c6 | 5 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n006 2 07a8 0661 | 3 0743 (0) 07a8 (0) 0661 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 0438 | 1 0438 (0)\n010 0 | 0\n011 0 | 0\n012 1 0451 | 1 0451 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","private_key":"be4604105acf932a56aeb47b672aa90728f8e2a6b5e4eac4c582dd5646f61358","name":"node_045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","services":["streamer"],"enable_msg_events":true,"port":37847},"up":true}},{"node":{"info":{"id":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","name":"node_9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","enode":"enode://9ca38a60e6b0d6f83aca233c9b27c0817b0d3ab7644e05fc12cd158726f9a752b4904052a3ec36b45ed9cd04fa8563b84a94d384ce66831e18f71cd74f9c6951@127.0.0.1:0","enr":"0xf88fb840d0e03834031b00b0b1497f467bf9bca7abd4b7e83a8a6534025d2f58b88220556789b327681ded4921f921cd6711f0f7b181b548c87ffefc722fb53c5fdb7f210183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039ca38a60e6b0d6f83aca233c9b27c0817b0d3ab7644e05fc12cd158726f9a752","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mJDm67LG+ae+xMJ3jgd+NxDOOvNW+CrptNMkgy0Vnvc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9890e6\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7dc2 775e 045b | 146 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n001 7 c1f9 e54b e883 fbc8 | 63 ec52 (0) ed2d (0) ef1b (0) ef07 (0)\n002 7 af02 a34e b95d b897 | 27 b626 (0) b65e (0) b7ca (0) b5b2 (0)\n003 3 8505 849b 82dd | 10 898d (0) 886a (0) 88fe (0) 88a1 (0)\n004 5 9076 90a8 959f 976e | 6 959f (0) 976e (0) 96fc (0) 915d (0)\n============ DEPTH: 5 ==========================================\n005 2 9d0f 9fa0 | 2 9d0f (0) 9fa0 (0)\n006 0 | 0\n007 0 | 0\n008 1 9852 | 1 9852 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","private_key":"91c1cd51e3963ac4ebcb1fe6e859426d29a1872f98d56582b779f77a16d76109","name":"node_9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","services":["streamer"],"enable_msg_events":true,"port":36407},"up":true}},{"node":{"info":{"id":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","name":"node_775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","enode":"enode://0fbe2eb4516d803819afa51e4a2f9d86b0e2500f1f9c664c51c812be957a1eb071e0ff91c18545685b7c8d58366451323dfd6e919071e515387c9a9be992b424@127.0.0.1:0","enr":"0xf88fb8407865c59fc952191a2f0320a38291d0936783b994a63bb99bcbbc58fadc871a32638de097c22553f495619842efee63e70aa5550fc1bf656088bd1938df45ed5d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020fbe2eb4516d803819afa51e4a2f9d86b0e2500f1f9c664c51c812be957a1eb0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d1575QLfj9k4z5xC7k+sM+RgpLaZK57+uNwf993lxA8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 775e7b\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f31c 9890 | 110 ec52 (0) ed2d (0) ef07 (0) ef1b (0)\n001 3 045b 1672 19fa | 76 2f32 (0) 2d36 (0) 2ccf (0) 2c38 (0)\n002 5 534b 524d 4bcf 4c9e | 38 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n003 9 6ecb 6ea5 6c4d 6c73 | 20 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n004 6 7b90 7920 7e04 7dc2 | 7 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n============ DEPTH: 5 ==========================================\n005 3 7125 7290 738c | 3 7125 (0) 7290 (0) 738c (0)\n006 0 | 0\n007 0 | 0\n008 1 77d2 | 1 77d2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","private_key":"1d0023ab98fa043da972badeee9fd4d8df9514307a8158fdddee5c7ba1df9405","name":"node_775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","services":["streamer"],"enable_msg_events":true,"port":38817},"up":true}},{"node":{"info":{"id":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","name":"node_738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","enode":"enode://cda9d251eca9ce01ba41a3c17fa3b1f665bd822176bb5e8713e9865c8aa07e087f75d33c65c897484f96471c8877a32f746463e4fb55a0bb3d2ec550abbf66d8@127.0.0.1:0","enr":"0xf88fb8406c67c864c9f890ffca30545b73befcd0c86f9fd8ad5e355d00b6a3c631ebdab07b4d54f271fd817f63f621d48593488c298ce9abf52c8ecdc08d65dbf149c5070183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cda9d251eca9ce01ba41a3c17fa3b1f665bd822176bb5e8713e9865c8aa07e08","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c4wtQkWJZdA8j58FXq8OPt89+ipN4KBI7AW3jnt2XJA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 738c2d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 af02 b897 849b c1f9 | 110 915d (0) 90a8 (0) 9076 (0) 959f (0)\n001 3 21a0 1672 19fa | 76 2f32 (0) 2d36 (0) 2ccf (0) 2c38 (0)\n002 6 524d 44a1 4559 4bcf | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 9 6c73 6c4d 6ea5 6831 | 20 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n004 6 7920 7b90 7e04 7dbb | 7 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n005 2 77d2 775e | 2 77d2 (0) 775e (0)\n============ DEPTH: 6 ==========================================\n006 1 7125 | 1 7125 (0)\n007 1 7290 | 1 7290 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","private_key":"728881169692d835251307412b70e5bf5bab2e025d4075c0571eb4575cd8fa0a","name":"node_738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","services":["streamer"],"enable_msg_events":true,"port":44907},"up":true}},{"node":{"info":{"id":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","name":"node_e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","enode":"enode://f4feccd03c0ab9c061130b9bc469d72e44850b40c65c1dfca65ebd585d1ff154419ac9cae4b7253273128994742c14550d13d278cddc876adbe481e1a8acc07d@127.0.0.1:0","enr":"0xf88fb840c5269e2a1ffb34a29af3d3688ea0843b35546e0313938addaccbde1f97c82c823c987f0b038109c00a1a3552cef7c3dcdd95180fbe5ed39821c257e0a378f34d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f4feccd03c0ab9c061130b9bc469d72e44850b40c65c1dfca65ebd585d1ff154","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5/pxEq3HsCPdWWXmICdxIlQhU/h+r13urMilHxd4unc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e7fa71\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 3efc 19fa 67dc 738c | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 4 849b b897 b95d af02 | 47 915d (0) 90a8 (0) 9076 (0) 959f (0)\n002 6 db6a daec d299 d1d7 | 26 df1e (0) d887 (0) d863 (0) db6a (0)\n003 3 f31c f528 f45f | 19 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n004 7 eb98 e854 e8ef e883 | 10 eb98 (0) e854 (0) e8ef (0) e883 (0)\n005 1 e027 | 1 e027 (0)\n============ DEPTH: 6 ==========================================\n006 5 e5d7 e5ad e514 e547 | 5 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n007 0 | 0\n008 1 e775 | 1 e775 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","private_key":"3698971ede47de5ef29ce2ab0eb433184d7570578147e4189713e90a2cfc37a6","name":"node_e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","services":["streamer"],"enable_msg_events":true,"port":44579},"up":true}},{"node":{"info":{"id":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","name":"node_f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","enode":"enode://dbf1445ea421e785c6e095596b2a52a7179cd19f387200d9c0e855c53419fefcee80384b81636c5d042ef9bbebaaa11d1b32df623a942e01ab10692f3db30324@127.0.0.1:0","enr":"0xf88fb840946cc04d7fc58d61080fd4bb13dd8e38ec6b5e85d92296892845774c4a0a3b496587cd1807eda5a924c4eb9a6d9377f0ff6c65b98f0d35e0b8cebeb91c0c49350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102dbf1445ea421e785c6e095596b2a52a7179cd19f387200d9c0e855c53419fefc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9F8fLlnpR+BPoVvPh/hy721ztz93jhLR+biTDqFm7vw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f45f1f\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7dc2 738c 67dc 3ec5 | 146 4109 (0) 41d9 (0) 46fe (0) 461c (0)\n001 10 82dd 849b 96fc 9fa0 | 47 915d (0) 90a8 (0) 9076 (0) 959f (0)\n002 5 daec d1d7 d299 c620 | 26 df1e (0) d863 (0) d887 (0) db6a (0)\n003 5 ee5e eb98 e027 e775 | 18 eb98 (0) e854 (0) e8ef (0) e883 (0)\n004 4 fe21 fbf5 fbc8 f925 | 6 ff36 (0) fe31 (0) fe21 (0) f925 (0)\n005 2 f31c f27f | 3 f2d5 (0) f27f (0) f31c (0)\n006 2 f7ba f773 | 4 f629 (0) f7fa (0) f7ba (0) f773 (0)\n007 3 f528 f5dc f5b2 | 3 f528 (0) f5b2 (0) f5dc (0)\n============ DEPTH: 8 ==========================================\n008 1 f4e0 | 1 f4e0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 f456 | 1 f456 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","private_key":"dbee637d6a6f6facfb47a418c9c1b36a97b04592930833d23aba31c3ca7d5c3d","name":"node_f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","services":["streamer"],"enable_msg_events":true,"port":34023},"up":true}},{"node":{"info":{"id":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","name":"node_19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","enode":"enode://f6f1250fa9e6af3e6fd9195d9f8f7c0608e1afc6f538eecc930b507ee1225cac227a89b3bf1012473ba75ab38aa7a4147f2696b9f562aeda5bdd0ad29550f285@127.0.0.1:0","enr":"0xf88fb840d2cc7d831dfc47bb778b496762213f2d10d8f52b0403aff469b5adf2362312877560ab18951eae9326f58eeba05ce563d4e39a48953e8184de4f0f55d4447d260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f6f1250fa9e6af3e6fd9195d9f8f7c0608e1afc6f538eecc930b507ee1225cac","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GfqviR62pxaQLsKdIB3CCU7kdKz/GIrob6+XYGdLLTc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 19faaf\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e7fa f45f | 110 959f (0) 976e (0) 96fc (0) 915d (0)\n001 4 524d 775e 738c 67dc | 70 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n002 5 2abb 21a0 314a 3ec5 | 32 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n003 4 0c28 0328 0661 045b | 22 0b72 (0) 0a00 (0) 0af9 (0) 0fc5 (0)\n004 10 11d4 103b 13d6 154b | 12 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n005 3 1f85 1c8a 1c9c | 6 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n============ DEPTH: 6 ==========================================\n006 2 1a2a 1b83 | 2 1a2a (0) 1b83 (0)\n007 1 18f6 | 1 18f6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","private_key":"05c69a8793e77331075909934a1e61ac9f380584e32a35ecc8f42887d20cb77a","name":"node_19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","services":["streamer"],"enable_msg_events":true,"port":35641},"up":true}},{"node":{"info":{"id":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","name":"node_67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","enode":"enode://0f351aaf6a4b09eb918bb712e8a79718d083d4214c2406c36f0074d8ad70802689f53f164b38cb9e83e59edb887df1b27e57e48214a7070b32cdc903da0cfd38@127.0.0.1:0","enr":"0xf88fb8404bcca6e121f7562863b5b6ac375f6e953cdb6ab0c36f265ef3366ba7eefdf7ef01ad1990f3c942767f70f2e5d5887ffccb367ad0e344b78133814537196687920183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f351aaf6a4b09eb918bb712e8a79718d083d4214c2406c36f0074d8ad708026","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z9z9IezjC0Gjm8VcCYb8qPQBuzrLqCGWlRnwnQkz6L0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67dcfd\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e7fa f45f af02 | 110 915d (0) 90a8 (0) 9076 (0) 959f (0)\n001 3 21a0 0328 19fa | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 5 524d 44a1 4bcf 4d6b | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 7 7920 7e04 7dbb 7dc2 | 12 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n004 6 6c73 6c4d 6e68 6ea5 | 11 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n005 5 6103 605a 6337 628e | 6 6103 (0) 60d7 (0) 605a (0) 6337 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 66e7 | 1 66e7 (0)\n008 0 | 0\n009 1 67aa | 1 67aa (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","private_key":"9f85db9ae6c9cd4db65d7ccb16a9d89efce6ec7d02aac8d35721d5a94ef55f76","name":"node_67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","services":["streamer"],"enable_msg_events":true,"port":45525},"up":true}},{"node":{"info":{"id":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","name":"node_af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","enode":"enode://6b4c01daeddfe0f12d5f3bf6f1e60b261982605a1312d4ddacaa9f6a761f8d4da61c42c09410ac2eff9ab2f5b4a650fc3b92480df5822f85f07f632bc7ee2fd2@127.0.0.1:0","enr":"0xf88fb840c68f36e51ad8efcb6e966d5d8b2a31e1b13e6da82559ded1950420552c3f7c4770459222d11e203f7a841ae5148f9d021adbd26d94a04210def38224db50977c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026b4c01daeddfe0f12d5f3bf6f1e60b261982605a1312d4ddacaa9f6a761f8d4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rwK10QezoX9TnH+QIOvnQyJDRjTnDEIKf1Z3brXZ23M=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: af02b5\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0c28 21a0 2abb 314a | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 6 c1f9 f31c f45f f773 | 63 df1e (0) d887 (0) d863 (0) db6a (0)\n002 8 96fc 9076 9fa0 9890 | 20 959f (0) 976e (0) 96fc (0) 915d (0)\n003 6 b502 b2a5 b2b5 b897 | 17 b7ca (0) b626 (0) b65e (0) b5b2 (0)\n004 5 a369 a34e a46d a653 | 5 a369 (0) a34e (0) a46d (0) a653 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 ac4d ad98 | 2 ac4d (0) ad98 (0)\n007 2 ae2b aeb4 | 2 ae2b (0) aeb4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","private_key":"272d73cf1639238294e76d97933c731ba4d307d8b4551361e31c99a5548b352c","name":"node_af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","services":["streamer"],"enable_msg_events":true,"port":34209},"up":true}},{"node":{"info":{"id":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","name":"node_6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","enode":"enode://aacecc9f59aaf5f89dccbc0f54658dc28b0c01036b15e949465c69469611f86d685911890629199edbcc30c5f8c9de080fa95cdfc4bd9e4ba48ca6572b425efc@127.0.0.1:0","enr":"0xf88fb840466f1c17c93f63d6256f50ab183789dcb5f940f2f5965173b02e3411c452bf525d835c457a1e62bbb60313212f47c91f20e1042e0ec85130d9872724cd47b7890183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102aacecc9f59aaf5f89dccbc0f54658dc28b0c01036b15e949465c69469611f86d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YlHpVARIcmpgFpnvTNGeUMlpp0baJyKJZzOM3AnWKL8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6251e9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ee5e daec d1d7 c1f9 | 110 df1e (0) d863 (0) d887 (0) db6a (0)\n001 3 0328 21a0 3efc | 76 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n002 3 44a1 4c9e 524d | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 7 7920 7dc2 7dbb 7e04 | 12 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n004 6 6f2d 6e68 6c73 6c4d | 11 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n005 3 66e7 67aa 67dc | 3 66e7 (0) 67aa (0) 67dc (0)\n006 3 6103 60d7 605a | 3 6103 (0) 60d7 (0) 605a (0)\n============ DEPTH: 7 ==========================================\n007 1 6337 | 1 6337 (0)\n008 1 628e | 1 628e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","private_key":"60256936fed4be723c1215b22d031aac3b557568a1f9ad98436a946002f6ceb1","name":"node_6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","services":["streamer"],"enable_msg_events":true,"port":42317},"up":true}},{"node":{"info":{"id":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","name":"node_3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","enode":"enode://c250393ff34081bb09b6ee97df2aa2fe93d7335b4623376a0ede17dd046719e32496e4a67a7e160efda5985e2d384b75b04416aaa0b99627c1fc87ba118e3033@127.0.0.1:0","enr":"0xf88fb840696ee67e59754db968f1147865e6fefc0faf7d85b54e7bcefbfa391263921be65b031de9a59d4b9285fea97cbdbdbfe81217ed0070911cf050644c3c4d0b2d590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c250393ff34081bb09b6ee97df2aa2fe93d7335b4623376a0ede17dd046719e3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PvxLEgs+7qwYa/OkzULrjGR/ftsIwj7mQ+K+ydcsW+0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3efc4b\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e7fa f45f 849b af02 | 110 df1e (0) d887 (0) d863 (0) db6a (0)\n001 4 4c9e 524d 6ea5 6251 | 70 4109 (0) 41d9 (0) 46fe (0) 4646 (0)\n002 4 1c8a 19fa 045b 0c28 | 44 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n003 5 21a0 256e 24b8 2f32 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 4 314a 33b5 3780 378e | 10 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n005 2 3b78 3b88 | 3 39d1 (0) 3b78 (0) 3b88 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 3f94 | 1 3f94 (0)\n008 0 | 0\n009 1 3e8e | 1 3e8e (0)\n010 1 3ec5 | 1 3ec5 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","private_key":"c5e74524cfda7833835e2f15a5bdb1a551e63bf87e2ba94faf778776acaa422e","name":"node_3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","services":["streamer"],"enable_msg_events":true,"port":44145},"up":true}},{"node":{"info":{"id":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","name":"node_6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","enode":"enode://f87232a3077f74f8aadead28608baee93a2b0f196b7b40dbba13f3f3b68381bbe474b527aba8bf8df37c35ec861c9ca430a6fb1fd568aaf8ecc439e4638888bd@127.0.0.1:0","enr":"0xf88fb840e62f5938f4645beb16ccd0ff2cda19b29599be7deb95ca52b1e6c0cfe5c5d94742d1407950829383b339174f1b9927df3bda8368d7ac143d0fbc8e1e15290dd90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f87232a3077f74f8aadead28608baee93a2b0f196b7b40dbba13f3f3b68381bb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bqUftuR4PzUdu/pHtQjHjHMjPrqtpAnftVRGIX+SxL0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ea51f\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 af02 b95d b897 | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 3 0c28 21a0 3efc | 76 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n002 5 524d 44a1 4bcf 4d6b | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 6 775e 738c 7920 7dbb | 12 7a60 (0) 7b90 (0) 7920 (0) 7dbb (0)\n004 4 60d7 66e7 67aa 67dc | 9 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n005 2 6831 6967 | 2 6831 (0) 6967 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 3 6fe9 6f5f 6f2d | 3 6fe9 (0) 6f5f (0) 6f2d (0)\n============ DEPTH: 8 ==========================================\n008 2 6e05 6e68 | 2 6e05 (0) 6e68 (0)\n009 1 6ecb | 1 6ecb (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","private_key":"ed77945ec41ca5949c86e0e85e2dcc36e3334a85b705187ec4227bcdb3122ea8","name":"node_6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","services":["streamer"],"enable_msg_events":true,"port":46181},"up":true}},{"node":{"info":{"id":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","name":"node_0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","enode":"enode://bec2d78f8d965930c57e3156c95b56aedc58439ffffea7b36857dcdfe54089c9cee8b61b907fcca85cbea54e1ccafd63b48eefd700e841fe21da9ea70d00c9a3@127.0.0.1:0","enr":"0xf88fb8407399470e3737fa8272666e8fbd34bdca814621e3e955369900b266e29c0fa58744c674080c49ca4e6b59676ee2486cb144a30a95904959d8b5878edb805a4faa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bec2d78f8d965930c57e3156c95b56aedc58439ffffea7b36857dcdfe54089c9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DCjNExWJBimJbQ/lUXUk1Ot4j3REcJwTXqaQuk5hA9U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0c28cd\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ee5e f45f af02 b95d | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 5 4c9e 44a1 524d 6967 | 70 4109 (0) 41d9 (0) 46fe (0) 4646 (0)\n002 7 21a0 256e 2abb 378e | 32 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n003 6 1436 179f 1672 1f85 | 22 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n004 5 0328 00c6 0661 07a8 | 11 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n005 2 0a00 0af9 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 2 0ff2 0fc5 | 3 0e5e (0) 0ff2 (0) 0fc5 (0)\n007 2 0d8a 0de3 | 2 0d8a (0) 0de3 (0)\n============ DEPTH: 8 ==========================================\n008 1 0cf5 | 1 0cf5 (0)\n009 1 0c64 | 1 0c64 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","private_key":"e4f96de1ae6c788aee624501af093f341f540fac893f97ced8d5f1189c24c67f","name":"node_0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","services":["streamer"],"enable_msg_events":true,"port":36203},"up":true}},{"node":{"info":{"id":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","name":"node_6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","enode":"enode://e505e79cdb3fcf2ca7c4f9dd26a2c8fe2b7f6ae9b788f6a904eaf8fbc4160d011c02333c5127215f980fba718d4b3a285c2e88a4fb44a15d266a91377d3b48e5@127.0.0.1:0","enr":"0xf88fb840d716acddd75f7eb58dd24dbcafe9a68ab943a8c16e6bd0e8c2895345b80d0a91716890cb91bd5d41bcaa60a862cb05a82b25fd626cda6d8930c48fb6619437e90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e505e79cdb3fcf2ca7c4f9dd26a2c8fe2b7f6ae9b788f6a904eaf8fbc4160d01","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aWfnQ4ElwgRdV1659Ae0o40b+dzRwcGpf3UNpqIa7/c=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6967e7\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ee5e 849b | 110 df1e (0) d863 (0) d887 (0) db6a (0)\n001 5 3b88 314a 21a0 2abb | 76 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n002 2 4c9e 524d | 38 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n003 5 7dc2 7e04 77d2 775e | 12 7a60 (0) 7b90 (0) 7920 (0) 7dbb (0)\n004 5 66e7 67aa 67dc 628e | 9 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n============ DEPTH: 5 ==========================================\n005 9 6c73 6c4d 6fe9 6f5f | 9 6c73 (0) 6c4d (0) 6fe9 (0) 6f5f (0)\n006 0 | 0\n007 1 6831 | 1 6831 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","private_key":"b2e4ecb1d88acc51fd5c7268060e5bc618f3e72b5b7c52f4e455216d80962dc0","name":"node_6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","services":["streamer"],"enable_msg_events":true,"port":35593},"up":true}},{"node":{"info":{"id":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","name":"node_849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","enode":"enode://b0afa8b09566cfd0a41f4197f7997a219c84adac6259015ce3698a009fb6abf8d1cdbe5450429b7e05c28a0d49b2b9f8f2bdd7335fc98e834b8bb0628eae7fc7@127.0.0.1:0","enr":"0xf88fb840393a953e4ec2059acf7f9d3275f18559d6680009999862bd154f9fd1ee1f999d45494fe71181ffbc753878d558571d57d1b697d91b82b240075a2dcd39fefbfb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b0afa8b09566cfd0a41f4197f7997a219c84adac6259015ce3698a009fb6abf8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hJvLub5Dt5n+/F5onvx1El2if1Nul+W3khAxUgrm5dg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 849bcb\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 0c28 3b88 3ec5 3efc | 146 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n001 7 c1f9 f31c f773 f45f | 63 df1e (0) d887 (0) d863 (0) da67 (0)\n002 6 a6fb af02 b502 b2b5 | 27 a369 (0) a34e (0) a46d (0) a653 (0)\n003 6 9fa0 9852 9890 9076 | 10 915d (0) 90a8 (0) 9076 (0) 959f (0)\n004 4 8f21 898d 88a1 88fe | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n============ DEPTH: 5 ==========================================\n005 3 8025 82f9 82dd | 3 8025 (0) 82f9 (0) 82dd (0)\n006 0 | 0\n007 1 8505 | 1 8505 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","private_key":"a069eed892fd44938d06d266a1b6e95863c80eac1fa44fccaeebc41efc5ed441","name":"node_849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","services":["streamer"],"enable_msg_events":true,"port":41647},"up":true}},{"node":{"info":{"id":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","name":"node_b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","enode":"enode://616dc404ad737ba64ed652df2d9b1eb7fbc7d27072123ffacbd5768b7b3a2808cc1ea3f7273bc1a8e881a0ed5cf764d793fc0ee1fda9a62a2e5219a90f7b97e4@127.0.0.1:0","enr":"0xf88fb8403b649d56e05ba7d5845e7dc235d0b38a8817441e5e2a7dae66c6959b44f3331a4718237e4751e5b45041e65998db19f244b263394f454f246db8d863a0b2f9a80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102616dc404ad737ba64ed652df2d9b1eb7fbc7d27072123ffacbd5768b7b3a2808","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uJeTw8zZ6mQggHKHMs598zd4ZT/tPR2POiXmBnDjMyU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b89793\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7e04 738c 6ea5 44a1 | 146 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n001 5 f45f f5dc e7fa efea | 63 df1e (0) d863 (0) d887 (0) da67 (0)\n002 5 96fc 9076 9890 9fa0 | 20 915d (0) 90a8 (0) 9076 (0) 959f (0)\n003 4 af02 a6fb a369 a34e | 10 ac4d (0) ad98 (0) aeb4 (0) ae2b (0)\n004 4 b502 b02b b2a5 b2b5 | 8 b65e (0) b626 (0) b7ca (0) b5b2 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 badd baf2 ba88 bb90 | 4 baf2 (0) badd (0) ba88 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b911 b95d | 2 b911 (0) b95d (0)\n008 1 b820 | 1 b820 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","private_key":"0bc50a7b766d6bc874ba369321f3b4a7f46e967445811ba2511e2698ca848d6f","name":"node_b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","services":["streamer"],"enable_msg_events":true,"port":37439},"up":true}},{"node":{"info":{"id":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","name":"node_3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","enode":"enode://21eeb4f1bb6f01a16243e4a426ed7cc92b6fbc6f8004c7bd662db3891b43f68ff5952440f106b72cac72fb55e0d2e9efa1696011cd33351094dc6c2e13fa3a67@127.0.0.1:0","enr":"0xf88fb840be1d0ed9539666492df4644d2aed2cad4aa9462d5e4bea665e163639db67f4da335d828dd4a5e24ed611a8d48ce089696a907d9a7f47829e9c5413c90360eeec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10321eeb4f1bb6f01a16243e4a426ed7cc92b6fbc6f8004c7bd662db3891b43f68f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PsUwdh3bh/kw/akZvmffGAdMbweVKSrdGyqR/z2cOeM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3ec530\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 ee5e ed2d f773 f5dc | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 2 4c9e 524d | 70 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n002 7 1436 17db 19fa 0328 | 44 1e2a (0) 1f67 (0) 1f85 (0) 1c47 (0)\n003 5 21a0 24b8 256e 2f32 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 4 378e 33b5 30be 314a | 10 35e6 (0) 3630 (0) 3780 (0) 378e (0)\n005 2 3b78 3b88 | 3 39d1 (0) 3b78 (0) 3b88 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 3f94 | 1 3f94 (0)\n008 0 | 0\n009 1 3e8e | 1 3e8e (0)\n010 1 3efc | 1 3efc (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","private_key":"c4b8862c8a0e3546078dca8083dcf8de77697d5dc9c4287a249fe5593f2ca90d","name":"node_3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","services":["streamer"],"enable_msg_events":true,"port":37999},"up":true}},{"node":{"info":{"id":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","name":"node_524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","enode":"enode://99f219a31926c42a84a19fd9aea063ef2ccb9f87f3f3ce40a8f04c86844559a054cd3b92341e71f2c349582310c55ba9d086a6f5c3306860778bedbb03528ec0@127.0.0.1:0","enr":"0xf88fb8402ab8e87c3dbe9a6ec2cac6b5b115117c51c3fa4a47a0cdb6eb173d6c313304c33d04648bd348128c2a2214fc92458c6056d91e66d8698ef94c65f0eecbe6c2320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10299f219a31926c42a84a19fd9aea063ef2ccb9f87f3f3ce40a8f04c86844559a0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Uk24GxNa+Nwwm5QsCCpykd3bhRhm/GCHU/k37ncBW+A=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 524db8\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ee5e b897 b95d | 110 df1e (0) d863 (0) d887 (0) da67 (0)\n001 5 19fa 0c28 3b88 3efc | 76 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n002 15 7920 7dbb 7dc2 7e04 | 32 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n003 4 4636 44a1 4559 4c9e | 23 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n004 2 5823 5cd2 | 7 5b63 (0) 58ed (0) 5823 (0) 5f00 (0)\n005 1 574f | 1 574f (0)\n006 2 51db 512e | 2 51db (0) 512e (0)\n============ DEPTH: 7 ==========================================\n007 4 53a8 53fe 5308 534b | 4 53a8 (0) 53fe (0) 5308 (0) 534b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","private_key":"2f5862456985e522a96e35955f2236ea2996dbc1ae46e4cd98b90a43a097da88","name":"node_524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","services":["streamer"],"enable_msg_events":true,"port":36823},"up":true}},{"node":{"info":{"id":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","name":"node_b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","enode":"enode://36447aeebafb12ba1c78c6a46a110934e1cd8927ed11dface43f85436177abde695118ad9a8539534b4f4141d990d917f905f7ecaa18baaebc0916b0205c8e2e@127.0.0.1:0","enr":"0xf88fb84085f456734d0dc37f56567ca4283aaf0355c1fa8925ff4c21ea20d7528816d28d2f74360586c27977522735076e9fd0f4e0c89ff5e78369ea4fefb33a06c132730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10236447aeebafb12ba1c78c6a46a110934e1cd8927ed11dface43f85436177abde","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uV2I/2US746qpr2EL6RBdcFIT8LoYBuD1Qpf+pkr+jo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b95d88\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3b88 0c28 7e04 6ea5 | 146 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n001 8 c1f9 ee5e ed2d e7fa | 63 df1e (0) d887 (0) d863 (0) db6a (0)\n002 4 9890 9fa0 96fc 849b | 20 915d (0) 90a8 (0) 9076 (0) 959f (0)\n003 3 af02 a34e a6fb | 10 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n004 4 b2b5 b2a5 b626 b502 | 8 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 badd baf2 bb90 | 4 ba88 (0) badd (0) baf2 (0) bb90 (0)\n============ DEPTH: 7 ==========================================\n007 2 b820 b897 | 2 b820 (0) b897 (0)\n008 0 | 0\n009 1 b911 | 1 b911 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","private_key":"7dd97b58fb51f901cffaf8552811e55ed1f745fbc8de989e59715731046e1c58","name":"node_b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","services":["streamer"],"enable_msg_events":true,"port":40425},"up":true}},{"node":{"info":{"id":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","name":"node_4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","enode":"enode://403136530469a350901a30c33fc7c809363b53c13ca95dcd6a7080ec55a3b2fcbbd3f07db1278c257db628914b8b98ebfe5410a5359cd0b5c72fcdeb559100cf@127.0.0.1:0","enr":"0xf88fb8409ef5c3e51708bd096ce7dcdf5540f7e5db79918330956f05073be4da985467075fbed23d2dba3eeb49140ac47e83bf6d93b7353a47dd6d7fd4df928eb9dc79200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103403136530469a350901a30c33fc7c809363b53c13ca95dcd6a7080ec55a3b2fc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TJ6rirRUBabUurRkMO/AS45q7B2UT4hDXspBNhkl83k=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c9eab\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ee5e 849b b95d | 110 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n001 4 0c28 3efc 3ec5 3b88 | 76 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n002 10 7dc2 7e04 738c 775e | 32 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n003 5 5823 574f 534b 53fe | 15 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n004 5 4646 4636 44a1 4559 | 12 4109 (0) 41d9 (0) 47bf (0) 4782 (0)\n005 4 49cd 4ac7 4a8b 4bcf | 6 4990 (0) 49cd (0) 49ea (0) 4ac7 (0)\n006 1 4e5a | 1 4e5a (0)\n============ DEPTH: 7 ==========================================\n007 3 4d10 4d6b 4d59 | 3 4d10 (0) 4d59 (0) 4d6b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","private_key":"7a577f1da7e66657ebe473b20ef72d95fc90848f65d8f7227f9eedb8dd2d3e36","name":"node_4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","services":["streamer"],"enable_msg_events":true,"port":38639},"up":true}},{"node":{"info":{"id":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","name":"node_ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","enode":"enode://e66e86a0d8b4fe8bc6037006527db1566125b2f17053e993b1e6e0a5cf3096da8e44246fd1f52fa9c677d078df9bf67486a1f1a1a08a9a633b509a9a01cc0d52@127.0.0.1:0","enr":"0xf88fb8404bb9f05fb11c108c893d2acac05872631cf5338eb304846ac251737b9548d01240a48e2b9001871de694d6c2f671520f9e9ffbb8005f99e4f6e949e9fed7dadb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e66e86a0d8b4fe8bc6037006527db1566125b2f17053e993b1e6e0a5cf3096da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7l5332kDKcEy8vf8oiPP04S3vDTsOHY6TrQngOBYVlY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ee5e77\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0c28 3ec5 524d 4c9e | 146 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n001 4 849b a6fb b95d b897 | 47 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n002 7 c6cf c43f c1f9 c26f | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 6 fe21 f31c f773 f45f | 19 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n004 4 e027 e54b e775 e7fa | 8 e027 (0) e5d7 (0) e5ad (0) e514 (0)\n005 4 eb98 e854 e8ef e883 | 4 eb98 (0) e854 (0) e8ef (0) e883 (0)\n006 2 ec52 ed2d | 2 ec52 (0) ed2d (0)\n============ DEPTH: 7 ==========================================\n007 3 ef1b ef07 efea | 3 ef1b (0) ef07 (0) efea (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","private_key":"5622bc6c32ee27ea32ea20654dd0ce86eaf3f03c76b7873bae6de889e3b89961","name":"node_ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","services":["streamer"],"enable_msg_events":true,"port":39579},"up":true}},{"node":{"info":{"id":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","name":"node_68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","enode":"enode://b128b6cecc8f2cf260a135b1c480349d02ac0d60843d4e5112e6b974c18ef523effc3437092835f6f1fa3db2059063ace1de775116568700f3058a2adb47dc7b@127.0.0.1:0","enr":"0xf88fb840ceddc27e475fd5b30430a62f464bf89b48b1cae471a6a1e058e20dbf6641057e1a29eaeb0a05c85c688b1f83254fcc847704c40740dfd0ee7942ad5792f29c780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b128b6cecc8f2cf260a135b1c480349d02ac0d60843d4e5112e6b974c18ef523","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aDF0MeT6Vb5KcA41xqV4MHzDK3IzZnm1xWGLYi7wxgI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 683174\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a6fb 849b ee5e | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 5 1436 165f 1672 17db | 76 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n002 4 524d 4636 44a1 4c9e | 38 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n003 4 7e04 7dc2 738c 775e | 12 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n004 3 67aa 67dc 6251 | 9 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n============ DEPTH: 5 ==========================================\n005 9 6c73 6c4d 6fe9 6f5f | 9 6fe9 (0) 6f5f (0) 6f2d (0) 6e68 (0)\n006 0 | 0\n007 1 6967 | 1 6967 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","private_key":"1411ce49011b5e54719d32b3c8ee30e4e193aca2197047ff1878ec787ac339ac","name":"node_68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","services":["streamer"],"enable_msg_events":true,"port":45763},"up":true}},{"node":{"info":{"id":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","name":"node_3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","enode":"enode://f83fbc7b2e60a5ff4336bb527a72e161cd34aa8263923321c51a04ac74a3e361817581c460f34af4383da37b22729b7ba4bf4c15d7cbe276e9c889012ed3914a@127.0.0.1:0","enr":"0xf88fb840d4647a73a557c64ec9967abd7177386635f95f0ca12c9448349e1ba7e51b526e0f5690e7a06679eb95a475414adb1a6bf0d787343a9310b45114284f99eda12a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f83fbc7b2e60a5ff4336bb527a72e161cd34aa8263923321c51a04ac74a3e361","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O4ikcr66Shj430VniIj9NZusOCOQDuz+ADf9ya1U1BY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b88a4\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 d1d7 f5dc e027 efea | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 8 524d 49cd 4c9e 44a1 | 70 5b63 (0) 5823 (0) 58ed (0) 5db0 (0)\n002 8 0de3 045b 07a8 0328 | 44 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n003 4 2abb 21a0 256e 24b8 | 15 256e (0) 24b8 (0) 20ae (0) 2101 (0)\n004 5 33b5 30be 314a 3780 | 10 3237 (0) 3373 (0) 33b5 (0) 3089 (0)\n005 4 3f94 3e8e 3efc 3ec5 | 4 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n============ DEPTH: 6 ==========================================\n006 1 39d1 | 1 39d1 (0)\n007 0 | 0\n008 1 3b78 | 1 3b78 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","private_key":"375d6617b99adaf6d42a2645a0cf39107d821b1de2bd8a65b429b3a08f5a9bf5","name":"node_3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","services":["streamer"],"enable_msg_events":true,"port":44069},"up":true}},{"node":{"info":{"id":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","name":"node_44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","enode":"enode://2a7158451573eff25378de21fbabcff17326a0fc8247f6458d8aa97d024f7a8323240b745cfe394201f1be22313612dcbaac070227f39a01884f31e654543103@127.0.0.1:0","enr":"0xf88fb8400c1b56475eeb14186a876e72f3a08af9d4bff9d3ef73358874e77af19f982809410403a991c8fdc1f40ffdbc049f9e227cbbe0c21be45c526004d08af4db1cee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032a7158451573eff25378de21fbabcff17326a0fc8247f6458d8aa97d024f7a83","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RKEFMMN2shW6/4Ux7rKvuNZxTE0DUNGm8ydhqXzWx+w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 44a105\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 a6fb b95d b897 849b | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 3 0de3 0c28 3b88 | 76 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n002 10 6251 66e7 67aa 67dc | 32 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n003 3 524d 534b 574f | 15 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n004 5 49cd 4bcf 4a8b 4c9e | 11 4990 (0) 49ea (0) 49cd (0) 4ac7 (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 6 47bf 4782 46fe 4646 | 6 47bf (0) 4782 (0) 46fe (0) 4646 (0)\n============ DEPTH: 7 ==========================================\n007 2 4558 4559 | 2 4558 (0) 4559 (0)\n008 1 4447 | 1 4447 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","private_key":"c92c1299282223ac7bd3a783268df8976213e2780f5b1fa979226ac67dc17d66","name":"node_44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","services":["streamer"],"enable_msg_events":true,"port":38773},"up":true}},{"node":{"info":{"id":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","name":"node_7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","enode":"enode://bb02c7e6af72f5794c6c0e8f70aa4cb3f84690c0f191cd8a7826c0ffb077510cf3a26fd6ad876b06f2e5944db84ec2eae05a4d0d9a5096ec4efffe3f3e3a7afc@127.0.0.1:0","enr":"0xf88fb8409f4cf59b81d3287012b59795e4be8f109968bd13739a36e9aa83cd88d152dc653f4d5471a570a8b3b5edf29c145584dcc9a9c43c40eaf96267ad7030b77ce96b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bb02c7e6af72f5794c6c0e8f70aa4cb3f84690c0f191cd8a7826c0ffb077510c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fgRY7N9wgUQ8q1QSUp85SOzmWfrKygMghJbIDdE25wQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7e0458\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 a6fb b897 b95d 849b | 110 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n001 5 0de3 1c8a 17db 1436 | 76 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n002 6 574f 524d 4c9e 4636 | 38 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n003 7 6251 67dc 6831 6967 | 20 66e7 (0) 67aa (0) 67dc (0) 6103 (0)\n004 5 7125 7290 738c 77d2 | 5 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n005 3 7a60 7b90 7920 | 3 7920 (0) 7a60 (0) 7b90 (0)\n============ DEPTH: 6 ==========================================\n006 3 7dbb 7dd3 7dc2 | 3 7dbb (0) 7dd3 (0) 7dc2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","private_key":"ea6c1bb2edf4d57e62ea561fcc9ba70c43c2a1090c7a34f31e047846d20e1ecd","name":"node_7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","services":["streamer"],"enable_msg_events":true,"port":40827},"up":true}},{"node":{"info":{"id":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","name":"node_f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","enode":"enode://08d06f19a921d3ea71d5c21913f5a847342419531a220f0da8d9e08bcefd1a0378205d1540b494ce8614bf2735320a49b00e7e9b4c73bc7845cbb81de6b1bf3a@127.0.0.1:0","enr":"0xf88fb8408b284fdc213acbd87073a716711d397be5a8b101dd3611a4833b0871cb3afdac21356d090fbe7737468658f36f642f1e0a2dad2c4179385a98354e9c23d5669f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10208d06f19a921d3ea71d5c21913f5a847342419531a220f0da8d9e08bcefd1a03","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9dx4/3GmP8IBS5VTcj7mdsY/wHijKka3yxcvNXoRgUA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f5dc78\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 3b88 3ec5 17db 4559 | 146 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n001 5 96fc 849b b897 b95d | 47 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n002 7 c898 caf6 c786 c43f | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 4 e027 ee5e efea ed2d | 18 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n004 4 fbf5 fbc8 ff36 fe21 | 6 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n005 3 f2d5 f27f f31c | 3 f2d5 (0) f27f (0) f31c (0)\n006 3 f629 f7fa f773 | 4 f629 (0) f7ba (0) f7fa (0) f773 (0)\n007 3 f4e0 f45f f456 | 3 f456 (0) f45f (0) f4e0 (0)\n============ DEPTH: 8 ==========================================\n008 1 f528 | 1 f528 (0)\n009 1 f5b2 | 1 f5b2 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","private_key":"a6746718798088d317cd7d6225dda0a32b67a827b88d4a80a28bcde59066ed49","name":"node_f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","services":["streamer"],"enable_msg_events":true,"port":33297},"up":true}},{"node":{"info":{"id":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","name":"node_a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","enode":"enode://0f12517c087f26001777a74267986c3d70abd56b9d17bd9061733e04d502ac2e7e9feb69aa0ac8aaa716add8e77c398c539e99e4665d1a48c81b74b30caafde0@127.0.0.1:0","enr":"0xf88fb840ff6e1d2403a5021cfc7a38d52571942b9c94756c73ba48c5ed420b788bc58ece089b54204b870f0a6c6a56ba811234ec38f78bb09ac098bef92436427f751c410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f12517c087f26001777a74267986c3d70abd56b9d17bd9061733e04d502ac2e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pvvha4HSQP8vLtbJPP2VkHMd+y5+w/zhwJj+VCvt8pk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a6fbe1\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3b88 17db 1c8a 44a1 | 146 11d4 (0) 103b (0) 13d6 (0) 154b (0)\n001 9 c6cf d299 d1d7 f4e0 | 63 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n002 7 96fc 9fa0 82dd 82f9 | 20 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n003 8 b502 b5b2 b626 b02b | 17 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n004 3 ad98 aeb4 af02 | 5 ac4d (0) ad98 (0) ae2b (0) aeb4 (0)\n005 2 a369 a34e | 2 a369 (0) a34e (0)\n============ DEPTH: 6 ==========================================\n006 1 a46d | 1 a46d (0)\n007 0 | 0\n008 1 a653 | 1 a653 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","private_key":"23841056b6597d35a5a91856ad166332b11761512af382f62b98d43b330c665d","name":"node_a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","services":["streamer"],"enable_msg_events":true,"port":45043},"up":true}},{"node":{"info":{"id":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","name":"node_ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","enode":"enode://a21876606bf6da53567f80f07c547c2c1d78eec18c7a793474aa1e554ed619945557b52c8557ad72b0b0953245c3dccc6a7c2e6969fa67cdb47559104f684454@127.0.0.1:0","enr":"0xf88fb8402a854c764d8a54505e85302e872616bb82bc6a7a4b1449e2edb01bfe25178a005d5002aa7cc69c8483eacebcbcd5eba719144823d665af12e4fb859eceec2bce0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a21876606bf6da53567f80f07c547c2c1d78eec18c7a793474aa1e554ed61994","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7S0+HlaTtESUgIkHyY7FTW0IMxlF0qLAPjETD+8dJYY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed2d3e\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0de3 1436 1c8a 21a0 | 146 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n001 3 96fc b95d a6fb | 47 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n002 8 c6cf c43f c26f c1f9 | 26 c9f5 (0) c832 (0) c898 (0) ca04 (0)\n003 7 fe21 f31c f773 f4e0 | 19 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n004 4 e7fa e54b e547 e027 | 8 e5d7 (0) e5ad (0) e514 (0) e54b (0)\n005 4 eb98 e854 e883 e8ef | 4 eb98 (0) e854 (0) e8ef (0) e883 (0)\n============ DEPTH: 6 ==========================================\n006 4 efea ef07 ef1b ee5e | 4 ee5e (0) ef07 (0) ef1b (0) efea (0)\n007 1 ec52 | 1 ec52 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","private_key":"2f00e9f328828c2ef1bbf37d3db3377e0b4a02e7b9f6c3c721de6b28d64e6524","name":"node_ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","services":["streamer"],"enable_msg_events":true,"port":39543},"up":true}},{"node":{"info":{"id":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","name":"node_6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","enode":"enode://c17a20dfd7be57a18cf26dcd1c304d5d01f2bb6068e09de961e1e30ffe334f151dac48d199bf561c8521dd3eaaed28583b57f2d8aca1c073f06b13ac7c771e0f@127.0.0.1:0","enr":"0xf88fb840044d1bdf571743721ed4e147a3d9a181174532883199678affb2bc6db47eca1001a2b0b3f97cc98c720570887c8551261489998bce175bfc7e7c5148b30f4b510183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c17a20dfd7be57a18cf26dcd1c304d5d01f2bb6068e09de961e1e30ffe334f15","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bE3N/e4BZKmj9BlDBybdUfkZjGX/bn3nqqb2MtzeZ5Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c4dcd\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc a6fb c6cf d1d7 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 6 378e 3b88 0de3 1436 | 76 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n002 5 574f 524d 4c9e 4636 | 38 58ed (0) 5823 (0) 5b63 (0) 5db0 (0)\n003 7 738c 775e 77d2 7b90 | 12 7125 (0) 7290 (0) 738c (0) 775e (0)\n004 4 67dc 67aa 60d7 6251 | 9 6103 (0) 605a (0) 60d7 (0) 6337 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n============ DEPTH: 6 ==========================================\n006 7 6e05 6e68 6ecb 6ea5 | 7 6e68 (0) 6e05 (0) 6ecb (0) 6ea5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 6c73 | 1 6c73 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","private_key":"14959eff979bd6f1bd74aacbc23ad2c7cb285be7e1675fab6d17567cf10fad34","name":"node_6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","services":["streamer"],"enable_msg_events":true,"port":35017},"up":true}},{"node":{"info":{"id":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","name":"node_efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","enode":"enode://ddf6985e527e42d2f0b37b8e4efc6da2a5f68c0dcb89c92077390d6d6710adc001c172965c9ad744734a92ac1538392df4a714953a5ac33ec6e68fe8c9b0e3a3@127.0.0.1:0","enr":"0xf88fb84018e335f1758ad544ccb9a6381d6f5eeab5d27dab2936bb0dfad1e1e9623305ba03de5b05753d9cc1598585baef377ec5c714e6f06d43b7ab651e5fa82cc2c27b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ddf6985e527e42d2f0b37b8e4efc6da2a5f68c0dcb89c92077390d6d6710adc0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7+rjt/YQ3BCsxRBo53GIdtFHzXipooeIxduluzppUNw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: efeae3\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1436 24b8 378e 3b88 | 146 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n001 3 b502 b897 96fc | 47 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n002 5 c6cf c43f c1f9 c26f | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 5 fe21 f31c f4e0 f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 6 e027 e7fa e775 e5ad | 8 e5d7 (0) e5ad (0) e514 (0) e54b (0)\n005 4 eb98 e854 e883 e8ef | 4 eb98 (0) e854 (0) e8ef (0) e883 (0)\n006 2 ed2d ec52 | 2 ec52 (0) ed2d (0)\n007 1 ee5e | 1 ee5e (0)\n============ DEPTH: 8 ==========================================\n008 2 ef1b ef07 | 2 ef07 (0) ef1b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","private_key":"3551e1831fe811a97293215d19ab637fc344bb26a2e7c28837cc25d9d3052c96","name":"node_efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","services":["streamer"],"enable_msg_events":true,"port":41545},"up":true}},{"node":{"info":{"id":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","name":"node_96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","enode":"enode://72736087dff95f03e9af1a0bbdd5858d8f4a50191b1009fa72ad6139b18353b15f3279fefbc352d1152aeb84a63f03a86daada01292ac8355b7b2cc5c0bdbb80@127.0.0.1:0","enr":"0xf88fb840a74a4a8f60d5b3cc5affc9d1801b03958b73091bc0eae33da8a9ea19859e87aa7a447fe2e68fdd6cd94e10757d1d8ce01334922460cca97c80b2dc26a2c4dd380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10272736087dff95f03e9af1a0bbdd5858d8f4a50191b1009fa72ad6139b18353b1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lvzxTH+QNQCRrG/LWDBsz7nko409pZ+KtlaFQzKETL0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 96fcf1\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 4559 44a1 7e04 6c4d | 146 58ed (0) 5823 (0) 5b63 (0) 5db0 (0)\n001 11 c26f c786 c6cf d299 | 63 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n002 7 a6fb af02 b2b5 b5b2 | 27 bcc6 (0) ba88 (0) badd (0) baf2 (0)\n003 6 88fe 8505 849b 82f9 | 10 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n004 4 9d0f 9fa0 9852 9890 | 4 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n005 3 90a8 9076 915d | 3 90a8 (0) 9076 (0) 915d (0)\n============ DEPTH: 6 ==========================================\n006 1 959f | 1 959f (0)\n007 1 976e | 1 976e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","private_key":"dfe1f61a9d85c8c6b37a649568512c4247752f892548a5d10128c68168c53fa0","name":"node_96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","services":["streamer"],"enable_msg_events":true,"port":38025},"up":true}},{"node":{"info":{"id":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","name":"node_0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","enode":"enode://0ced9e64272a4cb6b4f08a7577cfb1318c6de0fc82b45829643a3864110c0b809d0431af3ccd8700544fb5b6bba382810ba02181f15aca5e3d22d19361ab6657@127.0.0.1:0","enr":"0xf88fb84043c00b34db2f00d166f5f835baedf82ade48ba0751e49942a1e43eea487b20731c17c117fd43602af8059005c27d4f1534b92e310f5e5c63e0a7cf7bc51ac0850183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030ced9e64272a4cb6b4f08a7577cfb1318c6de0fc82b45829643a3864110c0b80","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DeORWwvMaAQMiqdvvSz6BxTps0ydvgg4p8uoHE9zWBw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0de391\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 96fc d1d7 ed2d e027 | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 4 6c4d 7e04 44a1 4559 | 70 58ed (0) 5823 (0) 5b63 (0) 5db0 (0)\n002 5 378e 3ec5 3b88 256e | 32 2d36 (0) 2c79 (0) 2c38 (0) 2ccf (0)\n003 5 1400 1436 17db 1f85 | 22 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n004 6 02d8 0328 045b 0438 | 11 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n005 3 0b72 0a00 0af9 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 2 0fc5 0ff2 | 3 0e5e (0) 0fc5 (0) 0ff2 (0)\n============ DEPTH: 7 ==========================================\n007 3 0cf5 0c64 0c28 | 3 0cf5 (0) 0c64 (0) 0c28 (0)\n008 0 | 0\n009 1 0d8a | 1 0d8a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","private_key":"b229b8d1f2575dc4c211d64fbcf552eadcf00482f0c55c8dfa3336ffe81b010e","name":"node_0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","services":["streamer"],"enable_msg_events":true,"port":38979},"up":true}},{"node":{"info":{"id":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","name":"node_e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","enode":"enode://42f4817eb446d17b96c18c2538bfdf9fee4b7d278972ce27ed86dda5d91ea3ec330cbb910a82891a66844c42127955360c97e744cd8c46592d82f0ae51f31845@127.0.0.1:0","enr":"0xf88fb840c0e372772fcb685e048c3e5fa6f01d0c119feb88cdc1cb7cdee06d41fd6b143c37da7e6ff58e2fdaa90c07a05779586aa7dd6e4678007678b886c09c39a532690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10342f4817eb446d17b96c18c2538bfdf9fee4b7d278972ce27ed86dda5d91ea3ec","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4Cep9xUmQcSkEVT4zk2v0jiVwxIVDv6oa/QVLIjQyoY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e027a9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7e04 3b88 1436 0de3 | 146 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n001 2 a6fb 96fc | 47 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n002 4 c43f c6cf db6a d1d7 | 26 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n003 7 fe21 f31c f773 f4e0 | 19 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n004 6 eb98 e8ef e883 efea | 10 eb98 (0) e854 (0) e8ef (0) e883 (0)\n============ DEPTH: 5 ==========================================\n005 7 e5d7 e5ad e514 e54b | 7 e5d7 (0) e5ad (0) e514 (0) e547 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","private_key":"42236a2ba130a7a24f34201b6bceda8e237a0e2e4c4780e6dd8c423e79719722","name":"node_e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","services":["streamer"],"enable_msg_events":true,"port":33483},"up":true}},{"node":{"info":{"id":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","name":"node_d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","enode":"enode://80bb1c84b9239a4dcaca4b19398c7a54833efb060f0491e8f5efdb7549edffa41a10442da7ce9a44959a7220411d56f2ca686b1d2351ec652d3074a9bbecd50a@127.0.0.1:0","enr":"0xf88fb84099d84c8e0b6d56c16e509e6809e9057dfe42891fff4ff8e974189245419b9371212e1e3ecd5c2ec314cafb25c996d8ef320486b364a58b8f1e533b4afb42de240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10280bb1c84b9239a4dcaca4b19398c7a54833efb060f0491e8f5efdb7549edffa4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0dcZzh3KUHWYRJr+lmOWwWCtJa1jIRKrJosdkTtJDb0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d1d719\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 4559 44a1 7e04 6251 | 146 7125 (0) 7290 (0) 738c (0) 775e (0)\n001 3 b2b5 a6fb 96fc | 47 bcc6 (0) bb90 (0) ba88 (0) baf2 (0)\n002 11 fe21 f31c f773 f45f | 37 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n003 4 c1f9 c26f c43f c6cf | 15 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n004 5 df1e d887 daec da67 | 6 df1e (0) d887 (0) d863 (0) daec (0)\n005 2 d7ac d640 | 2 d7ac (0) d640 (0)\n============ DEPTH: 6 ==========================================\n006 2 d3b0 d299 | 2 d3b0 (0) d299 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","private_key":"c8c5ea87fb82c55c9d58f48496b2fd47c86008f9ed782575bb4d64dedd096136","name":"node_d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","services":["streamer"],"enable_msg_events":true,"port":42295},"up":true}},{"node":{"info":{"id":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","name":"node_1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","enode":"enode://ccb62edd9cbb83630d2c5ca827a44633de8aa6a65c68b263563159e02cec0d8554ae6c1bbc6450aa60f4900f3acca4d2ba529b6462d17792e360a5256b0e7517@127.0.0.1:0","enr":"0xf88fb8402251f72e3876c375bdf5474dd9b47aa6a4ec1c1cb255bd976fb6a7607c35a8f45943221daba85c637fa764b89f1d4e637e7edfc5bfb242e35a690f9bc6c3109a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ccb62edd9cbb83630d2c5ca827a44633de8aa6a65c68b263563159e02cec0d85","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HIoQ7L1yrLK7u4t36lQE+ekPTb8wbsgTTP7XC0Cu85k=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1c8a10\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc a6fb ed2d f4e0 | 110 bcc6 (0) bb90 (0) badd (0) baf2 (0)\n001 4 7e04 77d2 6c4d 4559 | 70 7920 (0) 7a60 (0) 7b90 (0) 7dd3 (0)\n002 6 256e 24b8 3efc 3b88 | 32 2f32 (0) 2d36 (0) 2ccf (0) 2c79 (0)\n003 4 07a8 0c28 0d8a 0de3 | 22 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n004 7 13d6 154b 1400 1436 | 12 103b (0) 11d4 (0) 13d6 (0) 154b (0)\n005 3 19fa 1a2a 1b83 | 4 18f6 (0) 19fa (0) 1a2a (0) 1b83 (0)\n006 3 1e2a 1f67 1f85 | 3 1e2a (0) 1f67 (0) 1f85 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 1c47 | 1 1c47 (0)\n009 0 | 0\n010 0 | 0\n011 1 1c9c | 1 1c9c (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","private_key":"530e6c41fc6e6889ceddd163a578f3db02856187b2f0466de53f7f29408159b3","name":"node_1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","services":["streamer"],"enable_msg_events":true,"port":45657},"up":true}},{"node":{"info":{"id":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","name":"node_17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","enode":"enode://e7d8ae7faaa3f720519c1ea490e184f238bf3e3c0be1da066ff25d1814339b79b018b95285a4db1d0d13e73503d99f590591dc1258d7bec591ae354c82a53839@127.0.0.1:0","enr":"0xf88fb840cec78fd16c7bdeaeb29d0f2f4fe3acb0f668c0432a9dac2be2d42460e02005a7493749ccc7b1b4faa5e51dae74cb0f39aac4d54d801dd26bfc466b82b76984390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e7d8ae7faaa3f720519c1ea490e184f238bf3e3c0be1da066ff25d1814339b79","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F9sViTvzm0JZPuHel1q6aDIEbZ2ltLST7EQnJziinO8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 17db15\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a6fb 96fc f4e0 f5dc | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 5 7e04 77d2 6831 6c4d | 70 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n002 5 24b8 256e 3b88 3ec5 | 32 2d36 (0) 2c79 (0) 2c38 (0) 2ccf (0)\n003 2 07a8 0de3 | 22 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n004 4 19fa 1b83 1f85 1c8a | 10 18f6 (0) 19fa (0) 1a2a (0) 1b83 (0)\n005 3 13d6 11d4 103b | 3 13d6 (0) 11d4 (0) 103b (0)\n006 4 1436 1400 14df 154b | 4 154b (0) 14df (0) 1400 (0) 1436 (0)\n007 2 165f 1672 | 2 165f (0) 1672 (0)\n============ DEPTH: 8 ==========================================\n008 1 1704 | 1 1704 (0)\n009 1 179f | 1 179f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","private_key":"2e941f41c9fc6b53b84ce73e68eaa0a486a0a2c4030d915897f04f366440d05e","name":"node_17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","services":["streamer"],"enable_msg_events":true,"port":41487},"up":true}},{"node":{"info":{"id":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","name":"node_455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","enode":"enode://4dc18460e3997bb0a5e9952976154083a46b2bf6b0c7f2810f7eee10b4b2254a8489d82eaed18436650b62980b531b8b1fb1808cfcc121d7749d3af1d718b12f@127.0.0.1:0","enr":"0xf88fb8402972e719eafce249c1d6c5b0af19eba09f751e4788398e88be87ee8619739c1c7d34faa74943a0227a4606a4a1c7ec1ecefdfc40a4cb0eca51ee1aa0dcaf300d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034dc18460e3997bb0a5e9952976154083a46b2bf6b0c7f2810f7eee10b4b2254a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RVk2/SLEN5Tm4hBP2R0/XSRuOCPo/46vjcJ6qfPS7gg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 455936\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc f4e0 f5dc d1d7 | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 6 378e 07a8 0de3 1c8a | 76 2ccf (0) 2c38 (0) 2c79 (0) 2d36 (0)\n002 6 77d2 738c 7dc2 7e04 | 32 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n003 2 574f 524d | 15 5b63 (0) 58ed (0) 5823 (0) 5db0 (0)\n004 5 49cd 4bcf 4a8b 4d6b | 11 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 5 4646 4636 46fe 47bf | 6 47bf (0) 4782 (0) 46fe (0) 4646 (0)\n============ DEPTH: 7 ==========================================\n007 2 4447 44a1 | 2 4447 (0) 44a1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 4558 | 1 4558 (0)\n========================================================================="}},"config":{"id":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","private_key":"7dbb064b0d47a7fc81d65e512613d0f099b690b6148f3867d9a2a7b689e3ff0e","name":"node_455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","services":["streamer"],"enable_msg_events":true,"port":44695},"up":true}},{"node":{"info":{"id":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","name":"node_1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","enode":"enode://c5e2dced64cebb7bcf961588b05aa6135f14b133db83b9f039adea823547e6ca6a4ae66dd060942b5ddf0e35a7cf9c23aeef18cfefb07822f52a3a0d6e01b12f@127.0.0.1:0","enr":"0xf88fb84093bfc5b68fff885df3ca3ca5159f4ac4816cd313e0880bd4b9fc9dc6642606263cdb0d436c19251deec31df9fe25f1d7038d04d44f93325c8f5ee48ed202a2540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c5e2dced64cebb7bcf961588b05aa6135f14b133db83b9f039adea823547e6ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FDaqqHcOnxxilOSfQGbBaxyqUFJOm4/QWAWeQWV9KoM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1436aa\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 96fc d299 efea ed2d | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 5 7e04 6831 6c4d 4636 | 70 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n002 5 256e 24b8 21a0 3ec5 | 32 2d36 (0) 2c38 (0) 2c79 (0) 2ccf (0)\n003 3 07a8 0c28 0de3 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 5 1b83 19fa 1c9c 1c8a | 10 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n005 2 11d4 13d6 | 3 103b (0) 11d4 (0) 13d6 (0)\n006 5 165f 1672 1704 17db | 5 165f (0) 1672 (0) 1704 (0) 179f (0)\n007 1 154b | 1 154b (0)\n============ DEPTH: 8 ==========================================\n008 1 14df | 1 14df (0)\n009 0 | 0\n010 1 1400 | 1 1400 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","private_key":"30f78566606a3588a6ae7452aae120e984a681f8c1dfe235806102b387d1b5e1","name":"node_1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","services":["streamer"],"enable_msg_events":true,"port":37199},"up":true}},{"node":{"info":{"id":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","name":"node_378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","enode":"enode://62d1a6cca7bfbd3f31cbd86708971f47cf9eab3c318a42ca0784a3c76ed5bb697a9f7ec6987f2456c84aeaf468b4a99277dd1c85fb850c51d91f683ec2bfd821@127.0.0.1:0","enr":"0xf88fb84096dbe71818bc9bff8cab39cad479b1e8be50f63de0e73a02ab147856d3a7eb6866b2acfcb4f171d75eb8d44e9075bd3fc106e373e87ecbb2424c2c443996816f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10362d1a6cca7bfbd3f31cbd86708971f47cf9eab3c318a42ca0784a3c76ed5bb69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"N45698wBkYbU8mmedT4tcTAvjzVlVywTt6GxxctHRDw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 378e7a\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ed2d efea f4e0 d299 | 110 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n001 6 6c4d 6f2d 77d2 49cd | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 8 0c28 0de3 07a8 1f85 | 44 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n003 2 256e 24b8 | 15 2d36 (0) 2ccf (0) 2c38 (0) 2c79 (0)\n004 3 3b88 3efc 3ec5 | 7 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n005 5 3373 33b5 314a 3089 | 6 3237 (0) 3373 (0) 33b5 (0) 314a (0)\n006 1 35e6 | 1 35e6 (0)\n============ DEPTH: 7 ==========================================\n007 1 3630 | 1 3630 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 3780 | 1 3780 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","private_key":"f87ae143c4de5fb51892f311d616d4800d4963ecf3e3d1db6a4e31639d894c37","name":"node_378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","services":["streamer"],"enable_msg_events":true,"port":42999},"up":true}},{"node":{"info":{"id":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","name":"node_c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","enode":"enode://445bc4dbafd666bb2218c9ec6a582bf6bfb2fadbc7624ea9f724fb35a0b58d12a074a968505f280eb85b7240f437aac8986ba15cae3fb075b916c7620784004e@127.0.0.1:0","enr":"0xf88fb840ac8583022ed007db510135b8c593b46044e897f3fee1fd57fc3b04847325b40c5166ebd8aa464b82755d700da0d197da02f5d7be64bc2a5df55409f7040a10610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102445bc4dbafd666bb2218c9ec6a582bf6bfb2fadbc7624ea9f724fb35a0b58d12","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xs9GI5B47fs0PGRfA5cl/e4bu6iwptoC4sxFa5IjyaI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c6cf46\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 77d2 6c4d 6f2d 4559 | 146 5db0 (0) 5cd2 (0) 5f00 (0) 5efb (0)\n001 4 a6fb b2b5 8025 96fc | 47 ac4d (0) ad98 (0) aeb4 (0) ae2b (0)\n002 5 ed2d ee5e efea e027 | 37 eb98 (0) e854 (0) e8ef (0) e883 (0)\n003 5 da67 db6a d299 d3b0 | 11 df1e (0) d863 (0) d887 (0) daec (0)\n004 4 cc20 c898 caf6 ca04 | 6 cc20 (0) caf6 (0) ca04 (0) c9f5 (0)\n005 2 c26f c1f9 | 2 c1f9 (0) c26f (0)\n006 4 c59e c49c c43f c441 | 4 c59e (0) c49c (0) c441 (0) c43f (0)\n============ DEPTH: 7 ==========================================\n007 1 c786 | 1 c786 (0)\n008 1 c620 | 1 c620 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","private_key":"1227a7906f23478558c2ff562b54e86b2e16710eb7290823a1a7587ff14161e7","name":"node_c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","services":["streamer"],"enable_msg_events":true,"port":42921},"up":true}},{"node":{"info":{"id":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","name":"node_f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","enode":"enode://d57c1ed1af3de513ab3ca9168f80d3a51ffcb3af7a20c1f854d01312afa00097dd7257ccdc5bf0bed966eaabd495e22ee59207246b35d88a2f1027f2cb696b90@127.0.0.1:0","enr":"0xf88fb840ce18c84e0bf1b525d2a1ffc03cc7281c5c032526b3c258ba6e0c1b428e830b3b56b8c158871961b7f6fb5bcee112aa4bdba312e2c333b52e613e50ef0855ac980183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d57c1ed1af3de513ab3ca9168f80d3a51ffcb3af7a20c1f854d01312afa00097","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9OCfiSh70a94M6zYW6fMcf2z/zTy9AnhzyqHjc0xg9w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4e09f\npopulation: 44 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 4559 6f2d 24b8 378e | 146 103b (0) 11d4 (0) 13d6 (0) 1672 (0)\n001 5 a6fb b502 b2b5 8025 | 47 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n002 11 da67 db6a d7ac d1d7 | 26 df1e (0) d863 (0) d887 (0) daec (0)\n003 4 e027 ed2d ee5e efea | 18 eb98 (0) e854 (0) e8ef (0) e883 (0)\n004 4 fe21 ff36 fbf5 fbc8 | 6 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n005 3 f2d5 f27f f31c | 3 f2d5 (0) f27f (0) f31c (0)\n006 3 f629 f7fa f773 | 4 f629 (0) f7ba (0) f7fa (0) f773 (0)\n007 3 f528 f5dc f5b2 | 3 f5b2 (0) f5dc (0) f528 (0)\n============ DEPTH: 8 ==========================================\n008 2 f45f f456 | 2 f456 (0) f45f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","private_key":"068db7a4942ca7125ac96d19e14274fd6a94b300707941d0c28a2a334ec18d10","name":"node_f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","services":["streamer"],"enable_msg_events":true,"port":39333},"up":true}},{"node":{"info":{"id":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","name":"node_d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","enode":"enode://9921bbce6608fb1ad3311caeaf2d70b08c24b0c5097af6a7702cf8d750b57627cdfc9327ded122c82ad215e428777e2bc5bf667722eb531e3ababb25ed49e0a5@127.0.0.1:0","enr":"0xf88fb840de77d70c78a672c75090aa9196c7f37e174342b0b89db3c3d8208df199e66ae61c6c9d6d0849f2e4283008fbb2df674c815c4fadcbc9c5b1a3f5205d19eb1cca0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039921bbce6608fb1ad3311caeaf2d70b08c24b0c5097af6a7702cf8d750b57627","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0plB1ris2GzzL9HCGB2jqx2jwggxNLBoyknOKaqGt4M=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d29941\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 256e 378e 07a8 1436 | 146 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n001 4 96fc 8025 a6fb b2b5 | 47 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n002 7 e7fa ee5e ed2d fe21 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 5 ca04 c6cf c59e c43f | 15 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n004 5 d887 d863 daec da67 | 6 df1e (0) d887 (0) d863 (0) daec (0)\n005 2 d640 d7ac | 2 d640 (0) d7ac (0)\n============ DEPTH: 6 ==========================================\n006 1 d1d7 | 1 d1d7 (0)\n007 1 d3b0 | 1 d3b0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","private_key":"ed9cc2d516c3a37362d70e5337c6285651e7d1478038434939544e5f0a2558c5","name":"node_d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","services":["streamer"],"enable_msg_events":true,"port":35669},"up":true}},{"node":{"info":{"id":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","name":"node_6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","enode":"enode://6cadca795e1a9332ff620a0fa3972acbc4701938fd9ee90a2e0e3b06e0c12bc10e743b1605698003c58cbb67f3f6695e5b4a7b939a5f95e29661fdbed5c174b2@127.0.0.1:0","enr":"0xf88fb84086f29094a4468911665b009f5ad2ec7bb6dd33e9faab8e89844e394b676e514d1f1765853026e1c53a16b6a854ac35880408fdda19598f40e0550620310caa9a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026cadca795e1a9332ff620a0fa3972acbc4701938fd9ee90a2e0e3b06e0c12bc1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"by11ZWbdW0oT/+6p9ofHhRSPNAelAuKLnW7f0DuQX9w=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6f2d75\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f4e0 c6cf d299 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 3 378e 24b8 07a8 | 76 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n002 4 4636 44a1 4559 574f | 38 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n003 8 7e04 7dbb 7dc2 7dd3 | 12 7920 (0) 7a60 (0) 7b90 (0) 7dd3 (0)\n004 4 60d7 6251 628e 67aa | 9 6337 (0) 628e (0) 6251 (0) 6103 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 4 6e68 6e05 6ecb 6ea5 | 4 6e68 (0) 6e05 (0) 6ecb (0) 6ea5 (0)\n============ DEPTH: 8 ==========================================\n008 1 6fe9 | 1 6fe9 (0)\n009 1 6f5f | 1 6f5f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","private_key":"3d64f67a082f7e4185e83ea4414849a0146c7104250ce8de6eb30c628b9b8459","name":"node_6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","services":["streamer"],"enable_msg_events":true,"port":43877},"up":true}},{"node":{"info":{"id":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","name":"node_07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","enode":"enode://3f7f839709363b1db97fd83da689de1fe397a6c4574f1186f20116ae3674c3777d47487ba386136c9f90670450caaaa8d08942f2d5b57e66e54333609ea826fb@127.0.0.1:0","enr":"0xf88fb8407eb35279cb43bd4502b17e6cf9227e0948b7d39a193d9dd1a66d0718d0f3a9ee4998694774985993b7ac021e4705e12e04741158f1838372359ff61c5a7fea0b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033f7f839709363b1db97fd83da689de1fe397a6c4574f1186f20116ae3674c377","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"B6jJAP7GxHdYDtWziEioaB3FKhnln6TNMvVx/n+yODo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 07a8c9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b2b5 c6cf d299 f4e0 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 6 574f 53a8 4559 4636 | 70 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n002 4 3b88 378e 256e 24b8 | 32 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n003 6 1436 1400 17db 1b83 | 22 103b (0) 11d4 (0) 13d6 (0) 165f (0)\n004 3 0c28 0d8a 0de3 | 11 0b72 (0) 0a00 (0) 0af9 (0) 0e5e (0)\n005 3 00c6 02d8 0328 | 5 0067 (0) 00c6 (0) 02d8 (0) 03cc (0)\n006 2 0438 045b | 3 0438 (0) 0451 (0) 045b (0)\n============ DEPTH: 7 ==========================================\n007 1 0661 | 1 0661 (0)\n008 1 0743 | 1 0743 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","private_key":"57fbc15d67af2d8593073c689c611a38db6bde0721b57199615b19d8038b5653","name":"node_07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","services":["streamer"],"enable_msg_events":true,"port":38689},"up":true}},{"node":{"info":{"id":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","name":"node_24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","enode":"enode://f4d9569b664ccde6dbfd8ffeb4524cf63fb038a8310e6faacf75999847a8a2aebf5463047743c0bbe50bfbf096cd1a88cc77c287c65777fe1aa700b92ff22931@127.0.0.1:0","enr":"0xf88fb84064a70dff70951c7ae9cd2b2c670490da42501b1011736ec633815cc654d0de98202748d2e22ba9fc5a5b006d005036985328ad38f7efe4ee0a095ed6983caa3a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f4d9569b664ccde6dbfd8ffeb4524cf63fb038a8310e6faacf75999847a8a2ae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JLhcEPCYclk46n2HzSSksQNYEpkG/Kl5D8Jm6oeEtTg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 24b85c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8025 96fc b502 b2b5 | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 4 4636 49cd 6f2d 77d2 | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 7 17db 1436 1400 1c8a | 44 103b (0) 11d4 (0) 13d6 (0) 165f (0)\n003 6 3ec5 3efc 3b88 314a | 17 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n004 3 2f32 2ccf 2abb | 9 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n============ DEPTH: 5 ==========================================\n005 4 20ae 2101 217f 21a0 | 4 20ae (0) 2101 (0) 217f (0) 21a0 (0)\n006 0 | 0\n007 1 256e | 1 256e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","private_key":"c43bfbf2bb506dcd5608000c4a2f2a4ad8be5b1c1d5ecb3bc1bc59109c0b6b16","name":"node_24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","services":["streamer"],"enable_msg_events":true,"port":38967},"up":true}},{"node":{"info":{"id":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","name":"node_1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","enode":"enode://73040f7d8f962f54e6691a4b9f2c4b324d3dfbbe742387c453b5950b1adfc52a5f12c4a3b6511e824f9be6bf49cf996c448cff189ae3068d639a50438b0fbd22@127.0.0.1:0","enr":"0xf88fb840976c5a30ad5f6c348eaf3a368ab63084b1eae6ff36dfd982c5aeb47271554dc577959a9ce734707a16bc9bd64d23dca99b3c766c6b4243d75249708abd5189fd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10273040f7d8f962f54e6691a4b9f2c4b324d3dfbbe742387c453b5950b1adfc52a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"H4W4wF5dzv8L2CVvj22A1LkCqXVM65UtleouEVDvnlk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1f85b8\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b2b5 fe21 f4e0 c26f | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 3 574f 4636 77d2 | 70 5823 (0) 58ed (0) 5b63 (0) 5cd2 (0)\n002 4 378e 30be 256e 24b8 | 32 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n003 4 0c28 0de3 0d8a 07a8 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0ff2 (0)\n004 3 17db 1400 1436 | 12 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n005 4 19fa 18f6 1a2a 1b83 | 4 19fa (0) 18f6 (0) 1a2a (0) 1b83 (0)\n006 3 1c47 1c9c 1c8a | 3 1c47 (0) 1c9c (0) 1c8a (0)\n============ DEPTH: 7 ==========================================\n007 1 1e2a | 1 1e2a (0)\n008 1 1f67 | 1 1f67 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","private_key":"59c61bd4b5c1b4f8c1995c2c5162afae8f31e9c643be34f24fa05cc989be881e","name":"node_1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","services":["streamer"],"enable_msg_events":true,"port":38831},"up":true}},{"node":{"info":{"id":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","name":"node_77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","enode":"enode://d75b2925001a8eeae3e6c484278d65e4c64b829e79e4f4f9ffbfbfda98e713f2c194160e65c7afd3241b956106959174badaa1127f984a992d0d653bafad1ef2@127.0.0.1:0","enr":"0xf88fb84090355b49c231a49d0a8588ce047d0541ad615d101206c5f0d3460bdd3cb0046703875d1527046828aaab5698f064414207e768132bd4c870cfdefbc386c1c61a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d75b2925001a8eeae3e6c484278d65e4c64b829e79e4f4f9ffbfbfda98e713f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d9LsUtq9XX8ybUxq/SqtEQSHxr3/ophAYFKHFrqHNGI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 77d2ec\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d299 c26f c43f c6cf | 110 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n001 7 07a8 17db 1c8a 1f85 | 76 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n002 7 4636 4559 4a8b 5f00 | 38 5efb (0) 5f00 (0) 5db0 (0) 5cd2 (0)\n003 10 67aa 67dc 6251 6103 | 20 6337 (0) 628e (0) 6251 (0) 6103 (0)\n004 5 7b90 7a60 7dd3 7dc2 | 7 7dbb (0) 7dd3 (0) 7dc2 (0) 7e04 (0)\n============ DEPTH: 5 ==========================================\n005 3 7125 738c 7290 | 3 7125 (0) 738c (0) 7290 (0)\n006 0 | 0\n007 0 | 0\n008 1 775e | 1 775e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","private_key":"682c5165cd7b0aefc0947ef86781161eeab41ef910322502ffe6b2db732e6f00","name":"node_77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","services":["streamer"],"enable_msg_events":true,"port":36957},"up":true}},{"node":{"info":{"id":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","name":"node_256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","enode":"enode://53a39015a7a349078a4861f507013efbe2e42c44a48210c7f41dfad8fe09503c0d8604c8ba351fa6b5da4179e598f7987bd5a4f5072028ea6c35867f4e0e3452@127.0.0.1:0","enr":"0xf88fb84096ffa0a393f3fa959e87c33678cde0b74e73829a0e1cc5a53e580d06d9d9b14373e52acbfd14808c4cfdb02cb4f2511fd88bbe7fb76ff0c58d87afb2f286bd960183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10253a39015a7a349078a4861f507013efbe2e42c44a48210c7f41dfad8fe09503c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JW6Bxab7Q700M0VHf4+WqhlH8HrDKX9jGrA/BgFHsGI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 256e81\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 fe21 c6cf d299 db6a | 110 df1e (0) d887 (0) d863 (0) daec (0)\n001 5 574f 49cd 4636 67aa | 70 5b63 (0) 58ed (0) 5823 (0) 5cd2 (0)\n002 9 0c28 0d8a 0de3 07a8 | 44 0a00 (0) 0af9 (0) 0b72 (0) 0e5e (0)\n003 7 3b88 3efc 3ec5 3780 | 17 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n004 3 2f32 2ccf 2abb | 9 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n============ DEPTH: 5 ==========================================\n005 4 20ae 217f 2101 21a0 | 4 20ae (0) 217f (0) 2101 (0) 21a0 (0)\n006 0 | 0\n007 1 24b8 | 1 24b8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","private_key":"45dc210e5a7309cf6d363540be2d1d849e0f2dc92ab7bb5df059d521246f9ff1","name":"node_256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","services":["streamer"],"enable_msg_events":true,"port":41465},"up":true}},{"node":{"info":{"id":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","name":"node_8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","enode":"enode://f14e1b9f746918024f3f3b5afb64d85f230790c5f8e6f530da3723875e1ba92922eec9c790e3bcf9a0266fa565f0af0d840edb1fa61b03c7f58196c038833999@127.0.0.1:0","enr":"0xf88fb840b4e407fbcca71bbbd27293f0aa73df4b38c2e5d75e916f3bb6f68b312823e00b6e349f5500dee5e74f29eff4153d436fabd7fbccfdd803ff167002ad2244b3450183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f14e1b9f746918024f3f3b5afb64d85f230790c5f8e6f530da3723875e1ba929","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gCXB/LmOU/knZ9HUOjBXoKzR6JlLtKfj9eJEEQ4Nz5E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8025c1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 512e 574f 4558 4636 | 146 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n001 7 c26f c43f c6cf d299 | 63 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n002 3 a6fb b502 b2b5 | 27 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n003 5 9d0f 9fa0 959f 96fc | 10 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n004 3 898d 886a 88fe | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n005 2 8505 849b | 2 8505 (0) 849b (0)\n============ DEPTH: 6 ==========================================\n006 2 82dd 82f9 | 2 82dd (0) 82f9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","private_key":"0c41aca505e0136ca72a3c58217ecd9a78eea3796b96dd546d96472f328cf37f","name":"node_8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","services":["streamer"],"enable_msg_events":true,"port":41367},"up":true}},{"node":{"info":{"id":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","name":"node_4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","enode":"enode://10f863a5bc8ec93dee6896e14260ef8642e83ee113ee0ed55e0ee9d2ad4feba5670b38d5e529811d454fffb530187992f11f0151ac5031122b0837f845acc95c@127.0.0.1:0","enr":"0xf88fb8405098b23b6301b63dedf00769712c97314e7c701599028eabebef4e123b8d775622dfd46163d23effb9dc9e0738d925989bb5b390f4fe66a740815305619af8b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10210f863a5bc8ec93dee6896e14260ef8642e83ee113ee0ed55e0ee9d2ad4feba5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RjbwC+YKm0lKPryatBzHy1PsCwvv8hTbLQokjcOutq8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4636f0\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8025 b2b5 | 110 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n001 6 378e 24b8 256e 07a8 | 76 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n002 7 67aa 6f2d 6c4d 6831 | 32 7920 (0) 7a60 (0) 7b90 (0) 7dbb (0)\n003 3 5b63 524d 574f | 15 5db0 (0) 5cd2 (0) 5efb (0) 5f00 (0)\n004 5 49cd 4a8b 4bcf 4c9e | 11 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 4 4558 4559 4447 44a1 | 4 4447 (0) 44a1 (0) 4558 (0) 4559 (0)\n007 2 47bf 4782 | 2 47bf (0) 4782 (0)\n008 1 46fe | 1 46fe (0)\n============ DEPTH: 9 ==========================================\n009 1 4646 | 1 4646 (0)\n010 1 461c | 1 461c (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","private_key":"c7fd7cc73cf8fe60e42f0df8dba49b5b7c12529c7fabb2b5b769965ce13afb0b","name":"node_4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","services":["streamer"],"enable_msg_events":true,"port":40557},"up":true}},{"node":{"info":{"id":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","name":"node_b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","enode":"enode://d15330bc0ac2d05c53b502c8a5c9017e56f190332491742de058a920784f5ab943f482c2d1872603adc7d3bd42e77cb875434f3520ca93b47fe35a21fa62669a@127.0.0.1:0","enr":"0xf88fb840574761f8bb54fcd95cfa7b75775147cd15e5320d20cb64c70eda14db527c1ea24a6fde40dcbe9cd641f83d726c2d55878fbb2dfe0777ff514fd17b8bbfd106ee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d15330bc0ac2d05c53b502c8a5c9017e56f190332491742de058a920784f5ab9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"srW6G7GI8Y95spXywNSMUsHR1EnsublLmYTzpheXMsc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2b5ba\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 24b8 256e 07a8 1f85 | 146 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n001 9 ca04 c6cf c26f da67 | 63 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n002 6 9076 96fc 976e 849b | 20 9852 (0) 9890 (0) 9d0f (0) 9fa0 (0)\n003 2 af02 a6fb | 10 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n004 3 baf2 b95d b897 | 9 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n005 5 b7ca b65e b626 b5b2 | 5 b7ca (0) b65e (0) b626 (0) b5b2 (0)\n============ DEPTH: 6 ==========================================\n006 1 b02b | 1 b02b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 b2a5 | 1 b2a5 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","private_key":"6e70ae5c645585cea4f6e117e84118dcdc9efb654cc766a374ca297817172dc0","name":"node_b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","services":["streamer"],"enable_msg_events":true,"port":33709},"up":true}},{"node":{"info":{"id":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","name":"node_fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","enode":"enode://efdfaaad939ceb845670e7c93e476a841dbc743aa1d3ba9836be214025381c0bf8fe8967634b433603fc4657ee30d1b0e860ac88f70406374d23c7b72532f3f5@127.0.0.1:0","enr":"0xf88fb8402b581c48bc9b046b1ac97ca1d73ba39bd09847eb3b4ccaee9cfb8cb46ef2d7393cde50a04a69fd36f4c6a06b66252d6372ff5781a97a9eba519a182ab6ff34ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103efdfaaad939ceb845670e7c93e476a841dbc743aa1d3ba9836be214025381c0b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/iFn/TPzgxEOs/bKp72QXKVPoMgQ8bijRIOoRvPL3as=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fe2167\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 256e 1f85 574f | 146 0b72 (0) 0af9 (0) 0a00 (0) 0e5e (0)\n001 3 8025 b502 b2b5 | 47 9fa0 (0) 9d0f (0) 9852 (0) 9890 (0)\n002 7 d1d7 d299 da67 db6a | 26 d7ac (0) d640 (0) d1d7 (0) d3b0 (0)\n003 6 ed2d ee5e efea e5ad | 18 eb98 (0) e854 (0) e883 (0) e8ef (0)\n004 8 f2d5 f31c f773 f629 | 13 f31c (0) f27f (0) f2d5 (0) f629 (0)\n005 3 f925 fbf5 fbc8 | 3 f925 (0) fbf5 (0) fbc8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ff36 | 1 ff36 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 fe31 | 1 fe31 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","private_key":"82f871774e58e78c4be095210436adb4fb35f177d17042837b069f1793339635","name":"node_fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","services":["streamer"],"enable_msg_events":true,"port":40051},"up":true}},{"node":{"info":{"id":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","name":"node_c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","enode":"enode://89a40b4828258a45ddffc2eeca354e23356b818fc965a12c6a7e026d0e8bf72b43c98d81e2fa73356eff0f6100ae19475e42fa933113c8767b13dd5b04b84f5a@127.0.0.1:0","enr":"0xf88fb840d5565171400508ba844253cef0a659a7007e98b0ea4ea1d3174005f982b12e0f5d79bc818df366da989fde409077401d9b95cabac335c1d33761dfb511833e550183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10289a40b4828258a45ddffc2eeca354e23356b818fc965a12c6a7e026d0e8bf72b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wm/V5lBMez8KbZEz/4fJjBEOscIBxfO89rEGU/K5ctI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c26fd5\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1f85 67aa 77d2 574f | 146 0067 (0) 00c6 (0) 03cc (0) 0328 (0)\n001 6 96fc 976e 8025 82f9 | 47 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n002 8 ed2d efea ee5e e547 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 7 da67 db6a d863 d640 | 11 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n004 4 cc20 c898 caf6 ca04 | 6 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n============ DEPTH: 5 ==========================================\n005 7 c49c c43f c441 c59e | 7 c786 (0) c620 (0) c6cf (0) c59e (0)\n006 1 c1f9 | 1 c1f9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","private_key":"736c6a6244885a1ad39fb0d125a7a2bf50d5515f38b1360dcf2c82a12f76fac5","name":"node_c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","services":["streamer"],"enable_msg_events":true,"port":39119},"up":true}},{"node":{"info":{"id":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","name":"node_574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","enode":"enode://5f9fe022355b31091330921e29c0ad61c9fdf8ee82f66c36fb03b2302f8fe2e3c32b931a30a66613a2c8f79c5788077e652cb6abdeeb0a330c9d264a8db6fad7@127.0.0.1:0","enr":"0xf88fb8404d529d52c3e76b4faa7d0a3bd82b1141a7a6c579aa512fc3f8a9d7d980c977a8626eb6d9c3351103f11cff3b7d222edf1f0c5c4b6ba304f2215882fc818b63bd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035f9fe022355b31091330921e29c0ad61c9fdf8ee82f66c36fb03b2302f8fe2e3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V09lhnSCCRruJ3QDMRbCM1Je6nEXBrWum6CbVOiW0wI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 574f65\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 8025 b2b5 b502 f528 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 4 256e 0d8a 07a8 1f85 | 76 0067 (0) 00c6 (0) 03cc (0) 0328 (0)\n002 7 7e04 7b90 7290 77d2 | 32 7dbb (0) 7dd3 (0) 7dc2 (0) 7e04 (0)\n003 9 4c9e 49cd 4a8b 44a1 | 23 4109 (0) 41d9 (0) 4559 (0) 4558 (0)\n004 2 5823 5b63 | 7 5cd2 (0) 5db0 (0) 5f00 (0) 5efb (0)\n============ DEPTH: 5 ==========================================\n005 7 51db 512e 5308 534b | 7 51db (0) 512e (0) 5308 (0) 534b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","private_key":"d229f5b69bcdd60b64b4dbd3bbb0d8f06e4ce741c0ef2df9ccf7efa269b788e6","name":"node_574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","services":["streamer"],"enable_msg_events":true,"port":34895},"up":true}},{"node":{"info":{"id":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","name":"node_db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","enode":"enode://5eafc16cce4d7660bd2fbb314e96cc2cf9eb8ea56939776d7278b6d59cc46da7f9bd3236f1171a955cf401d05ba08861cadec21cd434a8fb1be4d95ba9e8334a@127.0.0.1:0","enr":"0xf88fb8405f6b3f6d51114a126675f72d0b280db019f6e5068b71d72e5a522e4083436c64689a304c802a95d836e8f5e273f123dba269e9df3e99b8b9760e25b4fef30abc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025eafc16cce4d7660bd2fbb314e96cc2cf9eb8ea56939776d7278b6d59cc46da7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"22ofazQva+lRf43wEAN5fBHIN9mu4826W3hZIws2w10=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: db6a1f\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1f85 256e 574f | 146 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n001 5 b2b5 b502 976e 82f9 | 47 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n002 8 ed2d ee5e e7fa e547 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 7 c9f5 caf6 ca04 c26f | 15 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n004 5 d7ac d640 d3b0 d299 | 5 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n005 1 df1e | 1 df1e (0)\n006 2 d887 d863 | 2 d887 (0) d863 (0)\n============ DEPTH: 7 ==========================================\n007 2 daec da67 | 2 daec (0) da67 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","private_key":"dfd2fca92d5a4f222ac845159014d664d54ea1f9b33035068dc1f2572296fc46","name":"node_db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","services":["streamer"],"enable_msg_events":true,"port":39263},"up":true}},{"node":{"info":{"id":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","name":"node_c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","enode":"enode://3fc6aafc24fea946b6e17b7a684b14df9e9eb28514b7332fa30fd325816de5cc8cc49b992cd85f654a3fac88deea0804c52317cc6de693cd9f057f26fddb4c5a@127.0.0.1:0","enr":"0xf88fb840f87236d325dbf8011e68c5678b19ce6e8c0f1f66642a6a0af4028d2d16dc012e4d16b88c631287a65df9c7a7cc2267c8da224e6c804be3d605675c79e68988940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023fc6aafc24fea946b6e17b7a684b14df9e9eb28514b7332fa30fd325816de5cc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xD++6VOAAHJ0uPIx/jS81ZtcDvCDCxdJZ9RwJieYT8Y=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c43fbe\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1400 0d8a 77d2 7290 | 146 00c6 (0) 0067 (0) 03cc (0) 0328 (0)\n001 4 976e 8025 82f9 b502 | 47 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n002 8 efea ee5e ed2d e027 | 37 ef07 (0) ef1b (0) efea (0) ee5e (0)\n003 5 d7ac d1d7 d299 da67 | 11 d640 (0) d7ac (0) d1d7 (0) d3b0 (0)\n004 2 caf6 ca04 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c26f c1f9 | 2 c1f9 (0) c26f (0)\n006 3 c6cf c620 c786 | 3 c786 (0) c620 (0) c6cf (0)\n007 1 c59e | 1 c59e (0)\n============ DEPTH: 8 ==========================================\n008 1 c49c | 1 c49c (0)\n009 1 c441 | 1 c441 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","private_key":"6be49afc08c546676c011c401073a17e9b8840fa9edd1182f255e19073662d73","name":"node_c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","services":["streamer"],"enable_msg_events":true,"port":46219},"up":true}},{"node":{"info":{"id":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","name":"node_b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","enode":"enode://9d7d6722f1a51680a6f8affc6d1a10ede4ab4b4aa4ae1a4d406eec85c93875f1def190fdb2692f50153e62406fba95d939b2ca56910888b306eb3c9d50d76250@127.0.0.1:0","enr":"0xf88fb840beb0423e5654bf643406b5a5c35aa97675d9d7c3fef9bb2ddf7a0bfdb63b17b24b0224e5c5a31332fdc59e32c64eea5e59861707e1baa864e3e439cd273fcd430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029d7d6722f1a51680a6f8affc6d1a10ede4ab4b4aa4ae1a4d406eec85c93875f1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tQJdFTWB0zO0TfS5v6adh94TiQUXLk/TF+FvcJml/Pg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5025d\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 24b8 67aa 77d2 7290 | 146 3f94 (0) 3efc (0) 3ec5 (0) 3e8e (0)\n001 9 e5ad efea fe21 f4e0 | 63 eb98 (0) e854 (0) e883 (0) e8ef (0)\n002 6 88fe 849b 8025 82f9 | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 3 a6fb a653 af02 | 10 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n004 3 baf2 b95d b897 | 9 bcc6 (0) bb90 (0) ba88 (0) badd (0)\n005 2 b2a5 b2b5 | 3 b02b (0) b2a5 (0) b2b5 (0)\n============ DEPTH: 6 ==========================================\n006 3 b7ca b65e b626 | 3 b7ca (0) b65e (0) b626 (0)\n007 0 | 0\n008 1 b5b2 | 1 b5b2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","private_key":"3a7659e35466d850264b95d5726e83847b52c4fe2ef8e76a5feac0100809deb4","name":"node_b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","services":["streamer"],"enable_msg_events":true,"port":45515},"up":true}},{"node":{"info":{"id":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","name":"node_f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","enode":"enode://9684e28e4a62f154f17f11253fb9011cc96e2d0d4ba400d12cf1b503cf26af50e7a8bf6e7f70c1536728100d6130ed58e2df364130255fbebe0d5d04b1fd70ed@127.0.0.1:0","enr":"0xf88fb8402dba0c34158122d8574a009ad32db3fe3e685cb1ca434ffbb06840fdc6eedf0918916d137d709bfd379a9142fb8a368674eaa6a9069a88209fb456b34b32b26d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039684e28e4a62f154f17f11253fb9011cc96e2d0d4ba400d12cf1b503cf26af50","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9Siqr9Z7INr9zhAdsiSqAccPk73JHBT1D6jbHb+fw4Y=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f528aa\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 574f 49cd 67aa 7290 | 146 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n001 3 b502 82f9 976e | 47 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n002 5 db6a da67 ca04 c26f | 26 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n003 7 ed2d efea e8ef e027 | 18 ee5e (0) ef1b (0) ef07 (0) efea (0)\n004 5 fbc8 fbf5 ff36 fe31 | 6 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n005 3 f31c f27f f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 3 f629 f7fa f773 | 4 f629 (0) f7ba (0) f7fa (0) f773 (0)\n007 3 f4e0 f45f f456 | 3 f456 (0) f45f (0) f4e0 (0)\n============ DEPTH: 8 ==========================================\n008 2 f5b2 f5dc | 2 f5b2 (0) f5dc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","private_key":"0074e098350248a953ff96635c5646441ade6fbfa6928e7e7750f648e3b500ee","name":"node_f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","services":["streamer"],"enable_msg_events":true,"port":43141},"up":true}},{"node":{"info":{"id":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","name":"node_976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","enode":"enode://f1a481f05b3add0348b325714cd13f8a882a8d2b664914693d9941f93594ca157866eea0d82ebc7cb2fe170adeff113230c00d363f046910cd52ab0d55492ebe@127.0.0.1:0","enr":"0xf88fb84014a108662ac31a996bb4e33b0cf7555059548c4001a3ef8a193d8466ea9d19560d11b9724d49c733a3cb7a33e6b586c3c1e7d29b5cfaec3a6ae783fc8cdd11100183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f1a481f05b3add0348b325714cd13f8a882a8d2b664914693d9941f93594ca15","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"l25X0MMiJyIr/Qy7gC8mm9zVLV0zz2icZrEsAj9fqL8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 976e57\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 512e 4558 46fe 4782 | 146 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n001 7 ca04 c26f c786 c43f | 63 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n002 4 b2b5 b626 b5b2 b502 | 27 aeb4 (0) ae2b (0) af02 (0) ad98 (0)\n003 5 898d 88fe 849b 8025 | 10 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n004 4 9852 9890 9fa0 9d0f | 4 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n005 3 90a8 9076 915d | 3 90a8 (0) 9076 (0) 915d (0)\n============ DEPTH: 6 ==========================================\n006 1 959f | 1 959f (0)\n007 1 96fc | 1 96fc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","private_key":"773efb429c0f38acad55b6036ac34ae481afe60385254d46a9bde06da2cb9688","name":"node_976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","services":["streamer"],"enable_msg_events":true,"port":34309},"up":true}},{"node":{"info":{"id":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","name":"node_7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","enode":"enode://5a17da2705e5b0debd1d99553696c4a5bbafb01aed9d25a59cc3138327b93cab177c0bcf0e776be1303d3ff5f00776f20c7014e244b21f403862867c778811b7@127.0.0.1:0","enr":"0xf88fb840e597671ce4248b4b2e417ca6323a8a567e7ef2d7410a33b01a359dbd7ecb815c2d88ee75860442c11680c729d27a72df1fb9720fae553a7935ef2d26436f68190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035a17da2705e5b0debd1d99553696c4a5bbafb01aed9d25a59cc3138327b93cab","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cpDNOv+t5fnnKdGwNUms6vslds28Z4n9aIyVSV8Qus0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7290cd\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c43f da67 f528 b502 | 110 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n001 3 02d8 0d8a 1400 | 76 3f94 (0) 3e8e (0) 3efc (0) 3ec5 (0)\n002 9 5b63 53a8 574f 4558 | 38 51db (0) 512e (0) 524d (0) 5308 (0)\n003 5 6ecb 6fe9 6337 60d7 | 20 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n004 5 7e04 7dd3 7dc2 7b90 | 7 7e04 (0) 7dbb (0) 7dd3 (0) 7dc2 (0)\n005 2 775e 77d2 | 2 775e (0) 77d2 (0)\n============ DEPTH: 6 ==========================================\n006 1 7125 | 1 7125 (0)\n007 1 738c | 1 738c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","private_key":"c64631a1d6a68b8a5627d9020f3e5b7139f946885d83e07bc5704da66d3166c7","name":"node_7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","services":["streamer"],"enable_msg_events":true,"port":41897},"up":true}},{"node":{"info":{"id":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","name":"node_82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","enode":"enode://491601ffb74c3a9ebf3de209bc241d4c92ac22845e14acc401f895473f0bc655a9cfea75088a8c844eb406d545723ae828d2f12c500b0b54af2dd1fa476fb492@127.0.0.1:0","enr":"0xf88fb8403595298556b2fc3d72aad1199b8884bb4964f0329c3e542b25cdb97b44aa51647ad064f3bb12519401f2d5e1a205f0437711a1a9ae0d7ced24515e75874358490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102491601ffb74c3a9ebf3de209bc241d4c92ac22845e14acc401f895473f0bc655","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gvnJAJ8J3i1qd7VJdtFMFCEermXYhvbtV1YMcAcW3Vw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82f9c9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4558 4a8b 49cd 67aa | 146 3f94 (0) 3e8e (0) 3ec5 (0) 3efc (0)\n001 6 ca04 c26f c43f db6a | 63 cc20 (0) c9f5 (0) c832 (0) c898 (0)\n002 5 a6fb b2b5 b626 b5b2 | 27 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n003 6 9d0f 9fa0 915d 959f | 10 9890 (0) 9852 (0) 9d0f (0) 9fa0 (0)\n004 4 8f21 898d 886a 88fe | 5 8f21 (0) 898d (0) 886a (0) 88a1 (0)\n005 2 8505 849b | 2 8505 (0) 849b (0)\n============ DEPTH: 6 ==========================================\n006 1 8025 | 1 8025 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 82dd | 1 82dd (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","private_key":"0ef1f1623ac066de7c84777cf3fdec022dd693c8afd056e66d11862de46a6b46","name":"node_82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","services":["streamer"],"enable_msg_events":true,"port":35447},"up":true}},{"node":{"info":{"id":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","name":"node_67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","enode":"enode://df05a5d2153d7fb7c457936ec0e15ff559604a97443ea6452b72f52f0bf4f7141b33e639ea57beeef6f9a66105875690ff4b2ab4747566fd982574190e3de8ad@127.0.0.1:0","enr":"0xf88fb840a795f4ec6f1fdb826e6b2093cab7198649eb34d52ca4b62ce368e45ac4faa1f528a90244e6f7e816652c6b385873781f7c5100d927d40bba2c80f904ae4bfe140183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df05a5d2153d7fb7c457936ec0e15ff559604a97443ea6452b72f52f0bf4f714","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z6pUY+SzKzY7PQHSpBzLAxmUEQVydvSWLQUxYL4ppu8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67aa54\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f528 c26f c43f da67 | 110 ef1b (0) ef07 (0) efea (0) ee5e (0)\n001 5 256e 30be 02d8 0d8a | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 7 524d 53a8 574f 44a1 | 38 574f (0) 524d (0) 5308 (0) 534b (0)\n003 4 7a60 7b90 77d2 7290 | 12 7dd3 (0) 7dc2 (0) 7dbb (0) 7e04 (0)\n004 7 6831 6967 6c4d 6ea5 | 11 6831 (0) 6967 (0) 6c73 (0) 6c4d (0)\n005 5 6337 6251 628e 6103 | 6 628e (0) 6251 (0) 6337 (0) 6103 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 66e7 | 1 66e7 (0)\n008 0 | 0\n009 1 67dc | 1 67dc (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","private_key":"b796ff6a7ea6c2ded46cda26187abc9f36f967d9926239cfadb31eb97c349ca6","name":"node_67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","services":["streamer"],"enable_msg_events":true,"port":41807},"up":true}},{"node":{"info":{"id":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","name":"node_49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","enode":"enode://3c3dd1934b208eb8c478606579f8392337b4793113196b083d2ab9599f30a2217b82e47b41b2446956ef7bc98a5c7017010d405e89625cfaa7ec82503202e598@127.0.0.1:0","enr":"0xf88fb840bef6e7ddcbe9097f31c066f2007867456dac705bcafc0d983fafa95339cf22cf0dbe62c98d695ab072cf52a83210e68e4ccd1ae28c315d504b31c18875a7a6280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c3dd1934b208eb8c478606579f8392337b4793113196b083d2ab9599f30a221","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Sc0e/talanivTqSrQIEwE+dsal+50gKe4C212A9eQaY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 49cd1e\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c43f ca04 f528 b502 | 110 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n001 10 30be 378e 3780 3b88 | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 4 7b90 7290 60d7 67aa | 32 7dd3 (0) 7dc2 (0) 7dbb (0) 7e04 (0)\n003 5 512e 53a8 574f 5f00 | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 8 4447 44a1 4559 4558 | 12 4109 (0) 41d9 (0) 44a1 (0) 4447 (0)\n005 3 4e5a 4c9e 4d6b | 5 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n006 3 4bcf 4ac7 4a8b | 3 4bcf (0) 4ac7 (0) 4a8b (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 4990 | 1 4990 (0)\n010 1 49ea | 1 49ea (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","private_key":"563539e7699dfba87188db2ed5bd0040cfa037d5206f5a9aea1126ba8152310e","name":"node_49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","services":["streamer"],"enable_msg_events":true,"port":41057},"up":true}},{"node":{"info":{"id":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","name":"node_46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","enode":"enode://a0de85bf37f6c9a5f3721d82e07290b2aff2e6a485e2f5ddf83375faa1ce9e2d017ddc7b100b4380ed76cfdecc7b264e3c387ea994ae3e04084de10b9ce0debe@127.0.0.1:0","enr":"0xf88fb840a6baf80ae45dad3d244387e2e3306969fc26628f3f7f6d0c4db267ea2c532b6b2afab9ca8d89a8c3e90d540e1ddff77ea90e5a57af1485e6cdf579d33d54d8990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a0de85bf37f6c9a5f3721d82e07290b2aff2e6a485e2f5ddf83375faa1ce9e2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rv7mna2LamqH01bRDbJdg1oMThVL8Xnoj7TMZfl9ctc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 46fee6\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b502 976e ca04 da67 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 3 0d8a 1b83 1400 | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 6 7290 7a60 7b90 6fe9 | 32 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n003 4 5b63 574f 53a8 512e | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 3 4ac7 4a8b 49cd | 11 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 4 4447 44a1 4559 4558 | 4 44a1 (0) 4447 (0) 4559 (0) 4558 (0)\n007 2 47bf 4782 | 2 47bf (0) 4782 (0)\n============ DEPTH: 8 ==========================================\n008 3 4646 461c 4636 | 3 4646 (0) 461c (0) 4636 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","private_key":"6fc017c68b2b6d1e4693c27cfaf816ee8b7e583f9c28e3236413cc80fef9a431","name":"node_46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","services":["streamer"],"enable_msg_events":true,"port":44839},"up":true}},{"node":{"info":{"id":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","name":"node_4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","enode":"enode://de5cedf56d1615e739c3b5ca058d2eea156785daef1c7f6e902c2bff170ea20cf2d7bbb3675b4e578abc41a540756f95f3737dc19ebd04edabd1f16878ff499b@127.0.0.1:0","enr":"0xf88fb840020d593599f4d4fdd4b673eaa585fd98665cc182ed5584ba2d601525f0a039d052b21ad75071dad2b20f02fc88ac764fb23d96be4848d01c42922b552755b01d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103de5cedf56d1615e739c3b5ca058d2eea156785daef1c7f6e902c2bff170ea20c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SothDgnTWqIcQquMPjjeYAqUTAlOa4bqVoKLXmkE8fc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a8b61\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b502 976e 82f9 da67 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 2 0d8a 1400 | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 5 60d7 7b90 7a60 77d2 | 32 7dbb (0) 7dd3 (0) 7dc2 (0) 7e04 (0)\n003 4 512e 53a8 574f 5b63 | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 8 4447 44a1 4559 4558 | 12 41d9 (0) 4109 (0) 44a1 (0) 4447 (0)\n005 2 4d6b 4c9e | 5 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n006 3 4990 49ea 49cd | 3 4990 (0) 49ea (0) 49cd (0)\n============ DEPTH: 7 ==========================================\n007 1 4bcf | 1 4bcf (0)\n008 0 | 0\n009 1 4ac7 | 1 4ac7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","private_key":"3deb6c6e230a0dae4c0fedc0272e1053d1abd2a0db710d50aef93887fa30a915","name":"node_4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","services":["streamer"],"enable_msg_events":true,"port":46571},"up":true}},{"node":{"info":{"id":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","name":"node_478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","enode":"enode://8fccdf07a7c9e466c0b785b6e7c08ab0f94389a6dd46b9a57854589a96a603e97aa8de47419c1d494b354330e85090d9c6caaeb9c4b9569614ed744bb18a812d@127.0.0.1:0","enr":"0xf88fb8405875381eb6fee735b5b8a7f7d40d20b341a0100ea48efe8538f28a4f40cd5a1323c240cd86add212d1642a4178d5f89048e6a9c2ddb9ff519e8baacfeffa0bbc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038fccdf07a7c9e466c0b785b6e7c08ab0f94389a6dd46b9a57854589a96a603e9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R4J4GHzZr3megzQKL0mwt/Ei+44IwKNyqHeVQm6rNks=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 478278\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b502 976e da67 | 110 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n001 2 1400 0d8a | 76 2995 (0) 2a0a (0) 2a97 (0) 2abb (0)\n002 2 7290 60d7 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 4 5b63 574f 53a8 512e | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 2 49cd 4a8b | 11 4e5a (0) 4d10 (0) 4d59 (0) 4d6b (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 4 4447 44a1 4559 4558 | 4 44a1 (0) 4447 (0) 4559 (0) 4558 (0)\n============ DEPTH: 7 ==========================================\n007 4 4646 461c 4636 46fe | 4 4646 (0) 461c (0) 4636 (0) 46fe (0)\n008 0 | 0\n009 0 | 0\n010 1 47bf | 1 47bf (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","private_key":"7134099c68806e422529987394e8a1ad8f242e3afdeaae1cbfc9502144f217d7","name":"node_478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","services":["streamer"],"enable_msg_events":true,"port":34389},"up":true}},{"node":{"info":{"id":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","name":"node_da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","enode":"enode://09c17ada4739980768a07f0c58b53d5a85809644bfc0eec14c46c61dc3e49b9b0464027601e91df63272219003508fbadb50af0b1e50cbf277df9393cf564a43@127.0.0.1:0","enr":"0xf88fb84026df424d93a356c6547f1236e5f3bcc0d324405bae4298855c59614f051e780b5a8e7f8b31e16a6c03c68c5b14c7f57b56aeec3423be94288bd6122dc84744bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10309c17ada4739980768a07f0c58b53d5a85809644bfc0eec14c46c61dc3e49b9b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2mes409wdqHVULxhvCox2ojWzZ+d9DsUKoxrut4bSu4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: da67ac\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 02d8 0d8a 1400 7290 | 146 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n001 3 b2b5 976e 82f9 | 47 ad98 (0) ac4d (0) ae2b (0) aeb4 (0)\n002 6 e547 ed2d e8ef fe21 | 37 ee5e (0) ef1b (0) ef07 (0) efea (0)\n003 7 c26f c59e c43f c49c | 15 c1f9 (0) c26f (0) c620 (0) c6cf (0)\n004 4 d1d7 d299 d7ac d640 | 5 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n005 1 df1e | 1 df1e (0)\n006 2 d887 d863 | 2 d887 (0) d863 (0)\n============ DEPTH: 7 ==========================================\n007 1 db6a | 1 db6a (0)\n008 1 daec | 1 daec (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","private_key":"fe594383342620bd1c9a63e85f0d89178817a1ee319e2ae87883c4ea5095460e","name":"node_da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","services":["streamer"],"enable_msg_events":true,"port":38619},"up":true}},{"node":{"info":{"id":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","name":"node_ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","enode":"enode://314cf099608d4d93ba78e270ccccdc14e79ba93f1a35a21f22026b5185704dac75d3be0c47fa7ec804e43c36778fa2465de371bc88b65f0fe0fe7a20fcad4d41@127.0.0.1:0","enr":"0xf88fb840991f1a646d5b8c7b7ac450787d726b85d140b857b28b860546b9845b01192b1d33b0a9e2e8c65650934640d7cfda928a758c700c424697626a27fb804accd7f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103314cf099608d4d93ba78e270ccccdc14e79ba93f1a35a21f22026b5185704dac","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ygQdoNxRRkPQF0WNCP9pYuxSyeZlcaI57DldyLJUZwk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ca041d\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1400 02d8 0d8a 46fe | 146 2a97 (0) 2abb (0) 2a0a (0) 2995 (0)\n001 7 82f9 976e baf2 b2b5 | 47 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n002 4 e547 e5ad f4e0 f528 | 37 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n003 5 d299 d7ac d640 db6a | 11 d1d7 (0) d3b0 (0) d299 (0) d640 (0)\n004 8 c6cf c786 c59e c49c | 9 c1f9 (0) c26f (0) c59e (0) c49c (0)\n005 1 cc20 | 1 cc20 (0)\n============ DEPTH: 6 ==========================================\n006 3 c9f5 c832 c898 | 3 c9f5 (0) c832 (0) c898 (0)\n007 0 | 0\n008 1 caf6 | 1 caf6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","private_key":"9cc996c03300b4fbea17d12fdd08e09b69c5fb6285146a6ba449e039c93eb995","name":"node_ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","services":["streamer"],"enable_msg_events":true,"port":43867},"up":true}},{"node":{"info":{"id":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","name":"node_60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","enode":"enode://a14e22f8e8c82419c10076d96cdbe472237999f2149eee60543d344bb340cc0aba0065b6d152c59b8c5e95b6c85aad12133aa728af74492d114c66589b78a993@127.0.0.1:0","enr":"0xf88fb8408bf40ac90d17fcdb8b9194819add563ad27402ad5360ee89d31cd70ecae375697c825f76d7f9ff1386c1f4effce6a27828d685ca5f67dbdbdeffb230ebac73700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a14e22f8e8c82419c10076d96cdbe472237999f2149eee60543d344bb340cc0a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YNczfvgGvpXMr3udZjpCifmvxo7c7WKQSrUGAc8RP0U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 60d733\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e547 e5ad da67 ca04 | 110 ad98 (0) ac4d (0) aeb4 (0) ae2b (0)\n001 3 1b83 1400 0d8a | 76 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n002 7 512e 5b63 4a8b 49cd | 38 574f (0) 524d (0) 5308 (0) 534b (0)\n003 4 77d2 7290 7a60 7b90 | 12 775e (0) 77d2 (0) 7125 (0) 738c (0)\n004 6 6c73 6c4d 6ea5 6e05 | 11 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n005 2 66e7 67aa | 3 66e7 (0) 67dc (0) 67aa (0)\n006 3 6337 628e 6251 | 3 6337 (0) 628e (0) 6251 (0)\n============ DEPTH: 7 ==========================================\n007 1 6103 | 1 6103 (0)\n008 1 605a | 1 605a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","private_key":"d865723cac5fd73301f42e8bd68cfc9378898c91568207d80b7594237cbee540","name":"node_60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","services":["streamer"],"enable_msg_events":true,"port":37363},"up":true}},{"node":{"info":{"id":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","name":"node_0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","enode":"enode://9f72dc03cfdcb02e051151d117994d208c6b1accb3fa75fd4c8f6973b90760fa21a742f873bbdd6abb98b45feab218b475d88600d83f3e155c0cd3a2bc8cd8e0@127.0.0.1:0","enr":"0xf88fb8401d3b8aa52b102a17d0ec1a0fbb92d0c4d45b8c64280e68a6de5c10d42ac23c57363fb8dd32efeb83e9578e85d240b6e9e6cb00753baf3d5a7877201720e406c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029f72dc03cfdcb02e051151d117994d208c6b1accb3fa75fd4c8f6973b90760fa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DYqRkgf7LVcY6rfalfjv6wGk4a45YC0xX4ui/xdS2do=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d8a91\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e547 da67 c43f ca04 | 110 aeb4 (0) ae2b (0) af02 (0) ad98 (0)\n001 12 53a8 574f 5b63 49cd | 70 574f (0) 524d (0) 534b (0) 5308 (0)\n002 4 256e 2ccf 3780 30be | 32 21a0 (0) 2101 (0) 217f (0) 20ae (0)\n003 4 1c8a 1f85 1b83 1400 | 22 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n004 4 0438 0743 07a8 02d8 | 11 045b (0) 0451 (0) 0438 (0) 0661 (0)\n005 2 0af9 0b72 | 3 0b72 (0) 0a00 (0) 0af9 (0)\n006 3 0e5e 0fc5 0ff2 | 3 0e5e (0) 0fc5 (0) 0ff2 (0)\n============ DEPTH: 7 ==========================================\n007 3 0cf5 0c64 0c28 | 3 0cf5 (0) 0c64 (0) 0c28 (0)\n008 0 | 0\n009 1 0de3 | 1 0de3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","private_key":"714005eb63c1f681f6e6d248618fbb384992707e07292f666ee9d475997ad0fe","name":"node_0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","services":["streamer"],"enable_msg_events":true,"port":36819},"up":true}},{"node":{"info":{"id":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","name":"node_140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","enode":"enode://e1ccb6417d15f6494ffafaa9d244c8b4dde696a72ca60fbd5dd6ad25d2b01530265fb2dff62548999fb9e9c7e4d8721cd1605b3e2259032ce3740e125a2724d9@127.0.0.1:0","enr":"0xf88fb840c1aba5fa71e995c2d05e38311251405e2aed69381bc4256421eefc3e58022db80bf4ee6dbb83cce873b18448ea8e2943c0c07ffcad5e79649279e3adec6b95d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e1ccb6417d15f6494ffafaa9d244c8b4dde696a72ca60fbd5dd6ad25d2b01530","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FAAgojqEC4hAugwsOE+FOmBjMOl0OIXplnz0lTPbKC4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 140020\npopulation: 45 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 e5ad e547 c43f ca04 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 13 53a8 46fe 4782 4558 | 70 574f (0) 524d (0) 5308 (0) 534b (0)\n002 4 256e 24b8 378e 30be | 32 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n003 6 0438 07a8 02d8 0cf5 | 22 045b (0) 0451 (0) 0438 (0) 0661 (0)\n004 8 1c47 1c9c 1c8a 1e2a | 10 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n005 2 13d6 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 4 1672 17db 179f 1704 | 5 165f (0) 1672 (0) 1704 (0) 179f (0)\n007 1 154b | 1 154b (0)\n============ DEPTH: 8 ==========================================\n008 1 14df | 1 14df (0)\n009 0 | 0\n010 1 1436 | 1 1436 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","private_key":"556950a90a1dad390b6fc5d9b5b1c233161f015de2d7fef6e8e6079733d4f698","name":"node_140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","services":["streamer"],"enable_msg_events":true,"port":35227},"up":true}},{"node":{"info":{"id":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","name":"node_7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","enode":"enode://5d077c804ebd13e7fa79b13210a9f8eaf0a72b5eb61816e9b780eb88a9794cf264334213ab605cbd538f71e0d354cc87c7c65b6ca6d492ca04a11f64dc401ee2@127.0.0.1:0","enr":"0xf88fb84044f3dd1993ede3a59f643421431f806409d41c9f6212b331bac4586d156afc1f75c391daa990c8e52046f96d52133b6b52ac0607d88f47108c0cb28b4e2ccb990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025d077c804ebd13e7fa79b13210a9f8eaf0a72b5eb61816e9b780eb88a9794cf2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e5DpOa4qJA8NdKkjr7a78R9tW5mnv4Xxglseo2vOdEw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7b90e9\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b626 da67 e547 | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 3 1b83 1400 02d8 | 76 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n002 10 4ac7 4a8b 49cd 46fe | 38 574f (0) 524d (0) 5308 (0) 534b (0)\n003 8 6c4d 6fe9 6f2d 6ecb | 20 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n004 4 7290 738c 77d2 775e | 5 775e (0) 77d2 (0) 7125 (0) 738c (0)\n005 4 7e04 7dbb 7dd3 7dc2 | 4 7e04 (0) 7dbb (0) 7dd3 (0) 7dc2 (0)\n============ DEPTH: 6 ==========================================\n006 1 7920 | 1 7920 (0)\n007 1 7a60 | 1 7a60 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","private_key":"e008f9a954df6848345e13074de64581f826eb05f1c85014a22afe07d7afd655","name":"node_7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","services":["streamer"],"enable_msg_events":true,"port":40801},"up":true}},{"node":{"info":{"id":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","name":"node_02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","enode":"enode://92a4724c2dc7a409c261888c4cd9cf6414fc6cf9df011f8877dcafb8a0f09fccc292ad4cea02561c68b2226b6058e8803230ac5adce4d829a6be49161e9672a6@127.0.0.1:0","enr":"0xf88fb840545027bb61080c38c187a5d84369aa4b4790c385613ee02331515b99e60b1dd8228951b517cb1ff48bf5de46057359f0dfa5c064e46b20ccfbe05526e9aa9daa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10292a4724c2dc7a409c261888c4cd9cf6414fc6cf9df011f8877dcafb8a0f09fcc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Athbn45HdiJK5QiGg6h4N7grK/t+BHzzc6KDk+espuE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 02d85b\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b626 da67 ca04 e5ad | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 9 53a8 512e 5b63 4558 | 70 574f (0) 524d (0) 534b (0) 5308 (0)\n002 4 2ccf 2995 3780 30be | 32 20ae (0) 21a0 (0) 2101 (0) 217f (0)\n003 2 1b83 1400 | 22 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n004 3 0cf5 0de3 0d8a | 11 0b72 (0) 0a00 (0) 0af9 (0) 0fc5 (0)\n005 5 07a8 0743 0451 045b | 6 0661 (0) 07a8 (0) 0743 (0) 045b (0)\n006 2 00c6 0067 | 2 00c6 (0) 0067 (0)\n============ DEPTH: 7 ==========================================\n007 2 03cc 0328 | 2 03cc (0) 0328 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","private_key":"e4ec3c40d474533d24394b73a40c70a533fdc023259146333c3ba30a6ef2e9ab","name":"node_02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","services":["streamer"],"enable_msg_events":true,"port":36493},"up":true}},{"node":{"info":{"id":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","name":"node_e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","enode":"enode://7171c11a093b51b6cc82078234ce48f2d0ebb3b56cc76ae5f988726c9857d7d69bc3fb5a01f4c6af0c862751c134804f1bdf13dc430fc007ae9c2dd5d0d6ff83@127.0.0.1:0","enr":"0xf88fb8408b53c905f3415f9c2c6e63f66a60385e30d6ff9285113905d760adb0db4eac275fefd5031cc64d050f70a502687314d59a1bd9c113edfd553d48a55a7a9c204e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037171c11a093b51b6cc82078234ce48f2d0ebb3b56cc76ae5f988726c9857d7d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5UeEz7zYnDfI91iq5w7OOrS3+MMPtO91Q+BKqJ/0OGs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e54784\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 1400 1b83 0d8a 02d8 | 146 2995 (0) 2a97 (0) 2abb (0) 2a0a (0)\n001 4 9d0f 959f 915d b626 | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 10 c26f c786 c49c c59e | 26 df1e (0) d887 (0) d863 (0) db6a (0)\n003 3 fe21 f2d5 f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 3 e8ef ed2d efea | 10 ec52 (0) ed2d (0) ee5e (0) ef1b (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e775 (0) e7fa (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e5d7 e5ad | 2 e5d7 (0) e5ad (0)\n009 1 e514 | 1 e514 (0)\n010 0 | 0\n011 0 | 0\n012 1 e54b | 1 e54b (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","private_key":"6855155d7773437dde5625696c1fd21e0b93d11b8f418fe17b83735999241de6","name":"node_e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","services":["streamer"],"enable_msg_events":true,"port":44601},"up":true}},{"node":{"info":{"id":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","name":"node_45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","enode":"enode://1d85f00468f786d1f65c994867636f183a120622cffb3f2934c00dba86d528843a0c8b82e64a43212e3cb8b496fd71390b505c78ab6e3be9415fd3c56318aff7@127.0.0.1:0","enr":"0xf88fb840afb40932bf66ca7c121a0c54ece652628981b3fae02dd8c65f5de31913ddfd985cc09c42a7843bf6fc85803cae0b508643b06bb46b9c38f9c7c4570dc325063c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031d85f00468f786d1f65c994867636f183a120622cffb3f2934c00dba86d52884","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RVhKS+u5SO9fe1XUhG7FVJ12I2ghacDtyrWzUj5ox9o=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 45584a\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8025 82f9 959f 976e | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 4 30be 02d8 1400 1b83 | 76 2101 (0) 217f (0) 21a0 (0) 20ae (0)\n002 5 60d7 6fe9 7290 7a60 | 32 66e7 (0) 67dc (0) 67aa (0) 6251 (0)\n003 4 574f 53a8 512e 5b63 | 15 574f (0) 524d (0) 5308 (0) 534b (0)\n004 3 49cd 4a8b 4ac7 | 11 4e5a (0) 4d10 (0) 4d6b (0) 4d59 (0)\n005 2 4109 41d9 | 2 4109 (0) 41d9 (0)\n006 6 4646 4636 461c 46fe | 6 4646 (0) 461c (0) 4636 (0) 46fe (0)\n============ DEPTH: 7 ==========================================\n007 2 44a1 4447 | 2 44a1 (0) 4447 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 4559 | 1 4559 (0)\n========================================================================="}},"config":{"id":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","private_key":"9608a1c360a2f5a546c575e523d9afd2b89f14ea1058b2f3be09cb1ba5ba4240","name":"node_45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","services":["streamer"],"enable_msg_events":true,"port":44403},"up":true}},{"node":{"info":{"id":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","name":"node_1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","enode":"enode://73130b08d35d59e21a3991dc309b956f7bcd8dc6946b53bba74e40d612c993b6b8bfc34ee4e2cebfb54120afb070360aba61e91ebf845a4d0bc2f5a94f7918b2@127.0.0.1:0","enr":"0xf88fb84087efc4c166904eeedc3b6692d887773016e8af688980eff63dbd8053a6662a994b81ef2f726fb80b4fb522f0551ebbe913fedbb471e94c6e1b6c26882f9e963b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10273130b08d35d59e21a3991dc309b956f7bcd8dc6946b53bba74e40d612c993b6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"G4MO1ISydKlux7ovmkK2hZQStTNKVkAU/z8RWX6joy0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1b830e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c786 e547 | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 8 60d7 6fe9 7b90 7a60 | 70 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n002 3 2ccf 3780 30be | 32 20ae (0) 21a0 (0) 2101 (0) 217f (0)\n003 5 07a8 0438 02d8 0cf5 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 4 1704 17db 1436 1400 | 12 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n005 4 1f67 1f85 1c47 1c8a | 6 1c47 (0) 1c9c (0) 1c8a (0) 1e2a (0)\n============ DEPTH: 6 ==========================================\n006 2 19fa 18f6 | 2 19fa (0) 18f6 (0)\n007 1 1a2a | 1 1a2a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","private_key":"9a7dd3d621d32ff5a718455ac877ef986e5aaa5f787e0c07a01221179c5655a6","name":"node_1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","services":["streamer"],"enable_msg_events":true,"port":44895},"up":true}},{"node":{"info":{"id":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","name":"node_5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","enode":"enode://7180d5a2452d8f6f57da742809146caacf5d03be267b31242048646bfa4961bf2284cfeab0b4af050aca2a42f14742163ac4fdfe364bb31111ee5aad221f17da@127.0.0.1:0","enr":"0xf88fb84057305ca13e6cae11290507a0fc500d9008b375e0f3e6c6a47714cc7fe9c0c390643b679806a97c42225f87daf53e3b30ee361ed30fb4980947d7d1734dfeb46e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027180d5a2452d8f6f57da742809146caacf5d03be267b31242048646bfa4961bf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W2Mur3ANFz/xX0cnuFgX5hcyKMMEtCJDSgjCytQ4uCU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5b632e\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b626 e5ad e547 d7ac | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 4 30be 0d8a 02d8 1b83 | 76 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n002 8 6337 60d7 6e05 6fe9 | 32 66e7 (0) 67dc (0) 67aa (0) 6337 (0)\n003 9 49cd 4a8b 4ac7 4636 | 23 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n004 4 574f 53a8 51db 512e | 8 574f (0) 524d (0) 534b (0) 5308 (0)\n005 3 5cd2 5db0 5f00 | 4 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n============ DEPTH: 6 ==========================================\n006 2 5823 58ed | 2 5823 (0) 58ed (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","private_key":"745b337c790505716596b24711aeb834f9da50436f3c21c469cc58d9ed44bade","name":"node_5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","services":["streamer"],"enable_msg_events":true,"port":39847},"up":true}},{"node":{"info":{"id":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","name":"node_512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","enode":"enode://1ab954a0243f9922c7cc2353fed4531e695ab0f6c7d1f8b71ad381ce5b816d82d3e28fec5e7c29b4803a212c4b95b2e36764a217983fe60077800f6cc1042e8f@127.0.0.1:0","enr":"0xf88fb84083fbd1c8452f3f73ce4a2b36c81e402e17ae6440d2848e50b2948a3e01e62a840e4e008afd0dbb92800b63a93d399149a0cf7181d700305c34a238931bf5eca00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031ab954a0243f9922c7cc2353fed4531e695ab0f6c7d1f8b71ad381ce5b816d82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"US7Fwua014hIJGLZQRF8gfzA5z8MFVRXlN0bTgO/IQI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 512ec5\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 915d 976e 959f 8025 | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 2 02d8 30be | 76 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n002 4 60d7 6fe9 7b90 7a60 | 32 66e7 (0) 67dc (0) 67aa (0) 6251 (0)\n003 8 49cd 4ac7 4a8b 4447 | 23 4c9e (0) 4d10 (0) 4d59 (0) 4d6b (0)\n004 2 5f00 5b63 | 7 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n005 1 574f | 1 574f (0)\n============ DEPTH: 6 ==========================================\n006 5 524d 5308 534b 53fe | 5 524d (0) 5308 (0) 534b (0) 53fe (0)\n007 0 | 0\n008 1 51db | 1 51db (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","private_key":"a9936124e7fb45265f6f877d31652c355a01c95aafa0759b600b0b01bda446eb","name":"node_512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","services":["streamer"],"enable_msg_events":true,"port":42415},"up":true}},{"node":{"info":{"id":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","name":"node_c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","enode":"enode://0f947b6b5ef1e5851a56a3a6852d472207b64d611146bc3070524184aa3530da88475fb850affcc256762fd9be921202f017475ff8cd8ffaeed209ab886fff12@127.0.0.1:0","enr":"0xf88fb840f891417b94f031211a81ebabc83fda5d22dee1e76ffbf5ed206cdfdc2e0ad84110d709ff637d2b0727e8e5968902fd13220cd26f881e0b8b8cf2978d2cf78daf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020f947b6b5ef1e5851a56a3a6852d472207b64d611146bc3070524184aa3530da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"x4b/hmf1CbWpUZmEwdlcg6XS4ldQCnFCno8jr2EM53E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c786ff\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 30be 1b83 5b63 512e | 146 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n001 5 96fc 976e 959f 9d0f | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 9 f5dc f4e0 f925 fe31 | 37 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n003 5 d863 db6a da67 d640 | 11 df1e (0) d887 (0) d863 (0) db6a (0)\n004 4 c9f5 c832 ca04 caf6 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 4 c59e c441 c43f c49c | 4 c43f (0) c441 (0) c49c (0) c59e (0)\n============ DEPTH: 7 ==========================================\n007 2 c620 c6cf | 2 c620 (0) c6cf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","private_key":"ac3f95d0c0be51c8eb8e612f911fc75f2c7796eb845e974b365f8ca34e1cf47f","name":"node_c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","services":["streamer"],"enable_msg_events":true,"port":33023},"up":true}},{"node":{"info":{"id":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","name":"node_7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","enode":"enode://bcc004d204a81c01d6723867a47b697318eb158b54dcd5ded13d8dcc571f81e8bb51e56b4f5d2dae98a48aa41e77429bf1aed102194df88ce7a4ec9761c78733@127.0.0.1:0","enr":"0xf88fb840cdabbbf5e1facab29f6e6f89d212c7fae606ccfa0ebe589ea48a109bc0e55ada757e2d5d4c65db8cb1a08f565d4a76dc5e565ba64f9411dfb4335217027c424f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bcc004d204a81c01d6723867a47b697318eb158b54dcd5ded13d8dcc571f81e8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"emCNLPnR2cWBncH56I5csoUqreoBxA4EfC4YS2LnFjw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7a608d\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b5b2 e8ef e5ad d7ac | 110 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n001 5 02d8 0d8a 1400 1b83 | 76 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n002 9 4a8b 4ac7 4558 46fe | 38 4c9e (0) 4d10 (0) 4d59 (0) 4d6b (0)\n003 9 6103 60d7 6337 67aa | 20 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n004 2 77d2 7290 | 5 775e (0) 77d2 (0) 7125 (0) 738c (0)\n005 4 7e04 7dbb 7dc2 7dd3 | 4 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n============ DEPTH: 6 ==========================================\n006 1 7920 | 1 7920 (0)\n007 1 7b90 | 1 7b90 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","private_key":"1482a769e4374b6a63d26c4cd99ac2a877d146de855386acc89bbbf8d92d634d","name":"node_7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","services":["streamer"],"enable_msg_events":true,"port":43929},"up":true}},{"node":{"info":{"id":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","name":"node_e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","enode":"enode://45396d74120c86243ba2a5201eb5c426df1e01a818cab326b1f835329328113dcbfc080c8d30f25d4b3100a6881df18cbedf46901fa1eba42e8b67217a03b6d4@127.0.0.1:0","enr":"0xf88fb840ef39cfe61b95ba34b613f30b0c843f8b08e7b8d7e1612460f235e2864e40110d59b1705cfc07c7f088345f97da1704cd0b1336fe5f79ef916551e2f99d9573240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10245396d74120c86243ba2a5201eb5c426df1e01a818cab326b1f835329328113d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5a2gQVyS7xURsV0E7fOVl2Rkr9mtw+kpxB1NIdJeMYI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5ada0\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 02d8 1400 30be 5b63 | 146 13d6 (0) 11d4 (0) 103b (0) 1672 (0)\n001 4 88fe b502 b5b2 b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 7 d7ac d640 caf6 ca04 | 26 df1e (0) d887 (0) d863 (0) db6a (0)\n003 3 fe21 f2d5 f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 3 ec52 efea e8ef | 10 ee5e (0) ef1b (0) ef07 (0) efea (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e775 (0) e7fa (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 3 e514 e54b e547 | 3 e514 (0) e54b (0) e547 (0)\n009 1 e5d7 | 1 e5d7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","private_key":"412a46a21e6ae42d21149e1e5a99ab8147be24ca5ca741bc0806394903c6a4e9","name":"node_e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","services":["streamer"],"enable_msg_events":true,"port":44795},"up":true}},{"node":{"info":{"id":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","name":"node_30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","enode":"enode://d4938f13c3e1a21366991a0040a5de8e8d3200ec4fa2e95ebd57bf291ae843e2e484f992690d2fbbc475b3fbf3d9ac44d29ff8b2bfaced1a76f0fca80a1e8499@127.0.0.1:0","enr":"0xf88fb840eff44640732004cd295f6d11cea92ed4934e714036a514bc63ea49a498010ad0630d6f351de844e1ad07c248cb15476b934e9ae674722be12109c12fceb667440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d4938f13c3e1a21366991a0040a5de8e8d3200ec4fa2e95ebd57bf291ae843e2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ML7HzQp9ACg5rtdlQSm9L+Lizn9CqnuuFWDov3GJVMM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 30bec7\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b626 d7ac c786 c59e | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 10 5b63 53a8 512e 49cd | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 6 02d8 0d8a 1400 1f85 | 44 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n003 6 20ae 217f 24b8 256e | 15 20ae (0) 21a0 (0) 2101 (0) 217f (0)\n004 2 3b88 3ec5 | 7 39d1 (0) 3b78 (0) 3b88 (0) 3f94 (0)\n005 3 3630 3780 378e | 4 35e6 (0) 3630 (0) 378e (0) 3780 (0)\n006 2 3237 33b5 | 3 3373 (0) 33b5 (0) 3237 (0)\n============ DEPTH: 7 ==========================================\n007 1 314a | 1 314a (0)\n008 0 | 0\n009 0 | 0\n010 1 3089 | 1 3089 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","private_key":"457e22ce24b3272b31f979367cff7d1675ce728dd8758a7e66779eab01b1f39a","name":"node_30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","services":["streamer"],"enable_msg_events":true,"port":40077},"up":true}},{"node":{"info":{"id":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","name":"node_6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","enode":"enode://e2ff496895056d4524e8809a260658da6ceec4c10793af4bcb6c057c8e49b09e58f567ba6f5276f0b7f0a77d9fdf7faa3240a2bd679395fcedabee5b9f3351a7@127.0.0.1:0","enr":"0xf88fb84070b049df191da1faabfd595e42918747d388a4aefef434acda7b08e59e72eef27c77b287320a2242d7483326ca4c879b2a973a90e8de4f7d318ae7837f2485a20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e2ff496895056d4524e8809a260658da6ceec4c10793af4bcb6c057c8e49b09e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"b+mgLpUKXDpf8Ca3WSLtaH1ZeVuo65wJKo0JpcZNJFM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6fe9a0\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 e8ef e5ad c49c c786 | 110 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n001 4 02d8 1400 1b83 30be | 76 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n002 9 53a8 512e 5f00 5b63 | 38 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n003 3 7290 7b90 7a60 | 12 775e (0) 77d2 (0) 7125 (0) 738c (0)\n004 5 66e7 67aa 6337 6103 | 9 66e7 (0) 67dc (0) 67aa (0) 6251 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 4 6e05 6e68 6ea5 6ecb | 4 6ea5 (0) 6ecb (0) 6e68 (0) 6e05 (0)\n============ DEPTH: 8 ==========================================\n008 2 6f5f 6f2d | 2 6f5f (0) 6f2d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","private_key":"879ee7d6a5c3b9955ff62eaf879fe7b1cfccac856af66e529973919c66e623fc","name":"node_6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","services":["streamer"],"enable_msg_events":true,"port":39807},"up":true}},{"node":{"info":{"id":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","name":"node_b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","enode":"enode://bcb24f203bc073123e592cbe910596246943b55a8b23f83c44d9a9792ce617b3881167f7ea10979b8e0edbb7477d3caa2536b87ab288635a7f606b7f12e6fdf6@127.0.0.1:0","enr":"0xf88fb840bb20ffbb4f9e317c0920fd1e3c9ab49f236431a644b4ed2d281206876654ea5175878382b830f9312bf112a8799f0609ac8d280355c23d6062b4299a6d4957d40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bcb24f203bc073123e592cbe910596246943b55a8b23f83c44d9a9792ce617b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tibUcrVV5vlQpxQng9uN60Q6dOY+9r1yqH6vGvFMqAU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b626d4\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 02d8 30be 5b63 53a8 | 146 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n001 11 f2d5 e8ef e547 e5ad | 63 fbc8 (0) fbf5 (0) f925 (0) fe31 (0)\n002 5 915d 959f 976e 82f9 | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 3 ac4d a6fb a653 | 10 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n004 4 b95d ba88 badd baf2 | 9 bcc6 (0) b820 (0) b897 (0) b911 (0)\n005 2 b02b b2b5 | 3 b02b (0) b2a5 (0) b2b5 (0)\n006 2 b5b2 b502 | 2 b502 (0) b5b2 (0)\n============ DEPTH: 7 ==========================================\n007 1 b7ca | 1 b7ca (0)\n008 0 | 0\n009 1 b65e | 1 b65e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","private_key":"a8c00eca98c6cb671796a4d64ed46a6e68a4299a429d774c69674a2844e1b7eb","name":"node_b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","services":["streamer"],"enable_msg_events":true,"port":45367},"up":true}},{"node":{"info":{"id":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","name":"node_d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","enode":"enode://af8ad49dda536a983269aeea2d7dca08e480fe8314968145e98dc97cd7b009ed461036eccaa3b638ee49d16e627b2234eb3f362ec7d15abc46e5c36b54e53638@127.0.0.1:0","enr":"0xf88fb840e94ce96dfda68df3191de91c495debd7006cfc51027649581bd11c598e9ab2f214d984a700cab94c2e6de920ccb7f73533a32c3f8dfb71f22d53f5e21ffd7b320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102af8ad49dda536a983269aeea2d7dca08e480fe8314968145e98dc97cd7b009ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"16yo8hgrxiXSs8lCvRFhyFvPHCs07L4+L9I8+ua4qHE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d7aca8\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 30be 7a60 6fe9 5b63 | 146 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n001 3 88fe b5b2 b626 | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 9 e8ef ec52 e547 e5ad | 37 f925 (0) fbc8 (0) fbf5 (0) ff36 (0)\n003 8 ca04 caf6 c26f c786 | 15 cc20 (0) c898 (0) c832 (0) c9f5 (0)\n004 4 df1e d863 da67 db6a | 6 df1e (0) d887 (0) d863 (0) db6a (0)\n============ DEPTH: 5 ==========================================\n005 3 d1d7 d3b0 d299 | 3 d1d7 (0) d3b0 (0) d299 (0)\n006 0 | 0\n007 1 d640 | 1 d640 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","private_key":"0301a81bf982f07c1bb98bf99f353b8d2a82b03e69c21e1d74c8ceaad8396be0","name":"node_d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","services":["streamer"],"enable_msg_events":true,"port":34989},"up":true}},{"node":{"info":{"id":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","name":"node_4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","enode":"enode://518d6f5949bd69109142c1b8c458304de346817905a7cffb3be16be375f045f0c8d104d1d8dfeb19c79400877a63ad2ee8e87d9a1f57ce8f80ae645cbf4eef67@127.0.0.1:0","enr":"0xf88fb8406bb867b351cac2f28189ea4e9784fdf036ef21c4f2f01e0e0219a597544f9e026023632fca76371095ae079ec4432604b31db489477ff2bcb07772cf56116cc20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103518d6f5949bd69109142c1b8c458304de346817905a7cffb3be16be375f045f0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SsdVEj3MZO9E25KAMRr1Hz96k+De5nNw1nMmEiA1brk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4ac755\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b5b2 b626 e8ef d7ac | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 5 0d8a 1400 1b83 3780 | 76 13d6 (0) 11d4 (0) 103b (0) 1672 (0)\n002 3 7b90 7a60 6fe9 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 4 5f00 5b63 512e 53a8 | 15 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n004 4 4447 4558 46fe 47bf | 12 41d9 (0) 4109 (0) 44a1 (0) 4447 (0)\n005 2 4c9e 4d6b | 5 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n006 3 4990 49ea 49cd | 3 4990 (0) 49ea (0) 49cd (0)\n============ DEPTH: 7 ==========================================\n007 1 4bcf | 1 4bcf (0)\n008 0 | 0\n009 1 4a8b | 1 4a8b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","private_key":"f8fa80aec89f65eae7ced03937bb7d9ffb1cfecd1ac8217600cf47c3bff7bfed","name":"node_4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","services":["streamer"],"enable_msg_events":true,"port":38749},"up":true}},{"node":{"info":{"id":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","name":"node_c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","enode":"enode://3909a562bce9e929066fb8e20922518612b890356bb3e697259c816e2517f826e527c1899afe88e6b7c605624fb9260ec468201d8baa1e17fc0ca07e1629ac74@127.0.0.1:0","enr":"0xf88fb84055d8b49729febc40ab5a07b226db8df1a30bab38bbffbcdf525ad479d3d859e360ab5dcb1431b296f0eeaff955d7f74ddc76c4af156067256afe7dd5d718293e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023909a562bce9e929066fb8e20922518612b890356bb3e697259c816e2517f826","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xZ45U7ZOW5/75TmQo1iRTy+o41UdM/krnjpEG9G68s0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c59e39\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 30be 47bf 4ac7 | 146 0b72 (0) 0a00 (0) 0af9 (0) 0fc5 (0)\n001 4 959f 88fe b5b2 b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 3 e8ef e547 e5ad | 37 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n003 6 da67 d863 df1e d299 | 11 df1e (0) d887 (0) d863 (0) db6a (0)\n004 2 ca04 caf6 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 3 c786 c620 c6cf | 3 c620 (0) c6cf (0) c786 (0)\n============ DEPTH: 7 ==========================================\n007 3 c43f c441 c49c | 3 c43f (0) c441 (0) c49c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","private_key":"2d2665fd12ac020bb8aa6997cba5174e95d07b7f2dd9687d68abd431a6133895","name":"node_c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","services":["streamer"],"enable_msg_events":true,"port":42839},"up":true}},{"node":{"info":{"id":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","name":"node_47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","enode":"enode://99a8f99fc0cfe5ad73c6d3c6784bd3c8a36e664d0c586724f2a5dacd88ae1de2c2b2afe39786236af913ea9ea1d6f81726598d4fedf4f9698bc4d622dfa74456@127.0.0.1:0","enr":"0xf88fb84003f4b14b4db4abd57728bdc34701e10c40aa56b4937b21e60de55c6e0dc32a4e429766f47337d209a05d753ba33fb2e781dbccc3dece305fca6b5aa020f556b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10299a8f99fc0cfe5ad73c6d3c6784bd3c8a36e664d0c586724f2a5dacd88ae1de2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R7+jdnzvzAgx1BDVQC6TluikEsjJb69VtFHT/zEPOwI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 47bfa3\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 88fe b5b2 b626 e8ef | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 2 3780 30be | 76 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n002 3 6e05 6fe9 7a60 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 4 5f00 5b63 512e 53a8 | 15 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n004 3 49cd 4a8b 4ac7 | 11 4e5a (0) 4c9e (0) 4d10 (0) 4d59 (0)\n005 2 41d9 4109 | 2 41d9 (0) 4109 (0)\n006 4 44a1 4447 4559 4558 | 4 4559 (0) 4558 (0) 44a1 (0) 4447 (0)\n============ DEPTH: 7 ==========================================\n007 4 4646 4636 461c 46fe | 4 4646 (0) 461c (0) 4636 (0) 46fe (0)\n008 0 | 0\n009 0 | 0\n010 1 4782 | 1 4782 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","private_key":"e14e52fa9b610fd29123ec266b01cb4554f23f0985eaf4f397ee8e36da9fb734","name":"node_47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","services":["streamer"],"enable_msg_events":true,"port":36519},"up":true}},{"node":{"info":{"id":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","name":"node_53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","enode":"enode://7cb2f74beeafb23eb1c3733aa06b15fcf9ec81c7bcd0c7fca13880190575b2efc50576733e125720aa8ca507c8763d15fc8c6a2d45ece04586cec04a52cf219f@127.0.0.1:0","enr":"0xf88fb8406637aa6250f6d822fa890a388e4a0568c5ba66b7f182fc1e3bde5ea9387252335b403469fdffbc037d26e4abdb86926c506f134f6bb74408cd656037fe7f8a250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037cb2f74beeafb23eb1c3733aa06b15fcf9ec81c7bcd0c7fca13880190575b2ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U6iFlo1o2Ov37VFOZizBP6AxhtI2EACgNXZTH9yiol8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 53a885\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 88fe b5b2 b626 c49c | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 7 1400 0d8a 02d8 0438 | 76 0661 (0) 0743 (0) 07a8 (0) 0451 (0)\n002 6 67aa 6fe9 6e05 7290 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 8 49cd 4a8b 4ac7 4558 | 23 4e5a (0) 4d10 (0) 4d6b (0) 4d59 (0)\n004 4 5f00 5efb 5b63 5823 | 7 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n005 1 574f | 1 574f (0)\n006 2 51db 512e | 2 51db (0) 512e (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 534b 5308 | 2 534b (0) 5308 (0)\n009 1 53fe | 1 53fe (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","private_key":"969e9079ff9417e9019194be48bd5ca8390e4b1da63300776d6ba493e5b0e3df","name":"node_53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","services":["streamer"],"enable_msg_events":true,"port":34549},"up":true}},{"node":{"info":{"id":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","name":"node_e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","enode":"enode://61681c2fcd285866105bfa4d3e47a2c7d765368cde74a62218935aecf0fd15966a88226b5f12e371f41954a0063b806cce53468884b34e817120d5b41386fe22@127.0.0.1:0","enr":"0xf88fb840276c3036a03aa8627db3a54002f6257878aa8046c3174fd3a3052160dafc7a8445e68a88d8bfd35ff1174b47c53c3fec471867db75b9f0670a68993bcf09c1f40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261681c2fcd285866105bfa4d3e47a2c7d765368cde74a62218935aecf0fd1596","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6O/oAW/mz2SbJ1W+4i2jXMxsnFXUBNU4XWH26ie4Q4A=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8efe8\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 30be 7a60 6fe9 4ac7 | 146 13d6 (0) 103b (0) 11d4 (0) 1704 (0)\n001 4 88fe baf2 b626 b5b2 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 6 caf6 c49c c59e da67 | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 4 f2d5 f629 f7fa f528 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 5 e027 e7fa e547 e5d7 | 8 e027 (0) e775 (0) e7fa (0) e514 (0)\n005 6 ee5e ef1b ef07 efea | 6 ee5e (0) ef1b (0) ef07 (0) efea (0)\n006 1 eb98 | 1 eb98 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 e854 | 1 e854 (0)\n009 1 e883 | 1 e883 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","private_key":"8ce9e530f5c91869432f678c7427fbcae8495679b569edd4de349825b348c94a","name":"node_e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","services":["streamer"],"enable_msg_events":true,"port":41325},"up":true}},{"node":{"info":{"id":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","name":"node_d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","enode":"enode://17dda987ab35c708fe928fd6daff3da8a18784789c581cb861079dca3d05584c6516824bb15729d0d6e4ca77908c3ae96a4a8f8edfb415eef4f9f31481e0b2cf@127.0.0.1:0","enr":"0xf88fb8401e90e884b49904ec677447f4c5edbe69de30ec6df088f673b1b613313d66a2c30ec1b3b452bf12152b16f4361f665f5cbce63a6f2680effd69ef9dcda94114440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10317dda987ab35c708fe928fd6daff3da8a18784789c581cb861079dca3d05584c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1kBHI1GWmlV45UGspyt2QMWDuZX9YmB/8+4/PzE5qv0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d64047\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 47bf 53a8 | 146 13d6 (0) 11d4 (0) 103b (0) 1672 (0)\n001 4 b626 b5b2 915d 88fe | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 7 f629 f2d5 e5d7 e5ad | 37 fbc8 (0) fbf5 (0) f925 (0) fe31 (0)\n003 8 c9f5 ca04 caf6 c26f | 15 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n004 4 df1e d863 db6a da67 | 6 df1e (0) d887 (0) d863 (0) db6a (0)\n============ DEPTH: 5 ==========================================\n005 3 d299 d3b0 d1d7 | 3 d1d7 (0) d3b0 (0) d299 (0)\n006 0 | 0\n007 1 d7ac | 1 d7ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","private_key":"7dda4f1f1b00b27dcba963ca38a79091c69eacbc993590b9774b515e9138ddca","name":"node_d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","services":["streamer"],"enable_msg_events":true,"port":39283},"up":true}},{"node":{"info":{"id":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","name":"node_c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","enode":"enode://0c6d8311b47b26830eeecd5200414fb26fc1147f01b938dcc610c2407af63cf617079655416b03336b0695f7ed5d42efc11803d5dbee44fd5d05c487921f1548@127.0.0.1:0","enr":"0xf88fb840154c57974260b37e441e6874dff8009220b1b7cb71ed9271d0543f018a32274012616ddf46d4aec53d939099c377e0f189c1c9259858e7ec80a7c1e23fb1c6520183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c6d8311b47b26830eeecd5200414fb26fc1147f01b938dcc610c2407af63cf6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xJyv8Thi3AifH5uBgNbvpFVkg3VmJxknIQLE+AKHmdY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c49caf\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7a60 6e05 6fe9 53a8 | 146 13d6 (0) 11d4 (0) 103b (0) 165f (0)\n001 5 915d 88fe b65e b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 8 f2d5 f629 f7fa e5d7 | 37 e027 (0) e775 (0) e7fa (0) e514 (0)\n003 5 df1e da67 d863 d7ac | 11 df1e (0) d887 (0) d863 (0) db6a (0)\n004 2 ca04 caf6 | 6 cc20 (0) c898 (0) c832 (0) c9f5 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 2 c6cf c786 | 3 c620 (0) c6cf (0) c786 (0)\n007 1 c59e | 1 c59e (0)\n============ DEPTH: 8 ==========================================\n008 2 c441 c43f | 2 c43f (0) c441 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","private_key":"751d508bcd33604fcc32799146ee07845fc1159580d23d46d4c8f86939cfd368","name":"node_c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","services":["streamer"],"enable_msg_events":true,"port":35349},"up":true}},{"node":{"info":{"id":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","name":"node_caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","enode":"enode://032b6cb479ba63501feaba6ea9a5a1c0a5952e228ce6223a71ce74de13ee98d0b1f5167229e9609313ed643e1dbf3ff6124ec3c1158ea76885378b1867f90d54@127.0.0.1:0","enr":"0xf88fb8405c6b6d2ebf985d21c8d0ac47d9fde8e7bb43b8b2dcc9731ed7adea09b973a34f1407c6d0801c18739521dc7e60fd663a0f8888a1dfd86e3d8284aab6b811246e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102032b6cb479ba63501feaba6ea9a5a1c0a5952e228ce6223a71ce74de13ee98d0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yvao43/UHB5q13qFdc2QNUuxaTiTlSMBycrrR3nDONM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: caf6a8\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3780 6e05 53a8 4447 | 146 13d6 (0) 103b (0) 11d4 (0) 165f (0)\n001 5 915d 88fe b65e b626 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 9 e8ef ec52 e5ad e5d7 | 37 e027 (0) e775 (0) e7fa (0) e514 (0)\n003 4 d863 db6a d7ac d640 | 11 d887 (0) d863 (0) db6a (0) daec (0)\n004 7 c26f c6cf c786 c59e | 9 c1f9 (0) c26f (0) c620 (0) c6cf (0)\n005 1 cc20 | 1 cc20 (0)\n============ DEPTH: 6 ==========================================\n006 3 c9f5 c898 c832 | 3 c9f5 (0) c898 (0) c832 (0)\n007 0 | 0\n008 1 ca04 | 1 ca04 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","private_key":"7404cb8ddf7d531f80b522df15471c04183be2225349a44f9f07d118e9b508be","name":"node_caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","services":["streamer"],"enable_msg_events":true,"port":37023},"up":true}},{"node":{"info":{"id":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","name":"node_b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","enode":"enode://6ba4f9939fe79c2fa62906da87f6145579ce26244c232ef3a0ee23ceb8298c98cefef00b37faae81fc5535255f16604e5be09f2a544cb2dd1007f489ca73d910@127.0.0.1:0","enr":"0xf88fb840a537a74b55567b80ec626e0a4a8e8e4515acc8a9fe9b893068e006a292c9609609a11873cee2c6bff37d1b5e2b0406d5b61c997e3a28f76fa0a3f561d6d293810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ba4f9939fe79c2fa62906da87f6145579ce26244c232ef3a0ee23ceb8298c98","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tbJFMtKBDjEeELHWBrr2AH+RJLiKF4sycTzx7drgib4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5b245\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 53a8 4ac7 4447 47bf | 146 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n001 9 f2d5 e5ad e8ef d7ac | 63 e027 (0) e775 (0) e7fa (0) e514 (0)\n002 6 959f 96fc 976e 915d | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 4 ac4d ad98 a6fb a653 | 10 ae2b (0) aeb4 (0) af02 (0) ad98 (0)\n004 3 ba88 badd baf2 | 9 bcc6 (0) b911 (0) b95d (0) b820 (0)\n005 3 b02b b2a5 b2b5 | 3 b02b (0) b2a5 (0) b2b5 (0)\n============ DEPTH: 6 ==========================================\n006 3 b65e b626 b7ca | 3 b7ca (0) b65e (0) b626 (0)\n007 0 | 0\n008 1 b502 | 1 b502 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","private_key":"bb9cccb7fbaaf1b02e691345fdc13fbfb49ed17129b679b20e4cd008ed173b26","name":"node_b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","services":["streamer"],"enable_msg_events":true,"port":35555},"up":true}},{"node":{"info":{"id":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","name":"node_88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","enode":"enode://d002db12f24e09a012d47d716f63576d836cb4e6af9bbc4c563fffdeb4fb138675904bd4ee8ae0325a2be23e1017032cbda9124ba121b6df6bf3f129d4101cf4@127.0.0.1:0","enr":"0xf88fb840595a1f1435cf159c616f21eb11caab1ff821b51aa99b5f08bccb592945e7e073140d4625a0d25290d1a867fe36afe9b7b9740c374a72727f3375d7c9b75013190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d002db12f24e09a012d47d716f63576d836cb4e6af9bbc4c563fffdeb4fb1386","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iP77dQYQXA4mm69SlVoBsZ9VUEsTEzusC+q0HJ9uaUI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 88fefb\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6e05 512e 53a8 4447 | 146 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n001 9 f7fa f2d5 e5ad e8ef | 63 d887 (0) d863 (0) db6a (0) daec (0)\n002 6 a653 baf2 b65e b626 | 27 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n003 5 9d0f 959f 96fc 976e | 10 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n004 5 849b 8505 8025 82dd | 5 8505 (0) 849b (0) 8025 (0) 82dd (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 898d | 1 898d (0)\n008 1 886a | 1 886a (0)\n009 1 88a1 | 1 88a1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","private_key":"60486eb333333a142330c9bf765d7fb5ea28918c3185e0013df6b65a50992256","name":"node_88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","services":["streamer"],"enable_msg_events":true,"port":36621},"up":true}},{"node":{"info":{"id":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","name":"node_37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","enode":"enode://ebdc2cb76ffdb28b7bc171d5210f6b3747caf9ef2a30848b043adff7d009ffbbd7e98427ef4035a46cbd69fd4f3f584d1d8f3bb96e36d865e626e4d9c82e4a91@127.0.0.1:0","enr":"0xf88fb8407932c8f5686fbbe250ac8a2d185c457889e6e4a89dce92326c0617685aa6f95212bd56382e464dac57d4be61991248c9485e070205d6e4065e47d40a1ad024860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ebdc2cb76ffdb28b7bc171d5210f6b3747caf9ef2a30848b043adff7d009ffbb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"N4AejX1GFD94kk7WYJn2WKlNN+39L1jQKsuFrdA+GJQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 37801e\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f2d5 caf6 c441 c49c | 110 db6a (0) daec (0) da67 (0) d887 (0)\n001 6 53a8 4ac7 49cd 47bf | 70 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n002 5 1b83 02d8 0438 0cf5 | 44 103b (0) 11d4 (0) 13d6 (0) 1672 (0)\n003 6 256e 20ae 217f 2a0a | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 3 3b88 3efc 3f94 | 7 39d1 (0) 3b78 (0) 3b88 (0) 3e8e (0)\n005 4 3373 314a 3089 30be | 6 3237 (0) 33b5 (0) 3373 (0) 314a (0)\n006 1 35e6 | 1 35e6 (0)\n============ DEPTH: 7 ==========================================\n007 1 3630 | 1 3630 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 378e | 1 378e (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","private_key":"369eb71eeb7b71c096c321177228fa31e9c9a28aa40a86cbfa645ba35b159f4f","name":"node_37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","services":["streamer"],"enable_msg_events":true,"port":46281},"up":true}},{"node":{"info":{"id":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","name":"node_915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","enode":"enode://22e79b248e289cce0fc5fa7dca0ce3cfdb2050b0151cc1435e3c0023cd1a07de7719d47f0dd8db4755266a2ec1bac0074f9753c8999c21cc1bcb5bf2f3abcd24@127.0.0.1:0","enr":"0xf88fb84078cc030ac8045a0e60c0ae70e0eb9bb3fd12770df422402905e64920ed3a568e19abd70ff4ea28b81fd7266a1eda7bb7aa25062222117467acd36f13d37fd78a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10222e79b248e289cce0fc5fa7dca0ce3cfdb2050b0151cc1435e3c0023cd1a07de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kV16BRC60ZJm7vjwDKDLLvw0AlN3VwZJX8qLkWC1Esw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 915d7a\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 512e 4558 4447 6e05 | 146 5cd2 (0) 5db0 (0) 5efb (0) 5f00 (0)\n001 10 f2d5 f7fa f629 ec52 | 63 d887 (0) d863 (0) db6a (0) daec (0)\n002 4 a653 baf2 b626 b5b2 | 27 af02 (0) aeb4 (0) ae2b (0) ad98 (0)\n003 4 82f9 898d 886a 88fe | 10 8505 (0) 849b (0) 8025 (0) 82dd (0)\n004 2 9fa0 9d0f | 4 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n005 3 96fc 976e 959f | 3 96fc (0) 976e (0) 959f (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 9076 90a8 | 2 9076 (0) 90a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","private_key":"46f8ff7c336416d502bd2c3ba10235eec55193182d1b1c0e74fc4763e2f12cb2","name":"node_915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","services":["streamer"],"enable_msg_events":true,"port":37115},"up":true}},{"node":{"info":{"id":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","name":"node_6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","enode":"enode://6cb33a608378cb32052368b80030aab00ffa4d25aeab3b017a18abcc39e2a8ca270fc88bfbe418dd31d426abd53107fdd99fcc230eb92632b5444644f101ac7c@127.0.0.1:0","enr":"0xf88fb8408e844dc2f0db4b3e2208b2adec83b24a99e19229c8902879c8c81877e506b4e32d3209a9af0119e2aa59342192dba0e72b3c74064f9f23a08ae09aa91199fb080183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026cb33a608378cb32052368b80030aab00ffa4d25aeab3b017a18abcc39e2a8ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bgUXnckKj2ZU0Mmj8GFzNx3PsYuFL9138191448nMSU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e0517\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 c49c c441 caf6 f2d5 | 110 db6a (0) daec (0) da67 (0) d887 (0)\n001 5 0743 0438 217f 2ccf | 76 103b (0) 11d4 (0) 13d6 (0) 1672 (0)\n002 5 53a8 5f00 5b63 47bf | 38 5823 (0) 58ed (0) 5b63 (0) 5cd2 (0)\n003 2 7b90 7a60 | 12 775e (0) 77d2 (0) 7125 (0) 738c (0)\n004 4 67aa 6103 60d7 6337 | 9 66e7 (0) 67dc (0) 67aa (0) 6103 (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c73 6c4d | 2 6c73 (0) 6c4d (0)\n007 3 6fe9 6f2d 6f5f | 3 6f2d (0) 6f5f (0) 6fe9 (0)\n============ DEPTH: 8 ==========================================\n008 2 6ea5 6ecb | 2 6ea5 (0) 6ecb (0)\n009 1 6e68 | 1 6e68 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","private_key":"1b7026a2b010aecd3db0637e03b2e0cf0bddfa9b0ad9d677056e091a03970305","name":"node_6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","services":["streamer"],"enable_msg_events":true,"port":35543},"up":true}},{"node":{"info":{"id":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","name":"node_f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","enode":"enode://0bed55a524855cf4b0ffa7a813b7cbbe61499512bd4579832af6444cce55217dc68f57f430feed9ef8214a49dbe0779600980fe1fa51afe837f8a9185d799ee6@127.0.0.1:0","enr":"0xf88fb84037c16835f858e5ccd867b9239f718531d6980f0b8d13d0eb0407dee672e37425392b42e2a352333d146fbebe5306020187121998d97f4caa33944a2667c4010c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020bed55a524855cf4b0ffa7a813b7cbbe61499512bd4579832af6444cce55217d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8tVTPu1LDBhJUthZ1n5Eq+WnWl3mERyMEGuPSy2Mz8Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f2d553\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 3780 217f 2ccf 4447 | 146 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n001 8 88fe 915d 959f a653 | 47 af02 (0) aeb4 (0) ae2b (0) ad98 (0)\n002 7 d863 d7ac d640 c49c | 26 d1d7 (0) d3b0 (0) d299 (0) d7ac (0)\n003 6 ef07 ef1b e8ef e547 | 18 e027 (0) e775 (0) e7fa (0) e514 (0)\n004 3 fe31 fe21 ff36 | 6 f925 (0) fbc8 (0) fbf5 (0) fe21 (0)\n005 7 f4e0 f5dc f528 f629 | 10 f456 (0) f45f (0) f4e0 (0) f5b2 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f31c | 1 f31c (0)\n008 1 f27f | 1 f27f (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","private_key":"6e3b2aeb1f3f715a86807af2cd2090519998b92df4dfd138d51b3cce2526dbb0","name":"node_f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","services":["streamer"],"enable_msg_events":true,"port":44807},"up":true}},{"node":{"info":{"id":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","name":"node_444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","enode":"enode://9ef94c855735b705843c447b2998afbb14eb30166ca1c8dbc09b763fa8e04e67376ebc830d745404753f08b76f454e3948b4546c340209c1d2e4739e170a8bec@127.0.0.1:0","enr":"0xf88fb84033c73ee216ccaa7cd66408fa60642ea37fcf44ff76073b098a962c13f1a4df8a4ce4188d4a34a26de1df6c40daa70adfb66850b5cf39eeda6218fabb91bf4ea70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029ef94c855735b705843c447b2998afbb14eb30166ca1c8dbc09b763fa8e04e67","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"REcioVsBoNjmeUeY0jn+Yh1ZvfwIgjq0fL2Lms69I7Q=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 444722\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 915d 88fe b5b2 b65e | 110 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n001 9 1a2a 0438 0cf5 3780 | 76 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n002 4 6337 6fe9 6ecb 6e05 | 32 775e (0) 77d2 (0) 7125 (0) 738c (0)\n003 5 5db0 5f00 5b63 512e | 15 5823 (0) 58ed (0) 5b63 (0) 5cd2 (0)\n004 3 49cd 4ac7 4a8b | 11 4e5a (0) 4d59 (0) 4d6b (0) 4d10 (0)\n005 2 4109 41d9 | 2 41d9 (0) 4109 (0)\n006 6 4646 4636 461c 46fe | 6 4646 (0) 4636 (0) 461c (0) 46fe (0)\n============ DEPTH: 7 ==========================================\n007 2 4559 4558 | 2 4559 (0) 4558 (0)\n008 1 44a1 | 1 44a1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","private_key":"1a57d82b5818ffcf64fda640f5ed8c9fc1578d29faabdd9297f9bafcedf16afc","name":"node_444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","services":["streamer"],"enable_msg_events":true,"port":36309},"up":true}},{"node":{"info":{"id":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","name":"node_c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","enode":"enode://9cef4cd1c3b7a978ced64f36c0c3a9098aba2c07c45787c884a7946e6d21976321f7c05ebe7abfd92c63f1ca54c46acddb27b2c6bfd01759cb09c78a4ec0544f@127.0.0.1:0","enr":"0xf88fb8400693860ca7cd4d67ebdb615eaaf42fa1ae8f5ff87a593cd0ad7e2a34020e6e2748358c72363e272974698017a897ccbb600b0be698450de6df9d6870ed976fa10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039cef4cd1c3b7a978ced64f36c0c3a9098aba2c07c45787c884a7946e6d219763","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xEHSel9KuqjjsPBApu+Fu4yXADHWpXUDpnTjaz1pFdk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c441d2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2ccf 217f 3780 6e05 | 146 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n001 5 898d 959f 915d b65e | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 5 f2d5 f629 f7fa ec52 | 37 ee5e (0) efea (0) ef1b (0) ef07 (0)\n003 4 d863 df1e d640 d7ac | 11 d3b0 (0) d299 (0) d1d7 (0) d7ac (0)\n004 4 ca04 caf6 c9f5 c832 | 6 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n005 2 c1f9 c26f | 2 c1f9 (0) c26f (0)\n006 3 c620 c6cf c786 | 3 c620 (0) c6cf (0) c786 (0)\n007 1 c59e | 1 c59e (0)\n============ DEPTH: 8 ==========================================\n008 1 c49c | 1 c49c (0)\n009 1 c43f | 1 c43f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","private_key":"a67d3fd0aeb245cdd802262166fd8226b4f6034f416053f7ef9956a99c473419","name":"node_c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","services":["streamer"],"enable_msg_events":true,"port":37581},"up":true}},{"node":{"info":{"id":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","name":"node_baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","enode":"enode://1c3d285d17974092dcbdb97e35e1885bbf94addb9dba5954e71c3ffc7348c4c58fdbf99598683dd6298c32ebaa5e7220e01715f4f5d2907af981f3b3167bdcce@127.0.0.1:0","enr":"0xf88fb840753f3903e7fa19460a5e7e20abc7555ba49cf8d52c7bbccd74918fc7f82461cb1e68b9970b23609530b70fd3059329b633f8639230949e4fe2cbdcd6af87edc40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021c3d285d17974092dcbdb97e35e1885bbf94addb9dba5954e71c3ffc7348c4c5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uvIZ6SKZIbdz0a1+t+tSFs+mDM7Ko8XEh+O3HLYAuhI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: baf219\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6e05 4447 3780 217f | 146 7125 (0) 738c (0) 7290 (0) 77d2 (0)\n001 6 f2d5 e5d7 e8ef ec52 | 63 eb98 (0) e854 (0) e883 (0) e8ef (0)\n002 3 88fe 915d 959f | 20 8505 (0) 849b (0) 8025 (0) 82dd (0)\n003 3 ad98 ac4d a653 | 10 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n004 5 b2b5 b502 b5b2 b626 | 8 b02b (0) b2a5 (0) b2b5 (0) b502 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 b897 b95d b911 | 4 b820 (0) b897 (0) b95d (0) b911 (0)\n007 1 bb90 | 1 bb90 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 ba88 | 1 ba88 (0)\n010 1 badd | 1 badd (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","private_key":"a5e1aa7f7374964afa85de3c3c1b2fa8a1caf2a27cf7be2844136deaf4f0ffa7","name":"node_baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","services":["streamer"],"enable_msg_events":true,"port":40635},"up":true}},{"node":{"info":{"id":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","name":"node_2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","enode":"enode://f81b4d7e1b4722dad58825039b3c38ddbebefc1a236c2080a520401e9483f6584433e2692ec15fcdc707d03bb9a6bf0ff7c912be023789af49c0a309da7631d4@127.0.0.1:0","enr":"0xf88fb8408bebaa03804d729c21adf92503814a0abf62421bf5f9a3830e95f47bcbf6fdb235a690cfd4e81ca66a5934af140d762788ac0f9c110afd2a54400eb8429453320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f81b4d7e1b4722dad58825039b3c38ddbebefc1a236c2080a520401e9483f658","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LM+1sfOSPTX++Ig4xQi5i1UWxdQJZDiB0jBK5J5Q7tM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2ccfb5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c441 ec52 f7fa f2d5 | 110 fbc8 (0) fbf5 (0) f925 (0) fe31 (0)\n001 4 6337 6e05 49cd 4447 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 7 1b83 1c47 0438 02d8 | 44 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n003 3 30be 3089 3780 | 17 3e8e (0) 3efc (0) 3ec5 (0) 3f94 (0)\n004 5 256e 24b8 20ae 2101 | 6 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n005 4 2995 2a0a 2abb 2a97 | 4 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n006 1 2f32 | 1 2f32 (0)\n007 1 2d36 | 1 2d36 (0)\n============ DEPTH: 8 ==========================================\n008 2 2c79 2c38 | 2 2c79 (0) 2c38 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","private_key":"056d524a765c48a6c1ab41c42f6cf836183cf10b73481f79cc49b79a3f6b5769","name":"node_2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","services":["streamer"],"enable_msg_events":true,"port":43231},"up":true}},{"node":{"info":{"id":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","name":"node_217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","enode":"enode://37f0965106672daa2a8e343623357ad538b5115d0f80fe74ef78f1d21863978762f82a776b97a1ea718ac52944af0a9e3c616d9f0c89f719a5aa940dd5b27a05@127.0.0.1:0","enr":"0xf88fb840f5488dc6acca9725c22fa1877fdf275cc7fc44feb78fb19f3cc4d712b78fa4820df8834c815cd7f6aeda861ba2236c7d6b425861780f726bd4f1277b707c2f390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10337f0965106672daa2a8e343623357ad538b5115d0f80fe74ef78f1d218639787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IX+ZUq8etY1cpax752NxbP4sCk883U6+S131Y/kZ4tI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 217f99\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c441 f7fa f2d5 ec52 | 110 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n001 4 6337 6e05 49cd 4447 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 3 0cf5 03cc 0438 | 44 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n003 4 3089 30be 3630 3780 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3e8e (0)\n004 6 2995 2a97 2a0a 2d36 | 9 2995 (0) 2abb (0) 2a97 (0) 2a0a (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 20ae | 1 20ae (0)\n008 1 21a0 | 1 21a0 (0)\n009 1 2101 | 1 2101 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","private_key":"2713b4b4549ba404d31cc2bc1f2bef523f8e70e0d00cca2667bb393532c2ec78","name":"node_217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","services":["streamer"],"enable_msg_events":true,"port":36795},"up":true}},{"node":{"info":{"id":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","name":"node_0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","enode":"enode://2a609a2f7bee18e9ace30fb43ae2c4440d114f3c4888ec0a34d24ebd1fa6156d633c4f2aa0f3eaed2db3abdc5fd1f634fb8a511fce8c719cde7248d202de66df@127.0.0.1:0","enr":"0xf88fb8408d5e6847e83be24d36a5259f7935a065f251552352ee158a5edfa798e6e86fbe00cbbc7bc7f90319931c1b7398f3e81894b504f3abfde6bcdec7daa4a90062350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032a609a2f7bee18e9ace30fb43ae2c4440d114f3c4888ec0a34d24ebd1fa6156d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BDj1ZwRdRVag56aXAo1ons/QriD56FwJtI2fH9DuR2U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0438f5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f7fa e5d7 b65e 959f | 110 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n001 4 53a8 4447 6e05 6337 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 4 3780 3089 2ccf 217f | 32 3b88 (0) 3b78 (0) 39d1 (0) 3f94 (0)\n003 6 1704 1400 1b83 1a2a | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 5 0b72 0de3 0d8a 0c64 | 11 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n005 5 0067 00c6 03cc 0328 | 5 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n006 3 0661 07a8 0743 | 3 0661 (0) 07a8 (0) 0743 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 2 045b 0451 | 2 045b (0) 0451 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","private_key":"7550104c3b78bd70d311385917b9e119ce140cd3584dfe07f18913b06e289257","name":"node_0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","services":["streamer"],"enable_msg_events":true,"port":39107},"up":true}},{"node":{"info":{"id":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","name":"node_959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","enode":"enode://94c05c36e8bda926576025fad9d891d1ae55f406eadb1b2a7040191907ac20a4618ab4af002e997762e3f4a747f417b9c66d3341b0819cb39514b2cfcbf633f8@127.0.0.1:0","enr":"0xf88fb840de6c271ba449dd87a205230febdcc13445277635cb2fb770e1bc7d4df1a6d488210fe6caff9e998f66112dba40d39585301fd3e88f2e0493f3f02c71a684f6e10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10294c05c36e8bda926576025fad9d891d1ae55f406eadb1b2a7040191907ac20a4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lZ/aCGbTwY6TmemEhdYnBEB51vhrB17a6pMVQC9dk5U=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 959fda\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4558 512e 5f00 6337 | 146 574f (0) 524d (0) 534b (0) 5308 (0)\n001 9 c786 c59e c441 f7fa | 63 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n002 6 ac4d a653 baf2 b5b2 | 27 aeb4 (0) ae2b (0) af02 (0) ad98 (0)\n003 5 8025 82f9 88fe 886a | 10 8505 (0) 849b (0) 8025 (0) 82dd (0)\n004 3 9890 9fa0 9d0f | 4 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n005 3 90a8 9076 915d | 3 9076 (0) 90a8 (0) 915d (0)\n============ DEPTH: 6 ==========================================\n006 2 96fc 976e | 2 96fc (0) 976e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","private_key":"a67fcf115dfe059791011d5d3825dec2155cabd72c208e838b3fbb2f28ac41a9","name":"node_959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","services":["streamer"],"enable_msg_events":true,"port":36529},"up":true}},{"node":{"info":{"id":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","name":"node_b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","enode":"enode://26664c55fa01411c68d45ee7e420631080f79cb0864dab6839e3fbd228061380f8d6ec4ed7e0d1fccfb3a6db94d25e49381fbd05f82d256e83694b44e75d326b@127.0.0.1:0","enr":"0xf88fb840b6133c0426dafd1efb3e89f6bc48cc63eca4c7bdf38f294f43a2805d2298640c241968809a87cf5d2889912bce5dbad860521fe9d6baf1a7b79d82530f26d4a00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10326664c55fa01411c68d45ee7e420631080f79cb0864dab6839e3fbd228061380","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tl7iVJU2qAbO70p8zJVEVnyv5iBAgJKfyEffCjeBzMk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b65ee2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6e05 5f00 4447 217f | 146 574f (0) 51db (0) 512e (0) 524d (0)\n001 9 df1e c441 c49c caf6 | 63 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n002 5 898d 886a 88fe 9d0f | 20 8505 (0) 849b (0) 8025 (0) 82dd (0)\n003 2 ac4d a653 | 10 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n004 3 ba88 badd baf2 | 9 bcc6 (0) b897 (0) b820 (0) b95d (0)\n005 2 b02b b2b5 | 3 b2a5 (0) b2b5 (0) b02b (0)\n006 2 b5b2 b502 | 2 b502 (0) b5b2 (0)\n============ DEPTH: 7 ==========================================\n007 1 b7ca | 1 b7ca (0)\n008 0 | 0\n009 1 b626 | 1 b626 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","private_key":"318a101c039a46bd0175afcb703828e82134ecef76cdcb18287938d57831ee61","name":"node_b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","services":["streamer"],"enable_msg_events":true,"port":44539},"up":true}},{"node":{"info":{"id":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","name":"node_0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","enode":"enode://450a836838f2759b33e799ec371253efe81e90e74db6f41b868bacb6429d0683dcf1fa1a8b4b761114fbc8826a796bcfc02f6a1798640d4ca58d845f064cadfd@127.0.0.1:0","enr":"0xf88fb840a59d9bcd8c093e82d30493da5fae7fd2e389dcd1428aeb3e828ddecadc97eb861f318f3f6d9652abb3e775bd5fa6fd84f4eb2b2d5c72ddb8ed22919c30f07dab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103450a836838f2759b33e799ec371253efe81e90e74db6f41b868bacb6429d0683","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DPWWr5HrmwQf5tvmsojFcwQThQMhtasXbIFEfjTvecU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0cf596\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e5d7 b65e | 110 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n001 3 4447 5f00 6337 | 70 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n002 5 3780 3089 20ae 217f | 32 39d1 (0) 3b88 (0) 3b78 (0) 3e8e (0)\n003 6 1c47 18f6 1a2a 1b83 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 6 0067 02d8 03cc 0743 | 11 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n005 3 0b72 0af9 0a00 | 3 0b72 (0) 0af9 (0) 0a00 (0)\n006 3 0fc5 0ff2 0e5e | 3 0fc5 (0) 0ff2 (0) 0e5e (0)\n007 2 0d8a 0de3 | 2 0de3 (0) 0d8a (0)\n============ DEPTH: 8 ==========================================\n008 2 0c28 0c64 | 2 0c28 (0) 0c64 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","private_key":"aa043f31ce0392fc2403ba8df2e8a31397d5e5f23c22dabce1e4f94a3ae1ae3a","name":"node_0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","services":["streamer"],"enable_msg_events":true,"port":33613},"up":true}},{"node":{"info":{"id":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","name":"node_e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","enode":"enode://62058bc379f81fa123e4296db03c67338ae62a539937d7b70a28a703624cdd451e739398d8dc6ed3f1b8c73cbb334b5cb7784d308b033ec5a9e61bedd06b050f@127.0.0.1:0","enr":"0xf88fb840e8da211f089ba6f711e92e1ad129af4bb030723cd33a3e2ad4e50fe4b81095403bbe8888a9e5b4ce5c0100c564b97767d80733b74ee5bafd5fc702364ecab3a10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10362058bc379f81fa123e4296db03c67338ae62a539937d7b70a28a703624cdd45","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5deU1kADclp0ZC8JfA7nZwbXhBm28+qBnUQLwK0Wbqw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5d794\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5f00 6337 3089 217f | 146 4e5a (0) 4c9e (0) 4d10 (0) 4d6b (0)\n001 6 b65e baf2 a653 9d0f | 47 8505 (0) 849b (0) 82dd (0) 82f9 (0)\n002 8 d640 d7ac d863 df1e | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 4 ff36 f2d5 f629 f7fa | 19 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n004 4 e8ef ef1b ef07 ec52 | 10 eb98 (0) e854 (0) e883 (0) e8ef (0)\n005 1 e027 | 1 e027 (0)\n006 2 e775 e7fa | 2 e775 (0) e7fa (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 3 e514 e54b e547 | 3 e514 (0) e54b (0) e547 (0)\n009 1 e5ad | 1 e5ad (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","private_key":"d57174d811911d6109444b6859f566feda29464787037865b1e86f3d852d82c3","name":"node_e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","services":["streamer"],"enable_msg_events":true,"port":33845},"up":true}},{"node":{"info":{"id":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","name":"node_ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","enode":"enode://78ada9ae0e9eeed303dfc34f560a3a254035857113ab0dd666ec66af33f65a057e050f3c0689eb1960f76f1cbd66ce97d03969c529ac8e264419b8c97aeb5b33@127.0.0.1:0","enr":"0xf88fb84019543c86b688b2e1ac9bb456d94ff1626ea0e8f1afe71fbd92ac278bc30265d850ecec065550473c16a03073e2eb1955d5307248437930167b599a69c298e7610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10378ada9ae0e9eeed303dfc34f560a3a254035857113ab0dd666ec66af33f65a05","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7FInBgQAdnPRv9oe29i/qUWiEUHv2F5CtoSp8w+M3a4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec5227\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 217f 2ccf 0743 1c47 | 146 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n001 6 9d0f 959f 915d b65e | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 10 c786 c441 c49c c9f5 | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 4 ff36 f629 f7ba f7fa | 19 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n004 3 e514 e5ad e5d7 | 8 e027 (0) e775 (0) e7fa (0) e54b (0)\n005 2 e854 e8ef | 4 eb98 (0) e854 (0) e883 (0) e8ef (0)\n============ DEPTH: 6 ==========================================\n006 4 ee5e efea ef1b ef07 | 4 ee5e (0) efea (0) ef1b (0) ef07 (0)\n007 1 ed2d | 1 ed2d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","private_key":"2eef17b1cd655ba656219906144f6dd5423e5c13fb8cfa3888a3fd60cc378cbd","name":"node_ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","services":["streamer"],"enable_msg_events":true,"port":43813},"up":true}},{"node":{"info":{"id":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","name":"node_63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","enode":"enode://e8a75bd7d2c0fa2c24d5e2505d6498a8158fa26cb0d97c3b4b68beb3abc827f44a87c3ecf11c56c0378c0572dd72d089765fe6598de6d897bb96cf033f27e730@127.0.0.1:0","enr":"0xf88fb8402480841002b2349bc7b775205391159f0d46294fd74c074f0e498aa92ba083f758bfa4f1b5b909441c0ac5304e35b6fb23b60d61ac7ca6a63cc099dae63215e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8a75bd7d2c0fa2c24d5e2505d6498a8158fa26cb0d97c3b4b68beb3abc827f4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YzcOKIqy5LhAPGZ46cRK5cdJa16tYUMG/OuFmG7SnRg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 63370e\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 9d0f 959f a653 f629 | 110 8025 (0) 82dd (0) 82f9 (0) 8505 (0)\n001 12 2a0a 2ccf 20ae 2101 | 76 256e (0) 24b8 (0) 21a0 (0) 2101 (0)\n002 5 4447 5308 5b63 5f00 | 38 4e5a (0) 4c9e (0) 4d6b (0) 4d59 (0)\n003 5 7290 738c 7dd3 7b90 | 12 775e (0) 77d2 (0) 7125 (0) 7290 (0)\n004 4 6f5f 6fe9 6ecb 6e05 | 11 6967 (0) 6831 (0) 6c73 (0) 6c4d (0)\n005 3 66e7 67aa 67dc | 3 66e7 (0) 67dc (0) 67aa (0)\n006 3 60d7 605a 6103 | 3 60d7 (0) 605a (0) 6103 (0)\n============ DEPTH: 7 ==========================================\n007 2 628e 6251 | 2 628e (0) 6251 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","private_key":"abec58c20cbfc6963e54b76ae6003547d7125c820d4c878b12e7e7ffcee87cae","name":"node_63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","services":["streamer"],"enable_msg_events":true,"port":35121},"up":true}},{"node":{"info":{"id":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","name":"node_f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","enode":"enode://760e043d37f149548183d41cdc870ab25e79461d0fb8ffdea5449bc04a3a83556d528ac0d81aba167a040d28e4ed2698c1022c1c2d0363d2c5f06f81563a721d@127.0.0.1:0","enr":"0xf88fb840a766a95d16d134be07e5941a44194fdc8e04d99ff58c3a35bd21692a7e8659921b69df71c2d402ac905d91f8f8c1bfe4b13117faf6aa42d79df4319efb5ea6c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103760e043d37f149548183d41cdc870ab25e79461d0fb8ffdea5449bc04a3a8355","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9/ophuyfhIIrEaawC9A6HdJvKg+rkLGzCPCMrq1Dz+E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f7fa29\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5f00 6337 2ccf 217f | 146 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n001 8 9d0f 959f 915d 898d | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 8 c832 c9f5 caf6 c49c | 26 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n003 5 e5d7 e8ef ef1b ef07 | 18 e027 (0) e775 (0) e7fa (0) e514 (0)\n004 3 fbf5 fe31 ff36 | 6 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n005 2 f31c f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 4 f4e0 f5b2 f5dc f528 | 6 f456 (0) f45f (0) f4e0 (0) f5b2 (0)\n007 1 f629 | 1 f629 (0)\n============ DEPTH: 8 ==========================================\n008 1 f773 | 1 f773 (0)\n009 1 f7ba | 1 f7ba (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","private_key":"5b66c852efc722720d943acdff6e44cf35572b3ebc9e25c2efb6d44a44ec4f34","name":"node_f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","services":["streamer"],"enable_msg_events":true,"port":37377},"up":true}},{"node":{"info":{"id":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","name":"node_03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","enode":"enode://f5754931b229bb88a9054a16e5a825c93b24fa190fd5cb1346f9c8d3ef63f4df173e4ca8cdf98ff3be0fc5d3ab44524bd95a9089a8d071964cc628219d22c11f@127.0.0.1:0","enr":"0xf88fb84071325b9451536f678c1dfebe4f7aa8106a51d55f3bff1e449d2721a6fbededad0602cb742328ce7c26870565fea9a7efa0b78c561848cf9d9bd1a185fca960dc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f5754931b229bb88a9054a16e5a825c93b24fa190fd5cb1346f9c8d3ef63f4df","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A8zY1SWX0YwLF4q3Nh2EfWOq06+SCig0WXeuFwodr80=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 03ccd8\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 898d 9d0f f7fa | 110 8505 (0) 849b (0) 8025 (0) 82dd (0)\n001 3 6ecb 6337 5f00 | 70 7125 (0) 738c (0) 7290 (0) 775e (0)\n002 5 2a0a 2ccf 217f 20ae | 32 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n003 5 1704 18f6 1a2a 1f67 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 4 0a00 0e5e 0cf5 0c64 | 11 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n005 4 0661 0743 0438 0451 | 6 045b (0) 0451 (0) 0438 (0) 0661 (0)\n006 2 00c6 0067 | 2 00c6 (0) 0067 (0)\n============ DEPTH: 7 ==========================================\n007 1 02d8 | 1 02d8 (0)\n008 1 0328 | 1 0328 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","private_key":"f9bcfddd59b4cd6907137f85a165d8d1d046ea6f941259d24d6f2665345cf86b","name":"node_03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","services":["streamer"],"enable_msg_events":true,"port":41855},"up":true}},{"node":{"info":{"id":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","name":"node_1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","enode":"enode://63429a53e98ea2c805da1f72629bc2dfa38477f37e946c23a9a556e105170d09ba9fc04a92c9c002f5afacb97323330dd80c7b6facee5c66d70acb13f0a2ef07@127.0.0.1:0","enr":"0xf88fb840c8a077c9b0ef7333f8f167874fe84783be8d6e18a6017fc6cacf229dab3e7a4b1f898958a70aebef08571f0bc40a3de1545c0b4c6bd945f28c5615df92fa47050183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10363429a53e98ea2c805da1f72629bc2dfa38477f37e946c23a9a556e105170d09","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HEetW9iEb3d9r1lYf+zMMI9Nxj9tJ7E4X/gIXHW7Gqw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1c47ad\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ec52 f629 a653 | 110 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n001 2 6337 5f00 | 70 7125 (0) 738c (0) 7290 (0) 775e (0)\n002 4 3089 2ccf 2a0a 20ae | 32 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n003 6 0cf5 0c64 0451 0438 | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 2 1400 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n005 3 18f6 1b83 1a2a | 4 19fa (0) 18f6 (0) 1b83 (0) 1a2a (0)\n006 3 1e2a 1f85 1f67 | 3 1e2a (0) 1f85 (0) 1f67 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 1c9c 1c8a | 2 1c9c (0) 1c8a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","private_key":"ebc5324f8eb3a357f8d1969f069ce39c7c3fb22ccf7525110318b3ac880c1ca3","name":"node_1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","services":["streamer"],"enable_msg_events":true,"port":42947},"up":true}},{"node":{"info":{"id":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","name":"node_5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","enode":"enode://480ba1e732c94f5f601e880599ab5b96e240599a8966fe2ddda4073307a99742a535dff51f6af5bd1b53fce8537be4bc5e2fa76c49449c0415442adba987460a@127.0.0.1:0","enr":"0xf88fb8401875d2a45f120ec3d8f94c4cf3efefff3c45785956e1a09d0446b9ea48b3cb1820585e3f5ab525ca7b0fb517ce83fbebc51c66913a99e3e1a3121c9d2583f0950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102480ba1e732c94f5f601e880599ab5b96e240599a8966fe2ddda4073307a99742","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XwCzvr7y9UhP8ThimK3WimdDoQYgCuihOifbtScU7o8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5f00b3\npopulation: 45 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 d863 df1e ec52 e5d7 | 110 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n001 12 2a0a 2c38 2d36 2101 | 76 2f32 (0) 2d36 (0) 2c79 (0) 2c38 (0)\n002 9 7b90 7a60 77d2 6337 | 32 7125 (0) 738c (0) 7290 (0) 775e (0)\n003 6 4447 47bf 461c 4646 | 23 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n004 4 53a8 5308 512e 51db | 8 574f (0) 524d (0) 53fe (0) 53a8 (0)\n005 2 5b63 58ed | 3 5b63 (0) 5823 (0) 58ed (0)\n============ DEPTH: 6 ==========================================\n006 2 5cd2 5db0 | 2 5cd2 (0) 5db0 (0)\n007 1 5efb | 1 5efb (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","private_key":"9b3dc4d343d8005de0a128e913e4ed62e5caec6a02eb7c00580bec4be6126b5e","name":"node_5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","services":["streamer"],"enable_msg_events":true,"port":36775},"up":true}},{"node":{"info":{"id":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","name":"node_0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","enode":"enode://19c7cdd72825b48029116b58a6a68b357fcc7dade4a419c159b7a1479b9aaaca9040f86319f2e30d881a255728459f53f62e11907116fb7f0d95b17cf8acd4ce@127.0.0.1:0","enr":"0xf88fb84082a5fb67d177a01d43d741c548086b575590cb32e8f8ca21ea57c96b5d3e3b247a3aa5b69c1cf6eb5ea7e667736efd50f3bf23a658d2738640b8e8f01c8684780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10219c7cdd72825b48029116b58a6a68b357fcc7dade4a419c159b7a1479b9aaaca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"B0O88qqnfpFvSjZ9YVlHPH2A9GouTL6e80bkI9OdcHI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0743bc\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 fe31 f629 e5d7 ec52 | 110 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n001 4 6f5f 6ecb 6e05 5f00 | 70 77d2 (0) 775e (0) 7125 (0) 738c (0)\n002 3 2a0a 20ae 3089 | 32 2f32 (0) 2c79 (0) 2c38 (0) 2ccf (0)\n003 3 1704 1f67 1c47 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 4 0e5e 0d8a 0c64 0cf5 | 11 0af9 (0) 0a00 (0) 0b72 (0) 0fc5 (0)\n005 3 0067 03cc 02d8 | 5 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n006 2 0451 0438 | 3 045b (0) 0451 (0) 0438 (0)\n============ DEPTH: 7 ==========================================\n007 1 0661 | 1 0661 (0)\n008 1 07a8 | 1 07a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","private_key":"47ac9bcf8a80092ec709388ead63309357c024e48a9d084b0242dfc58046fd79","name":"node_0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","services":["streamer"],"enable_msg_events":true,"port":44873},"up":true}},{"node":{"info":{"id":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","name":"node_a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","enode":"enode://613e2fd1046ee6d486077d07c0150b2097f1f5ed197194b6be66369087dcc6e8c069a8c8a08f5688f7510670ba92b71f21713a7771e353b6f2f32f07ff2050d6@127.0.0.1:0","enr":"0xf88fb84069a4ec3dacd9e94a16a63e64b329fd81c61bd7485b97b81e2469e3c26c6844cd09ddfcf98ba00def4ea96b1a61fab34b651e8087daa8b49677211a8bf3b616e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102613e2fd1046ee6d486077d07c0150b2097f1f5ed197194b6be66369087dcc6e8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"plMwJzDfPVj3lpBqk5M6qBSU8liNlIWrdnbsOwzLtCY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a65330\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 6337 5f00 2a0a 20ae | 146 775e (0) 77d2 (0) 7125 (0) 738c (0)\n001 7 df1e d863 e5d7 ec52 | 63 cc20 (0) c9f5 (0) c898 (0) c832 (0)\n002 5 88fe 898d 9d0f 915d | 20 82dd (0) 82f9 (0) 8025 (0) 849b (0)\n003 5 baf2 b502 b5b2 b626 | 17 bcc6 (0) b95d (0) b911 (0) b820 (0)\n004 5 af02 ae2b aeb4 ad98 | 5 af02 (0) ae2b (0) aeb4 (0) ad98 (0)\n005 2 a34e a369 | 2 a34e (0) a369 (0)\n============ DEPTH: 6 ==========================================\n006 1 a46d | 1 a46d (0)\n007 0 | 0\n008 1 a6fb | 1 a6fb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","private_key":"0b39a127c1bcb229d9f78601108abe82d675a725983831143efa53f899d08bdf","name":"node_a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","services":["streamer"],"enable_msg_events":true,"port":43953},"up":true}},{"node":{"info":{"id":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","name":"node_30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","enode":"enode://77bb6be6fe33a79ce2b05a3ea945520fb76c9262e75002a66961e3d27470fec41d9d93ee7fa847b6848f95fbf48806f4e9b0dd1a7e2a75738eaf6ff87e566696@127.0.0.1:0","enr":"0xf88fb8408975a075a76b03b6e862198c62788a23869e631fc2f37775f9a9269229cab59419c1f12dfa51ed37f6993170944a259abdee74afa02303737414e5824a67173a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10277bb6be6fe33a79ce2b05a3ea945520fb76c9262e75002a66961e3d27470fec4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MIl0koJLGVQNE+8XxwhFvm3eRV3KTk+Ez8oUosNzlp8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 308974\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f629 e5d7 d863 df1e | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 3 6ecb 6337 5f00 | 70 7125 (0) 738c (0) 7290 (0) 77d2 (0)\n002 9 1704 1a2a 1c47 1f67 | 44 13d6 (0) 11d4 (0) 103b (0) 154b (0)\n003 9 2ccf 2c38 2d36 2995 | 15 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n004 2 39d1 3f94 | 7 3b88 (0) 3b78 (0) 39d1 (0) 3e8e (0)\n005 4 35e6 3630 378e 3780 | 4 35e6 (0) 3630 (0) 378e (0) 3780 (0)\n006 3 33b5 3373 3237 | 3 33b5 (0) 3373 (0) 3237 (0)\n============ DEPTH: 7 ==========================================\n007 1 314a | 1 314a (0)\n008 0 | 0\n009 0 | 0\n010 1 30be | 1 30be (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","private_key":"dbfd3f618dd2960c68e8eeac259fef1c20d8154f8fcafa4992bc5568c7c8a9d9","name":"node_30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","services":["streamer"],"enable_msg_events":true,"port":38135},"up":true}},{"node":{"info":{"id":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","name":"node_0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","enode":"enode://ecda090f3e2fbbd974141d7beee44746688e9b805c8a76e68f3b4ac9d9e5a22f006596991f82625fa651aebd36ccab7262fd90a08040402982a11b92c8301e4e@127.0.0.1:0","enr":"0xf88fb8400ac80bea14f01369a3774d4c98b4218c5d0d180bda798635c393bdc35befe3c72cca308d1e84b165fd5b1012e749086db6634a096cb618c14645c91e59e906480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ecda090f3e2fbbd974141d7beee44746688e9b805c8a76e68f3b4ac9d9e5a22f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DGTlr4abFmX9QBaubQTI7t1CNjbwbXjsuUTujjJyqCo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0c64e5\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a653 886a 898d f629 | 110 82f9 (0) 82dd (0) 8025 (0) 8505 (0)\n001 3 5f00 6337 6ecb | 70 77d2 (0) 775e (0) 7125 (0) 7290 (0)\n002 4 2d36 2a0a 20ae 3089 | 32 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n003 5 1704 1f67 1e2a 1c47 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 6 0743 0451 0438 00c6 | 11 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n005 2 0af9 0a00 | 3 0b72 (0) 0af9 (0) 0a00 (0)\n006 2 0fc5 0e5e | 3 0ff2 (0) 0fc5 (0) 0e5e (0)\n007 2 0de3 0d8a | 2 0de3 (0) 0d8a (0)\n============ DEPTH: 8 ==========================================\n008 1 0cf5 | 1 0cf5 (0)\n009 1 0c28 | 1 0c28 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","private_key":"7c777cdb8d0d0d9cf6dc20d975185908b22a1774e4e9abf683b3ee25c8ccc5a8","name":"node_0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","services":["streamer"],"enable_msg_events":true,"port":38547},"up":true}},{"node":{"info":{"id":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","name":"node_f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","enode":"enode://f12ee7006d3189d601c33a5aa4d0852e4f5aa621abedc967a106064c05dfb5de7f813d8356ae58fdad01d1453a563482e960120fb92cfa61d3ebba3c9c331b41@127.0.0.1:0","enr":"0xf88fb840d30cb092c1b2933d7cc9b7444ef7da1f3fe07ae780285ecced6998041385ca0d14e88aa1dea59469ff033450bc73e099bc2bb9773d568846e4d640c797590b160183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f12ee7006d3189d601c33a5aa4d0852e4f5aa621abedc967a106064c05dfb5de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9im4ueecdaxVna+b9PyGcr/dWVzyxdF6iIUoJib8ZaU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f629b8\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 6ecb 6337 5f00 3089 | 146 7e04 (0) 7dc2 (0) 7dd3 (0) 7dbb (0)\n001 6 898d 915d 959f b65e | 47 8505 (0) 849b (0) 8025 (0) 82dd (0)\n002 9 c832 c9f5 caf6 c49c | 26 cc20 (0) ca04 (0) caf6 (0) c9f5 (0)\n003 5 e5d7 e8ef ef1b ef07 | 18 e027 (0) e775 (0) e7fa (0) e54b (0)\n004 4 fbf5 ff36 fe21 fe31 | 6 f925 (0) fbc8 (0) fbf5 (0) fe21 (0)\n005 2 f27f f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 4 f4e0 f5b2 f5dc f528 | 6 f456 (0) f45f (0) f4e0 (0) f5b2 (0)\n============ DEPTH: 7 ==========================================\n007 3 f773 f7ba f7fa | 3 f773 (0) f7ba (0) f7fa (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","private_key":"ed331558b7b08a35ac962ee04dd387cf1355874a1e4998244fb9c4530bc3036c","name":"node_f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","services":["streamer"],"enable_msg_events":true,"port":43737},"up":true}},{"node":{"info":{"id":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","name":"node_20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","enode":"enode://e0e6fe997dda2f2ae96f021131f1f3975da9807d14dbb610fd82ef3b8d37ac6934e616d60bf7cdba99b9db2edcb0991febc119d93ad7ff35e4b6ce09903446ae@127.0.0.1:0","enr":"0xf88fb840946c1b232e0d6a23993e1b0b244cc3b22c4f091277d1507a29146bda9aad796e3d1c7dcd6a3de9c37c9355fe2f6a4db100ed11f07d0acfaab3676e42175906470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e0e6fe997dda2f2ae96f021131f1f3975da9807d14dbb610fd82ef3b8d37ac69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IK6xT1Z90W8GsNO1ibgyg9qgCl7RDkR4YL2pRrrM3S0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 20aeb1\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a653 9d0f df1e f7fa | 110 8505 (0) 849b (0) 8025 (0) 82dd (0)\n001 4 4447 5f00 6337 6ecb | 70 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n002 7 03cc 0743 0cf5 0c64 | 44 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n003 6 3f94 3780 3373 3237 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3efc (0)\n004 6 2ccf 2c38 2d36 2995 | 9 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 21a0 217f 2101 | 3 21a0 (0) 217f (0) 2101 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","private_key":"2e8fb7fdd8a9a42774dbb1e04397d0092d1722e16dc44ee9ec98dcceef319366","name":"node_20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","services":["streamer"],"enable_msg_events":true,"port":33621},"up":true}},{"node":{"info":{"id":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","name":"node_2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","enode":"enode://41ce2c9d43b344d3ee113b760fcf2e9254f4e650568be23a964a1cf6e0354ef3616bd129e46a868f713a9a507acdc6b219d5923a7aa09b96092f161d2f76fad4@127.0.0.1:0","enr":"0xf88fb840cb2dee7c73e503707c6b93468e93e8602d07fb552da0e1429d5e05393a553625665eaedb8ac4db4f1fc86bf952d9a3937b0d40f9df2b5d81a6900949b0cc79140183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10241ce2c9d43b344d3ee113b760fcf2e9254f4e650568be23a964a1cf6e0354ef3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KgqOrxonSeaPi4QVeMFgaZz3kH/yOELG1hatiE5fYT4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a0a8e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a653 9d0f d863 df1e | 110 8505 (0) 849b (0) 82dd (0) 82f9 (0)\n001 5 5f00 5db0 4447 6337 | 70 4990 (0) 49ea (0) 49cd (0) 4bcf (0)\n002 6 0743 03cc 0c64 1f67 | 44 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n003 4 3f94 35e6 3780 3089 | 17 39d1 (0) 3b88 (0) 3b78 (0) 3ec5 (0)\n004 3 2101 217f 20ae | 6 24b8 (0) 256e (0) 21a0 (0) 217f (0)\n005 3 2d36 2ccf 2c38 | 5 2f32 (0) 2ccf (0) 2c79 (0) 2c38 (0)\n006 1 2995 | 1 2995 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 2abb 2a97 | 2 2abb (0) 2a97 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","private_key":"5ed9141147ced7a970cf200754db9d56e55104e714e7b8b6ab0372ea8e987b34","name":"node_2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","services":["streamer"],"enable_msg_events":true,"port":37145},"up":true}},{"node":{"info":{"id":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","name":"node_1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","enode":"enode://ce8284583c6db3b9420355ed2e31812b19ceb6157b78b991cf2275cba03fc42a1fc5ca4be2e339ce47a981b7c3fea09fb4ef0489234d5660488ab4cbde59044c@127.0.0.1:0","enr":"0xf88fb84069d4576c9390bdd8b0b134b81758b7b133feddbb1077abc43b3afdf7d3e40e8514903b6f2a002df47f3f977fae861bb7ad48e28cfd6037488e74e727929721ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ce8284583c6db3b9420355ed2e31812b19ceb6157b78b991cf2275cba03fc42a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GioOC7+DzUCTaZVnRBiuRpqiuSh2pM7qvYEo9Ta316I=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1a2a0e\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d863 df1e 9d0f | 110 c26f (0) c1f9 (0) c786 (0) c620 (0)\n001 7 4447 5db0 5f00 6337 | 70 49ea (0) 49cd (0) 4990 (0) 4bcf (0)\n002 4 3089 2101 20ae 2a0a | 32 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n003 5 03cc 0451 0438 0cf5 | 22 0067 (0) 00c6 (0) 02d8 (0) 0328 (0)\n004 2 1400 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n005 6 1e2a 1f85 1f67 1c8a | 6 1e2a (0) 1f85 (0) 1f67 (0) 1c8a (0)\n============ DEPTH: 6 ==========================================\n006 2 19fa 18f6 | 2 19fa (0) 18f6 (0)\n007 1 1b83 | 1 1b83 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","private_key":"66cedc68f62643418971c63cf6032c5cbfd77b99e9d052c406d568d23ad4a0a9","name":"node_1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","services":["streamer"],"enable_msg_events":true,"port":43217},"up":true}},{"node":{"info":{"id":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","name":"node_9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","enode":"enode://12a7d6a36db53d873c0acc5a559d296451cf06d07aa94a306ace9b6043fb3c2d9e1e1c49b9ebfc9564a9611e315d5fb1eb7967526de503234970b110793753da@127.0.0.1:0","enr":"0xf88fb8408f502648e715faaf2434932bad996cfe6aeb6abb2a2ea6e7c78e3397d1b442a6242b093c33df73b486aede52745c085f7081b037099ed3a238e285da2177b9bb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212a7d6a36db53d873c0acc5a559d296451cf06d07aa94a306ace9b6043fb3c2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nQ+ASEm3I5dka6SCCLoeAdz03gTniAFsShoMk+ZQ3fU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9d0f80\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 6337 6ecb 3089 2d36 | 146 4e5a (0) 4c9e (0) 4d59 (0) 4d6b (0)\n001 8 f7fa ff36 ec52 e547 | 63 eb98 (0) e854 (0) e883 (0) e8ef (0)\n002 5 badd b7ca b65e a653 | 27 bcc6 (0) b820 (0) b897 (0) b911 (0)\n003 6 8025 82f9 8f21 88fe | 10 8505 (0) 849b (0) 8025 (0) 82dd (0)\n004 6 9076 90a8 915d 96fc | 6 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n============ DEPTH: 5 ==========================================\n005 2 9852 9890 | 2 9852 (0) 9890 (0)\n006 1 9fa0 | 1 9fa0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","private_key":"5a3b48cfd6ec1d644a7c6a7c880a16141fb04b6362ca8b077c18e25508f97a8a","name":"node_9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","services":["streamer"],"enable_msg_events":true,"port":41537},"up":true}},{"node":{"info":{"id":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","name":"node_df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","enode":"enode://43a859488ad22646b38f98737b2ac09af8c9280038408f13c72deb3aa3bc0405f6d6b9d25961b7a83efe20f7700411dd0c70215ffce26d0b46e6581c902a6a6d@127.0.0.1:0","enr":"0xf88fb84024940eb9de5536da259f0f58a1e16285099071949f0e9ad9ed71742a5af3100c76f2ab3c852b256f9db69e18317adbb05ecf1dcff3e87fed713d59174e0c61780183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10343a859488ad22646b38f98737b2ac09af8c9280038408f13c72deb3aa3bc0405","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3x5ORujsJsrXS081qwcPEsj2/dyjWsRMEhj/YP4ea6s=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: df1e4e\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 5f00 6ecb 3089 2d36 | 146 4990 (0) 49ea (0) 49cd (0) 4bcf (0)\n001 6 b65e a653 ac4d 886a | 47 bcc6 (0) b897 (0) b820 (0) b911 (0)\n002 8 ec52 ef07 ef1b e514 | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 5 c832 c9f5 c59e c49c | 15 c1f9 (0) c26f (0) c786 (0) c6cf (0)\n004 3 d1d7 d7ac d640 | 5 d3b0 (0) d299 (0) d1d7 (0) d7ac (0)\n============ DEPTH: 5 ==========================================\n005 5 daec da67 db6a d887 | 5 daec (0) da67 (0) db6a (0) d887 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","private_key":"374fa339ea3cf4a0d8163261f0d431dfec275bd3323d60ffdd0e99868f234d3b","name":"node_df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","services":["streamer"],"enable_msg_events":true,"port":33131},"up":true}},{"node":{"info":{"id":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","name":"node_1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","enode":"enode://b38f84e3fb5c5995741a2a998215c68d6eee0548072f49bea0d3e3f638779977df96caf15932edea56c8b18e27fb660a269dffcdb628ef6fea0c86a8faa6c560@127.0.0.1:0","enr":"0xf88fb840060e7e6c9c1f7f7cfbf60354cd454fa5d169bf184f13f458845764571079a9e6070092d3d33322c88d0eb91c50376453e016e118f6636745d50bf17b9bee95190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b38f84e3fb5c5995741a2a998215c68d6eee0548072f49bea0d3e3f638779977","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"H2cMU7TFl76v+s2E46aXIlsEze2SGdCijh/lJaPK3PU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1f670c\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ac4d d863 df1e | 110 bcc6 (0) b911 (0) b95d (0) b820 (0)\n001 3 6103 6f5f 6ecb | 70 49cd (0) 49ea (0) 4990 (0) 4bcf (0)\n002 6 3089 2d36 2a0a 2995 | 32 3b88 (0) 3b78 (0) 39d1 (0) 3e8e (0)\n003 6 0c64 0067 03cc 0451 | 22 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n004 4 11d4 14df 154b 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 1436 (0)\n005 3 1b83 1a2a 18f6 | 4 19fa (0) 18f6 (0) 1b83 (0) 1a2a (0)\n006 3 1c8a 1c9c 1c47 | 3 1c8a (0) 1c9c (0) 1c47 (0)\n============ DEPTH: 7 ==========================================\n007 1 1e2a | 1 1e2a (0)\n008 1 1f85 | 1 1f85 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","private_key":"8b2847a2b9e1ffbd91e4f0e7386339eb2dbf3391956547ad876d3d7fafbdda9c","name":"node_1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","services":["streamer"],"enable_msg_events":true,"port":43053},"up":true}},{"node":{"info":{"id":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","name":"node_d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","enode":"enode://f9a61c9819677e84a716705685a63dc1bc77bfc1e9c23cf9127e4e00228d82f7487a4133ee6f5a39686c64e5f95e222dbefdbd0d2c59ea4d4ed69e49843236d5@127.0.0.1:0","enr":"0xf88fb8407f43c74479afec5cde0df2a8e4c7452558c0414e10ac7319c29567d1fe9706597c8d0fac508af58ce2b580e31877a08fa7ea9a712348c98bbf5debbdbb5a3e640183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f9a61c9819677e84a716705685a63dc1bc77bfc1e9c23cf9127e4e00228d82f7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2GO6dAXrB8zdvx0077y+woZ6k6EJ7ZQT2a7PMNNkWmo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d863ba\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 5f00 6ecb 0743 1704 | 146 4bcf (0) 4a8b (0) 4ac7 (0) 4990 (0)\n001 4 898d 9d0f ac4d a653 | 47 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n002 6 ff36 f2d5 f629 f7fa | 37 eb98 (0) e854 (0) e883 (0) e8ef (0)\n003 8 c26f c786 c441 c49c | 15 c1f9 (0) c26f (0) c620 (0) c6cf (0)\n004 3 d299 d7ac d640 | 5 d1d7 (0) d3b0 (0) d299 (0) d7ac (0)\n005 1 df1e | 1 df1e (0)\n============ DEPTH: 6 ==========================================\n006 3 daec da67 db6a | 3 daec (0) da67 (0) db6a (0)\n007 0 | 0\n008 1 d887 | 1 d887 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","private_key":"8febd8aeb1300031923fe49da5869050860d96d11eb4508c497687c8ccddc31f","name":"node_d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","services":["streamer"],"enable_msg_events":true,"port":39911},"up":true}},{"node":{"info":{"id":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","name":"node_2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","enode":"enode://5a16cc82bdff422be5114cecf38c16efaa5cf372e4b9da981b04bf795e5d6dd58f2128d1ea860d1fc5ab50341562b3fe220930224978c5fc9cc470236e731f8a@127.0.0.1:0","enr":"0xf88fb8402065a0e31a085320c01f09fe4cac1f3443c89d2aa42a78120ab8af3197c6c3a00501e91b9adefc7a55eccc59b6a25a614cea33a121aa6e794419d8a9990d90ce0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025a16cc82bdff422be5114cecf38c16efaa5cf372e4b9da981b04bf795e5d6dd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LTZFxP35ooCakJB2ue5fuY+ogPb67/kU8aKYevkozXk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2d3645\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ac4d 9d0f ff36 f629 | 110 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n001 2 5f00 6ecb | 70 4bcf (0) 4a8b (0) 4ac7 (0) 49cd (0)\n002 4 1f67 1704 0c64 0451 | 44 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n003 7 39d1 3b78 3f94 35e6 | 17 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n004 3 20ae 217f 2101 | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 4 2995 2abb 2a97 2a0a | 4 2abb (0) 2a97 (0) 2a0a (0) 2995 (0)\n006 1 2f32 | 1 2f32 (0)\n============ DEPTH: 7 ==========================================\n007 3 2c79 2c38 2ccf | 3 2ccf (0) 2c79 (0) 2c38 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","private_key":"60acfdf5adccd8cecfff6c7041a09ca32eaa3aa3a70df16eb20f58826c441ecd","name":"node_2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","services":["streamer"],"enable_msg_events":true,"port":41863},"up":true}},{"node":{"info":{"id":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","name":"node_6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","enode":"enode://04684e9608ae1597b26dcf982a1102e6cdd9d2437b9b0d2e4dc0c1acada0b112d11b3d80dd326baea3005f626e94985b91e0cca937f63323a0ff9dd434f31601@127.0.0.1:0","enr":"0xf88fb8401c006cfaa1eed4491442b8516c8bdf525694e5c4b6e1e65cfd0409927b90027e5242612b7461f7b42127f5f0de749f08eec7d18fe8b3292fdf06dd809f43c4d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10304684e9608ae1597b26dcf982a1102e6cdd9d2437b9b0d2e4dc0c1acada0b112","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bstcNvwBUMKHRGroqGgtYpodOTQSMHFyBiGbq+O99lk=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ecb5c\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 898d 9d0f f629 ff36 | 110 eb98 (0) e854 (0) e883 (0) e8ef (0)\n001 12 0c64 03cc 0743 0451 | 76 0af9 (0) 0a00 (0) 0b72 (0) 0ff2 (0)\n002 8 58ed 5f00 5db0 5308 | 38 49cd (0) 49ea (0) 4990 (0) 4bcf (0)\n003 5 7290 77d2 775e 7b90 | 12 7125 (0) 738c (0) 7290 (0) 77d2 (0)\n004 2 6337 6103 | 9 67dc (0) 67aa (0) 66e7 (0) 605a (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c4d 6c73 | 2 6c73 (0) 6c4d (0)\n007 3 6fe9 6f2d 6f5f | 3 6fe9 (0) 6f2d (0) 6f5f (0)\n============ DEPTH: 8 ==========================================\n008 2 6e68 6e05 | 2 6e68 (0) 6e05 (0)\n009 1 6ea5 | 1 6ea5 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","private_key":"6ccda16d24593d76eeb7948a4af3fb05397678300cffc7c91a33b30131038c07","name":"node_6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","services":["streamer"],"enable_msg_events":true,"port":45685},"up":true}},{"node":{"info":{"id":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","name":"node_21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","enode":"enode://98c213523753d4a7653cb5b73bab12b51338713fea9dc6f12a63a8336614c389ffdf44b011e51bd2c8083da8e80e4f1918739bbae11667d68f310f526fd020cb@127.0.0.1:0","enr":"0xf88fb840abbddde7f121cefe95a32471993c96b1df78fac759c6d32c3c2f3a5442d3b96d0f4cb71c4dabeadd6ea7962640f6d04e731dc0b3d6f37c63316c9e7b10919cd40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10398c213523753d4a7653cb5b73bab12b51338713fea9dc6f12a63a8336614c389","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IQEqOm7x7OSP2dfP/mLcdYOd0GLvzzrF+WLCN4FNpAc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 21012a\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 df1e ff36 9d0f ac4d | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 5 51db 5f00 6337 6103 | 70 49ea (0) 49cd (0) 4990 (0) 4bcf (0)\n002 5 0451 1f67 1a2a 18f6 | 44 0a00 (0) 0af9 (0) 0b72 (0) 0ff2 (0)\n003 5 3b78 39d1 3f94 35e6 | 17 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n004 8 2a0a 2a97 2995 2f32 | 9 2abb (0) 2a97 (0) 2a0a (0) 2995 (0)\n005 2 256e 24b8 | 2 256e (0) 24b8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 20ae | 1 20ae (0)\n008 1 21a0 | 1 21a0 (0)\n009 1 217f | 1 217f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","private_key":"0c649ddaf655f9e8eee8b3a2d2050c9b93305a4e7a28f3684f68aee88ab0ef2e","name":"node_21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","services":["streamer"],"enable_msg_events":true,"port":38963},"up":true}},{"node":{"info":{"id":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","name":"node_17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","enode":"enode://319cd6619ea64ca816341d84c8b1ca4aa41b3a0eca34fbdf923acd1396287078e2808d85b58fbb61dbffc5c14b726c002731803095ec20ebe8079edf94ef274c@127.0.0.1:0","enr":"0xf88fb8402778c296526d28fd3bd0b985c90367db08c61a457ddf60dd9e79024d56fdd6dc78b02d84ec47cdabda998e2326ffca652eeb8fad6517d8e5238bdacffc6fdeba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102319cd6619ea64ca816341d84c8b1ca4aa41b3a0eca34fbdf923acd1396287078","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FwQKOq1ZMNjg3hAR/SmWt9CSJZifDcGuj356Ut0mq04=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 17040a\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d863 ff36 898d ac4d | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 3 5db0 6f5f 6ecb | 70 4990 (0) 49cd (0) 49ea (0) 4bcf (0)\n002 6 3089 2d36 2c38 2995 | 32 3b88 (0) 3b78 (0) 39d1 (0) 3e8e (0)\n003 8 0e5e 0cf5 0c64 03cc | 22 0b72 (0) 0af9 (0) 0a00 (0) 0ff2 (0)\n004 6 1c47 1e2a 1f67 1b83 | 10 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n005 2 103b 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 4 154b 1436 1400 14df | 4 154b (0) 1436 (0) 1400 (0) 14df (0)\n007 2 165f 1672 | 2 165f (0) 1672 (0)\n============ DEPTH: 8 ==========================================\n008 2 179f 17db | 2 179f (0) 17db (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","private_key":"6fd569b047d43c53be962cedfa9155cbdd5b612bf6ae51d3b02aa8c1bab608c1","name":"node_17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","services":["streamer"],"enable_msg_events":true,"port":38715},"up":true}},{"node":{"info":{"id":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","name":"node_04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","enode":"enode://52bb359e4ef492631139b8f55c6bd84f6fdf764b06373ff664baec44a296aefa8a30ce0f4a3792af214e4f1025f5d4f5d67c52b754720ee7f8cff0b069716439@127.0.0.1:0","enr":"0xf88fb840cab6c885934f1ff7d8d41a71e525765c7eec705d6d47779bc453c39f000c9be43e5d2c812ef5c9fddbf705cfba32604383775a77297727a3b98fbe0937845b110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10352bb359e4ef492631139b8f55c6bd84f6fdf764b06373ff664baec44a296aefa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BFGNcSD6ilKNmDyh7m1dCbokpOhT+yK8kITN80mV6V8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 04518d\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fe31 ff36 898d ac4d | 110 c1f9 (0) c26f (0) c786 (0) c6cf (0)\n001 4 5db0 6f5f 6ecb 6103 | 70 4990 (0) 49cd (0) 49ea (0) 4bcf (0)\n002 5 2101 2a97 2995 2d36 | 32 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n003 6 1f67 1e2a 1c47 1a2a | 22 1c8a (0) 1c9c (0) 1c47 (0) 1e2a (0)\n004 5 0a00 0b72 0e5e 0cf5 | 11 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n005 3 02d8 03cc 0067 | 5 00c6 (0) 0067 (0) 02d8 (0) 0328 (0)\n006 2 0661 0743 | 3 0661 (0) 07a8 (0) 0743 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 0438 | 1 0438 (0)\n010 0 | 0\n011 0 | 0\n012 1 045b | 1 045b (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","private_key":"2e166ac09eefef316a31e45dc6fa94185d8d91cc1d537f03044c7cb46ab00347","name":"node_04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","services":["streamer"],"enable_msg_events":true,"port":33881},"up":true}},{"node":{"info":{"id":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","name":"node_610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","enode":"enode://27461fddb23d01661d9e0752253b5f1ff25fd09606c0f07fd3161be1d08015a00addcfe28ebcdd5bd3974ce43579047df1d16e2de978b55a62885a3f9b919aeb@127.0.0.1:0","enr":"0xf88fb8402aa36d20ffb02eb4363c646927544d3ef64e739c150d0cf86e67c9f1e55d968171dc7a65d680a25f704a35163488cb3427ded17d666bdb22ef7be92242260d3c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10327461fddb23d01661d9e0752253b5f1ff25fd09606c0f07fd3161be1d08015a0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YQM0oHctNBRlK1dfLKpvLbMiJJB8JNBv2mQ9ufLsKv4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 610334\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ff36 898d ac4d | 110 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n001 7 2101 2995 2c38 1f67 | 76 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n002 8 4109 461c 4d10 5308 | 38 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n003 6 7dd3 7dbb 7920 7a60 | 12 775e (0) 77d2 (0) 7290 (0) 738c (0)\n004 5 6fe9 6f5f 6e68 6e05 | 11 6967 (0) 6831 (0) 6c4d (0) 6c73 (0)\n005 3 66e7 67aa 67dc | 3 66e7 (0) 67aa (0) 67dc (0)\n006 3 6251 628e 6337 | 3 6251 (0) 628e (0) 6337 (0)\n============ DEPTH: 7 ==========================================\n007 2 60d7 605a | 2 60d7 (0) 605a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","private_key":"a239693a1557643d38ba187a95721a30768f347591e6f8868b289ec3f95b5e3f","name":"node_610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","services":["streamer"],"enable_msg_events":true,"port":46809},"up":true}},{"node":{"info":{"id":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","name":"node_ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","enode":"enode://134ad215979bb59e0854da374768a63faad6b7322ab9e96996f9d5121bf3f3093736c2b9e465cc3141fe55ae189e6e708af53bdb2f165ddfb934adbfd15f8b13@127.0.0.1:0","enr":"0xf88fb8400b13e5d05cf91166873c521a1779fec8d2519ba5960b369a7ca65f83fcc01cea397a6dec2e9098a898ae93a78056944abf096f46e1a62592a7d067b013da30f00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103134ad215979bb59e0854da374768a63faad6b7322ab9e96996f9d5121bf3f309","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rE0taDbizfTIgiH2ATqscKRR3RW8QDKIvRDQuRHNmis=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ac4d2d\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 2c38 2d36 2a97 2995 | 146 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n001 6 c832 df1e d863 f629 | 63 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n002 3 959f 9d0f 898d | 20 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n003 6 b5b2 b626 b65e ba88 | 17 bcc6 (0) b897 (0) b820 (0) b95d (0)\n004 2 a369 a653 | 5 a34e (0) a369 (0) a46d (0) a6fb (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 af02 aeb4 ae2b | 3 af02 (0) aeb4 (0) ae2b (0)\n007 1 ad98 | 1 ad98 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","private_key":"aaaa8d07b535646ac07aef1d6dbe233da8938015e1fbb22d29bb1667cccdbd9c","name":"node_ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","services":["streamer"],"enable_msg_events":true,"port":44875},"up":true}},{"node":{"info":{"id":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","name":"node_ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","enode":"enode://caea642b8d5bd71c4dc4f25c29351b369cae4b0b2cc5c09805f09dbe91dff565c639652d2997ef93df5a8814a088dcb6eeb10cde26ef5114f39f86f96c61dfe1@127.0.0.1:0","enr":"0xf88fb840a8727941728a486f3f2399e65bacb4139c6b4ffcda9c78b7ba54db0561b8b3496543e9ac4ddc130e407c629d8346439a2ac645f858ff17da07fa89b93e4cfbe00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103caea642b8d5bd71c4dc4f25c29351b369cae4b0b2cc5c09805f09dbe91dff565","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/zaogQ3UT20fpCqpH/Yga8+0wf+6sN9zoYHa7OMp4OM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ff36a8\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 6f5f 6ecb 6103 18f6 | 146 1c9c (0) 1c8a (0) 1c47 (0) 1e2a (0)\n001 5 9d0f 886a 898d ad98 | 47 96fc (0) 976e (0) 959f (0) 9076 (0)\n002 5 c786 c9f5 c832 d863 | 26 c26f (0) c1f9 (0) c6cf (0) c620 (0)\n003 5 e514 e5d7 ec52 ef1b | 18 e027 (0) e775 (0) e7fa (0) e54b (0)\n004 9 f31c f2d5 f528 f5dc | 13 f31c (0) f27f (0) f2d5 (0) f45f (0)\n005 3 fbf5 fbc8 f925 | 3 fbf5 (0) fbc8 (0) f925 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 fe21 fe31 | 2 fe21 (0) fe31 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","private_key":"2e244474154628879e0fe12f4e3f1fbd5803d0a643d609efa8b704912812cd68","name":"node_ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","services":["streamer"],"enable_msg_events":true,"port":44299},"up":true}},{"node":{"info":{"id":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","name":"node_2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","enode":"enode://47952da4c6b64e3f0d74a7444c626ac5ec1dc5cc34a4a62e8cbfb6016015afddb5e37081dbee4fd825dddc79d455d4ed6e589e93bb20b43dd9be174c885c9a19@127.0.0.1:0","enr":"0xf88fb840adbbd5eaf9c32e9a2af15ed32ea2cfb62da1704c409d35e7467a4a3290586ef679381b40e61f36d843e27f7fa96add6a5c419f50d30455c897732b2ba0a615b80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10347952da4c6b64e3f0d74a7444c626ac5ec1dc5cc34a4a62e8cbfb6016015afdd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LDiUtuR88ZrH7p/iExljEvZ2JW9nDf8lsDVjSSVQvHQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c3894\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ff36 ac4d 898d | 110 d299 (0) d3b0 (0) d1d7 (0) d7ac (0)\n001 6 4447 461c 51db 5f00 | 70 775e (0) 77d2 (0) 7125 (0) 738c (0)\n002 5 18f6 1e2a 1704 0067 | 44 0b72 (0) 0af9 (0) 0a00 (0) 0fc5 (0)\n003 8 39d1 3f94 3373 3237 | 17 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n004 3 20ae 217f 2101 | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 4 2abb 2a97 2a0a 2995 | 4 2a0a (0) 2abb (0) 2a97 (0) 2995 (0)\n006 1 2f32 | 1 2f32 (0)\n007 1 2d36 | 1 2d36 (0)\n============ DEPTH: 8 ==========================================\n008 1 2ccf | 1 2ccf (0)\n009 1 2c79 | 1 2c79 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","private_key":"1fb0fb0f5bfcd2c5012cb4dcbf3d383d99034d7fc8646fe2fa0239e1f7b51453","name":"node_2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","services":["streamer"],"enable_msg_events":true,"port":33033},"up":true}},{"node":{"info":{"id":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","name":"node_898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","enode":"enode://29ee8c7cc132a4f84a34e6c9a61e9f98998e563662619c46f89e5a5c92e5b62c66230acaaf18ebc8b957a8a49a939fb01da5f5a3493fc7730cfc9e060c72b79f@127.0.0.1:0","enr":"0xf88fb840293b9155cb46e3fe29d5d357c867f2782ac2bc5187314b335ebef943733badfd73796b642fdbc11e618e294d62120f11f47d2c59854f164e09788562a607f4ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329ee8c7cc132a4f84a34e6c9a61e9f98998e563662619c46f89e5a5c92e5b62c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iY0vfUa0lhtkbVphQtVNYjO3+A9mjOI0Ui3QLizFRcs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 898d2f\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 5db0 6103 6ecb 2a97 | 146 775e (0) 77d2 (0) 738c (0) 7290 (0)\n001 7 df1e d863 c441 c832 | 63 d1d7 (0) d3b0 (0) d299 (0) d7ac (0)\n002 7 b7ca b65e badd ba88 | 27 bcc6 (0) b820 (0) b897 (0) b95d (0)\n003 5 90a8 915d 976e 959f | 10 96fc (0) 976e (0) 959f (0) 915d (0)\n004 5 8505 849b 8025 82dd | 5 8505 (0) 849b (0) 8025 (0) 82dd (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 886a 88fe 88a1 | 3 88a1 (0) 88fe (0) 886a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","private_key":"25e10afa4ffc02c1856aaba9b6fa69c4caf4ae6c8d973c1750b152061c409dad","name":"node_898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","services":["streamer"],"enable_msg_events":true,"port":35709},"up":true}},{"node":{"info":{"id":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","name":"node_18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","enode":"enode://df37042646f5b0435bb902440a5d413958bd9962f689e0d6961bae39f3d57cb89b2d3d68f1c1fabd9e003f19da6adafaa8ff0562d694b0971ef0f8e2e0f86ed0@127.0.0.1:0","enr":"0xf88fb84034efdfae1a4a243bc8ceefd19e7c4e762ea36361737f82c06ef963c92c4d112353472336b474557faf93d9ce5a1c58bd8b9bcba68785b4e52629ee8ffd7354590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102df37042646f5b0435bb902440a5d413958bd9962f689e0d6961bae39f3d57cb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GPbmbhzI5iCAiQG1cf31Je6PQYUPrAvQ5cWk3nDF+HM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 18f6e6\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ff36 df1e c832 ad98 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 2 5db0 6103 | 70 775e (0) 77d2 (0) 7290 (0) 738c (0)\n002 3 2101 2c38 2a97 | 32 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n003 6 0b72 0e5e 0cf5 03cc | 22 0a00 (0) 0af9 (0) 0b72 (0) 0ff2 (0)\n004 3 11d4 154b 1704 | 12 13d6 (0) 103b (0) 11d4 (0) 1436 (0)\n005 5 1c9c 1c47 1f85 1f67 | 6 1c8a (0) 1c9c (0) 1c47 (0) 1f85 (0)\n============ DEPTH: 6 ==========================================\n006 2 1a2a 1b83 | 2 1b83 (0) 1a2a (0)\n007 1 19fa | 1 19fa (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","private_key":"f7529dd416080bdc3c1016be896cd1e6d87fb71bc55f747c44045c3c9402c95b","name":"node_18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","services":["streamer"],"enable_msg_events":true,"port":43611},"up":true}},{"node":{"info":{"id":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","name":"node_2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","enode":"enode://c54171c617812d43a66bacc6697a272aefbfe1ea882f9a9842b2e79e50d9db13428c9eaff2ffcfc8e81379c05ecfb7c2ffbf49be202d77295d7a5fec2acb9871@127.0.0.1:0","enr":"0xf88fb840eaa8f6fbd8efdf7f4ac5c88ea73f5cee6af1b1758a94af489c271983e5bb2c4f3bb50aeb95ce0a622acd1b27df421f79272a7b9c7586105d10d13eff4da67a590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c54171c617812d43a66bacc6697a272aefbfe1ea882f9a9842b2e79e50d9db13","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KpfTCKcgJ0pEDfppAcoKVICvm6tY3YpsSv25yD6pZMM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a97d3\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 898d ad98 ac4d c832 | 110 9076 (0) 90a8 (0) 915d (0) 96fc (0)\n001 4 6f5f 461c 51db 5db0 | 70 7125 (0) 7290 (0) 738c (0) 775e (0)\n002 5 0e5e 0451 0067 1704 | 44 0a00 (0) 0af9 (0) 0b72 (0) 0de3 (0)\n003 7 39d1 3f94 35e6 3630 | 17 314a (0) 30be (0) 3089 (0) 3237 (0)\n004 3 20ae 2101 217f | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 5 2f32 2ccf 2c79 2c38 | 5 2f32 (0) 2d36 (0) 2ccf (0) 2c79 (0)\n006 1 2995 | 1 2995 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 2a0a | 1 2a0a (0)\n009 0 | 0\n010 1 2abb | 1 2abb (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","private_key":"2b2842453e6ed09eca9428c5db19b8b65672776bc2596ca6a169f7e0c1f3267e","name":"node_2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","services":["streamer"],"enable_msg_events":true,"port":37171},"up":true}},{"node":{"info":{"id":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","name":"node_29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","enode":"enode://3d3730044b8ce4d12ccf3b85eb20d027bf821a3bc0bba763f66d0e201835ec7251c7e983adadb9fc9ad2fb49970947d933cfe6879c5177ee537e2296f637da44@127.0.0.1:0","enr":"0xf88fb840d429fc88603170892285ce1f6086380d3216e336fd781e762f59b9bafe65394e20fb7f1b86aa2fa9cb38deb354e1d1f709002da5bc651bfefc311dac483657af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023d3730044b8ce4d12ccf3b85eb20d027bf821a3bc0bba763f66d0e201835ec72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KZV+jpKSWox5vfUTKV2Wv7Yvv8WX7hz3Z8fvQI8bEpU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 29957e\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ef07 ff36 c832 ac4d | 110 e027 (0) e775 (0) e7fa (0) e5d7 (0)\n001 4 461c 5db0 6103 6f5f | 70 4bcf (0) 4ac7 (0) 4a8b (0) 49cd (0)\n002 5 1704 1f67 02d8 0067 | 44 1c8a (0) 1c9c (0) 1c47 (0) 1e2a (0)\n003 6 3b78 3f94 3089 3237 | 17 314a (0) 30be (0) 3089 (0) 3237 (0)\n004 3 20ae 217f 2101 | 6 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n005 4 2d36 2ccf 2c79 2c38 | 5 2f32 (0) 2d36 (0) 2ccf (0) 2c79 (0)\n============ DEPTH: 6 ==========================================\n006 3 2a0a 2abb 2a97 | 3 2a0a (0) 2abb (0) 2a97 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","private_key":"ecb685b96196b2b1ed90974c8c85cfed18d6274a7639640eecea3d33df729790","name":"node_29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","services":["streamer"],"enable_msg_events":true,"port":40859},"up":true}},{"node":{"info":{"id":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","name":"node_6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","enode":"enode://86a0201b07812ffcb8509f76f8966046bb1d05e0aee48cb884b9929d0a20359fe1ac35441ba1519a58dbfa6590727410bae272f3d71a30b917d894e1e5cc8989@127.0.0.1:0","enr":"0xf88fb8401f19a5134f5248a512cc0875add535eef2498e2fac24985b79b3428e94f87a440936fb0de43a4848b4b08bb438377153809518e99bd2b3b41ab92877893578fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10386a0201b07812ffcb8509f76f8966046bb1d05e0aee48cb884b9929d0a20359f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"b19ad+YJLiXlMIQT4CumLBxVkCSJOn+5jiaw80/ti/4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6f5f5a\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 ef07 f7ba ff36 c9f5 | 110 fbf5 (0) fbc8 (0) f925 (0) fe21 (0)\n001 8 0451 0743 1f67 1e2a | 76 1c9c (0) 1c8a (0) 1c47 (0) 1e2a (0)\n002 9 4d10 4109 4646 461c | 38 4bcf (0) 4a8b (0) 4ac7 (0) 49cd (0)\n003 2 77d2 7a60 | 12 738c (0) 7290 (0) 7125 (0) 775e (0)\n004 2 6337 6103 | 9 66e7 (0) 67dc (0) 67aa (0) 628e (0)\n005 2 6967 6831 | 2 6967 (0) 6831 (0)\n006 2 6c4d 6c73 | 2 6c4d (0) 6c73 (0)\n007 4 6e68 6e05 6ea5 6ecb | 4 6e68 (0) 6e05 (0) 6ea5 (0) 6ecb (0)\n============ DEPTH: 8 ==========================================\n008 1 6fe9 | 1 6fe9 (0)\n009 1 6f2d | 1 6f2d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","private_key":"92f754c50871b54e305f835a6faf7722bfb219adcd6aea6b430a4fe082d5dca5","name":"node_6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","services":["streamer"],"enable_msg_events":true,"port":38657},"up":true}},{"node":{"info":{"id":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","name":"node_886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","enode":"enode://d5df6e2d4f88e0e6096cd3273f0008286a9f7a36e5c6705f89116595e4ea8c52e37570e6afe957ff70d0a32871c3e5a6a3ab64e9d2927eeba8ef68030010c6c4@127.0.0.1:0","enr":"0xf88fb840f7ff3872ab2265f9c5aafbf228e1003c7903bf3c757e67fdff401a6bfd8a886223114715cada6784003648d4e7484150b8ec46c245a46acf0330afde54cefd7e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d5df6e2d4f88e0e6096cd3273f0008286a9f7a36e5c6705f89116595e4ea8c52","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iGr/Hx47hr/pAQZrt5SEUcGP4/jNG3MYsFFUiQyo9zg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 886aff\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0c64 0067 2995 461c | 146 1c8a (0) 1c9c (0) 1c47 (0) 1e2a (0)\n001 8 fe31 ff36 f7fa f7ba | 63 fbf5 (0) fbc8 (0) f925 (0) fe21 (0)\n002 5 b65e b7ca ba88 badd | 27 b2b5 (0) b2a5 (0) b02b (0) b502 (0)\n003 4 959f 915d 90a8 9d0f | 10 96fc (0) 976e (0) 959f (0) 915d (0)\n004 4 8505 82f9 82dd 8025 | 5 8025 (0) 82dd (0) 82f9 (0) 849b (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 898d | 1 898d (0)\n008 2 88a1 88fe | 2 88a1 (0) 88fe (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","private_key":"4cb5893d2151dd13ceab60cbb42058108639b9cc2b3914cbc6145530b864a491","name":"node_886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","services":["streamer"],"enable_msg_events":true,"port":39861},"up":true}},{"node":{"info":{"id":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","name":"node_5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","enode":"enode://a13bd5a44dd15b8d08f8dd72bb7a2c87930d339c65d0073457d89576d4efa9aae2dc8c1cf98cf1849ffbb3025d74e4ba6d7ab69d0f7de9a01b3fcd1c33602678@127.0.0.1:0","enr":"0xf88fb840c81df54245181d95cd7921f23a74ae3d33fd56b42989c6460164f5738ac8b5153164e33366793fcadd86b527e176f78b30442e14f9d726c55e28e808ff75a6860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a13bd5a44dd15b8d08f8dd72bb7a2c87930d339c65d0073457d89576d4efa9aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XbCENsZPTMnis5UONbyK1zmCXj76Z6ZCx3HZWzTLQgw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5db084\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f7ba ad98 898d 886a | 110 f925 (0) fbf5 (0) fbc8 (0) fe21 (0)\n001 9 1704 1a2a 18f6 0451 | 76 1c8a (0) 1c9c (0) 1c47 (0) 1f85 (0)\n002 4 6337 6103 6ecb 6f5f | 32 775e (0) 77d2 (0) 738c (0) 7290 (0)\n003 3 4d10 4447 461c | 23 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n004 2 5308 51db | 8 574f (0) 524d (0) 53a8 (0) 53fe (0)\n005 3 58ed 5823 5b63 | 3 5b63 (0) 5823 (0) 58ed (0)\n============ DEPTH: 6 ==========================================\n006 2 5efb 5f00 | 2 5efb (0) 5f00 (0)\n007 1 5cd2 | 1 5cd2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","private_key":"3ded975bfe84c252cd54697144ffcd0ac6978fc1c80ab6663d4c0b2cb7338d2a","name":"node_5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","services":["streamer"],"enable_msg_events":true,"port":34077},"up":true}},{"node":{"info":{"id":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","name":"node_ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","enode":"enode://909113f035bbc97985e3d769ea806d56160d43b644c84bde7c5f980a314c36cf1016ceab475ccd4f4bda05f0e4143c2d74ac98f7f9ccb910d7864406f2f8865e@127.0.0.1:0","enr":"0xf88fb840148b90cf90d9ca81f69924d5705f155d5adc230d87a2b48d4b1bdedf4936c9a8421003eef921a088bbc6e7b5cdf66d0f50b88dadfff07ee128418404cc5314c90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102909113f035bbc97985e3d769ea806d56160d43b644c84bde7c5f980a314c36cf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rZiZ94ZZSS7CSKiEknp1fz87TnbNKrxGrYdmJR/Yr+0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ad9899\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 2a97 18f6 0067 6f5f | 146 314a (0) 30be (0) 3089 (0) 3237 (0)\n001 6 fe31 ff36 f7ba ef07 | 63 fbc8 (0) fbf5 (0) f925 (0) fe21 (0)\n002 3 9076 898d 886a | 20 96fc (0) 976e (0) 959f (0) 915d (0)\n003 6 b5b2 b7ca bb90 badd | 17 bcc6 (0) b820 (0) b897 (0) b95d (0)\n004 4 a369 a46d a6fb a653 | 5 a46d (0) a6fb (0) a653 (0) a34e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 af02 ae2b aeb4 | 3 af02 (0) aeb4 (0) ae2b (0)\n007 1 ac4d | 1 ac4d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","private_key":"c8586e1c253506ff671677e75e7d636dfd48f90798d59c6b42bfb77250056cba","name":"node_ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","services":["streamer"],"enable_msg_events":true,"port":33071},"up":true}},{"node":{"info":{"id":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","name":"node_c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","enode":"enode://76942d9ce0d444b30dbb6499273c4aca434d908d0bbe244316cd5621a4921967b8be1024dc9585544e08d91e53aa2e00ad209181beffa6caccc40b66f975dc55@127.0.0.1:0","enr":"0xf88fb840bf9df113c1a80e0937a0f28c991d4bb2c73ebc27ac1aa51c6db9806d3de0ec1439b8249fa929666c4c5b8cfee951e52e670ec77c7a2d5ec4ecd12bc3609e127e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10376942d9ce0d444b30dbb6499273c4aca434d908d0bbe244316cd5621a4921967","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yDK0rWShfaS3lv/KxkbCqmZrJ2qrt+s7/nmB1kpNpAI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c832b4\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 18f6 0067 2a97 2995 | 146 314a (0) 30be (0) 3089 (0) 3237 (0)\n001 4 898d 886a ac4d ad98 | 47 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n002 9 e514 ec52 ef1b ef07 | 37 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n003 4 d3b0 df1e d887 d863 | 11 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n004 3 c620 c786 c441 | 9 c1f9 (0) c26f (0) c6cf (0) c620 (0)\n005 1 cc20 | 1 cc20 (0)\n006 2 ca04 caf6 | 2 ca04 (0) caf6 (0)\n============ DEPTH: 7 ==========================================\n007 1 c9f5 | 1 c9f5 (0)\n008 1 c898 | 1 c898 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","private_key":"c35521b3ce161ef9f4891093a65fe799e2f359c3418a145bbe0b8d59330fd18a","name":"node_c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","services":["streamer"],"enable_msg_events":true,"port":41037},"up":true}},{"node":{"info":{"id":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","name":"node_461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","enode":"enode://7edde69d3daf04827701687380c3a97d52cdc2358ddae6c097ff34bc5eeeeac0aa926cd6fb97c888a0c344fb17b07929f21de48835de2a3c805e343f66814cf2@127.0.0.1:0","enr":"0xf88fb84011bf54c1453a78871d09dfbf3b20f2efedcd347c5a3fce32edf95929f083231527adad0d0e0ceb8cad68d1bcb7dc5c32ead8fd94aca4aca3e9bb6abc8b1bce3b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027edde69d3daf04827701687380c3a97d52cdc2358ddae6c097ff34bc5eeeeac0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RhzJ8GTm9PBv844NHz8A74gHujHHJY5FPMaC6VUbscY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 461cc9\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ad98 886a ef07 c9f5 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 7 0067 3f94 3237 3373 | 76 314a (0) 30be (0) 3089 (0) 3237 (0)\n002 3 6103 6ecb 6f5f | 32 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n003 6 5308 51db 58ed 5f00 | 15 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n004 2 4e5a 4d10 | 11 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n005 2 41d9 4109 | 2 41d9 (0) 4109 (0)\n006 3 4558 44a1 4447 | 4 4559 (0) 4558 (0) 44a1 (0) 4447 (0)\n007 2 4782 47bf | 2 4782 (0) 47bf (0)\n008 1 46fe | 1 46fe (0)\n============ DEPTH: 9 ==========================================\n009 1 4646 | 1 4646 (0)\n010 1 4636 | 1 4636 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","private_key":"af9f5d0414462a64a90ff3a2fee02742a99043e9971bd04754fbca5a117064c8","name":"node_461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","services":["streamer"],"enable_msg_events":true,"port":45431},"up":true}},{"node":{"info":{"id":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","name":"node_ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","enode":"enode://2d13e3fbcf2f401951af67ee410e6785e91904619b76822ce4337ddae7965c663773cfd671554e0c6ede7518907b8911f6676b5565313b08c451c90a8dcba823@127.0.0.1:0","enr":"0xf88fb84024126a4f41bfdaa7a672735c056cbdcd6917db518e518e9ad6d43d687a7275bb61f0232ccea5eeefd3ee8ffa770501c2a89ba614f63ec29b1f2ac08ba2bb5b8c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032d13e3fbcf2f401951af67ee410e6785e91904619b76822ce4337ddae7965c66","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7we+VZkU7EtZMNkNjYtvMtq566I6zDbxTVEjB/mXQ0g=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ef07be\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2a97 2995 0067 6f5f | 146 314a (0) 30be (0) 3089 (0) 3237 (0)\n001 4 8f21 886a badd ad98 | 47 976e (0) 96fc (0) 959f (0) 915d (0)\n002 3 df1e c9f5 c832 | 26 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n003 6 ff36 fe31 f2d5 f629 | 19 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n004 2 e5d7 e514 | 8 e027 (0) e7fa (0) e775 (0) e5ad (0)\n005 4 eb98 e854 e883 e8ef | 4 eb98 (0) e854 (0) e883 (0) e8ef (0)\n006 2 ed2d ec52 | 2 ed2d (0) ec52 (0)\n007 1 ee5e | 1 ee5e (0)\n============ DEPTH: 8 ==========================================\n008 1 efea | 1 efea (0)\n009 0 | 0\n010 0 | 0\n011 1 ef1b | 1 ef1b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","private_key":"cffbac62882babf0b4dfc14cd40307088b5ce5ccaa138a4f172914575e6393a3","name":"node_ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","services":["streamer"],"enable_msg_events":true,"port":38781},"up":true}},{"node":{"info":{"id":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","name":"node_006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","enode":"enode://f73c1f0ca14af6b0b8fb1eba1c49d0d653a7833cb03dd69d112260a24154d15515ed2fa276e27d6e70ac92d7f11b594ce55a25be21a9637d56289ac3b2294306@127.0.0.1:0","enr":"0xf88fb8400367dfb7465473b46b2a6502bf1f47fd2b2fe0f11e74a750c1c44e3d798efceb606a9f68a49de5f6c4d6a5606653c80257a8f993dd8f600042cbb5cea1b908ab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f73c1f0ca14af6b0b8fb1eba1c49d0d653a7833cb03dd69d112260a24154d155","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AGcn3G9ZsSCyTBe45j+A7zQ5EF+BGP/u1AjxBaSO5gw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 006727\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 886a ad98 c832 fe31 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 4 461c 51db 58ed 5db0 | 70 775e (0) 77d2 (0) 7290 (0) 738c (0)\n002 3 2c38 2a97 2995 | 32 314a (0) 30be (0) 3089 (0) 3237 (0)\n003 6 11d4 14df 1704 18f6 | 22 13d6 (0) 103b (0) 11d4 (0) 154b (0)\n004 7 0af9 0a00 0b72 0cf5 | 11 0af9 (0) 0a00 (0) 0b72 (0) 0d8a (0)\n005 5 0661 0743 0438 045b | 6 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n============ DEPTH: 6 ==========================================\n006 3 02d8 0328 03cc | 3 02d8 (0) 0328 (0) 03cc (0)\n007 0 | 0\n008 1 00c6 | 1 00c6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","private_key":"5eb85f550595a12882aba16bce31535a88504fca1f6f49492226c3baed943110","name":"node_006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","services":["streamer"],"enable_msg_events":true,"port":45081},"up":true}},{"node":{"info":{"id":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","name":"node_f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","enode":"enode://17cec2abc9a0e660f7fe13e3aab5154a566cbbde2e9e0abea28d40e39eb63ec0a917c1040c10c1b2522fc87afce58949b5d8512d66bd953577e7c8ffe29b2727@127.0.0.1:0","enr":"0xf88fb840d12213ec977f33e55ead3ff1c891eadaf9d35e5d9f80da8f41e1723cfc228d17411a705b829183356338bfb66a6e6a3f22d4cd095d3e916ee50c79501b6a92f20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10317cec2abc9a0e660f7fe13e3aab5154a566cbbde2e9e0abea28d40e39eb63ec0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"97rvh2piuS6+XKnsagheDrVP0x4kJeZi7sdH3zzXdZI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f7baef\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6f5f 58ed 5db0 0067 | 146 775e (0) 77d2 (0) 7125 (0) 7290 (0)\n001 6 8f21 886a ac4d ad98 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 2 c832 c9f5 | 26 d3b0 (0) d299 (0) d1d7 (0) d7ac (0)\n003 4 e514 ec52 ef1b ef07 | 18 e027 (0) e7fa (0) e775 (0) e5ad (0)\n004 4 fbf5 f925 ff36 fe31 | 6 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n005 3 f31c f27f f2d5 | 3 f31c (0) f27f (0) f2d5 (0)\n006 3 f45f f456 f5b2 | 6 f4e0 (0) f45f (0) f456 (0) f528 (0)\n007 1 f629 | 1 f629 (0)\n============ DEPTH: 8 ==========================================\n008 1 f773 | 1 f773 (0)\n009 1 f7fa | 1 f7fa (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","private_key":"bd8f1323739a31a9df6d3249c8a7c3b7f087513627688a48ae214cdf08c40828","name":"node_f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","services":["streamer"],"enable_msg_events":true,"port":35911},"up":true}},{"node":{"info":{"id":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","name":"node_c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","enode":"enode://ef16c8f953e0c91672402036963d6771c490e9e0b99eca6f2d42e524b671f062bd499b0de306fe5eed171f48df7bc9f34bd943010925328c9d60ef086579968b@127.0.0.1:0","enr":"0xf88fb840262713d5977cf6a3bafd1062509bc016e5c191c3afe9c7a08a48ed97868b7d933211c89aba69029de45bd8e766b7ff6f2d419b47a5c830ca236eeb4da5ffee270183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ef16c8f953e0c91672402036963d6771c490e9e0b99eca6f2d42e524b671f062","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yfWsr7v4xmZH3gWwhI15RR7uSQcJ1T8Rj8IFFBDMggM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c9f5ac\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6f5f 461c 58ed 5308 | 146 02d8 (0) 0328 (0) 03cc (0) 00c6 (0)\n001 5 886a b7ca badd ba88 | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 12 e5d7 e514 ec52 ef1b | 37 e027 (0) e775 (0) e7fa (0) e5ad (0)\n003 6 d640 df1e daec db6a | 11 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n004 3 c441 c620 c786 | 9 c26f (0) c1f9 (0) c6cf (0) c620 (0)\n005 1 cc20 | 1 cc20 (0)\n006 2 ca04 caf6 | 2 ca04 (0) caf6 (0)\n============ DEPTH: 7 ==========================================\n007 2 c898 c832 | 2 c898 (0) c832 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","private_key":"a8e9d35f1da0d512396196bd7847bf29fbc3e45dab549c77015562a5cd6c1d01","name":"node_c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","services":["streamer"],"enable_msg_events":true,"port":36247},"up":true}},{"node":{"info":{"id":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","name":"node_fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","enode":"enode://29c3a81b46834e3d0f6c4169b27c4ce7dea09b4f8ecdf8cafa3b4705fa9fd804d95a4d7f8639754533998af29d1c1681ffd26bf51aa4576a6bf66fd4e59c4636@127.0.0.1:0","enr":"0xf88fb8406318ee2852832b8479302a86a8c52101e4032df0a3751458a30005834cac33085a7c35b08af5014dc752719fbe5642f4752139c909996b751458d0b79ff759420183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10229c3a81b46834e3d0f6c4169b27c4ce7dea09b4f8ecdf8cafa3b4705fa9fd804","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/jFmeeyg4OuCMyWBKlb9J9oCZTsGraL9A7J1Ab2oNxo=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fe3166\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0b72 0067 0743 0451 | 146 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n001 6 8f21 886a ad98 b7ca | 47 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n002 3 c786 c832 c9f5 | 26 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n003 3 e514 ef1b ef07 | 18 e027 (0) e775 (0) e7fa (0) e5ad (0)\n004 5 f2d5 f528 f629 f7fa | 13 f31c (0) f27f (0) f2d5 (0) f4e0 (0)\n005 3 fbc8 fbf5 f925 | 3 fbc8 (0) fbf5 (0) f925 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ff36 | 1 ff36 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 fe21 | 1 fe21 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","private_key":"4cb7e774b4209f69e673c60ecdf42b2d97a6c7acee80dac037fc744274c03d0c","name":"node_fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","services":["streamer"],"enable_msg_events":true,"port":36479},"up":true}},{"node":{"info":{"id":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","name":"node_51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","enode":"enode://c015318af105b1c0aaec79e08f9e9487e8c204c3decc0f161307ee66a71cc5eb7857085301967316982edbd1b3af1895278747273ba557b313f39de6467cef30@127.0.0.1:0","enr":"0xf88fb84065c1481d82bab43cf2b73a6409653ca03d1143d68af8825b5abe412f0ffc61ac5d2f9f6521e6f02a0242b8fb6bff45bbfe129f271e03dd3a7df92a3ddf9a9b990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c015318af105b1c0aaec79e08f9e9487e8c204c3decc0f161307ee66a71cc5eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UdsRSlKCf1t0CIvQ/IfTUinndA59EhvXaZKYOWUWqIA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 51db11\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b7ca badd c9f5 fe31 | 110 9852 (0) 9890 (0) 9fa0 (0) 9d0f (0)\n001 7 39d1 3f94 2101 2a97 | 76 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n002 3 6103 6ecb 6f5f | 32 775e (0) 77d2 (0) 7290 (0) 738c (0)\n003 4 4d10 4109 4646 461c | 23 4a8b (0) 4ac7 (0) 4bcf (0) 49cd (0)\n004 7 5efb 5f00 5cd2 5db0 | 7 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n005 1 574f | 1 574f (0)\n============ DEPTH: 6 ==========================================\n006 5 524d 53a8 53fe 534b | 5 524d (0) 53a8 (0) 53fe (0) 534b (0)\n007 0 | 0\n008 1 512e | 1 512e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","private_key":"463982e5e17d8853a2119047040024cc3e05d9d4fed44bca081b9a757de79e78","name":"node_51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","services":["streamer"],"enable_msg_events":true,"port":46747},"up":true}},{"node":{"info":{"id":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","name":"node_58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","enode":"enode://35dd66ee032741a2c01c7184c5d372ac89b1bfa19121e0208b6bc4554e26a48e2866d923d323b999aa49db2e9c87ad0ba78da81a35d099d44b2ac12e4577c026@127.0.0.1:0","enr":"0xf88fb840043496ba46ff1222fe7d2927803a795654e938ed8bb711b917672f048ef3180357b54d37aa9fd541158c55dea24adf4c62ed7d291e7875c0d5f76a14a12be1670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10235dd66ee032741a2c01c7184c5d372ac89b1bfa19121e0208b6bc4554e26a48e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WO10aVv1J7rJo1DIbTBeU+CMSZl5XhHNOyo29c0l1jc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 58ed74\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c9f5 ef1b f7ba b7ca | 110 e027 (0) e7fa (0) e775 (0) e5ad (0)\n001 5 3f94 35e6 0b72 0e5e | 76 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n002 3 6103 6ecb 6f5f | 32 775e (0) 77d2 (0) 7290 (0) 738c (0)\n003 3 4d10 4109 461c | 23 4ac7 (0) 4a8b (0) 4bcf (0) 49cd (0)\n004 3 53fe 5308 51db | 8 574f (0) 524d (0) 53a8 (0) 53fe (0)\n005 4 5db0 5cd2 5efb 5f00 | 4 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n============ DEPTH: 6 ==========================================\n006 1 5b63 | 1 5b63 (0)\n007 0 | 0\n008 1 5823 | 1 5823 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","private_key":"6eeff6ab23e21598ffa4724e7f1c6d198e55378b5315c3e87a2b049bdec8dbba","name":"node_58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","services":["streamer"],"enable_msg_events":true,"port":46637},"up":true}},{"node":{"info":{"id":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","name":"node_baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","enode":"enode://4c1086d46d650500110758f88911d8de08c282320cb28b478685c979ba504a460324e40bf1c4d18435044daf1db70bf50fbad5e5bc783f75141ee51671da1c2a@127.0.0.1:0","enr":"0xf88fb84011f51bcd70f0e65f6e7ff877cd39d60fca04b7df569eecb3f9200c5983c30c66090beb6cfac47e9a17f3d69aa7771c4d48640fc4436bbb1499789941189d0bb00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c1086d46d650500110758f88911d8de08c282320cb28b478685c979ba504a46","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ut3HeK6pes27tbyZdEpVRaurn2BHyB8yh2FkUoesORw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: baddc7\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0e5e 5308 51db 58ed | 146 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n001 5 c9f5 ef07 ef1b fe31 | 63 fbf5 (0) fbc8 (0) f925 (0) ff36 (0)\n002 4 9d0f 90a8 898d 886a | 20 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n003 5 a369 aeb4 ae2b ad98 | 10 a46d (0) a6fb (0) a653 (0) a34e (0)\n004 6 b2a5 b02b b5b2 b626 | 8 b02b (0) b2b5 (0) b2a5 (0) b502 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 b820 b897 b95d b911 | 4 b897 (0) b820 (0) b95d (0) b911 (0)\n007 1 bb90 | 1 bb90 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 ba88 | 1 ba88 (0)\n010 1 baf2 | 1 baf2 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","private_key":"1b341e606e667d2dee5a1c605b8ab560bf7350972aac6daa482f10d3fcced991","name":"node_baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","services":["streamer"],"enable_msg_events":true,"port":42801},"up":true}},{"node":{"info":{"id":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","name":"node_b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","enode":"enode://830e8810ca164c9d2a65e2235aba3b15b5907afbf93dabb8c5a00c2a21f50b3a0f3f17a4add3a9dc11b898dfaffb40ed51faeaf15f8e8ca83bc7f9bdb499650b@127.0.0.1:0","enr":"0xf88fb8409a15792c3e8fda0fc6163a89bf642573178c1828ebfac480954ce5384512a9144d6ab33233a340364e8b2b24cbce1de306889b420de971650d2efea448ac33f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103830e8810ca164c9d2a65e2235aba3b15b5907afbf93dabb8c5a00c2a21f50b3a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"t8r+1B2sAd1Z4ryuqqtVHr/quOqh+XwYZv4N2udygHs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b7cafe\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0e5e 3f94 35e6 5308 | 146 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n001 5 c9f5 e514 ef1b f7ba | 63 d1d7 (0) d299 (0) d3b0 (0) d7ac (0)\n002 6 90a8 9d0f 8f21 898d | 20 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n003 3 a369 ae2b ad98 | 10 a46d (0) a6fb (0) a653 (0) a34e (0)\n004 5 bcc6 b911 bb90 ba88 | 9 bcc6 (0) b897 (0) b820 (0) b95d (0)\n005 3 b2b5 b2a5 b02b | 3 b2b5 (0) b2a5 (0) b02b (0)\n006 2 b502 b5b2 | 2 b502 (0) b5b2 (0)\n============ DEPTH: 7 ==========================================\n007 2 b626 b65e | 2 b626 (0) b65e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","private_key":"8734418063f761c7aebb5bd811d651e4eefd0a332a238b3407eab389d174d344","name":"node_b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","services":["streamer"],"enable_msg_events":true,"port":35765},"up":true}},{"node":{"info":{"id":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","name":"node_ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","enode":"enode://e65f236dc029e0361b5115dc919118463ccd09476638ef7c4cf88151a41986426bd3623c7dee6acc1cb636f084e8f2c1cd6a783627bbf0cb45ddbafd57e1c4d2@127.0.0.1:0","enr":"0xf88fb840673785f36dc917ec90991ef9b8599a3710d9a0c7d36ea2aecdc3ebc730f1f9531104d6620e68027de87d0f8574a91458fb0346324b22795901a3dffe062dc4540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e65f236dc029e0361b5115dc919118463ccd09476638ef7c4cf88151a4198642","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uohOXPoe5us4IXGBcR4Buww3s+M9FCTfqJ7T4p72IFs=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ba884e\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0e5e 3f94 3373 35e6 | 146 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n001 4 c9f5 ef1b e514 fe31 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 4 90a8 8f21 898d 886a | 20 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n003 4 a369 ae2b ac4d ad98 | 10 a6fb (0) a653 (0) a46d (0) a34e (0)\n004 6 b2a5 b02b b5b2 b626 | 8 b2b5 (0) b2a5 (0) b02b (0) b502 (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 3 b897 b820 b911 | 4 b820 (0) b897 (0) b95d (0) b911 (0)\n007 1 bb90 | 1 bb90 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 baf2 badd | 2 baf2 (0) badd (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","private_key":"ea93ee284f5d410641b1a5125b7deca5a425eb767d97519816ce904c9a5109d4","name":"node_ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","services":["streamer"],"enable_msg_events":true,"port":41725},"up":true}},{"node":{"info":{"id":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","name":"node_53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","enode":"enode://7faeabed37c1721532d3cf55386ceb61d7127283ea741074062c7387ae1b7c9ff851941e9c92460053143e3f856fd6defb1749214ca54c839ac64fe96a8a0c13@127.0.0.1:0","enr":"0xf88fb84025b6f7edf9c4cdbcc94eaa1b1c4f4a202e55a443e4ace9d9896d487de9e2b050369275954c54148b295eb47404201100c10320546a8e4ad3516ba4c280288ea20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037faeabed37c1721532d3cf55386ceb61d7127283ea741074062c7387ae1b7c9f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UwhwhHCMxe5jrEWbGPoQrlKoIxObTsumyGkdSTTy+XE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 530870\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c9f5 e514 ef1b b7ca | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 5 3f94 39d1 3630 1e2a | 76 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n002 6 7dd3 605a 6103 6337 | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 5 4e5a 4d10 4646 461c | 23 4559 (0) 4558 (0) 44a1 (0) 4447 (0)\n004 5 5f00 5cd2 5db0 5823 | 7 5efb (0) 5f00 (0) 5cd2 (0) 5db0 (0)\n005 1 574f | 1 574f (0)\n006 2 512e 51db | 2 512e (0) 51db (0)\n007 1 524d | 1 524d (0)\n============ DEPTH: 8 ==========================================\n008 2 53a8 53fe | 2 53a8 (0) 53fe (0)\n009 1 534b | 1 534b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","private_key":"9d1b128357783fdd85833562ee5ae70767a77d42c4a39b16e33cfceae74fe8cd","name":"node_53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","services":["streamer"],"enable_msg_events":true,"port":43957},"up":true}},{"node":{"info":{"id":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","name":"node_0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","enode":"enode://9de20b1b75da752d129b0fbd52eda941af9eceb5d14f591ba77175f5f153ab996b82146163328ca097a16b7fb0ed20190dd92ac98b14c785e70658a8c5be1929@127.0.0.1:0","enr":"0xf88fb8406df78c1282722ffe5f759e7116db3a62ef5c3b47ea34e4cef4aa028184b113d7735724260b3e1bf01753094e4c48687c79e5c9e7c7f58b547bec67fbeb7c49c80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039de20b1b75da752d129b0fbd52eda941af9eceb5d14f591ba77175f5f153ab99","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Dl4LsTg7LsVpsVeh0q5pAFkquJKig2f1YTpOKcsmUIg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e5e0b\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 90a8 b7ca ba88 badd | 110 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n001 3 4d10 58ed 5308 | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 4 2a97 3f94 3373 35e6 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 5 1704 14df 11d4 18f6 | 22 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n004 4 0743 0451 03cc 0067 | 11 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n005 3 0af9 0a00 0b72 | 3 0af9 (0) 0a00 (0) 0b72 (0)\n006 3 0d8a 0cf5 0c64 | 5 0de3 (0) 0d8a (0) 0cf5 (0) 0c28 (0)\n============ DEPTH: 7 ==========================================\n007 2 0ff2 0fc5 | 2 0fc5 (0) 0ff2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","private_key":"46271e4b8bcd11ac7ea284e6e69d5fbfdab7754d5a04213ffd66697dfea46bcd","name":"node_0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","services":["streamer"],"enable_msg_events":true,"port":36611},"up":true}},{"node":{"info":{"id":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","name":"node_ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","enode":"enode://eac5fa35e65602ec70fd918c6e95a35d1a117b246fe5000ae4bafc6295f7671e4c06e415eb09e684abf780512fc18b2d866c3b71bb3b3c9d43fc4398da38f10e@127.0.0.1:0","enr":"0xf88fb8400fa87d3bd5c13cdf564484f96122c2ebb1bdcce71fdd18d75afe908594a3866c456fe3a118e4261abc0ecce7cbb42c18f1d8566d6c83c5ebd5d07919eb17d5a40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102eac5fa35e65602ec70fd918c6e95a35d1a117b246fe5000ae4bafc6295f7671e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7xtwvwkLyZlLHUXigSxW7LQwqJw0akNr0QiAvNpwA1E=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ef1b70\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 4d10 58ed 5308 3f94 | 146 7e04 (0) 7dbb (0) 7dc2 (0) 7dd3 (0)\n001 8 8f21 88a1 90a8 a369 | 47 8025 (0) 82dd (0) 82f9 (0) 849b (0)\n002 4 df1e d887 c9f5 c832 | 26 d299 (0) d3b0 (0) d1d7 (0) d7ac (0)\n003 9 f27f f2d5 f5b2 f629 | 19 f925 (0) fbf5 (0) fbc8 (0) ff36 (0)\n004 4 e775 e5d7 e54b e514 | 8 e027 (0) e7fa (0) e775 (0) e5ad (0)\n005 3 eb98 e8ef e854 | 4 e883 (0) e8ef (0) e854 (0) eb98 (0)\n006 2 ed2d ec52 | 2 ed2d (0) ec52 (0)\n007 1 ee5e | 1 ee5e (0)\n============ DEPTH: 8 ==========================================\n008 1 efea | 1 efea (0)\n009 0 | 0\n010 0 | 0\n011 1 ef07 | 1 ef07 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","private_key":"108631b63afbc1b7d0f969a4d149576ac6bc3f55beffefa542345c2ff98ac10b","name":"node_ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","services":["streamer"],"enable_msg_events":true,"port":40971},"up":true}},{"node":{"info":{"id":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","name":"node_1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","enode":"enode://35cb12ad89b825a27459675abdf8b7d44cf40ebf61f8a6c848840c068f6cd8a7604420513fa6d34094211e2874d871f3664257b8bbde8d919848cf1ee30c9173@127.0.0.1:0","enr":"0xf88fb840eeddfc21dd882af77ed82462e015105a4fee9ec50091947b3ffb91eadd0bb4f061e244bedab8fcf2d9bd87b0d1c83cbaa50258bc33fac86e0dabb2d263e2f6c40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10335cb12ad89b825a27459675abdf8b7d44cf40ebf61f8a6c848840c068f6cd8a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HirKk/qUQqADSujSlVMN3hb8v6jDcifi5oY7q7D4fDQ=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1e2aca\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e514 ef1b | 110 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n001 4 6f5f 51db 5308 4d10 | 70 7290 (0) 738c (0) 7125 (0) 77d2 (0)\n002 7 2c38 3373 3237 3630 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 7 0451 0067 0b72 0af9 | 22 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n004 8 11d4 103b 13d6 165f | 12 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n005 2 1a2a 18f6 | 4 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n006 3 1c8a 1c9c 1c47 | 3 1c47 (0) 1c8a (0) 1c9c (0)\n============ DEPTH: 7 ==========================================\n007 2 1f67 1f85 | 2 1f85 (0) 1f67 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","private_key":"ca298ecc80c2176e1dce1fbf5ccfa90cf337a507c12be6f986d2de3350d01f28","name":"node_1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","services":["streamer"],"enable_msg_events":true,"port":34411},"up":true}},{"node":{"info":{"id":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","name":"node_e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","enode":"enode://fd27bc291857dfd075b45f5afda76cffc42c2fd3c6cbbd041160f4468daccd297f427de0a2d6d348a61fd628559798012d4a700d99f5d9c2ccefc12424e71a9e@127.0.0.1:0","enr":"0xf88fb8406833bd658c2dee1b0266e4979790bf604d3a078226e16c2bfcfbba4b009599331864bee8af31e7b121cd49e9caf0d21533f91bc0cdac69a7ff3660f0093e1a320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fd27bc291857dfd075b45f5afda76cffc42c2fd3c6cbbd041160f4468daccd29","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5RSc7dmQBy8qqpc1qSWfKJc8RYdmYMLYasEF5WzKjmg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5149c\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5308 4d10 3f94 3373 | 146 775e (0) 77d2 (0) 7290 (0) 738c (0)\n001 7 8f21 88a1 90a8 ae2b | 47 849b (0) 8505 (0) 8025 (0) 82dd (0)\n002 4 df1e d887 c832 c9f5 | 26 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n003 5 f5b2 f7ba f925 ff36 | 19 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n004 4 eb98 ec52 ef07 ef1b | 10 e854 (0) e883 (0) e8ef (0) eb98 (0)\n005 1 e027 | 1 e027 (0)\n006 2 e7fa e775 | 2 e7fa (0) e775 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 e5ad e5d7 | 2 e5ad (0) e5d7 (0)\n009 2 e547 e54b | 2 e547 (0) e54b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","private_key":"4f4ad194adef3b2bc3e2726a7b609ae7bda912d4e2086f1a13e4c4ba668c60ac","name":"node_e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","services":["streamer"],"enable_msg_events":true,"port":42997},"up":true}},{"node":{"info":{"id":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","name":"node_35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","enode":"enode://6c8c3cbf0d25b5021ca9930a6ec6a174a1408d306e91b340285357ce11ef1be7595292e2c9d678ecaad46e85c67e2548b6f8d001240ab47711a7bf12d84ccf82@127.0.0.1:0","enr":"0xf88fb84040cae853fa9515e6bbe0adcbf29a86d0a760543dcbc0e6d834dbbf0fa17b67074b1ac65a884606be1e2fd6bce5dee242940fccc40d35cb5189481b6a539a036f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026c8c3cbf0d25b5021ca9930a6ec6a174a1408d306e91b340285357ce11ef1be7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Neax0x9ZTAa3WVJUNKfnF+vm8nygGI8kftEkdmSlBWM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 35e6b1\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 8f21 90a8 ae2b ba88 | 110 849b (0) 8505 (0) 8025 (0) 82dd (0)\n001 2 58ed 4d10 | 70 7920 (0) 7a60 (0) 7b90 (0) 7e04 (0)\n002 2 0e5e 1e2a | 44 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n003 7 2101 2d36 2c79 2c38 | 15 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n004 3 39d1 3b78 3f94 | 7 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n005 5 314a 3089 3373 33b5 | 6 314a (0) 30be (0) 3089 (0) 3237 (0)\n============ DEPTH: 6 ==========================================\n006 3 3630 378e 3780 | 3 378e (0) 3780 (0) 3630 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","private_key":"2a62a26311a24b08194c69ebc1ed52e217472f0342db63d881497f987b889e06","name":"node_35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","services":["streamer"],"enable_msg_events":true,"port":46321},"up":true}},{"node":{"info":{"id":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","name":"node_3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","enode":"enode://218760aa13e26a18b74d2337eef240198ccd4014e8a65b603ed92ccdb48ccd8b943f256eb6e58c6fbdce24b409b2775b2d6004401320c919188e7fcb09244fd1@127.0.0.1:0","enr":"0xf88fb840177a2dfc1f89c96d70eddc71b4f1b0bac49f90fee6d0eac21cbb5d5d2405a3a942e28c9535399cbe5914256c761ecb4a5f3f6563090d48314533f0c5234aa2dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103218760aa13e26a18b74d2337eef240198ccd4014e8a65b603ed92ccdb48ccd8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"P5RpV9kQF5x+GoPEQ2mqz8MfVyexpkIaAcipeMzTSaI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3f9469\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 e514 ef1b 90a8 a369 | 110 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n001 5 5308 51db 58ed 461c | 70 738c (0) 7290 (0) 7125 (0) 77d2 (0)\n002 3 0e5e 0b72 1e2a | 44 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n003 7 20ae 2101 2a0a 2a97 | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 7 3089 3237 33b5 3373 | 10 314a (0) 30be (0) 3089 (0) 3237 (0)\n005 3 3b88 3b78 39d1 | 3 3b88 (0) 3b78 (0) 39d1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 3ec5 3efc 3e8e | 3 3ec5 (0) 3efc (0) 3e8e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","private_key":"de36f03ed3bf0ec0a7710fc3c4999f66c685bbfddcfb8e9d4317b92303a74e11","name":"node_3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","services":["streamer"],"enable_msg_events":true,"port":33705},"up":true}},{"node":{"info":{"id":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","name":"node_4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","enode":"enode://9fecc8c4179e541e1fdf6df9acbe9fae124b26643c32c708bf43248ffa03ddc74085be1fbc7c6b26380bd54278b407e48f5ec005564f3715ddefef423e750ba0@127.0.0.1:0","enr":"0xf88fb84029f04153f5367d5275a8df9d644838126a5b32d2c4a8f463c54a8609f02f5ad3544851613d9bb9b0bd12cf4b0dfc60c0172093608372dfa04498cc981d46ed330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029fecc8c4179e541e1fdf6df9acbe9fae124b26643c32c708bf43248ffa03ddc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TRA+xa/uVZpakkLo1lC2cwHq7BDpb8LxhONNSFVBCKI=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d103e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 90a8 ef1b e514 | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 9 1e2a 0e5e 0b72 3630 | 76 13d6 (0) 103b (0) 11d4 (0) 1672 (0)\n002 3 6f5f 6ecb 6103 | 32 7125 (0) 7290 (0) 738c (0) 77d2 (0)\n003 5 5308 51db 5efb 5db0 | 15 5cd2 (0) 5db0 (0) 5f00 (0) 5efb (0)\n004 3 461c 4646 4109 | 12 4558 (0) 4559 (0) 44a1 (0) 4447 (0)\n005 2 49ea 4990 | 6 4a8b (0) 4ac7 (0) 4bcf (0) 49cd (0)\n006 1 4e5a | 1 4e5a (0)\n007 1 4c9e | 1 4c9e (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 4d6b 4d59 | 2 4d6b (0) 4d59 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","private_key":"ad04bf4b2168140a7de043f21b791b383b022dac606699911e318f75f7e012a6","name":"node_4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","services":["streamer"],"enable_msg_events":true,"port":33673},"up":true}},{"node":{"info":{"id":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","name":"node_33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","enode":"enode://50cec87bfc82507362c651f325c755f33d697e3e496e3eb72eb1c8f641ced88174ccc2b56cb7eba56579b61aceb18409c188d359f42f940805f5719740feb48e@127.0.0.1:0","enr":"0xf88fb840fd82bf7592c1d6a7814691efa8bd411452d956b60e269042831484ddceacc538104f0cb3828b7c706e383762f656ed7ec9fd288aa59b3c8d81f301a7a7f324f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10250cec87bfc82507362c651f325c755f33d697e3e496e3eb72eb1c8f641ced881","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"M3N991u6wbQcY/Beos8VI7ly3xfyK9oCbbhKSaw14eM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 33737d\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ef1b e514 ae2b a369 | 110 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n001 3 461c 4109 4d10 | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 4 1e2a 0e5e 0a00 0b72 | 44 13d6 (0) 103b (0) 11d4 (0) 17db (0)\n003 5 20ae 2c38 2c79 2995 | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 4 3b78 39d1 3e8e 3f94 | 7 3b88 (0) 3b78 (0) 39d1 (0) 3ec5 (0)\n005 4 35e6 378e 3780 3630 | 4 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n006 2 314a 3089 | 3 314a (0) 30be (0) 3089 (0)\n============ DEPTH: 7 ==========================================\n007 1 3237 | 1 3237 (0)\n008 1 33b5 | 1 33b5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","private_key":"9f972993b709e1ac19e7f49e4661fb3fb6e83534f66a12560073a6b5f59e7a0c","name":"node_33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","services":["streamer"],"enable_msg_events":true,"port":45909},"up":true}},{"node":{"info":{"id":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","name":"node_0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","enode":"enode://54b6d4a2a040be9a1af28fe91fcc2b187d4d6db27d970a10e744a69da4ac97260a7c57234a2c4e8ca82d46c4c72fd473d0023c622618c46fa794574590533fc8@127.0.0.1:0","enr":"0xf88fb840557305af7ee9557cc3f0d4e0ddc142adc3005a0b56e35a383a8f246c5b42adb234b65621b68d96643290b25ed4e6fc5777c5fa7a380d5f7806b6778a185a98340183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10254b6d4a2a040be9a1af28fe91fcc2b187d4d6db27d970a10e744a69da4ac9726","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"C3IFRAP3imSnh/Runya/Dee7ulpgyxBeau6kbLSh2f4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0b7205\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 fe31 e514 a369 ae2b | 110 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n001 3 58ed 4109 4d10 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 5 39d1 3f94 3630 3237 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 6 1e2a 18f6 13d6 11d4 | 22 103b (0) 11d4 (0) 13d6 (0) 17db (0)\n004 4 0438 0451 00c6 0067 | 11 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n005 6 0d8a 0de3 0cf5 0ff2 | 8 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 0af9 0a00 | 2 0a00 (0) 0af9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","private_key":"2f67175c7773d3b089b81b72210bd644855f6736a44e7e931e02c64a35326338","name":"node_0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","services":["streamer"],"enable_msg_events":true,"port":38921},"up":true}},{"node":{"info":{"id":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","name":"node_90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","enode":"enode://a2ad93ada8513b3feec771d73b08d372a7b89a5c6454e82f911e9fcd3b0f23929a604336b8501f89709f9eec253ed726d85e6c8ab08fc2473ba7fc9e96850147@127.0.0.1:0","enr":"0xf88fb840254e8f00ffa322391cdce60e7cd38fdbd46e5ee8cafdd7062a8985c381f69bce78fbb9bd468d7bd2d237a777c29badc74945574f72987aa21368ce6417bd55280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a2ad93ada8513b3feec771d73b08d372a7b89a5c6454e82f911e9fcd3b0f2392","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kKhctzY+3hYewhzIn4udQ1DlZs8QWGpm0xsKhndiCqE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 90a85c\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 4109 4990 4d10 39d1 | 146 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n001 5 d887 f5b2 f925 ef1b | 63 f31c (0) f2d5 (0) f27f (0) f629 (0)\n002 11 b02b b7ca bcc6 b911 | 27 b2b5 (0) b2a5 (0) b02b (0) b502 (0)\n003 5 8505 898d 886a 88a1 | 10 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n004 4 9fa0 9d0f 9852 9890 | 4 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n005 3 96fc 976e 959f | 3 96fc (0) 976e (0) 959f (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 915d | 1 915d (0)\n008 1 9076 | 1 9076 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","private_key":"ffbd3e52d4e07351ecaee805eb3df2eb83b6551d4ccecf49abe430b00d7b91ef","name":"node_90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","services":["streamer"],"enable_msg_events":true,"port":39339},"up":true}},{"node":{"info":{"id":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","name":"node_32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","enode":"enode://e26885995135217d285cbb3b0e44b2071d1247163affddea0fcd9f8b15a18fa900829a0118a2b2d366315f76b3811f4eb2be6a1edeaee8822be120da9629c074@127.0.0.1:0","enr":"0xf88fb8402421fb3a7727b2a4dbe62787a620aae3cda4704b08fd927939ffcf06d34d03a2386a8a340e265804a54d9c97eafe0cd662091e66bc27ad1a15fb88004c154a800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e26885995135217d285cbb3b0e44b2071d1247163affddea0fcd9f8b15a18fa9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MjcXRBY/Czrv05VdxId+frgrF++VQcMzypwKn4rsMEU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 323717\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a369 88a1 90a8 | 110 fbc8 (0) fbf5 (0) f925 (0) ff36 (0)\n001 3 4d10 461c 4109 | 70 7b90 (0) 7a60 (0) 7920 (0) 7e04 (0)\n002 6 0b72 0af9 0a00 14df | 44 13d6 (0) 103b (0) 11d4 (0) 17db (0)\n003 6 20ae 2a97 2995 2d36 | 15 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n004 3 3f94 3b78 39d1 | 7 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n005 2 35e6 3630 | 4 35e6 (0) 378e (0) 3780 (0) 3630 (0)\n006 3 314a 30be 3089 | 3 314a (0) 30be (0) 3089 (0)\n============ DEPTH: 7 ==========================================\n007 2 33b5 3373 | 2 33b5 (0) 3373 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","private_key":"109c5f2cf1f93926c20d740de91bde530a1068766dcdbd6f5a6c9eb561fad11e","name":"node_32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","services":["streamer"],"enable_msg_events":true,"port":40865},"up":true}},{"node":{"info":{"id":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","name":"node_3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","enode":"enode://902e0d821e6d4faadd41284e24f3566060b4d34a47a6a0b333365eef089321dbf8bf9a37c56df31c9f8d4d8489a329022bff87a8cb8bd8017a3b18f328fd984e@127.0.0.1:0","enr":"0xf88fb8401181684970ecc7675258fe5a3c5d354b1a7cab6dd97d2507ab00388013e7c8a76456556bdd0950ab1348bc7afa60ba1c68dae5634f81e10f5b475f7e83ba68c50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102902e0d821e6d4faadd41284e24f3566060b4d34a47a6a0b333365eef089321db","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NjDgUya6zqj8xznexCCF+EX0Ft3GmMdv+R8JnrHcUAc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3630e0\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ae2b 90a8 88a1 | 110 f31c (0) f2d5 (0) f27f (0) f629 (0)\n001 4 5308 5efb 4d10 4109 | 70 6831 (0) 6967 (0) 6c4d (0) 6c73 (0)\n002 6 0af9 0a00 0b72 1e2a | 44 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n003 4 217f 2c79 2c38 2a97 | 15 256e (0) 24b8 (0) 21a0 (0) 217f (0)\n004 3 3f94 3b78 39d1 | 7 3efc (0) 3ec5 (0) 3e8e (0) 3f94 (0)\n005 6 30be 3089 314a 33b5 | 6 30be (0) 3089 (0) 314a (0) 33b5 (0)\n006 1 35e6 | 1 35e6 (0)\n============ DEPTH: 7 ==========================================\n007 2 378e 3780 | 2 378e (0) 3780 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","private_key":"4f229a82b34c1d7a77db8b8205e0b0b31f129792a80377a9f140d310e6b27d84","name":"node_3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","services":["streamer"],"enable_msg_events":true,"port":43205},"up":true}},{"node":{"info":{"id":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","name":"node_88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","enode":"enode://748dfc4bce4346bdaee02bcdfc7b514fc6f9f0b74a7a2004e7beed2f9d7aa6eb82f41ede70c832e42af0767aaca3b7057427d140425ca9c052769d13382a475e@127.0.0.1:0","enr":"0xf88fb840e79a123d27b2f56ef3ee3b91fba3d7b33bade6191df9567cb607d85c896d09d51ee353973b9b6f21075dbea43685d639fa90e16d920e31bc814d94e1e55fe06d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102748dfc4bce4346bdaee02bcdfc7b514fc6f9f0b74a7a2004e7beed2f9d7aa6eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iKFBxgcBlHfHsSClBihachjK0vqgOAguC53fzJy3jQc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 88a141\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4990 4109 14df 3b78 | 146 77d2 (0) 775e (0) 7290 (0) 738c (0)\n001 5 f925 f5b2 e514 ef1b | 63 eb98 (0) e854 (0) e8ef (0) e883 (0)\n002 9 b7ca b02b bcc6 b911 | 27 b5b2 (0) b502 (0) b626 (0) b65e (0)\n003 3 9852 9076 90a8 | 10 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n004 3 849b 8505 82dd | 5 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n005 1 8f21 | 1 8f21 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 898d | 1 898d (0)\n008 1 886a | 1 886a (0)\n009 1 88fe | 1 88fe (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","private_key":"7c46b2b4c2eb41cbdc91b22dd94083a9d5a9ebcefddb2dca52e0356c8ab2d0f2","name":"node_88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","services":["streamer"],"enable_msg_events":true,"port":33659},"up":true}},{"node":{"info":{"id":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","name":"node_a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","enode":"enode://fc254f0aa0e39064101549ffcc69b2251433b96a80b540da96bfcde9c4e3f979f38f7351eb100fb11660b20a5da1e8c221073a719d331eaae06053de933916b8@127.0.0.1:0","enr":"0xf88fb840b3a10df042ede6a04af90f6ea1f32e3cc6144419c04ed87f500e8da294aec02e0a48ec2a277af3cf3663ad966204d93a0e74d0c581f38b72819a5f3bb3439db20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fc254f0aa0e39064101549ffcc69b2251433b96a80b540da96bfcde9c4e3f979","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"o2k4AakRgEEM8+hdfAmsgFSnaeex1VyeekaFDLghfaA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a36938\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0b72 14df 11d4 3373 | 146 0661 (0) 07a8 (0) 0743 (0) 0438 (0)\n001 5 d887 f5b2 f925 ef1b | 63 eb98 (0) e883 (0) e8ef (0) e854 (0)\n002 4 90a8 8505 8f21 88a1 | 20 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n003 5 b7ca b897 badd ba88 | 17 b502 (0) b5b2 (0) b626 (0) b65e (0)\n004 5 ac4d ad98 af02 aeb4 | 5 ac4d (0) ad98 (0) af02 (0) aeb4 (0)\n============ DEPTH: 5 ==========================================\n005 3 a46d a6fb a653 | 3 a6fb (0) a653 (0) a46d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 a34e | 1 a34e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","private_key":"9086c71a5873a4830e93448202ba724d3b0a168a8ef3a9fc05037416ae0e9ac9","name":"node_a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","services":["streamer"],"enable_msg_events":true,"port":41127},"up":true}},{"node":{"info":{"id":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","name":"node_41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","enode":"enode://48e3c3f7c9a9799de669a30ca9e8a74ed910aafd4ec3152cfe8688c9ce67997a955265bf9d18f30d988b81bcadb058fdfcd5822e37085fafd1cf3e3f0994a91c@127.0.0.1:0","enr":"0xf88fb840217cf3239a54cb3b089cbdc4bfa0fc3bd9e7921e1d28b05f7310e8c3a6f02b7c041bc83c1b95c201a33cbeedb581a51ce4fbdf683bc86ac1d6aaaa1127b7b8cd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10248e3c3f7c9a9799de669a30ca9e8a74ed910aafd4ec3152cfe8688c9ce67997a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QQkshS+sYw3yqcoIYnFvjp+4VmyQSknJY4kHEEa8aZ0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 41092c\npopulation: 45 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d887 90a8 8f21 88a1 | 110 e854 (0) e8ef (0) e883 (0) eb98 (0)\n001 9 0af9 0b72 11d4 14df | 76 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n002 7 6f5f 6e68 66e7 6103 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 6 5cd2 5823 58ed 51db | 15 574f (0) 524d (0) 53a8 (0) 53fe (0)\n004 6 4bcf 49ea 4990 4e5a | 11 4a8b (0) 4ac7 (0) 4bcf (0) 49cd (0)\n============ DEPTH: 5 ==========================================\n005 10 4559 4558 4447 44a1 | 10 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n006 0 | 0\n007 0 | 0\n008 1 41d9 | 1 41d9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","private_key":"6ddd3b1c12e06aba0ea262fc99bafec26b2f94fb5f347ab60518afc39741fdc9","name":"node_41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","services":["streamer"],"enable_msg_events":true,"port":39355},"up":true}},{"node":{"info":{"id":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","name":"node_ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","enode":"enode://63c769772cdc9c83c9254df508ecd82cf62909028da5d232e02375859a0c0e16ab09257681fccde8b6f99302465f29d7119a5a679e9eb722dd84aeeafad3290e@127.0.0.1:0","enr":"0xf88fb840ffd15988f81a75ca61b73d7267d740abba2f0fc56d28354888cf7f21cc6d5c006b2b1189d3572d77a3d8fb9067ff3678f24b6eff94085bb0fa0693f5ea885f8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10263c769772cdc9c83c9254df508ecd82cf62909028da5d232e02375859a0c0e16","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ris4dr29Y4h4G2XjHeGCVkxdgfRRHK+WWIsaKHdgs90=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ae2b38\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0b72 14df 3373 35e6 | 146 0438 (0) 045b (0) 0451 (0) 07a8 (0)\n001 5 f925 f5b2 ef1b e514 | 63 eb98 (0) e854 (0) e8ef (0) e883 (0)\n002 4 9076 90a8 8f21 88a1 | 20 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n003 6 b7ca b02b bcc6 badd | 17 b5b2 (0) b502 (0) b626 (0) b65e (0)\n004 4 a653 a46d a34e a369 | 5 a653 (0) a6fb (0) a46d (0) a34e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 ac4d ad98 | 2 ac4d (0) ad98 (0)\n007 1 af02 | 1 af02 (0)\n008 1 aeb4 | 1 aeb4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","private_key":"9812258a3e70549d501e1fb2b90b4728c6dcfc8ccbbb9892c370214b60d40535","name":"node_ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","services":["streamer"],"enable_msg_events":true,"port":36649},"up":true}},{"node":{"info":{"id":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","name":"node_39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","enode":"enode://64dd3388d784dcfff0bac93ac16b10d6a237024d609e79fd786f239d70d11292965e419f1feda3335a52b909229e85aeaa913d608cae51f7e22ea404a014b802@127.0.0.1:0","enr":"0xf88fb8403d980a1425e3cf5c0382d08284c76c76c84e06a2cc0019ff0fc7dbeb15976c6172bfe4f485c7d23c69f0e8139964ba0c7e55a3e460b1b9a18b3da2df51b4ae950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10264dd3388d784dcfff0bac93ac16b10d6a237024d609e79fd786f239d70d11292","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OdH8ri0jx3UhSYglFQXFd7mse2hRVY3fmkN9/hQ/OEU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39d1fc\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f5b2 d887 90a8 88a1 | 110 e854 (0) e8ef (0) e883 (0) eb98 (0)\n001 12 7125 7dd3 605a 6e68 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 8 00c6 0b72 0af9 0a00 | 44 0438 (0) 045b (0) 0451 (0) 07a8 (0)\n003 5 2a97 2d36 2c38 2c79 | 15 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n004 7 314a 3089 33b5 3373 | 10 314a (0) 30be (0) 3089 (0) 33b5 (0)\n005 2 3e8e 3f94 | 4 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n============ DEPTH: 6 ==========================================\n006 2 3b88 3b78 | 2 3b88 (0) 3b78 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","private_key":"3cba669ea7a686fe849ec5128b993a7fec64971638bff4ec54c386bff7214559","name":"node_39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","services":["streamer"],"enable_msg_events":true,"port":42159},"up":true}},{"node":{"info":{"id":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","name":"node_8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","enode":"enode://c61eb191e326e233f19223d31784f89dd3cb5712942a686877717d74afd735e118acf5e05da708b122eed47a681888a14c93072ccb1b425c3c58ffc60b1b6f7c@127.0.0.1:0","enr":"0xf88fb8401d4e08ac54c6ca41a0cbd145e8a06eada8b2a58062c2c9552957749da5bbd29c371325ed9de3b9214139dda907e2c2be86e1710583b02f6fe8550c6fa50e022c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c61eb191e326e233f19223d31784f89dd3cb5712942a686877717d74afd735e1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jyGCwsLQ7rLoh9vDUK5yV4GfU2AyhR/98p54QssaYsw=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8f2182\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4646 4109 11d4 35e6 | 146 67aa (0) 67dc (0) 66e7 (0) 6251 (0)\n001 10 d887 ef1b ef07 e514 | 63 e854 (0) e8ef (0) e883 (0) eb98 (0)\n002 10 b02b b7ca bcc6 b911 | 27 b502 (0) b5b2 (0) b626 (0) b65e (0)\n003 4 9d0f 9852 9076 90a8 | 10 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n004 4 82dd 82f9 849b 8505 | 5 8025 (0) 82f9 (0) 82dd (0) 849b (0)\n============ DEPTH: 5 ==========================================\n005 4 898d 886a 88fe 88a1 | 4 898d (0) 886a (0) 88fe (0) 88a1 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","private_key":"7da220e22f5a60bbb45c6c72883ee7c9680618b47c02741e3ffa840db42e0d8e","name":"node_8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","services":["streamer"],"enable_msg_events":true,"port":33809},"up":true}},{"node":{"info":{"id":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","name":"node_11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","enode":"enode://5a7570e6530a10db24b16f65a03b866013f409038c203dbdd432072f7d5048d389a66e7235576389e8633012bd367d983c5325a693ebc5bfe2b18a86e22ae598@127.0.0.1:0","enr":"0xf88fb840227240ac5b5e7e60e5754fbd36dadae2db7ba6a39745b0b02fc5303803afa203490c7fba99331c4338d767e68ce601f95e92d0cc9d4136708fca9cc5d9766a110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025a7570e6530a10db24b16f65a03b866013f409038c203dbdd432072f7d5048d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EdQ/btDd1a+lyKer98YqT6hlt6Je4pW/GklwHvMIE2M=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 11d43f\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d887 bb90 a369 8f21 | 110 eb98 (0) e8ef (0) e883 (0) e854 (0)\n001 5 7dd3 4990 49ea 4109 | 70 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n002 4 3237 3630 39d1 3b78 | 32 256e (0) 24b8 (0) 20ae (0) 217f (0)\n003 6 00c6 0067 0e5e 0b72 | 22 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n004 5 18f6 19fa 1e2a 1f67 | 10 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n005 9 1704 17db 179f 1672 | 9 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 6 ==========================================\n006 1 13d6 | 1 13d6 (0)\n007 1 103b | 1 103b (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","private_key":"219dac0c9e412e884796b76e8f34df3ab01ed79aec554cede6881de4d40236f8","name":"node_11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","services":["streamer"],"enable_msg_events":true,"port":40541},"up":true}},{"node":{"info":{"id":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","name":"node_3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","enode":"enode://24fd229270ea0d538333b0a4aafd5aff71f1783569175335b1d90f0edffade66ba7c66972ba0e5e1862b468c0cb4245f1852e5778d8eefc014daa1f55136a7af@127.0.0.1:0","enr":"0xf88fb840c92aeac9460bef8b28eecae10683b0871da8063062965e99ecc8a759dfdc230820f2a00376fb89d159b3f24bd098f7f2689ad9750ad6e7b960138598b3afc0b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10324fd229270ea0d538333b0a4aafd5aff71f1783569175335b1d90f0edffade66","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O3i8mHx8MclOitqbSxG125OH/nDdAc5/PpdtO+xDPew=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b78bc\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 88a1 bb90 a369 ae2b | 110 9890 (0) 9852 (0) 9fa0 (0) 9d0f (0)\n001 4 5efb 4990 4646 4109 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 6 00c6 0af9 0a00 14df | 44 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n003 5 2101 2995 2f32 2d36 | 15 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n004 6 3630 35e6 314a 3237 | 10 314a (0) 30be (0) 3089 (0) 33b5 (0)\n005 4 3e8e 3ec5 3efc 3f94 | 4 3ec5 (0) 3efc (0) 3e8e (0) 3f94 (0)\n============ DEPTH: 6 ==========================================\n006 1 39d1 | 1 39d1 (0)\n007 0 | 0\n008 1 3b88 | 1 3b88 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","private_key":"005d083eb3a257750c097d09e17a10c58264917fa06535586128643b104277c2","name":"node_3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","services":["streamer"],"enable_msg_events":true,"port":36675},"up":true}},{"node":{"info":{"id":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","name":"node_14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","enode":"enode://2a6142cda1601b228a9c6960fa90278c011610caf1c0109047931f409d5c69beb1383db75c7edd51dcae1b4a0a74af47ddbfb3cb14d4b9adac497d92c870ee2c@127.0.0.1:0","enr":"0xf88fb840a90ca3b818792d943f2120428d70855db44a6aa36d9a209e3ef9aadc13b3a3380939a0ea38235e3a786c5fa856c56bee157f75c45bc64251e000f5110bccf84c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022a6142cda1601b228a9c6960fa90278c011610caf1c0109047931f409d5c69be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FN+4QU0Xst8V6vWVcajP7Jmx/WdFYdpj7pmvhTvaB9o=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 14dfb8\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 88a1 a369 ae2b d887 | 110 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n001 4 49ea 4990 4109 4646 | 70 77d2 (0) 775e (0) 738c (0) 7290 (0)\n002 4 3237 3630 39d1 3b78 | 32 256e (0) 24b8 (0) 20ae (0) 217f (0)\n003 6 0067 00c6 0e5e 0b72 | 22 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n004 3 1c9c 1f67 1e2a | 10 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n005 3 13d6 103b 11d4 | 3 13d6 (0) 103b (0) 11d4 (0)\n006 5 1704 17db 179f 1672 | 5 1704 (0) 17db (0) 179f (0) 1672 (0)\n007 1 154b | 1 154b (0)\n============ DEPTH: 8 ==========================================\n008 2 1400 1436 | 2 1400 (0) 1436 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","private_key":"9f60424e94bf49f4831f8875a348ff8684b25041feb915b3062e329bc6bde720","name":"node_14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","services":["streamer"],"enable_msg_events":true,"port":33225},"up":true}},{"node":{"info":{"id":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","name":"node_d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","enode":"enode://e27e5fe8c0fc1d5c19e4c43062e74e25d5b285ab4d87d9f6f0639f977473f6132ebec497112fb9ae28257aba65e66cff848d950d90d74301faee81243b2b354e@127.0.0.1:0","enr":"0xf88fb840d61802d9193750fd40278a66d4f73473dfb6ff6577a0f122efdee8265ca9f02a080bed7a061796672fa8e20230725617a89f348724b82705106550e47856543e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e27e5fe8c0fc1d5c19e4c43062e74e25d5b285ab4d87d9f6f0639f977473f613","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2IcHCgVoKCxp6WzmVhK6ctXqJrXIBnFDXW4e0sS0kwE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d88707\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 49ea 4109 4646 39d1 | 146 775e (0) 77d2 (0) 7290 (0) 738c (0)\n001 9 90a8 8f21 88a1 a369 | 47 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n002 5 eb98 ef1b e514 f925 | 37 e027 (0) e7fa (0) e775 (0) e5ad (0)\n003 6 c1f9 c620 c9f5 c898 | 15 c26f (0) c1f9 (0) c49c (0) c441 (0)\n004 3 d1d7 d299 d3b0 | 5 d640 (0) d7ac (0) d1d7 (0) d299 (0)\n005 1 df1e | 1 df1e (0)\n============ DEPTH: 6 ==========================================\n006 3 db6a daec da67 | 3 db6a (0) da67 (0) daec (0)\n007 0 | 0\n008 1 d863 | 1 d863 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","private_key":"04afc55a06d4cfd448c6d6574905560d45f4bc8fffe230c686d444d678257ec8","name":"node_d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","services":["streamer"],"enable_msg_events":true,"port":46277},"up":true}},{"node":{"info":{"id":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","name":"node_0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","enode":"enode://ba05d71907202ec66f1ef7f46da693468efea28d0cff6a320b4ed04465b73789f7fb6a9b638d00d75c054815a86c8c71512c605c8a5328aa4f3de656dc83aa4b@127.0.0.1:0","enr":"0xf88fb84081e05173f55c4568ba75436e5ec395bddec7a8bbae9c3c65a8f91b42698bda8407a5e40cacce44a4cecb0384cc14285aaa07669a28a9e69cceb2ec18a4e73f2c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ba05d71907202ec66f1ef7f46da693468efea28d0cff6a320b4ed04465b73789","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CgBeucEMXMn3IM/sKmVYEdORZxWXtPMtEt8pHsdrLBM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0a005e\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bb90 d887 | 110 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n001 4 5efb 49ea 4990 4646 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 5 3630 3373 3237 3b78 | 32 256e (0) 24b8 (0) 20ae (0) 21a0 (0)\n003 3 1e2a 11d4 14df | 22 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n004 5 0451 03cc 0328 0067 | 11 07a8 (0) 0743 (0) 0661 (0) 0438 (0)\n005 7 0de3 0cf5 0c28 0c64 | 8 0d8a (0) 0de3 (0) 0cf5 (0) 0c28 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 0b72 | 1 0b72 (0)\n008 1 0af9 | 1 0af9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","private_key":"f1681c7b1205d9314840edd16ac9c55cfd362b4feeb60b0066c0a1c69f42f1c4","name":"node_0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","services":["streamer"],"enable_msg_events":true,"port":35965},"up":true}},{"node":{"info":{"id":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","name":"node_0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","enode":"enode://58412ea457c3c490d9c0792f1b0274281f17c3794c31304f2eed90d45520cc37cf639e4f5f2194743af16fedabea43bbc5071077a286b03cc4b65601983ab04d@127.0.0.1:0","enr":"0xf88fb8407fbed396b8c08f1a08e239904d9fbd388627aec4b0e21c946b6d6112154a7d327f8f868440c35fb7a46ceb36684ebaf4437f4472cd88a0983375e4f5b50d610a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10358412ea457c3c490d9c0792f1b0274281f17c3794c31304f2eed90d45520cc37","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Cvmlei9mg1zT5OcbwCYBOoqZyjN6e2tsw04R2NohKk8=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0af9a5\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bb90 f5b2 d887 | 110 e027 (0) e7fa (0) e775 (0) e5ad (0)\n001 4 4990 49ea 4109 4646 | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 4 3630 3237 3b78 39d1 | 32 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n003 6 1c9c 1e2a 11d4 103b | 22 1b83 (0) 1a2a (0) 19fa (0) 18f6 (0)\n004 4 0661 0328 0067 00c6 | 11 0438 (0) 0451 (0) 045b (0) 0743 (0)\n005 8 0d8a 0de3 0cf5 0c28 | 8 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 0b72 | 1 0b72 (0)\n008 1 0a00 | 1 0a00 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","private_key":"b5347eaddd49eda049687bb250949eca56628c3bddafbccae680b571175f1efe","name":"node_0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","services":["streamer"],"enable_msg_events":true,"port":45487},"up":true}},{"node":{"info":{"id":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","name":"node_4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","enode":"enode://29467abcaeb0c2dcf2dbb6835fbab644652983d04c3c5964c37eaed3c9b33a41f488528f8f11c8b4a73ae223a7c738bc6b1f8e56a5f319556a4c1ffd68865d13@127.0.0.1:0","enr":"0xf88fb84050850c1513e8379df0027113c46bb5f7df2ee2338d8768c7c7e14d4552813c9939b9417c32904d11dcdb010051f77a9f697ea2b46d603e852665b5a9293f08e70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329467abcaeb0c2dcf2dbb6835fbab644652983d04c3c5964c37eaed3c9b33a41","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rkb+TBGQeHOGErRKNWCJs8c6COEc/ZEGddIRrmsguP0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4646fe\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f5b2 d887 8f21 aeb4 | 110 c26f (0) c1f9 (0) c59e (0) c49c (0)\n001 6 3b78 39d1 11d4 14df | 76 256e (0) 24b8 (0) 20ae (0) 217f (0)\n002 6 605a 6c73 6f5f 6e68 | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 6 51db 5308 53fe 5f00 | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 8 4e5a 4c9e 4d10 4d6b | 11 4c9e (0) 4d10 (0) 4d6b (0) 4d59 (0)\n005 2 41d9 4109 | 2 41d9 (0) 4109 (0)\n006 4 4558 4559 4447 44a1 | 4 4558 (0) 4559 (0) 4447 (0) 44a1 (0)\n007 2 47bf 4782 | 2 4782 (0) 47bf (0)\n008 1 46fe | 1 46fe (0)\n============ DEPTH: 9 ==========================================\n009 2 461c 4636 | 2 461c (0) 4636 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","private_key":"d31b7865721d5d0ce0dcf9cca1a8187d793be7b377d9d03fc2cb2ee745bee6f3","name":"node_4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","services":["streamer"],"enable_msg_events":true,"port":41715},"up":true}},{"node":{"info":{"id":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","name":"node_bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","enode":"enode://ca69ebb1f7477323104e6a62f28c17ba29b748f75e2f49756f4cbe9393dc68781a244148d0137abd6fb1e4a1b33ffb03045681754e7ddbb371a57dbb88a315c8@127.0.0.1:0","enr":"0xf88fb840fb7786d0be189148e7144a7b9550267ba300810396855dd94b67bc0ba2072fd71c282ccdb2547c15206ad380a71a34fbf70dbfcfecd67df851f468c0b5294c050183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ca69ebb1f7477323104e6a62f28c17ba29b748f75e2f49756f4cbe9393dc6878","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"u5BGT3aahVScFQ+GF3WqZ5JMfGUfOT9scHcnBzdqXH4=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bb9046\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 3b78 11d4 0a00 0af9 | 146 256e (0) 24b8 (0) 20ae (0) 217f (0)\n001 3 d887 f925 f5b2 | 63 c26f (0) c1f9 (0) c59e (0) c43f (0)\n002 3 90a8 88a1 8f21 | 20 9fa0 (0) 9d0f (0) 9890 (0) 9852 (0)\n003 5 ad98 aeb4 ae2b a46d | 10 a6fb (0) a653 (0) a46d (0) a34e (0)\n004 3 b7ca b2a5 b02b | 8 b5b2 (0) b502 (0) b626 (0) b65e (0)\n005 1 bcc6 | 1 bcc6 (0)\n006 4 b897 b820 b95d b911 | 4 b897 (0) b820 (0) b95d (0) b911 (0)\n============ DEPTH: 7 ==========================================\n007 3 ba88 baf2 badd | 3 baf2 (0) badd (0) ba88 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","private_key":"1681a07f3bae8df9da96df7d590316463371480d0ff13eeb1581b97efa00c074","name":"node_bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","services":["streamer"],"enable_msg_events":true,"port":42761},"up":true}},{"node":{"info":{"id":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","name":"node_49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","enode":"enode://00ec342238cfe51f0c655c27411369dca96d92b20f550c84552b0a23cbe14033c1624dff2ff2418e3d11c01f508f68c296985b7f14b508613b8b93d45b743aa7@127.0.0.1:0","enr":"0xf88fb840b31c9684d99503737f5f45f02a3a43e20c768eed666bd2e56982eebc3d5167b06146d790a41a931e1aa570ebfd5928fceb5d9fc58e3520d92c42f2296c8384ce0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10300ec342238cfe51f0c655c27411369dca96d92b20f550c84552b0a23cbe14033","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SeqtaNI91j7yYCn6P04lePPeyocIu8g4dQ2Lbb6eqjg=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 49eaad\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f5b2 f925 d887 bb90 | 110 c26f (0) c1f9 (0) c59e (0) c49c (0)\n001 7 39d1 14df 11d4 103b | 76 24b8 (0) 256e (0) 20ae (0) 217f (0)\n002 5 7125 7dd3 605a 6c73 | 32 67aa (0) 67dc (0) 66e7 (0) 6337 (0)\n003 2 5cd2 5efb | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 3 4109 41d9 4646 | 12 41d9 (0) 4109 (0) 4447 (0) 44a1 (0)\n005 4 4e5a 4d10 4d6b 4d59 | 5 4c9e (0) 4d10 (0) 4d6b (0) 4d59 (0)\n006 3 4ac7 4a8b 4bcf | 3 4ac7 (0) 4a8b (0) 4bcf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 1 4990 | 1 4990 (0)\n010 1 49cd | 1 49cd (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","private_key":"9ab9903f8ffceadd1d6a7976373b073696a0ee0055a7208414a8f1679f35e70f","name":"node_49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","services":["streamer"],"enable_msg_events":true,"port":38883},"up":true}},{"node":{"info":{"id":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","name":"node_499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","enode":"enode://c582e81e3c1308e84e2faa3d0e6bc500e0b221cb23082c6d74785246b56e0cef2e971f545dfa3adef1ab1beff9b70e5325cdeff37b7b9c5dd20e1440a73fb632@127.0.0.1:0","enr":"0xf88fb840387099c7431e9b63d69d94cae6d580f16aebc307b79c74b73b25243f0bbf6c8216bc5d70f677116c8007b76373d3e7b4f18e47409a9965230fcc2373473836dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c582e81e3c1308e84e2faa3d0e6bc500e0b221cb23082c6d74785246b56e0cef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SZA2650Q/AA8kD8J6g7gDA0ns5VkmI1nrhEfNHPSLwc=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 499036\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b911 b02b 90a8 88a1 | 110 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n001 6 3b78 11d4 14df 0a00 | 76 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n002 4 7125 7dd3 6e68 605a | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 2 5cd2 5efb | 15 574f (0) 512e (0) 51db (0) 524d (0)\n004 3 4109 41d9 4646 | 12 41d9 (0) 4109 (0) 4447 (0) 44a1 (0)\n005 4 4d10 4d6b 4d59 4e5a | 5 4c9e (0) 4d59 (0) 4d6b (0) 4d10 (0)\n006 3 4ac7 4a8b 4bcf | 3 4ac7 (0) 4a8b (0) 4bcf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 2 49cd 49ea | 2 49cd (0) 49ea (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","private_key":"c1e2eeef980866cd77150633a76d6a829b17e8cfd20808fb1e2d37307ba092bd","name":"node_499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","services":["streamer"],"enable_msg_events":true,"port":44049},"up":true}},{"node":{"info":{"id":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","name":"node_f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","enode":"enode://e46f5b92ac1643853152ba3b247bd5b51cca33a1be2f8811912a8a4c5a5eb0164fb72f56315e64256925e324661087a4c7a679a181f5afc78f2294e6b2c4d482@127.0.0.1:0","enr":"0xf88fb840a9aa17d842225b019dc9bfc778d998c52b179d856b377bca673ec81ba5fc96043cd2edc2a04f0e9115fe2b78b12778948c8db42f5dd89e0826f0f3ab746be0960183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e46f5b92ac1643853152ba3b247bd5b51cca33a1be2f8811912a8a4c5a5eb016","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9bJKH9LNKQi0CFYvmiZe4aaSsTfncBN6+l/foHsjciE=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f5b24a\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 39d1 0af9 00c6 5efb | 146 24b8 (0) 256e (0) 20ae (0) 21a0 (0)\n001 8 90a8 8f21 88a1 bcc6 | 47 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n002 5 c620 c898 cc20 d3b0 | 26 c26f (0) c1f9 (0) c59e (0) c49c (0)\n003 5 e514 e775 ef1b e854 | 18 e027 (0) e7fa (0) e775 (0) e5ad (0)\n004 4 ff36 fbf5 fbc8 f925 | 6 fe21 (0) fe31 (0) ff36 (0) fbc8 (0)\n005 2 f31c f27f | 3 f31c (0) f2d5 (0) f27f (0)\n006 4 f629 f7fa f7ba f773 | 4 f629 (0) f7fa (0) f7ba (0) f773 (0)\n007 3 f4e0 f45f f456 | 3 f4e0 (0) f45f (0) f456 (0)\n============ DEPTH: 8 ==========================================\n008 1 f528 | 1 f528 (0)\n009 1 f5dc | 1 f5dc (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","private_key":"dbbb9c96e746abd3f4c880d9fbab46e390a208e8a8fca9b24e83fc12054d6601","name":"node_f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","services":["streamer"],"enable_msg_events":true,"port":38193},"up":true}},{"node":{"info":{"id":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","name":"node_aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","enode":"enode://408575dfa357953549c9a106e6944f5fe874044b6931be8662fe92bda869094fc8a63d0beb139bef8cc4084fea888f605755214a178949930042d4111a9d863f@127.0.0.1:0","enr":"0xf88fb84023e003cb4dba2e193bfda36d19918aba6afe1dd732715d94307795abadfc3f161cda9e4fa8067ebb95e9ee4e057d4be121f96ce68c706483ca3d278da0d210950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103408575dfa357953549c9a106e6944f5fe874044b6931be8662fe92bda869094f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rrTHWlfM/JrAU6PTY898Hj4gFAZYd2mrZhXVwvhqVBA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aeb4c7\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 154b 00c6 4646 5efb | 146 256e (0) 24b8 (0) 20ae (0) 217f (0)\n001 5 d887 cc20 e775 f925 | 63 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n002 6 9852 90a8 9076 8505 | 20 9d0f (0) 9fa0 (0) 9890 (0) 9852 (0)\n003 5 b2a5 b02b bb90 badd | 17 b502 (0) b5b2 (0) b626 (0) b65e (0)\n004 5 a6fb a653 a46d a34e | 5 a6fb (0) a653 (0) a46d (0) a34e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 ac4d ad98 | 2 ac4d (0) ad98 (0)\n007 1 af02 | 1 af02 (0)\n008 1 ae2b | 1 ae2b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","private_key":"557f3cfbd77e4d7aed5ee5eb12fe2b64a66b62b1565779336756894798686fba","name":"node_aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","services":["streamer"],"enable_msg_events":true,"port":41457},"up":true}},{"node":{"info":{"id":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","name":"node_5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","enode":"enode://09a213671160d6c9f446228ec2692c94080d1b2dc94c9d7731e95b0bc481bee4fc4ab0d06fd374a143939d8f7edec35b9412902e448f760d46dce08de953fbfc@127.0.0.1:0","enr":"0xf88fb84028e698a16106eee1826e468d8c150a43995c15e006336c12f9f855178ab5b7e5299f2f54ccdab44826172fc7c3b95fe6748aadccbfe2abc713b61a087af3a3540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10209a213671160d6c9f446228ec2692c94080d1b2dc94c9d7731e95b0bc481bee4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XNI3ciaCXcfqWCMVzRCNI1At9OnHwJ/AfntKpWRA3ik=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5cd237\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f925 bcc6 aeb4 | 110 df1e (0) db6a (0) da67 (0) daec (0)\n001 4 39d1 00c6 154b 103b | 76 24b8 (0) 256e (0) 20ae (0) 217f (0)\n002 4 7dd3 7125 6e68 605a | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 8 41d9 4109 461c 4646 | 23 41d9 (0) 4109 (0) 4558 (0) 4559 (0)\n004 5 51db 524d 5308 534b | 8 574f (0) 512e (0) 51db (0) 524d (0)\n005 3 5b63 5823 58ed | 3 5b63 (0) 58ed (0) 5823 (0)\n============ DEPTH: 6 ==========================================\n006 2 5f00 5efb | 2 5f00 (0) 5efb (0)\n007 1 5db0 | 1 5db0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","private_key":"a4284995d54ea16fb6c05b66a7661d7af0bcad9d23da505a56922f494792bcac","name":"node_5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","services":["streamer"],"enable_msg_events":true,"port":37509},"up":true}},{"node":{"info":{"id":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","name":"node_f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","enode":"enode://77fb0fa620b93ebe2af5e929eaa9f0cdaad26a3530f84e2026b2870c54d5e3f5204889e8ceb85a934b36b96f787031eae04a738bc4b32a53ff25d06f890ccd3f@127.0.0.1:0","enr":"0xf88fb84036fe76e82d48bc24b57dc4307d10a6168bc316938eedbd1a097ba018675fb30b1ab095482cf7f33c126a535acd04e34af2ab224d982993c49222da20f868a17d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10377fb0fa620b93ebe2af5e929eaa9f0cdaad26a3530f84e2026b2870c54d5e3f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+SXIXmRXrAHwzWspcVX5065hFgOJDY86ReE5bZN/hoA=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f925c8\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 154b 00c6 49ea 5cd2 | 146 35e6 (0) 378e (0) 3780 (0) 3630 (0)\n001 9 8f21 88a1 90a8 a369 | 47 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n002 6 d887 d3b0 c786 c620 | 26 d7ac (0) d640 (0) d1d7 (0) d299 (0)\n003 4 e514 e775 e854 eb98 | 18 e027 (0) e5ad (0) e5d7 (0) e547 (0)\n004 7 f31c f27f f773 f7ba | 13 f31c (0) f2d5 (0) f27f (0) f629 (0)\n005 3 ff36 fe21 fe31 | 3 ff36 (0) fe21 (0) fe31 (0)\n============ DEPTH: 6 ==========================================\n006 2 fbf5 fbc8 | 2 fbc8 (0) fbf5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","private_key":"68be1214b78195a55f8a0048f9bec727e50425b7c72b445f3e9b0cba006ce587","name":"node_f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","services":["streamer"],"enable_msg_events":true,"port":46319},"up":true}},{"node":{"info":{"id":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","name":"node_5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","enode":"enode://f0602e87ed48ff8c9e5b32418ddf3f1b1342911057a98f5c3cb1cb1c8053887b84f07d0aef26934db2ee88c543ffa8c5e60dbccbc693e1162466a2a84304ac34@127.0.0.1:0","enr":"0xf88fb8400ca2ddfc019ef6efe386c9432134ddcf621cc7d5d6d6c2a4df4b691968397ad32e8730138bac99bdfa701024d5590bb583ac57b4a314223baf49ba604b6daa7a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0602e87ed48ff8c9e5b32418ddf3f1b1342911057a98f5c3cb1cb1c8053887b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Xvs7/BmfVAj3m9a9UXG0vzMsaKjkkkLrT2pYm5Y1ZcY=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5efb3b\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 aeb4 f5b2 f925 | 110 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n001 6 3630 39d1 3b78 154b | 76 3237 (0) 3373 (0) 33b5 (0) 30be (0)\n002 4 7dd3 7125 6e68 605a | 32 77d2 (0) 775e (0) 7290 (0) 738c (0)\n003 5 4d10 4990 49ea 41d9 | 23 4109 (0) 41d9 (0) 4447 (0) 44a1 (0)\n004 4 51db 53fe 53a8 534b | 8 574f (0) 512e (0) 51db (0) 524d (0)\n005 2 58ed 5823 | 3 5b63 (0) 58ed (0) 5823 (0)\n============ DEPTH: 6 ==========================================\n006 2 5db0 5cd2 | 2 5db0 (0) 5cd2 (0)\n007 1 5f00 | 1 5f00 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","private_key":"dc9b24b93ea85bbf21ab6cc53fa814b1e43b7c727edeef705de678992d971ee6","name":"node_5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","services":["streamer"],"enable_msg_events":true,"port":40995},"up":true}},{"node":{"info":{"id":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","name":"node_00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","enode":"enode://7ca882c01f3ef0c979b3991b30d470a4e12d4daddb20ff5209e75e679be8d75e9d6b98c06a763dc9d6340daa2d98079a8ed5348c7b332d26dbe72cf162227e37@127.0.0.1:0","enr":"0xf88fb8400b62eaff12a9192a15e894c5eab3f37b7ed634294a51288c0c6a83ecf0fd4a6b542b6cb20fb7bd8435de98cc27008a3cf625eadd4938433921102803ed3c11cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037ca882c01f3ef0c979b3991b30d470a4e12d4daddb20ff5209e75e679be8d75e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AMZIioQuznqLDa8GTkBd4DpCV9MIhA6lK/1I0j9U2JU=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 00c648\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 cc20 f925 f5b2 a46d | 110 df1e (0) db6a (0) da67 (0) daec (0)\n001 4 49ea 4990 5cd2 5efb | 70 7a60 (0) 7b90 (0) 7920 (0) 7e04 (0)\n002 4 3b78 39d1 33b5 2c79 | 32 378e (0) 3780 (0) 3630 (0) 35e6 (0)\n003 7 1c9c 179f 14df 154b | 22 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n004 7 0b72 0af9 0a00 0c64 | 11 0d8a (0) 0de3 (0) 0cf5 (0) 0c64 (0)\n005 4 0438 045b 07a8 0661 | 6 0743 (0) 07a8 (0) 0661 (0) 0438 (0)\n============ DEPTH: 6 ==========================================\n006 3 02d8 03cc 0328 | 3 02d8 (0) 03cc (0) 0328 (0)\n007 0 | 0\n008 1 0067 | 1 0067 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","private_key":"264248088585a6d226623f7f606b7d9b2a5a80474bb9fbe6c2194848b7dc0586","name":"node_00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","services":["streamer"],"enable_msg_events":true,"port":46209},"up":true}},{"node":{"info":{"id":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","name":"node_bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","enode":"enode://e9d6493fb95f0cead7320163b4766f3eeb98040a441ca69854ad152ecc40f844b80748c9a40686ed50aeb691c54ebc32ed19e793294170171e644ac9cc903756@127.0.0.1:0","enr":"0xf88fb84006b4143a56faaab9a4674c3bf9dccdab55411262af7d7178d0d90275ac6bf97b13323f2de3c85480f392843ae1172ab763680293f68350afae51376861d75f460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e9d6493fb95f0cead7320163b4766f3eeb98040a441ca69854ad152ecc40f844","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vMZyTlT3YTYfhRR+sQKo0aGjiBCpQM52seNh3crayqM=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bcc672\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5cd2 103b 00c6 | 146 77d2 (0) 775e (0) 7290 (0) 738c (0)\n001 3 d887 f5b2 f925 | 63 df1e (0) db6a (0) da67 (0) daec (0)\n002 5 90a8 9076 9852 8f21 | 20 849b (0) 8505 (0) 8025 (0) 82f9 (0)\n003 4 a34e a46d ae2b aeb4 | 10 ac4d (0) ad98 (0) af02 (0) ae2b (0)\n004 3 b7ca b2a5 b02b | 8 b5b2 (0) b502 (0) b626 (0) b65e (0)\n============ DEPTH: 5 ==========================================\n005 8 baf2 badd ba88 bb90 | 8 baf2 (0) badd (0) ba88 (0) bb90 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","private_key":"abbd7b59425714f0316c2a0b0d09c70ac6a18bf91c5c6f8bacc927aa55e2e249","name":"node_bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","services":["streamer"],"enable_msg_events":true,"port":36589},"up":true}},{"node":{"info":{"id":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","name":"node_103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","enode":"enode://ab61a89b8c96d76938394e59d68d35411dd069a2913459c3b93753e155054808072826f8c3486e851277442229448a9a5aea76f1e5677d9d63bd233f662349f8@127.0.0.1:0","enr":"0xf88fb840ef3ce505f3f25f1acbd8cb9d485be9cf25dcd915112ff3c33982c65dce7331c020dc2aaedc07c497e5b48c7aafb32221e5879fd926cb39cce242f3fc1e70182c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ab61a89b8c96d76938394e59d68d35411dd069a2913459c3b93753e155054808","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EDsjJVK5QJAjIZXciPhII3AfNa5Ta1r23TP6ZVozy64=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 103b23\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 eb98 e883 e854 e775 | 110 e027 (0) e5ad (0) e5d7 (0) e547 (0)\n001 5 605a 49ea 4e5a 53fe | 70 77d2 (0) 775e (0) 7290 (0) 738c (0)\n002 3 3b78 39d1 2c79 | 32 3f94 (0) 3ec5 (0) 3efc (0) 3e8e (0)\n003 2 0af9 00c6 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n004 3 19fa 1e2a 1c9c | 10 1b83 (0) 1a2a (0) 18f6 (0) 19fa (0)\n005 7 1704 17db 179f 1672 | 9 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 6 ==========================================\n006 1 13d6 | 1 13d6 (0)\n007 1 11d4 | 1 11d4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","private_key":"416b236190cb9412038f2b53f7d6d2b804e6e2e47266fed6212b9950c7aaaa19","name":"node_103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","services":["streamer"],"enable_msg_events":true,"port":35829},"up":true}},{"node":{"info":{"id":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","name":"node_154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","enode":"enode://175ecd2838e0febb3825043e19c3da58fc7b0dbc13785420d0f6a9c558cf1f58bdebd47f93bac8cf9eb1b7fd91b13f8888481aa8a08adcb1ccad83d11306e4e1@127.0.0.1:0","enr":"0xf88fb840818f538de2e08485786c679ee895bb4922fb60fe5137ed730e676b8d4e033cbb5bf437ded58aeb37c30db94ed1d80e76fb52d999f936280a4107b502891b09710183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103175ecd2838e0febb3825043e19c3da58fc7b0dbc13785420d0f6a9c558cf1f58","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FUvpJV6a69E0qRQHD15vPUu6B52cpzi3QkTbFOG1ht0=","hive":"\n=========================================================================\nThu Feb 28 18:13:01 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 154be9\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fbf5 f925 aeb4 a46d | 110 e027 (0) e5ad (0) e5d7 (0) e514 (0)\n001 5 7dd3 605a 5cd2 5efb | 70 775e (0) 77d2 (0) 7290 (0) 738c (0)\n002 2 33b5 2c79 | 32 3f94 (0) 3ec5 (0) 3efc (0) 3e8e (0)\n003 3 0ff2 0fc5 00c6 | 22 0b72 (0) 0a00 (0) 0af9 (0) 0d8a (0)\n004 6 18f6 19fa 1f67 1e2a | 10 1a2a (0) 1b83 (0) 18f6 (0) 19fa (0)\n005 3 13d6 11d4 103b | 3 13d6 (0) 11d4 (0) 103b (0)\n006 5 1704 17db 179f 1672 | 5 1704 (0) 17db (0) 179f (0) 1672 (0)\n============ DEPTH: 7 ==========================================\n007 3 14df 1400 1436 | 3 14df (0) 1400 (0) 1436 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","private_key":"324821a542a5b9cbe5f5cde557280f1fa601cbb5592c2b60a578fd741be35770","name":"node_154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","services":["streamer"],"enable_msg_events":true,"port":41653},"up":true}}],"conns":[{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","other":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","other":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","up":true},{"one":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"4d59cf1aeecf370e94a7a231887450cef97053b9c88a7fd11e210840af070e29","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"3e8efcaf3002522b39065ea30c15426d1eb55916499eff8eb5a814e39d41853c","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","up":true},{"one":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","up":true},{"one":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"b65ee2549536a806ceef4a7ccc9544567cafe6204080929fc847df0a3781ccc9","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","up":true},{"one":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"58ed74695bf527bac9a350c86d305e53e08c4999795e11cd3b2a36f5cd25d637","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"e8830f2b2f7d08df15bd33f4b2841d01d9d62c1621234bd6ae86743e52360f3e","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","up":true},{"one":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"8025c1fcb98e53f92767d1d43a3057a0acd1e8994bb4a7e3f5e244110e0dcf91","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"154be9255e9aebd134a914070f5e6f3d4bba079d9ca738b74244db14e1b586dd","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","up":true},{"one":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7dc2a9573f253f362ef1b21bbfcc144b11a6febc58aa3c4430224160e9fa738c","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","up":true},{"one":"bcc6724e54f761361f85147eb102a8d1a1a38810a940ce76b1e361ddcadacaa3","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b911b8e2d72532b7c66ff5f7bffa70f5ddbeea6903a86f9333399f0c4b5f0fe8","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"18f6e66e1cc8e620808901b571fdf525ee8f41850fac0bd0e5c5a4de70c5f873","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","other":"1b830ed484b274a96ec7ba2f9a42b6859412b5334a564014ff3f11597ea3a32d","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"07a8c900fec6c477580ed5b38848a8681dc52a19e59fa4cd32f571fe7fb2383a","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"524db81b135af8dc309b942c082a7291dddb851866fc608753f937ee77015be0","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"605a46991af15cd60e67413c712b99ff8f21173c96a7990f2728ad6cac2bb9d8","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","other":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"caf6a8e37fd41c1e6ad77a8575cd90354bb1693893952301c9caeb4779c338d3","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"1c47ad5bd8846f777daf59587feccc308f4dc63f6d27b1385ff8085c75bb1aac","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","other":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a34ea2e87d4c12adb27d66c2c95300603ff50415974e000bbcc69a5ae059dbf1","up":true},{"one":"f4565dd2c428c03d7a8d5fad87a6dd5f92ae706529eb6152d36fa584e7cdbe4d","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"f5dc78ff71a63fc2014b9553723ee676c63fc078a32a46b7cb172f357a118140","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"c6cf46239078edfb343c645f039725fdee1bbba8b0a6da02e2cc456b9223c9a2","other":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"ae2b3876bdbd6388781b65e31de182564c5d81f4511caf96588b1a287760b3dd","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"0438f567045d4556a0e7a697028d689ecfd0ae20f9e85c09b48d9f1fd0ee4765","other":"045ba8da4641da3f0b8058bb0d9d8aafbb81496dc1cae2a3fd9c039a7e1cafb6","up":true},{"one":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d640472351969a5578e541aca72b7640c583b995fd62607ff3ee3f3f3139aafd","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","up":true},{"one":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"5db08436c64f4cc9e2b3950e35bc8ad739825e3efa67a642c771d95b34cb420c","other":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"29957e8e92925a8c79bdf513295d96bfb62fbfc597ee1cf767c7ef408f1b1295","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"b626d472b555e6f950a7142783db8deb443a74e63ef6bd72a87eaf1af14ca805","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"eb98fb45dd5754f24f9df0c9ecbb93932e3d9d7735cd6d0ddd4a8675bb4ef554","other":"e8efe8016fe6cf649b2755bee22da35ccc6c9c55d404d5385d61f6ea27b84380","up":true},{"one":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","up":true},{"one":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","other":"d863ba7405eb07ccddbf1d34efbcbec2867a93a109ed9413d9aecf30d3645a6a","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","other":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","up":true},{"one":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"2c3894b6e47cf19ac7ee9fe213196312f676256f670dff25b03563492550bc74","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"aeb4c75a57ccfc9ac053a3d363cf7c1e3e201406587769ab6615d5c2f86a5410","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","other":"bb90464f769a85549c150f861775aa67924c7c651f393f6c70772707376a5c7e","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"7920d69cf7e458fce0781ea1a4e07768e1a69f6818090eff0abf0b4a0c2c35f8","up":true},{"one":"775e7be502df8fd938cf9c42ee4fac33e460a4b6992b9efeb8dc1ff7dde5c40f","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"7b90e939ae2a240f0d74a923afb6bbf11f6d5b99a7bf85f1825b1ea36bce744c","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","up":true},{"one":"7dbbdeba3731e1ff43072f8cbd86db147761e1b61753eea7024774dbf46914bd","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"c59e3953b64e5b9ffbe53990a358914f2fa8e3551d33f92b9e3a441bd1baf2cd","other":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","up":true},{"one":"3efc4b120b3eeeac186bf3a4cd42eb8c647f7edb08c23ee643e2bec9d72c5bed","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","other":"37801e8d7d46143f78924ed66099f658a94d37edfd2f58d02acb85add03e1894","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f2d5533eed4b0c184952d859d67e44abe5a75a5de6111c8c106b8f4b2d8ccfc4","up":true},{"one":"9890e6ebb2c6f9a7bec4c2778e077e3710ce3af356f82ae9b4d324832d159ef7","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"04518d7120fa8a528d983ca1ee6d5d09ba24a4e853fb22bc9084cdf34995e95f","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","other":"e54b643cbc95d9f5d27ec3760d892b6802981bfabf4f9979267d66259df982c7","up":true},{"one":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","other":"b2b5ba1bb188f18f79b295f2c0d48c52c1d1d449ecb9b94b9984f3a6179732c7","up":true},{"one":"e027a9f7152641c4a41154f8ce4dafd23895c312150efea86bf4152c88d0ca86","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","up":true},{"one":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","other":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","up":true},{"one":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","other":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","up":true},{"one":"006727dc6f59b120b24c17b8e63f80ef3439105f8118ffeed408f105a48ee60c","other":"03285e06657032778feff0b43828c964dbf9de669f63171aeb587aa1a1facc0a","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"5b632eaf700d173ff15f4727b85817e6173228c304b422434a08c2cad438b825","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","up":true},{"one":"886aff1f1e3b86bfe901066bb7948451c18fe3f8cd1b7318b05154890ca8f738","other":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c786ff8667f509b5a9519984c1d95c83a5d2e257500a71429e8f23af610ce771","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f27f1044777e05f3f60165d0d2fc3e7667fe148e0ca7a097805d60b9f61025f7","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"67dcfd21ece30b41a39bc55c0986fca8f401bb3acba821969519f09d0933e8bd","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2d3645c4fdf9a2809a909076b9ee5fb98fa880f6faeff914f1a2987af928cd79","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"88a141c607019477c7b120a506285a7218cad2faa038082e0b9ddfcc9cb78d07","other":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","up":true},{"one":"849bcbb9be43b799fefc5e689efc75125da27f536e97e5b7921031520ae6e5d8","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"ad9899f78659492ec248a884927a757f3f3b4e76cd2abc46ad8766251fd8afed","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","up":true},{"one":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","other":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","up":true},{"one":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"7e0458ecdf7081443cab5412529f3948ece659facaca03208496c80dd136e704","other":"7a608d2cf9d1d9c5819dc1f9e88e5cb2852aadea01c40e047c2e184b62e7163c","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","up":true},{"one":"5cd2377226825dc7ea582315cd108d23502df4e9c7c09fc07e7b4aa56440de29","other":"5f00b3bebef2f5484ff1386298add68a6743a106200ae8a13a27dbb52714ee8f","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"efeae3b7f610dc10acc51068e7718876d147cd78a9a28788c5dba5bb3a6950dc","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"9852ce267d53106a6e584d6eddb08e0062eb4a422d2a8d39ad6dccaebac552ff","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"e7fa7112adc7b023dd5965e620277122542153f87eaf5deeacc8a51f1778ba77","other":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"a6fbe16b81d240ff2f2ed6c93cfd9590731dfb2e7ec3fce1c098fe542bedf299","other":"a3693801a91180410cf3e85d7c09ac8054a769e7b1d55c9e7a46850cb8217da0","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"f528aaafd67b20dafdce101db224aa01c70f93bdc91c14f50fa8db1dbf9fc386","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","other":"f925c85e6457ac01f0cd6b297155f9d3ae611603890d8f3a45e1396d937f8680","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"2a97d308a720274a440dfa6901ca0a5480af9bab58dd8a6c4afdb9c83ea964c3","other":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"1436aaa8770e9f1c6294e49f4066c16b1caa50524e9b8fd058059e41657d2a83","up":true},{"one":"6ea51fb6e4783f351dbbfa47b508c78c73233ebaada409dfb55446217f92c4bd","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"2c79af7ea85f96db7897cf8cdb4d002ad2308194e03981876edb8d904ef65137","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"ba884e5cfa1ee6eb38217181711e01bb0c37b3e33d1424dfa89ed3e29ef6205b","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"4a8b610e09d35aa21c42ab8c3e38de600a944c094e6b86ea56828b5e6904f1f7","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"2ccfb5b1f3923d35fef88838c508b98b5516c5d409643881d2304ae49e50eed3","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","up":true},{"one":"baf219e9229921b773d1ad7eb7eb5216cfa60ccecaa3c5c487e3b71cb600ba12","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","other":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0ff2d2c49547eebc96675e0b88073dea5e9091bee1843ffe567127e34486c348","up":true},{"one":"af02b5d107b3a17f539c7f9020ebe74322434634e70c420a7f56776eb5d9db73","other":"ac4d2d6836e2cdf4c88221f6013aac70a451dd15bc403288bd10d0b911cd9a2b","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"ff36a8810dd44f6d1fa42aa91ff6206bcfb4c1ffbab0df73a181daece329e0e3","up":true},{"one":"fbf5e917be45e909697a9393c4778206333cf1dd9a103978e8d71622ca3b1cc8","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"a653302730df3d58f796906a93933aa81494f2588d9485ab7676ec3b0ccbb426","other":"a46dd535e3bc8f111a8b2ce5594b62e87741c395e8a2b8fbae33edd29cb8caf8","up":true},{"one":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","other":"6f2d756566dd5b4a13ffeea9f687c785148f3407a502e28b9d6edfd03b905fdc","up":true},{"one":"103b232552b94090232195dc88f84823701f35ae536b5af6dd33fa655a33cbae","other":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"9fa0215e980dc907df4cc47ab4937f36527d78f9837493016fd4fc51e617299c","other":"959fda0866d3c18e9399e98485d627044079d6f86b075edaea9315402f5d9395","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"e5ada0415c92ef1511b15d04edf395976464afd9adc3e929c41d4d21d25e3182","up":true},{"one":"d3b0dea1dd3ac71e7e4a30941632eec53cb980aa7cb6cdac95042a5400a878c3","other":"d7aca8f2182bc625d2b3c942bd1161c85bcf1c2b34ecbe3e2fd23cfae6b8a871","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c43fbee95380007274b8f231fe34bcd59b5c0ef0830b174967d4702627984fc6","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6fe9a02e950a5c3a5ff026b75922ed687d59795ba8eb9c092a8d09a5c64d2453","up":true},{"one":"0cf596af91eb9b041fe6dbe6b288c5730413850321b5ab176c81447e34ef79c5","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"512ec5c2e6b4d788482462d941117c81fcc0e73f0c15545794dd1b4e03bf2102","other":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"35e6b1d31f594c06b759525434a7e717ebe6f27ca0188f247ed1247664a50563","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"2f32d54f06989efb6ca5431b74cd759fba05dbef36ecff8fd506e662026af983","other":"24b85c10f098725938ea7d87cd24a4b10358129906fca9790fc266ea8784b538","up":true},{"one":"628e7da3359ed6d9dcfbafc7581966e4e09245c321ec78ca75587c9cbb44697f","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1c9caf028df31681b1457a54d4b3ab20009f9fa5bd12417a1ba7efe0c660e6bd","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"da67ace34f7076a1d550bc61bc2a31da88d6cd9f9df43b142a8c6bbade1b4aee","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"534bcaa98cf9192b35b6014c650ae067e74332c015ebb516d63601427d7376b8","up":true},{"one":"33b5c521b4208e26414db2e05c9a8ccc001a524d928579d44d2e74d14a56593e","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"88fefb7506105c0e269baf52955a01b19f55504b13133bac0beab41c9f6e6942","other":"8f2182c2c2d0eeb2e887dbc350ae7257819f536032851ffdf29e7842cb1a62cc","up":true},{"one":"c620752a083ca1ff0398937235cf964133939452c293c799ce07ff8aa2bde420","other":"c26fd5e6504c7b3f0a6d9133ff87c98c110eb1c201c5f3bcf6b10653f2b972d2","up":true},{"one":"256e81c5a6fb43bd343345477f8f96aa1947f07ac3297f631ab03f060147b062","other":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"4d103ec5afee559a5a9242e8d650b67301eaec10e96fc2f184e34d48554108a2","other":"4c9eab8ab45405a6d4bab46430efc04b8e6aec1d944f88435eca41361925f379","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6e05179dc90a8f6654d0c9a3f06173371dcfb18b852fdd77f35f75e38f273125","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","up":true},{"one":"4bcf4eb531d5ec4b31d99e8354af03f976524c7858a1e7043e9b7055326f0952","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"3b78bc987c7c31c94e8ada9b4b11b5db9387fe70dd01ce7f3e976d3bec433dec","up":true},{"one":"478278187cd9af799e83340a2f49b0b7f122fb8e08c0a372a87795426eab364b","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"6251e9540448726a601699ef4cd19e50c969a746da27228967338cdc09d628bf","up":true},{"one":"5efb3bfc199f5408f79bd6bd5171b4bf332c68a8e49242eb4f6a589b963565c6","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","other":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","up":true},{"one":"32371744163f0b3aefd3955dc4877e7eb82b17ef9541c333ca9c0a9f8aec3045","other":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","up":true},{"one":"582330d8b8c49331b2aec790dc7325b9cd483fc8129323d31ec429d545042964","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"4636f00be60a9b494a3ebc9ab41cc7cb53ec0b0beff214db2d0a248dc3aeb6af","other":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","up":true},{"one":"738c2d42458965d03c8f9f055eaf0e3edf3dfa2a4de0a048ec05b78e7b765c90","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"1e2aca93fa9442a0034ae8d295530dde16fcbfa8c37227e2e6863babb0f87c34","other":"1f85b8c05e5dceff0bd8256f8f6d80d4b902a9754ceb952d95ea2e1150ef9e59","up":true},{"one":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","other":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","up":true},{"one":"ef07be559914ec4b5930d90d8d8b6f32dab9eba23acc36f14d512307f9974348","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"db6a1f6b342f6be9517f8df01003797c11c837d9aee3cdba5b7859230b36c35d","other":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"63370e288ab2e4b8403c6678e9c44ae5c7496b5ead614306fceb85986ed29d18","up":true},{"one":"30bec7cd0a7d002839aed7654129bd2fe2e2ce7f42aa7bae1560e8bf718954c3","other":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","up":true},{"one":"53fe2c13926507a7a6c27d0fb30a2c358c4c7bfa40df8b5fa8ec8986c2450519","other":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","up":true},{"one":"cc2037c08942a094df12f45831f28e0015fc3ac04d5b8f24ffea9bf3a0b02c39","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"30897492824b19540d13ef17c70845be6dde455dca4e4f84cfca14a2c373969f","other":"314a3530a5e0c37d5609149b3ae9c2e078573346bd8fce3c769ebaeb31726ec1","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"1f670c53b4c597beaffacd84e3a697225b04cded9219d0a28e1fe525a3cadcf5","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"3ec530761ddb87f930fda919be67df18074c6f0795292add1b2a91ff3d9c39e3","other":"3f946957d910179c7e1a83c44369aacfc31f5727b1a6421a01c8a978ccd349a2","up":true},{"one":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"0743bcf2aaa77e916f4a367d6159473c7d80f46a2e4cbe9ef346e423d39d7072","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","up":true},{"one":"82f9c9009f09de2d6a77b54976d14c14211eae65d886f6ed57560c700716dd5c","other":"850575577d6b420a87aba388af481e0c044c2f75cf29ff934daf5674318a61ba","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b820e480354000c837b1781ec1c493e8776b4834252e6453425ac05b925b5a58","up":true},{"one":"e8548b5df15adf0f2a997ff5709827beb5e1d36bb08a2f2d017746d5c0e83fca","other":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","up":true},{"one":"165f1af67aa1d24569e0bdff61d29b3c39e93250071d8f25b5be6face209ac6a","other":"17040a3aad5930d8e0de1011fd2996b7d09225989f0dc1ae8f7e7a52dd26ab4e","up":true},{"one":"16725e318322353befc2f2aba112f0984bc011821bb16c98e2cd8b39cd62aea1","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"33737df75bbac1b41c63f05ea2cf1523b972df17f22bda026db84a49ac35e1e3","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"4d6b939fb67338c484948ab92b2ceea4d4b666d7e08773673cd7c8f83f495b89","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"daec45eca40f48843b41f70267c07e94996ced829f02710f15354fbe26e177e7","other":"df1e4e46e8ec26cad74b4f35ab070f12c8f6fddca35ac44c1218ff60fe1e6bab","up":true},{"one":"53a885968d68d8ebf7ed514e662cc13fa03186d2361000a03576531fdca2a25f","other":"51db114a52827f5b74088bd0fc87d35229e7740e7d121bd7699298396516a880","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7125e05bf1bfe6df948c9276b62bc755fc6b0ec8d4ac7724b61ea49591adcf25","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b2a563ac59bab4dfddf7b6e27b80ee7afdeb2e4295411107903f484bcf9fc4f2","up":true},{"one":"68317431e4fa55be4a700e35c6a578307cc32b72336679b5c5618b622ef0c602","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"c832b4ad64a17da4b796ffcac646c2aa666b276aabb7eb3bfe7981d64a4da402","other":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","up":true},{"one":"e5149cedd990072f2aaa9735a9259f28973c45876660c2d86ac105e56cca8e68","other":"e54784cfbcd89c37c8f758aae70ece3ab4b7f8c30fb4ef7543e04aa89ff4386b","up":true},{"one":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"d1d719ce1dca507598449afe966396c160ad25ad632112ab268b1d913b490dbd","up":true},{"one":"461cc9f064e6f4f06ff38e0d1f3f00ef8807ba31c7258e453cc682e9551bb1c6","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"44a10530c376b215baff8531eeb2afb8d6714c4d0350d1a6f32761a97cd6c7ec","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"2abb938b889a2eb735134462985a56056be48f189b5b89d23b653864c76427f4","other":"2a0a8eaf1a2749e68f8b841578c160699cf7907ff23842c6d616ad884e5f613e","up":true},{"one":"915d7a0510bad19266eef8f00ca0cb2efc340253775706495fca8b9160b512cc","other":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"9d0f804849b72397646ba48208ba1e01dcf4de04e788016c4a1a0c93e650ddf5","up":true},{"one":"21012a3a6ef1ece48fd9d7cffe62dc75839dd062efcf3ac5f962c237814da407","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"179f21d2e0421b8056ee9a260bc0985bfa64a52a36d0a8fbce4e03f3120d1d65","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"6c73150490e8be9677c40086de0aefed1939581048e26f4a93f5ca26571a1a8f","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"ef1b70bf090bc9994b1d45e2812c56ecb430a89c346a436bd10880bcda700351","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"1c8a10ecbd72acb2bbbb8b77ea5404f9e90f4dbf306ec8134cfed70b40aef399","up":true},{"one":"3b88a472beba4a18f8df45678888fd359bac3823900eecfe0037fdc9ad54d416","other":"39d1fcae2d23c775214988251505c577b9ac7b6851558ddf9a437dfe143f3845","up":true},{"one":"67aa5463e4b32b363b3d01d2a41ccb03199411057276f4962d053160be29a6ef","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"ca041da0dc514643d017458d08ff6962ec52c9e66571a239ec395dc8b2546709","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b95d88ff6512ef8eaaa6bd842fa44175c1484fc2e8601b83d50a5ffa992bfa3a","up":true},{"one":"455936fd22c43794e6e2104fd91d3f5d246e3823e8ff8eaf8dc27aa9f3d2ee08","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"e775e9759d4701bd9b43c22f1d1be73c1262b2752bb23cb3857485daf1dcad2d","other":"e5d794d64003725a74642f097c0ee76706d78419b6f3ea819d440bc0ad166eac","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"fe2167fd33f383110eb3f6caa7bd905ca54fa0c810f1b8a34483a846f3cbddab","up":true},{"one":"c8986871e46f001d15ed8b70f2aa0fea8ae309d5e5671a500f619e3b348c8c15","other":"c9f5acafbbf8c66647de05b0848d79451eee490709d53f118fc2051410cc8203","up":true},{"one":"f5b24a1fd2cd2908b408562f9a265ee1a692b137e770137afa5fdfa07b237221","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"66e7fc2df51f5df8d7329851fe9357d895e9d5dfdc25f8d92bdb10a960f7e15a","other":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","up":true},{"one":"90765b72283f59be4cf9bf7a9e9a22fd6db701c3603cbc0817b4adf2f8e9ce08","other":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","up":true},{"one":"c441d27a5f4abaa8e3b0f040a6ef85bb8c970031d6a57503a674e36b3d6915d9","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","up":true},{"one":"baddc778aea97acdbbb5bc99744a5545abab9f6047c81f328761645287ac391c","other":"b89793c3ccd9ea642080728732ce7df33778653fed3d1d8f3a25e60670e33325","up":true},{"one":"6e68ea86440706a0d73a9508f2247492543163f8fa7e2dc2aa62b74d50261b8b","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"c49caff13862dc089f1f9b8180d6efa455648375662719272102c4f8028799d6","other":"c1f9e8e1d509febdf1f267bb227741e513420048a2e669ac9eef4b05a29cf10b","up":true},{"one":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","other":"46fee69dad8b6a6a87d356d10db25d835a0c4e154bf179e88fb4cc65f97d72d7","up":true},{"one":"fe316679eca0e0eb823325812a56fd27da02653b06ada2fd03b27501bda8371a","other":"fbc8087a723c564ca0139329902e79748af46699ea7be24d57909a7e8e96f681","up":true},{"one":"20aeb14f567dd16f06b0d3b589b83283daa00a5ed10e447860bda946baccdd2d","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"b5025d153581d333b44df4b9bfa69d87de138905172e4fd317e16f7099a5fcf8","other":"b7cafed41dac01dd59e2bcaeaaab551ebfeab8eaa1f97c1866fe0ddae772807b","up":true},{"one":"49eaad68d23dd63ef26029fa3f4e2578f3deca8708bbc838750d8b6dbe9eaa38","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"b5b24532d2810e311e10b1d606baf6007f9124b88a178b32713cf1eddae089be","other":"b02b01a5c37cb05c287a3dc7d04e305de26f8d62dc388542eeb43e97db7b4282","up":true},{"one":"03ccd8d52597d18c0b178ab7361d847d63aad3af920a28345977ae170a1dafcd","other":"06618d829a8a7317a98f1a40ecf8864e1c94c4e270a9e4c008229dc7cf937b7e","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","up":true},{"one":"02d85b9f8e4776224ae5088683a87837b82b2bfb7e047cf373a28393e7aca6e1","other":"00c6488a842ece7a8b0daf064e405de03a4257d308840ea52bfd48d23f54d895","up":true},{"one":"0c64e5af869b1665fd4016ae6d04c8eedd423636f06d78ecb944ee8e3272a82a","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6ecb5c36fc0150c287446ae8a8682d629a1d39341230717206219babe3bdf659","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","up":true},{"one":"17db15893bf39b42593ee1de975aba6832046d9da5b4b493ec44272738a29cef","other":"11d43f6ed0ddd5afa5c8a7abf7c62a4fa865b7a25ee295bf1a49701ef3081363","up":true},{"one":"d887070a0568282c69e96ce65612ba72d5ea26b5c80671435d6e1ed2c4b49301","other":"d29941d6b8acd86cf32fd1c2181da3ab1da3c2083134b068ca49ce29aa86b783","up":true},{"one":"3630e05326bacea8fcc739dec42085f845f416ddc698c76ff91f099eb1dc5007","other":"378e7af7cc019186d4f2699e753e2d71302f8f3565572c13b7a1b1c5cb47443c","up":true},{"one":"47bfa3767cefcc0831d410d5402e9396e8a412c8c96faf55b451d3ff310f3b02","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"4ac755123dcc64ef44db9280311af51f3f7a93e0dee67370d673261220356eb9","up":true},{"one":"53087084708cc5ee63ac459b18fa10ae52a823139b4ecba6c8691d4934f2f971","other":"574f65867482091aee2774033116c233525eea711706b5ae9ba09b54e896d302","up":true},{"one":"f7baef876a62b92ebe5ca9ec6a085e0eb54fd31e2425e662eec747df3cd77592","other":"f45f1f2e59e947e04fa15bcf87f872ef6d73b73f778e12d1f9b8930ea166eefc","up":true},{"one":"7290cd3affade5f9e729d1b03549aceafb2576cdbc6789fd688c95495f10bacd","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"4e5a46c004e85cf86a02fdfbf2243018825d015debfb9a077a1283d302293b3a","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"976e57d0c32227222bfd0cbb802f269bdcd52d5d33cf689c66b12c023f5fa8bf","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"ed2d3e1e5693b44494808907c98ec54d6d08331945d2a2c03e31130fef1d2586","up":true},{"one":"0a005eb9c10c5cc9f720cfec2a655811d391671597b4f32d12df291ec76b2c13","other":"0c28cd1315890629896d0fe5517524d4eb788f7444709c135ea690ba4e6103d5","up":true},{"one":"610334a0772d3414652b575f2caa6f2db32224907c24d06fda643db9f2ec2afe","other":"60d7337ef806be95ccaf7b9d663a4289f9afc68edced62904ab50601cf113f45","up":true},{"one":"0de3915b0bcc68040c8aa76fbd2cfa0714e9b34c9dbe0838a7cba81c4f73581c","other":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","up":true},{"one":"f773b83f1a1de2ab6660edb0b765cfccec6778061ee25c5a84f968625686ef60","other":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","up":true},{"one":"ec52270604007673d1bfda1edbd8bfa945a21141efd85e42b684a9f30f8cddae","other":"ee5e77df690329c132f2f7fca223cfd384b7bc34ec38763a4eb42780e0585656","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true},{"one":"82dd83838cb982b89505ef249d353a20e434346dd78b71cd9b809f71d5c112da","other":"898d2f7d46b4961b646d5a6142d54d6233b7f80f668ce234522dd02e2cc545cb","up":true},{"one":"6c4dcdfdee0164a9a3f419430726dd51f9198c65ff6e7de7aaa6f632dcde6794","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"6967e7438125c2045d575eb9f407b4a38d1bf9dcd1c1c1a97f750da6a21aeff7","other":"6f5f5a77e6092e25e5308413e02ba62c1c559024893a7fb98e26b0f34fed8bfe","up":true},{"one":"13d6cb9316e289923e2d1de7f3c966d0cbabce3acdb8017122944f4abb140912","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"f7fa2986ec9f84822b11a6b00bd03a1dd26f2a0fab90b1b308f08caead43cfe1","other":"f31cc744ea921fee8364c5269b1ce7ec6b5f0c0cbb6885efbf602de5b36f6169","up":true},{"one":"14dfb8414d17b2df15eaf59571a8cfec99b1fd674561da63ee99af853bda07da","other":"140020a23a840b8840ba0c2c384f853a606330e9743885e9967cf49533db282e","up":true},{"one":"45584a4bebb948ef5f7b55d4846ec5549d7623682169c0edcab5b3523e68c7da","other":"41092c852fac630df2a9ca0862716f8e9fb8566c904a49c96389071046bc699d","up":true},{"one":"499036eb9d10fc003c903f09ea0ee00c0d27b39564988d67ae111f3473d22f07","other":"49cd1efed6a56a78af4ea4ab40813013e76c6a5fb9d2029ee02db5d80f5e41a6","up":true},{"one":"1a2a0e0bbf83cd40936995674418ae469aa2b92876a4ceeabd8128f536b7d7a2","other":"19faaf891eb6a716902ec29d201dc2094ee474acff188ae86faf9760674b2d37","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"4646fe4c119078738612b44a356089b3c73a08e11cfd910675d211ae6b20b8fd","up":true},{"one":"77d2ec52dabd5d7f326d4c6afd2aad110487c6bdffa2984060528716ba873462","other":"7dd3078c71087ab88d4d26a962820bcb79b8ce30e91c1f9a69d4bf8d38086960","up":true},{"one":"217f9952af1eb58d5ca5ac7be763716cfe2c0a4f3cdd4ebe4b5df563f919e2d2","other":"21a044e772b7c955fe4a6fb7c3a9a20e95d48b7fd6b9518741782f04f5f1f5c2","up":true},{"one":"444722a15b01a0d8e6794798d239fe621d59bdfc08823ab47cbd8b9acebd23b4","other":"41d9c03e44bec3f84a6139ce40ef1e390530f38ed11860575acfad03a49db095","up":true},{"one":"0af9a57a2f66835cd3e4e71bc026013a8a99ca337a7b6b6cc34e11d8da212a4f","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0e5e0bb1383b2ec569b157a1d2ae6900592ab892a28367f5613a4e29cb265088","up":true},{"one":"0b72054403f78a64a787f46e9f26bf0de7bbba5a60cb105e6aeea46cb4a1d9fe","other":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","up":true},{"one":"96fcf14c7f90350091ac6fcb58306ccfb9e4a38d3da59f8ab656854332844cbd","other":"90a85cb7363ede161ec21cc89f8b9d4350e566cf10586a66d31b0a8677620aa1","up":true},{"one":"0d8a919207fb2d5718eab7da95f8efeb01a4e1ae39602d315f8ba2ff1752d9da","other":"0fc59bd04ac9de3195e3c9d0eb573952a5805dd2e7e572078b6e996778adec73","up":true},{"one":"f629b8b9e79c75ac559daf9bf4fc8672bfdd595cf2c5d17a8885282626fc65a5","other":"f4e09f89287bd1af7833acd85ba7cc71fdb3ff34f2f409e1cf2a878dcd3183dc","up":true}]} \ No newline at end of file diff --git a/swarm/network/stream/testing/snapshot_32.json b/swarm/network/stream/testing/snapshot_32.json deleted file mode 100644 index 527474d0aa..0000000000 --- a/swarm/network/stream/testing/snapshot_32.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","name":"node_427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","enode":"enode://e94f375f0c1c7974305cf5d1fecd64491ad73661ce194a272f674e89051c5d5b951abfebae5a5fa9dbc8a26adeec802ea6188fdf67b7577fabf7355e92cc5d27@127.0.0.1:0","enr":"0xf88fb840ec3deb0830cbb5f0f9a78c5de4a7ca5fdecd378778a9255dad6ed45bd13d5ee61278d01af7de31abfce7aeb9e6d5421c0f614db1be5e98fc2fc82806a56fdd590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e94f375f0c1c7974305cf5d1fecd64491ad73661ce194a272f674e89051c5d5b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Qn9L39OFeWivXaNu7qBBk46ncbxsXpDujTWFz1efE7c=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 427f4b\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e4f7 d756 | 15 e4f7 (0) eed4 (0) f4b8 (0) fb64 (0)\n001 2 2529 2f17 | 5 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n002 2 76cb 6ef5 | 8 76cb (0) 74b7 (0) 729a (0) 6646 (0)\n003 1 577b | 1 577b (0)\n============ DEPTH: 4 ==========================================\n004 1 4c5f | 1 4c5f (0)\n005 1 4601 | 1 4601 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","private_key":"fcb9f591c3d058107af08804ccd4dfda279051673a0b48360a625d6df6a02de9","name":"node_427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","services":["streamer"],"enable_msg_events":true,"port":45919},"up":true}},{"node":{"info":{"id":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","name":"node_6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","enode":"enode://bad4b2d1652369de53e8b0f8f6c150f6bc3b38fb2f0d308b9f04d67964fa9440fc07581d83ba0e665be33aeadaf738bd53f4bbecfe55e4fc31c5af587ef74c8e@127.0.0.1:0","enr":"0xf88fb840f17e139df282d76ab7238fe8faa15fb41d782a0664a4732df0f7ade8fbb865db350f23fdf65ac06bff32805a321d85092a22e6b315fc0400a4ef16b16f215f200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bad4b2d1652369de53e8b0f8f6c150f6bc3b38fb2f0d308b9f04d67964fa9440","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bvXeXByOVbyJlIvxCnoq0RsHFw87XwSeQKheJEEk7uQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ef5de\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eed4 e4f7 | 15 e4f7 (0) eed4 (0) f4b8 (0) fb64 (0)\n001 2 2643 11bd | 5 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n002 2 577b 427f | 4 577b (0) 4c5f (0) 4601 (0) 427f (0)\n003 2 729a 76cb | 3 76cb (0) 74b7 (0) 729a (0)\n============ DEPTH: 4 ==========================================\n004 4 6013 6304 62ac 6646 | 4 6646 (0) 6013 (0) 62ac (0) 6304 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","private_key":"9f0d5a60a7b0980371a7eef29848b7d3c4273955e10456b6bdc71881ee7154eb","name":"node_6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","services":["streamer"],"enable_msg_events":true,"port":37449},"up":true}},{"node":{"info":{"id":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","name":"node_11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","enode":"enode://4b00f923b2c2e9c70b840f0c0e90d0941bb0875cca7fa12ec8f43c5eeb563448b209ae04c2a8e7e6e9cf2a9e9ab9ffb3c6d463db1351d8a990be553742f34fe7@127.0.0.1:0","enr":"0xf88fb8400c58fcc017555e27e75db6ed84521f731670fb55dd5e1f57543d23daf810a39a4ea3d74ca6680f4fb340829a17fd81d21c970e3feb3f9a04b8d1c29f974c75930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034b00f923b2c2e9c70b840f0c0e90d0941bb0875cca7fa12ec8f43c5eeb563448","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Eb2BD3ukH0SBbzOhnZxwPSbyzK6ijEr4JfUoiAcK2Nc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 11bd81\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 cbd4 9e27 | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 6 577b 729a 76cb 6304 | 12 577b (0) 4c5f (0) 4601 (0) 427f (0)\n============ DEPTH: 2 ==========================================\n002 3 2529 2643 2f17 | 3 2f17 (0) 2529 (0) 2643 (0)\n003 1 08ff | 1 08ff (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","private_key":"ff99d767a883944922bbba96c25e19cb78641c0e9f32b2de37db70a29151473f","name":"node_11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","services":["streamer"],"enable_msg_events":true,"port":43277},"up":true}},{"node":{"info":{"id":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","name":"node_9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","enode":"enode://1140e5da7f3da364ca5e55f8598cd121887f4b1c780b8900f090cd35ef5b52873dad20397e7d2d1ba3da0c1c16df19be8d373165c5fe8af1fcab7c3daaa501aa@127.0.0.1:0","enr":"0xf88fb8400194560390e74c85e87bea47d73cf330581219f8acc6a7c4e5941f10b3d2970326116cf7258109729e7226bcc66d4624264aa4d717825090b70494d0664452810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021140e5da7f3da364ca5e55f8598cd121887f4b1c780b8900f090cd35ef5b5287","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nids22IiFQifDyAlKmq6IPV1Id+U1AHvoT9gS2JTTIA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9e276c\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 11bd 4c5f | 17 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 a11b bf27 | 4 bf27 (0) a11b (0) aa7e (0) ad46 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 94a2 | 1 94a2 (0)\n005 1 9934 | 1 9934 (0)\n006 1 9c93 | 1 9c93 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","private_key":"5509584c52b0fc75d12256db74098c2d08e2a03d515c415f6760c94ee65396a7","name":"node_9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","services":["streamer"],"enable_msg_events":true,"port":42197},"up":true}},{"node":{"info":{"id":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","name":"node_4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","enode":"enode://b4b928549c694b7d425330835de106ba3900fed27db077d7ef47b9de24d3f171dce1edfb7bc05dbb087d1935b11690fdefeeb8d52cb86c400241c739408077b0@127.0.0.1:0","enr":"0xf88fb8404932a241c860d9e3781f3d3e3dc57c0d0e9aa03ee53aa2e9cf343ca198f189e26f5912ca878cccc0b0e91669105af390f60cd802aa9c4d858eec97139ead6ab40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b4b928549c694b7d425330835de106ba3900fed27db077d7ef47b9de24d3f171","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TF+rt6F8Oj9YnH0uyjwN1aa4IXqrxUMjurdbavODrGw=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4c5fab\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ad46 9934 9c93 9e27 | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 2 2529 2f17 | 5 2f17 (0) 2529 (0) 2643 (0) 08ff (0)\n002 7 6304 62ac 6013 6646 | 8 729a (0) 76cb (0) 74b7 (0) 6646 (0)\n003 1 577b | 1 577b (0)\n============ DEPTH: 4 ==========================================\n004 2 4601 427f | 2 427f (0) 4601 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","private_key":"c8a57fa979d839a728714a0cc091d9c35560d850ce2faa0431b758abd3363c79","name":"node_4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","services":["streamer"],"enable_msg_events":true,"port":37685},"up":true}},{"node":{"info":{"id":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","name":"node_ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","enode":"enode://a1662488c10698fca196fe9453c596e65bcc779371b4d765754a24a188cd6b680c1c8e07e21686f6caf4241f9e661ceddbbf57663a59fd739d4d01d845ca26f5@127.0.0.1:0","enr":"0xf88fb840e0f39d0e5ddeae60c3fd876087f642a075cea50df66869f0ab54b49f320750ed3f59eb3a2f096cbf67fbc0eb018b819416073d12c1d4c8d14b02697b305448fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a1662488c10698fca196fe9453c596e65bcc779371b4d765754a24a188cd6b68","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rUZDWDqggrO+984buNz1X+LjIbiVQADPrGvHLEnoX1A=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ad4643\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2643 4c5f | 17 11bd (0) 08ff (0) 2f17 (0) 2529 (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 9c93 9934 | 4 9934 (0) 9c93 (0) 9e27 (0) 94a2 (0)\n003 1 bf27 | 1 bf27 (0)\n============ DEPTH: 4 ==========================================\n004 1 a11b | 1 a11b (0)\n005 1 aa7e | 1 aa7e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","private_key":"4bfc56ea8d973de3d6f451825ca9fcfcb36e1d6624c0f1d1641bee8e6683bc59","name":"node_ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","services":["streamer"],"enable_msg_events":true,"port":45407},"up":true}},{"node":{"info":{"id":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","name":"node_2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","enode":"enode://40b0f23d8cdc7ece33f3ebe012b2ad3c7b5d78c141883364116214d980d525cbd06bfce04c2312415cdbf028886a45ce1ff0e8b997c2a8b692415d5087f34641@127.0.0.1:0","enr":"0xf88fb8402fa9bc618382dbb09eb218dc9c159ceaf6b7f5daf74d44a16a47906fc9beaa9e2bdb5b7f188450d97625ec4536570e127e386356252f969bfe411c70d4c6d6390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10340b0f23d8cdc7ece33f3ebe012b2ad3c7b5d78c141883364116214d980d525cb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JkMINELunmlRf1AI5MpU2/pAcmveIiFrU7+QOJWqCuA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 264308\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f9ca ad46 94a2 | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 4 6013 6646 6ef5 74b7 | 12 6ef5 (0) 6646 (0) 62ac (0) 6304 (0)\n002 2 08ff 11bd | 2 11bd (0) 08ff (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 2f17 | 1 2f17 (0)\n005 0 | 0\n006 1 2529 | 1 2529 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","private_key":"de0328d5a7218ee32122b35212270355692c913773c59472d65894e53fac078c","name":"node_2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","services":["streamer"],"enable_msg_events":true,"port":37731},"up":true}},{"node":{"info":{"id":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","name":"node_94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","enode":"enode://943fb91f74aa53ab508162a6a27dec3da1265ead68613c62d2a8f6b75ca0862b94fb31c62d341adfaf3cba1b76a202633d46fc3b36115454b2fa4eaed4697376@127.0.0.1:0","enr":"0xf88fb8402f7f395a5e543c79b6700821d943be0527fff861c0faa5ad5ba3084922ac6733115483c5bb7d7d238ca7689f756d5814d916c5cefb739e622cfd7842f0392daa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102943fb91f74aa53ab508162a6a27dec3da1265ead68613c62d2a8f6b75ca0862b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lKKvprwS/pV2Xwn1eCjHfMnqRzzQ6eZVyp9G4burriI=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 94a2af\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 62ac 2529 2643 | 17 6ef5 (0) 6646 (0) 62ac (0) 6304 (0)\n001 5 eed4 e4f7 f4b8 fb64 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 a11b bf27 | 4 bf27 (0) a11b (0) aa7e (0) ad46 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 3 9c93 9e27 9934 | 3 9934 (0) 9c93 (0) 9e27 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","private_key":"830a6d825c4e4bd95f3f10d11739fcceb8aa5299d256b9530ee1c7928d4daa83","name":"node_94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","services":["streamer"],"enable_msg_events":true,"port":39189},"up":true}},{"node":{"info":{"id":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","name":"node_f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","enode":"enode://c65f56752b8a6c94d1b6aff48cdcb120cc05451e84e37a9af3284bc09212a1418f67818e62449dc6939cde59f698b48437516d84c29f89cb8ac9078838c53549@127.0.0.1:0","enr":"0xf88fb840dfd8ab1f1fa9679d9c6e818c3b9e3fc25c9ae3d006363c318df0eca480300692324e71c7c66011df3e78f5b8044c0714a7ac208dcddf8a1cb59fad30400d4f8e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c65f56752b8a6c94d1b6aff48cdcb120cc05451e84e37a9af3284bc09212a141","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+crJW0yRvqZw5eZyvGTkAOY94LVcQj7aXxSZzyGOskQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f9cac9\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2643 74b7 | 17 2643 (0) 2529 (0) 2f17 (0) 11bd (0)\n001 2 bf27 94a2 | 8 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n002 2 d756 cbd4 | 2 cbd4 (0) d756 (0)\n003 2 e4f7 eed4 | 2 eed4 (0) e4f7 (0)\n============ DEPTH: 4 ==========================================\n004 1 f4b8 | 1 f4b8 (0)\n005 0 | 0\n006 1 fb64 | 1 fb64 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","private_key":"74feff500b31c6440e380f5bdd141aa2925f0abf00745572b50929d2244efe98","name":"node_f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","services":["streamer"],"enable_msg_events":true,"port":37021},"up":true}},{"node":{"info":{"id":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","name":"node_74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","enode":"enode://68cd12c71355f1284f696a0c62da83c4088e91a867af6368efdd74ce3d7eff265e1589cb822ef12e50c8626eeb8eb774893fc9016f33d8458f268c44bfe7074c@127.0.0.1:0","enr":"0xf88fb840d287a3644573ef6ebbc18a1e6fb2782814e728d6a430103bf57e1dc4ff67c6c24f44514803e4eb41bce24de090ffbe118ebebe127131f9ab9a60dc1ac8a8f0c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10268cd12c71355f1284f696a0c62da83c4088e91a867af6368efdd74ce3d7eff26","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dLcg/Nk/+QfgovnI9i6TFeZML80CMYTr3f1IXXgrqV8=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 74b720\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bf27 f9ca | 15 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n001 2 2529 2643 | 5 2643 (0) 2529 (0) 2f17 (0) 11bd (0)\n002 2 4c5f 577b | 4 577b (0) 4c5f (0) 427f (0) 4601 (0)\n003 4 6646 6304 62ac 6013 | 5 6ef5 (0) 6646 (0) 62ac (0) 6304 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 1 729a | 1 729a (0)\n006 1 76cb | 1 76cb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","private_key":"83492b92e97ad908351537aa0f01d5614452490cf85d56215d3006e338bb389c","name":"node_74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","services":["streamer"],"enable_msg_events":true,"port":44117},"up":true}},{"node":{"info":{"id":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","name":"node_6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","enode":"enode://8cda75928f71a74705a2ed5f5be1de1c8691e042595382f84f23bebbbe69477e0ba0a568d97fe91e18861bdc4e7c9c0d9a466e22f6e00beab183543e864f4769@127.0.0.1:0","enr":"0xf88fb840a1c957342355083dacdeffbfef817d1a37e22e1bbb4ff136c9815dcf336050f93ae809fb2490493975a93d6f949147035cc66f88d474bf97f76a3eb34134c9b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038cda75928f71a74705a2ed5f5be1de1c8691e042595382f84f23bebbbe69477e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YBPUDAwV9aex3dWo72qAdX3pAisghTWTiwk3uRUHceA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6013d4\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bf27 e4f7 | 15 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n001 2 2643 2f17 | 5 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n002 2 4c5f 577b | 4 577b (0) 4c5f (0) 427f (0) 4601 (0)\n003 2 729a 74b7 | 3 729a (0) 76cb (0) 74b7 (0)\n004 1 6ef5 | 1 6ef5 (0)\n005 1 6646 | 1 6646 (0)\n============ DEPTH: 6 ==========================================\n006 2 6304 62ac | 2 62ac (0) 6304 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","private_key":"2275b1fd6c200d65748673efc3a9afdd59ff34baf765acaf0f008a928367dd28","name":"node_6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","services":["streamer"],"enable_msg_events":true,"port":40301},"up":true}},{"node":{"info":{"id":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","name":"node_e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","enode":"enode://69efa89de7d90f3f3edad743eef4e6e36934a6a14fa9e9e1080320e890a94a7da29546296e7bcd07d2b061ee43e244f07340fb03a1a3b269f92feddacd0a9b67@127.0.0.1:0","enr":"0xf88fb840ff8a7a209199998d93974593321244f0a2ee30732cdda0e24ea6aa4dc0d6f9a42a576b74fd95f259aa67c31deec2b7d34e85330281f60bfceca4d877a7745cda0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10369efa89de7d90f3f3edad743eef4e6e36934a6a14fa9e9e1080320e890a94a7d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5Pd23d2eR2YI+zNasi//GDYwm5RA7k7g/Teiun/KhQc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e4f776\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 427f 6ef5 6013 | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 d756 cbd4 | 2 cbd4 (0) d756 (0)\n============ DEPTH: 3 ==========================================\n003 3 f4b8 f9ca fb64 | 3 f4b8 (0) f9ca (0) fb64 (0)\n004 1 eed4 | 1 eed4 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","private_key":"4c402cd5bad71d24a8e1c56fa5ee6561720f8305502388535804bdc29597dc94","name":"node_e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","services":["streamer"],"enable_msg_events":true,"port":43119},"up":true}},{"node":{"info":{"id":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","name":"node_fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","enode":"enode://d50974428f44cbaf9fd8c7fa9472900980d63e4682d2997b985c1185abe3450c25406281ce806a8529ce399d671123ea32b363c7ea7f65d1d897bdc336f701d3@127.0.0.1:0","enr":"0xf88fb840848de2e989e6ff63e20a5895cf88ae9de52c8db2f19690ec42f4e41e7ee318a04c3600ad148eb7bcad1aa256c4dbef4597fea0e324996af6c61d7d8fdb252db20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d50974428f44cbaf9fd8c7fa9472900980d63e4682d2997b985c1185abe3450c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+2Q3C8BwchXkGvsNoaU/irpeEfRxuuT43EvYWjtmgno=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fb6437\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2f17 4601 | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 d756 cbd4 | 2 cbd4 (0) d756 (0)\n003 2 eed4 e4f7 | 2 eed4 (0) e4f7 (0)\n============ DEPTH: 4 ==========================================\n004 1 f4b8 | 1 f4b8 (0)\n005 0 | 0\n006 1 f9ca | 1 f9ca (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","private_key":"fba40333131adaf83dd0444a5f805a739af0de3f2e625a2d2a02ecbe0efbe070","name":"node_fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","services":["streamer"],"enable_msg_events":true,"port":46323},"up":true}},{"node":{"info":{"id":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","name":"node_460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","enode":"enode://7c183d9bceaff51f943081c68a318028c043466b0910f4bcdb80d8cea48ece224b458ac2c812cce8dd550b35a4fd52d07622f970b2c1aa6638ec8e62550c1da8@127.0.0.1:0","enr":"0xf88fb840fa49b18d0242ef72eb77b319e3a923d60f566facee5a69e8115a614a4be438dc4578fdb50fbfa54de817c0d391bbe60368231734f291232d222b7ea9e70ae5b30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027c183d9bceaff51f943081c68a318028c043466b0910f4bcdb80d8cea48ece22","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RgFIuERLcUtH8JKFqgzijcNBjLa59Fi1ICwFMyBfgqQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 460148\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 fb64 9c93 aa7e | 15 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n001 2 08ff 2f17 | 5 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n002 4 76cb 729a 6646 6304 | 8 729a (0) 76cb (0) 74b7 (0) 6ef5 (0)\n003 1 577b | 1 577b (0)\n============ DEPTH: 4 ==========================================\n004 1 4c5f | 1 4c5f (0)\n005 1 427f | 1 427f (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","private_key":"459d2f0468a2f990289cf0a0ec59948f82ede34b97dbab4f8ddd68dd7fc9639c","name":"node_460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","services":["streamer"],"enable_msg_events":true,"port":35919},"up":true}},{"node":{"info":{"id":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","name":"node_aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","enode":"enode://15ce819f63a4f20fde81216cd54aa442b1e47a86085d2a887e8b482da64bc15a125a2e31dfc8b65aff9a7babe1813162e591c204e8ec3e2d37ece40c9f42eb1e@127.0.0.1:0","enr":"0xf88fb8407e05321ea1e0ebf79e030cf98817c8e7b61df62645db829c2b2699afba8443297692b19615479f37442bec12f5a6d72301a8a661cc3e391997e699f0377c87e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10215ce819f63a4f20fde81216cd54aa442b1e47a86085d2a887e8b482da64bc15a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qn5F1Fg1cP44KCjk/z1gzNUmzqATJSEdh87rbMFK91M=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aa7e45\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 2f17 4601 | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) eed4 (0) e4f7 (0)\n002 2 9934 9c93 | 4 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n003 1 bf27 | 1 bf27 (0)\n============ DEPTH: 4 ==========================================\n004 1 a11b | 1 a11b (0)\n005 1 ad46 | 1 ad46 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","private_key":"b623e785770ec4f9bbecb44c624cc704b1a8cfbb565744fa329235d240453d32","name":"node_aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","services":["streamer"],"enable_msg_events":true,"port":36243},"up":true}},{"node":{"info":{"id":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","name":"node_9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","enode":"enode://8eb7c4844662e4bec44d1a6c0eeea367815e9c378910f5891c6d1288ef8e695c7d1970934d8f00c26efe46d0119ba01c90f3564e2f56e3ca062713cf0161d960@127.0.0.1:0","enr":"0xf88fb8409f6890c59e203693b5137924950100d7ea0bb4095f006df9c4ea5520bc66d3536d3a5a0f8f684b7301e33c0bd9e07a11139776e1f1072758400835dbd411fa7f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028eb7c4844662e4bec44d1a6c0eeea367815e9c378910f5891c6d1288ef8e695c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nJNfqvtBp7072hiovQIoeBBb+EU6W4PSv6TaRtjJCPg=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9c935f\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4c5f 4601 | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 2 d756 cbd4 | 7 cbd4 (0) d756 (0) fb64 (0) f9ca (0)\n002 2 ad46 aa7e | 4 bf27 (0) a11b (0) ad46 (0) aa7e (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 94a2 | 1 94a2 (0)\n005 1 9934 | 1 9934 (0)\n006 1 9e27 | 1 9e27 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","private_key":"3a9fc1630c5328ae9c4cfded644dab18a8eae96ddac7dc65542f37918447df3f","name":"node_9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","services":["streamer"],"enable_msg_events":true,"port":43587},"up":true}},{"node":{"info":{"id":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","name":"node_9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","enode":"enode://8f2dd1bb62e9253f7a43f26fd9de2181d827183eef6b578c4246637ed66324ef4487bcf99259f32b59dd66d2d314b939e0ec66b08917a933b4697615252093ab@127.0.0.1:0","enr":"0xf88fb8403e5081fcaca0fe89abed76a93405df6e2416d260e7986ad71d2b554ff81be728584602b1049e0767ecce05662e43acff92a0c720e9ff3068782c88c5333f53c20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038f2dd1bb62e9253f7a43f26fd9de2181d827183eef6b578c4246637ed66324ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mTQpX73jfUp/hnyafh9kKMSZbRtDhj28Wi9SpUZknvA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 993429\npopulation: 17 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6304 62ac 4c5f 2f17 | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 6 fb64 f4b8 eed4 e4f7 | 7 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n002 3 a11b aa7e ad46 | 4 aa7e (0) ad46 (0) a11b (0) bf27 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 94a2 | 1 94a2 (0)\n005 2 9e27 9c93 | 2 9e27 (0) 9c93 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","private_key":"498b023a2d77a2bcdf5fc8faee54349c6d9bcc7bcc3847c665145494c6395e63","name":"node_9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","services":["streamer"],"enable_msg_events":true,"port":33825},"up":true}},{"node":{"info":{"id":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","name":"node_08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","enode":"enode://0dd78993fa0c2b78e8abf537fef7b683f90255b48e4c5d62a676b4c5c06f0a9deba8777bfc8476e26af45438819993b89ab9697465a52396923ab63ea46de6d1@127.0.0.1:0","enr":"0xf88fb840df5e81a8734f5835674758db9c12bdea17ce6724347b9b3ee12ef8b19e645abe7a9ba7898badf352fe74e273f66e00800fc1a64cf4a1d94de871ef51116c5e670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030dd78993fa0c2b78e8abf537fef7b683f90255b48e4c5d62a676b4c5c06f0a9d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CP9UtgMHz7vZsgm/B8em8WQZK4DJ3V7q3SbjaK28fbw=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08ff54\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bf27 9934 | 15 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n001 4 729a 76cb 4601 577b | 12 4c5f (0) 4601 (0) 427f (0) 577b (0)\n============ DEPTH: 2 ==========================================\n002 3 2643 2529 2f17 | 3 2f17 (0) 2643 (0) 2529 (0)\n003 1 11bd | 1 11bd (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","private_key":"ee655daff35bf421813437b35da4b5cbc518cfadeb319c82c5211d697a821466","name":"node_08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","services":["streamer"],"enable_msg_events":true,"port":45679},"up":true}},{"node":{"info":{"id":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","name":"node_bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","enode":"enode://890aca84b10caa9057d6dca9730544992a7bcdf38b78e82508f5be6e0b2149592fbcd837b829232ccaa8310759a27aab18addec6239becffddc5942760d3aac4@127.0.0.1:0","enr":"0xf88fb840a1b52878b681cfd6dffb3a53f24aa4920cf5b65dc92c1bed8511407085072b7f5ebc71f1a59fae35d1e8e4896b3a9ee980cb318061f8c6a6652a353633b98f700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102890aca84b10caa9057d6dca9730544992a7bcdf38b78e82508f5be6e0b214959","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vyfczW95zIbTitejdbgzElrqrQYL4RfCPBtxKXsHLAA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bf27dc\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 74b7 6013 6646 08ff | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 3 f9ca cbd4 d756 | 7 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n002 2 9e27 94a2 | 4 94a2 (0) 9e27 (0) 9c93 (0) 9934 (0)\n============ DEPTH: 3 ==========================================\n003 3 a11b ad46 aa7e | 3 aa7e (0) ad46 (0) a11b (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","private_key":"d572f42e4c4b69acd62f2ced7411ffb238c6b5abd9039b6e3c47f01f6d1fde1b","name":"node_bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","services":["streamer"],"enable_msg_events":true,"port":44805},"up":true}},{"node":{"info":{"id":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","name":"node_6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","enode":"enode://fb3cece5266da81615d3398f3c34f6552eaaa9e55c79123f7282951226be7fab8db0cd0487ebcc3a5799d7dd25b91d3b4064c1959bc590ca6ddb8f10508e196b@127.0.0.1:0","enr":"0xf88fb84076bdf43d4d5251b70d43c1c650b2da1304cc4d6762d8368b75fa7063f92cde8b5129e9443fe40a0f3f421fb7a430eb451780ef473ce3caccde600cc00bafbc2f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fb3cece5266da81615d3398f3c34f6552eaaa9e55c79123f7282951226be7fab","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZkbsyHOY4J5UsOsZ5X1UPTE8PnNX/4TcqIhrg/ra4PQ=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6646ec\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a11b bf27 | 15 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n001 2 2643 2f17 | 5 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n002 2 4601 4c5f | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 3 74b7 76cb 729a | 3 729a (0) 74b7 (0) 76cb (0)\n004 1 6ef5 | 1 6ef5 (0)\n============ DEPTH: 5 ==========================================\n005 3 62ac 6304 6013 | 3 62ac (0) 6304 (0) 6013 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","private_key":"685914c526e3efe92ebef3400b22a51a7a4771de5c87ffd5f9da4e8db9d1282c","name":"node_6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","services":["streamer"],"enable_msg_events":true,"port":40729},"up":true}},{"node":{"info":{"id":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","name":"node_a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","enode":"enode://3c0855f7cf4fc19e61b4aeb52f69cc6eafe9800738da596b60366854eec2b55e1b82583803a6564d6f3f5fac83bcf41748cd8f4a316e131afe54b1a93ba235ec@127.0.0.1:0","enr":"0xf88fb84005478b240adc6c61921f460140f141ddceb6ae0cdbdf49cb0952cb457849b3ce4080fcf91b3b80ac6eb08e75e78f0ed80169a9269845bb24999a1828b5b7fd3d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023c0855f7cf4fc19e61b4aeb52f69cc6eafe9800738da596b60366854eec2b55e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oRs8Z+o21BJk/clxI6QchYaDcZlJZ4LnmUtr6DFXG3c=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a11b3c\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6646 577b | 17 2f17 (0) 2643 (0) 2529 (0) 11bd (0)\n001 2 cbd4 d756 | 7 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n002 3 9e27 9934 94a2 | 4 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n003 1 bf27 | 1 bf27 (0)\n============ DEPTH: 4 ==========================================\n004 2 ad46 aa7e | 2 aa7e (0) ad46 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","private_key":"100fcd428dcc5043b3dbdd4bbb18ee89cd22a1e122e6daa5173b38d971e81dd4","name":"node_a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","services":["streamer"],"enable_msg_events":true,"port":40597},"up":true}},{"node":{"info":{"id":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","name":"node_577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","enode":"enode://20ee1cefe65d31d3bbef59fc59deb8cd34a06204403fef7c4c52143e62d207bce55396cf2cd302a103fb15ef7df24832502feab7478b558c6d549555a4b9fbda@127.0.0.1:0","enr":"0xf88fb8402bb8237b2f944ce884436ea3d41fb22fda669660233b5844733075ba1d9e8e4163169f20b8fcb972c30375d9fa5af751434559d55d174c300c2842f899763ee40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10220ee1cefe65d31d3bbef59fc59deb8cd34a06204403fef7c4c52143e62d207bc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V3szQogDWbn6Qm/c6PwxXOpkBZK3h+bjrb3sZpn0sqo=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 577b33\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d756 a11b | 15 d756 (0) cbd4 (0) fb64 (0) f9ca (0)\n001 2 11bd 08ff | 5 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n002 4 74b7 6ef5 6013 62ac | 8 729a (0) 74b7 (0) 76cb (0) 6ef5 (0)\n============ DEPTH: 3 ==========================================\n003 3 4c5f 4601 427f | 3 4c5f (0) 4601 (0) 427f (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","private_key":"8b2f5863391217a259d77ab4007f410d37eb2f81f76b87497e738c1a6dc07042","name":"node_577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","services":["streamer"],"enable_msg_events":true,"port":41231},"up":true}},{"node":{"info":{"id":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","name":"node_62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","enode":"enode://0761ae452c8e6d8803e4dd3dd4b66a50b5f17ba7c25babf1f41b273572d90ba7fa6de5b9ff53bd29fb89c0f0aee57b9d4bd7508b58411c184c27c6b4d113c38c@127.0.0.1:0","enr":"0xf88fb840e15454baf140946f84455b01b25479ab82d8df1e547d32eb511a08db1b6d2fa13417e78cfaa91a62ff85b5be203ca4c525537fc21651ab6b721781ebe2367eba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020761ae452c8e6d8803e4dd3dd4b66a50b5f17ba7c25babf1f41b273572d90ba7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Yqxq8IrhZrDVYSvGWgfkFIdqOKNVIJHUYcgIxfa0cbA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 62ac6a\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9934 94a2 | 15 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n001 2 11bd 2529 | 5 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n002 2 4c5f 577b | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 2 74b7 729a | 3 729a (0) 74b7 (0) 76cb (0)\n004 1 6ef5 | 1 6ef5 (0)\n005 1 6646 | 1 6646 (0)\n============ DEPTH: 6 ==========================================\n006 1 6013 | 1 6013 (0)\n007 1 6304 | 1 6304 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","private_key":"c094ade67efd8691772e76ed09d41e9dcd2d0c478331223fdd1c7736d84736e8","name":"node_62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","services":["streamer"],"enable_msg_events":true,"port":33431},"up":true}},{"node":{"info":{"id":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","name":"node_2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","enode":"enode://d31fbb6c9836fc684468eaa5865756779ef13e13bfc5af8a819f68a3d388b5e9c8c54b17cbd5ddfb355e15fee71d1ec86dfed0472309edcfa84dce531caf3e4d@127.0.0.1:0","enr":"0xf88fb8404566296b99cb998abb9c6d5f61d4df6674dfed5706ae4bd804f2b0d1d2088bd35e152e18aaca113522024b0ed409292b8d596c50093d18e319240bb27f055fe00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d31fbb6c9836fc684468eaa5865756779ef13e13bfc5af8a819f68a3d388b5e9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JSnrbvu61FE8Ev//9yLCwklnWbXrPZUwL/m/fqzA1Cc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2529eb\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 94a2 eed4 | 15 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n001 4 427f 4c5f 74b7 62ac | 12 4c5f (0) 4601 (0) 427f (0) 577b (0)\n002 2 11bd 08ff | 2 11bd (0) 08ff (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 2f17 | 1 2f17 (0)\n005 0 | 0\n006 1 2643 | 1 2643 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","private_key":"f8cc4cad963f73aff2b340dfcf30ab658e08f58928824419a15246c2532c43e7","name":"node_2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","services":["streamer"],"enable_msg_events":true,"port":35361},"up":true}},{"node":{"info":{"id":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","name":"node_eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","enode":"enode://e11c49200047bdb02fac35163462fdeb3e40477670420f345db00b3f0cc008ed768b308bce67bf5ddf3c5728ccadf39f8362d18eafedd9c7c0f916e62d491470@127.0.0.1:0","enr":"0xf88fb8403e683663f20a82e4d0a4a2750956048ae4f294e82db9c02f2d31e574d2564b9605f5ca54db82f1e460613dbfa8570cb35a0badd8fdc581ce43f6fcab0026556a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e11c49200047bdb02fac35163462fdeb3e40477670420f345db00b3f0cc008ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7tS5oGvI+gtxlb7v8b+3l53zfHIN7JyJFGggq/SDaBo=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eed4b9\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6ef5 76cb 2529 | 17 4c5f (0) 4601 (0) 427f (0) 577b (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 cbd4 d756 | 2 d756 (0) cbd4 (0)\n============ DEPTH: 3 ==========================================\n003 3 f4b8 fb64 f9ca | 3 fb64 (0) f9ca (0) f4b8 (0)\n004 1 e4f7 | 1 e4f7 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","private_key":"00b0480a2de8f0b9a04988e6b64da01d184d36d84da1b6c377b19d991c6bfdc2","name":"node_eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","services":["streamer"],"enable_msg_events":true,"port":39613},"up":true}},{"node":{"info":{"id":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","name":"node_76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","enode":"enode://eb693286d13dd7d22dbf20c8a7bd9df2cec24474ed4f059cff8fbbb7013081d12ca2caa7d5e2084225ae04d7c6070fc61158f0f7de6e16213b48c01aea446f47@127.0.0.1:0","enr":"0xf88fb840af4b0c315818be89b44fbbed80450d4973e3ae933823e9dd5302edce8e5059744c616a175dc2d6d818ce0ad591f864fa0d9381df6d8a065beef99449ec3ecbb20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eb693286d13dd7d22dbf20c8a7bd9df2cec24474ed4f059cff8fbbb7013081d1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dstH66hKeuDp8A8TgbqFwu3p+n+JmoePlOSTt+KrQBc=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 76cb47\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f4b8 eed4 | 15 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n001 2 11bd 08ff | 5 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n002 3 427f 4601 4c5f | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 2 6646 6ef5 | 5 6ef5 (0) 6646 (0) 6013 (0) 6304 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 1 729a | 1 729a (0)\n006 1 74b7 | 1 74b7 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","private_key":"8ddfa941097daa1adbf355c69b301a9b9b4e984f51fbc021d6abbd2df8eb5391","name":"node_76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","services":["streamer"],"enable_msg_events":true,"port":33051},"up":true}},{"node":{"info":{"id":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","name":"node_f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","enode":"enode://8e1bd7a84722a0d831f2ce96f52c463bc3232306ab90de59ad821884df222db8cf6204e33398d2ccb347156b73088661c96f16da9b37a53c48f1cdc00897700e@127.0.0.1:0","enr":"0xf88fb840e5deda0993da1e8b4297c89a66ddf4b197118fc19c40d2eb65d35c08c607922252bfa120d52fcdacaa4d68bd36af44be179038dce4b9857b9b3b29737d9b508a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028e1bd7a84722a0d831f2ce96f52c463bc3232306ab90de59ad821884df222db8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9LipUFZzCgOm0XtnVDhg+V7tJrbkPwWhmS8nOZ09MSY=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f4b8a9\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6304 76cb | 17 11bd (0) 08ff (0) 2f17 (0) 2643 (0)\n001 2 9934 94a2 | 8 94a2 (0) 9934 (0) 9e27 (0) 9c93 (0)\n002 2 cbd4 d756 | 2 d756 (0) cbd4 (0)\n003 2 eed4 e4f7 | 2 e4f7 (0) eed4 (0)\n============ DEPTH: 4 ==========================================\n004 2 f9ca fb64 | 2 fb64 (0) f9ca (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","private_key":"ffe54ea17543345a77321ae2e3776751db00762580f661c0f15896f42500959e","name":"node_f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","services":["streamer"],"enable_msg_events":true,"port":33473},"up":true}},{"node":{"info":{"id":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","name":"node_6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","enode":"enode://d07fabc00b19f95c1732019dafb44716ccc4e19dce5e9985d4dc8237790811a6e7973a650f98183de314b6061f815b190dd620fd33a6ae2e398c10c57614224e@127.0.0.1:0","enr":"0xf88fb8408d97738fe8da5aeda2e04c10e3c563f61ecc6911afcf669e9e50b306b67b4e023292aec1a2d35c5dcec0c612b0d5cd02f21098fd8b3e3ad40679b1778be6dcc10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d07fabc00b19f95c1732019dafb44716ccc4e19dce5e9985d4dc8237790811a6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YwTisTVFXOAiA+vD9RS19ik+a7DJqYEpt7DW9svJjO8=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6304e2\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9934 f4b8 | 15 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n001 2 11bd 2f17 | 5 11bd (0) 08ff (0) 2643 (0) 2529 (0)\n002 2 4c5f 4601 | 4 4c5f (0) 4601 (0) 427f (0) 577b (0)\n003 2 74b7 729a | 3 729a (0) 74b7 (0) 76cb (0)\n004 1 6ef5 | 1 6ef5 (0)\n005 1 6646 | 1 6646 (0)\n============ DEPTH: 6 ==========================================\n006 1 6013 | 1 6013 (0)\n007 1 62ac | 1 62ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","private_key":"80cf26c0793a22bf69aa3bf4d71052a9ede84d73135a7b39d1ec068bdd2929c7","name":"node_6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","services":["streamer"],"enable_msg_events":true,"port":34879},"up":true}},{"node":{"info":{"id":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","name":"node_2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","enode":"enode://df8c978c17fbed86c3fc257bb0d3aca0a8831d358b13cf87413888240c12cf92840bd89e98350dc7aeb45c91a97a7bace5b60b42bac6831972ef0eecb5180c03@127.0.0.1:0","enr":"0xf88fb84015eb3d3b46b7b35f89720cf53396e495bda8dee9ac4fe55ad75cc91a7a3358f23e5c8fe05da05dbd5ecba9d42d131646b563810ac1603f78569e9b059c719fd60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df8c978c17fbed86c3fc257bb0d3aca0a8831d358b13cf87413888240c12cf92","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LxfhgNB4MkaOaqkVlknNabGZMTyyxv6S8VmNhvY02jM=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2f17e1\npopulation: 14 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 aa7e 9934 fb64 cbd4 | 15 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n001 6 4601 427f 4c5f 6646 | 12 577b (0) 4c5f (0) 4601 (0) 427f (0)\n002 2 08ff 11bd | 2 11bd (0) 08ff (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 2 2529 2643 | 2 2643 (0) 2529 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","private_key":"256815d05345b0618e277d6f2618ac89ef4fa493b339bf65f0eaec5cbd404e92","name":"node_2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","services":["streamer"],"enable_msg_events":true,"port":37517},"up":true}},{"node":{"info":{"id":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","name":"node_cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","enode":"enode://5cca6a56e89c4aed55749ad75c465e9fb86ff85723c02abb5037ef5db3c05b5fc45dc735575b737fec5a5bc572466e636c0fe7bdd56d98ea684a5314ea065f84@127.0.0.1:0","enr":"0xf88fb8405b51d4e5f768fab1263aad5fc3d836b5a9299f2e915bd7fde99ee1632440e56c40d1fae3bad1fc292927c07694c0a31e4bdaa4214df6ab41b5bd9eb847202c170183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025cca6a56e89c4aed55749ad75c465e9fb86ff85723c02abb5037ef5db3c05b5f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"y9SqXhRWbEepN1W1N9LRB3U0bvEabGQis30GYclImUE=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cbd4aa\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 729a 11bd 2f17 | 17 577b (0) 4c5f (0) 4601 (0) 427f (0)\n001 7 bf27 a11b aa7e ad46 | 8 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n============ DEPTH: 2 ==========================================\n002 5 eed4 e4f7 f4b8 fb64 | 5 e4f7 (0) eed4 (0) fb64 (0) f9ca (0)\n003 1 d756 | 1 d756 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","private_key":"c8cfa60b5e127e3bacb81f83e2b754b73a42724cda004a2a5ed5fbcf22dfddd4","name":"node_cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","services":["streamer"],"enable_msg_events":true,"port":44323},"up":true}},{"node":{"info":{"id":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","name":"node_729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","enode":"enode://fd9832b9b0eef81dc9fcab0852581e32bd63572f5e46a85c7aa0ad26596ca899a680f1c02bc80e2f9d9834a24a79071b26a4e040c8d4e7acfacfd07d1d8f7939@127.0.0.1:0","enr":"0xf88fb8402f0c70d6cc93f4019ac80464fe97225e30532a384869ad2228660e40a240ca1852d6750396d22e257cb2a1b79b4eeeb4c65303d87a91af08ce3c213c0751abf30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fd9832b9b0eef81dc9fcab0852581e32bd63572f5e46a85c7aa0ad26596ca899","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cpoYV5+tL8dda0RRZ+c1YV6Au3A3nnqSR6CbppFlecA=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 729a18\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d756 cbd4 | 15 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n001 2 11bd 08ff | 5 11bd (0) 08ff (0) 2529 (0) 2643 (0)\n002 2 4601 4c5f | 4 577b (0) 4c5f (0) 4601 (0) 427f (0)\n003 5 6ef5 6646 6013 62ac | 5 6ef5 (0) 6646 (0) 6013 (0) 62ac (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 74b7 76cb | 2 74b7 (0) 76cb (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","private_key":"675a65f43358f973c940f285b96994d598a5a63b511de041e959d415fc38f605","name":"node_729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","services":["streamer"],"enable_msg_events":true,"port":41717},"up":true}},{"node":{"info":{"id":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","name":"node_d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","enode":"enode://46a796a7e0ef14bf01598dafad914d15b6e16a7a15252f2e318dfb509897cc5e25fe3727de0e8cfd6d6ee2ed1c27981737b15038237650981465e6410f49e6b9@127.0.0.1:0","enr":"0xf88fb84039e08ba3a29f958abdbd524c52eb953e01d52dfc9c1f0259d81debaa7bf88aeb11819630685dbe6939805e57357068d0768dc6a4c7233564b1b783b45a4a4fc90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10346a796a7e0ef14bf01598dafad914d15b6e16a7a15252f2e318dfb509897cc5e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"11Y9bcagN4QGs3WOHMpCiklLdlJuBvrq20M1DK2YZ5I=","hive":"\n=========================================================================\nThu Feb 28 18:01:09 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d7563d\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 577b 427f 729a | 17 11bd (0) 08ff (0) 2529 (0) 2643 (0)\n001 7 bf27 aa7e ad46 a11b | 8 9934 (0) 9e27 (0) 9c93 (0) 94a2 (0)\n============ DEPTH: 2 ==========================================\n002 5 e4f7 eed4 f9ca fb64 | 5 e4f7 (0) eed4 (0) fb64 (0) f9ca (0)\n003 1 cbd4 | 1 cbd4 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","private_key":"eeeffb7fefb163eb424dbeedafc3a4b2de7c7aff8f531b8969b5bc809c4232ab","name":"node_d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","services":["streamer"],"enable_msg_events":true,"port":37925},"up":true}}],"conns":[{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","other":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","other":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"08ff54b60307cfbbd9b209bf07c7a6f164192b80c9dd5eeadd26e368adbc7dbc","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","other":"94a2afa6bc12fe95765f09f57828c77cc9ea473cd0e9e655ca9f46e1bbabae22","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","other":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","up":true},{"one":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"cbd4aa5e14566c47a93755b537d2d10775346ef11a6c6422b37d0661c9489941","other":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"6ef5de5c1c8e55bc89948bf10a7a2ad11b07170f3b5f049e40a85e244124eee4","other":"577b3342880359b9fa426fdce8fc315cea640592b787e6e3adbdec6699f4b2aa","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"2f17e180d07832468e6aa9159649cd69b199313cb2c6fe92f1598d86f634da33","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","up":true},{"one":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","other":"fb64370bc0707215e41afb0da1a53f8aba5e11f471bae4f8dc4bd85a3b66827a","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"460148b8444b714b47f09285aa0ce28dc3418cb6b9f458b5202c0533205f82a4","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","up":true},{"one":"e4f776dddd9e476608fb335ab22fff1836309b9440ee4ee0fd37a2ba7fca8507","other":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","up":true},{"one":"f4b8a95056730a03a6d17b67543860f95eed26b6e43f05a1992f27399d3d3126","other":"eed4b9a06bc8fa0b7195beeff1bfb7979df37c720dec9c89146820abf483681a","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"ad4643583aa082b3bef7ce1bb8dcf55fe2e321b8954000cfac6bc72c49e85f50","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"aa7e45d4583570fe382828e4ff3d60ccd526cea01325211d87ceeb6cc14af753","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"f9cac95b4c91bea670e5e672bc64e400e63de0b55c423eda5f1499cf218eb244","other":"bf27dccd6f79cc86d38ad7a375b833125aeaad060be117c23c1b71297b072c00","up":true},{"one":"9e276cdb622215089f0f20252a6aba20f57521df94d401efa13f604b62534c80","other":"a11b3c67ea36d41264fdc97123a41c8586837199496782e7994b6be831571b77","up":true},{"one":"9c935faafb41a7bd3bda18a8bd022878105bf8453a5b83d2bfa4da46d8c908f8","other":"d7563d6dc6a0378406b3758e1cca428a494b76526e06faeadb43350cad986792","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"2529eb6efbbad4513c12fffff722c2c2496759b5eb3d95302ff9bf7eacc0d427","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","up":true},{"one":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true},{"one":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","other":"6646ecc87398e09e54b0eb19e57d543d313c3e7357ff84dca8886b83fadae0f4","up":true},{"one":"427f4bdfd3857968af5da36eeea041938ea771bc6c5e90ee8d3585cf579f13b7","other":"76cb47eba84a7ae0e9f00f1381ba85c2ede9fa7f899a878f94e493b7e2ab4017","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"2643083442ee9e69517f5008e4ca54dbfa40726bde22216b53bf903895aa0ae0","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"9934295fbde37d4a7f867c9a7e1f6428c4996d1b43863dbc5a2f52a546649ef0","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","up":true},{"one":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"11bd810f7ba41f44816f33a19d9c703d26f2ccaea28c4af825f52888070ad8d7","up":true},{"one":"6013d40c0c15f5a7b1ddd5a8ef6a80757de9022b208535938b0937b9150771e0","other":"729a18579fad2fc75d6b445167e735615e80bb70379e7a9247a09ba6916579c0","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"4c5fabb7a17c3a3f589c7d2eca3c0dd5a6b8217aabc54323bab75b6af383ac6c","other":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","up":true},{"one":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","other":"62ac6af08ae166b0d5612bc65a07e414876a38a3552091d461c808c5f6b471b0","up":true},{"one":"6304e2b135455ce02203ebc3f514b5f6293e6bb0c9a98129b7b0d6f6cbc98cef","other":"74b720fcd93ff907e0a2f9c8f62e9315e64c2fcd023184ebddfd485d782ba95f","up":true}]} \ No newline at end of file diff --git a/swarm/network/stream/testing/snapshot_4.json b/swarm/network/stream/testing/snapshot_4.json deleted file mode 100644 index 81afb03f11..0000000000 --- a/swarm/network/stream/testing/snapshot_4.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","name":"node_0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","enode":"enode://918f13e29fcea21b47e553c60ea0ae63f856db5745c6010e31b566f819195f9a5f250788862c43b230dd93fbc24cb6b3d33c86069cc21de3a3612b2f32eeccbe@127.0.0.1:0","enr":"0xf88fb840ad1a67c3b07299bb50337351be97595ef05e5ab7988ab7831e06a3003d1fc4ad74e925ec495ab312ccc889eb9c05f2e14f625e56f813a76dc53ddd94ea0955f90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102918f13e29fcea21b47e553c60ea0ae63f856db5745c6010e31b566f819195f9a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"C0Bd7YfOTnEqrrswVecHFslx/gSaVJYSlMenoEcdEvY=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0b405d\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 a430 | 1 a430 (0)\n============ DEPTH: 1 ==========================================\n001 2 77ba 675c | 2 77ba (0) 675c (0)\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","private_key":"173c23bc3aec26afe7d299eb9556e7c189851378fe56125d929966ac7207bcb6","name":"node_0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","services":["streamer"],"enable_msg_events":true,"port":38277},"up":true}},{"node":{"info":{"id":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","name":"node_a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","enode":"enode://89b66f574168570cc5d347051c0e2b05b33578d42142ef8cc930f1fbb384266f2827e4b087f5e2985a32d8f2b353fb7be416193632da5c692cace99d1b9e4274@127.0.0.1:0","enr":"0xf88fb8402e6392d3d5377977fc4b4d29f4dbf4ca96e963df056ead84ec2fcb7ee071996670a935d3b49250455e02c392baacb4c8499f815f74b09c405316a5d2fdee94e60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10289b66f574168570cc5d347051c0e2b05b33578d42142ef8cc930f1fbb384266f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pDAQRcDN5ay1QG4fukbshowFZDmrQ+95WDB0j7a6Llo=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a43010\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 3 675c 77ba 0b40 | 3 675c (0) 77ba (0) 0b40 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","private_key":"5bcd3bbb886e5ad2317a6ac1de2b19ebe27db9337ba8e7daa76a1cdaa6a3d158","name":"node_a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","services":["streamer"],"enable_msg_events":true,"port":41325},"up":true}},{"node":{"info":{"id":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","name":"node_77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","enode":"enode://ecb56004a128067628a3198244080ba4ac79860cb2cf74407d7571955a80fb9243ad5f8265063a5aa209ea95329b4b57d0f1b492a85835ab87fce79881a895a9@127.0.0.1:0","enr":"0xf88fb84035ed878b2a99ed1bbd55df1701cd82115aebc649b1e8e68302e7caf5480a61322c74189d1fe66f2d16e79174f0e3479213f0bf963a4518d583078e164bd94a220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ecb56004a128067628a3198244080ba4ac79860cb2cf74407d7571955a80fb92","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"d7oUWkYjucg+ChSjdbpJxocZ8qvhYv/KZt5+8uMadfg=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 77ba14\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 a430 | 1 a430 (0)\n============ DEPTH: 1 ==========================================\n001 1 0b40 | 1 0b40 (0)\n002 0 | 0\n003 1 675c | 1 675c (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","private_key":"6f30c3d0135202cbf540669c8c76d9144bd53764aaf4ae18e8bee98ce05c6211","name":"node_77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","services":["streamer"],"enable_msg_events":true,"port":40785},"up":true}},{"node":{"info":{"id":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","name":"node_675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","enode":"enode://64a6b33b028b818a1961272651d1d7a976329e541b6e3e983f518d89326d7427f4c9243f78bb03fd2e2dc059f610ee50d1e664e3107db01ac603b9c3b20ebb4f@127.0.0.1:0","enr":"0xf88fb8407dbbb99300e04c6917c27d61bf396481aae19287c2869e8dd74e11b0f2ebb74174376a6152c26af95173a4868a0349aaf3be5d063918590fd5962f4af174e0010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10364a6b33b028b818a1961272651d1d7a976329e541b6e3e983f518d89326d7427","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z1z+0Ke0YfQ8/r1qEOzIho01skU4HXMavsRgi23OJQo=","hive":"\n=========================================================================\nThu Feb 28 17:59:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 675cfe\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 a430 | 1 a430 (0)\n============ DEPTH: 1 ==========================================\n001 1 0b40 | 1 0b40 (0)\n002 0 | 0\n003 1 77ba | 1 77ba (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","private_key":"d77006035afa5194053c0347021f7825a71f9643028c45b65756ef88ee53e6dd","name":"node_675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","services":["streamer"],"enable_msg_events":true,"port":37069},"up":true}}],"conns":[{"one":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","other":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","up":true},{"one":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","other":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","up":true},{"one":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","other":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","up":true},{"one":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","other":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","up":true},{"one":"77ba145a4623b9c83e0a14a375ba49c68719f2abe162ffca66de7ef2e31a75f8","other":"0b405ded87ce4e712aaebb3055e70716c971fe049a54961294c7a7a0471d12f6","up":true},{"one":"a4301045c0cde5acb5406e1fba46ec868c056439ab43ef795830748fb6ba2e5a","other":"675cfed0a7b461f43cfebd6a10ecc8868d35b245381d731abec4608b6dce250a","up":true}]} \ No newline at end of file diff --git a/swarm/network/stream/testing/snapshot_64.json b/swarm/network/stream/testing/snapshot_64.json deleted file mode 100644 index 715485564a..0000000000 --- a/swarm/network/stream/testing/snapshot_64.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","name":"node_33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","enode":"enode://189f684252bf3145e01947ecea3430ca79da66c9c79baba0c7afac7577fd8eb6cc663b270219bf730d98b9221eaea5dfeaf64c3a0097aba12ccc9bd2fea77174@127.0.0.1:0","enr":"0xf88fb8409210a452686c812613891a7481ab1ecb134964d862f61460027f50b5b112d39a256f7cd8dc529b01f133a7fb15be96b7a8ee77dcb92f1c3e39cb0d2cd3af09830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102189f684252bf3145e01947ecea3430ca79da66c9c79baba0c7afac7577fd8eb6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"M/5taXBpDo2eKwj/I0yx6vM2uqU7OYURzQeNzOLIsto=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 33fe6d\npopulation: 26 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c05d c67d c62e ff06 | 35 ce82 (0) c851 (0) c34b (0) c05d (0)\n001 8 5bf6 4e4e 4853 4443 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 5 0e8f 041c 10d5 1a93 | 8 10d5 (0) 12b8 (0) 1a93 (0) 1dd4 (0)\n============ DEPTH: 3 ==========================================\n003 5 2f1a 2b80 2b79 27c2 | 5 2293 (0) 27c2 (0) 2f1a (0) 2b79 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","private_key":"58cdd771550771fd62cd26564dda083ef20e140c1d5530cd86a85b7df1f7f269","name":"node_33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","services":["streamer"],"enable_msg_events":true,"port":45167},"up":true}},{"node":{"info":{"id":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","name":"node_b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","enode":"enode://b91f0615ca78edb614985f7643eeb09bdc0476aa30b73d0b711f87d59eaf466246423fc97d81dbd96192287bf373174ed814b96413bfcd872d4ccd53d3c4841c@127.0.0.1:0","enr":"0xf88fb8405b40eaf3f4b6452b70caa681969bd278b3912b26df53438d01543d219a38254e1ea4b61d25c38733700b16acb82ee9c22c26a62e9d21bbac2e105c734fd985ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b91f0615ca78edb614985f7643eeb09bdc0476aa30b73d0b711f87d59eaf4662","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sml6Py3m6g0TWGplVGN4JQlpHW8F2Q9F/QiCPn6vWgs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2697a\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6049 46af 5b93 33fe | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 4 ec08 c034 c67d c62e | 21 ce82 (0) c851 (0) c34b (0) c05d (0)\n002 2 83aa 8934 | 6 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n003 4 a259 ab25 aeff adfd | 4 a259 (0) aeff (0) adfd (0) ab25 (0)\n============ DEPTH: 4 ==========================================\n004 3 bbbc bc3e be5d | 3 be5d (0) bc3e (0) bbbc (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","private_key":"f7d4ee33924c6fecc03e8531d4a760dfa3f045c2070ead81351cc717118b94c4","name":"node_b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","services":["streamer"],"enable_msg_events":true,"port":45247},"up":true}},{"node":{"info":{"id":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","name":"node_8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","enode":"enode://594fd2ab5b614c45fcf39e323750e1d17a2f4054d8a9939c433993f5050e3990638006f044b8fe5f095108e0df4bb507375ddde04c9973283856f126fc553237@127.0.0.1:0","enr":"0xf88fb840c50ff8109fb29d7550e93a6b0c1e4411d83ff6d612cef057b29b0fe5d8f7fa193cc9d16dec8587e4b27c4cdc32c7304cf80b7c32087c779c819970be16ba18830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103594fd2ab5b614c45fcf39e323750e1d17a2f4054d8a9939c433993f5050e3990","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iTTua7/JyRKlpfsATrPfC2UxPiLozrjcPz4T0QhTIo8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8934ee\npopulation: 27 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0e8f 1dd4 2b79 27c2 | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 9 f16d fef2 ec3e e59a | 21 ce82 (0) c851 (0) c34b (0) c05d (0)\n002 5 aeff adfd ab25 be5d | 8 a259 (0) aeff (0) adfd (0) ab25 (0)\n003 3 9637 9009 9861 | 3 9861 (0) 9009 (0) 9637 (0)\n============ DEPTH: 4 ==========================================\n004 1 83aa | 1 83aa (0)\n005 1 8cb7 | 1 8cb7 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","private_key":"c1a5ff4b52beb6e91e007799d9b94a2afe91ad74a387ea3de8ae5a1b3daddcc0","name":"node_8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","services":["streamer"],"enable_msg_events":true,"port":35697},"up":true}},{"node":{"info":{"id":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","name":"node_4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","enode":"enode://426b52190ebc9cfa8e1d426d495ed10688ea702182bb347c25a37f362f2fc457df723fbafc48abbfcfb00d71ed2fb35bc642ea3fe52cf099a2513006165fa780@127.0.0.1:0","enr":"0xf88fb840f9687dee63db3d7523fc5e5345328e7d01d34286124dfb1d8565aebf86f3f2fb5c22b30d3c61ac8c8a3692d3c5dd1b4702c24da65bcd3c9e06c35e9eef56e5ed0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102426b52190ebc9cfa8e1d426d495ed10688ea702182bb347c25a37f362f2fc457","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"REOzSXCSyfIA/n1DwypTP4/J+nEpIm4eLH/V9/J+FxE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4443b3\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ce82 8934 | 35 ce82 (0) c851 (0) c34b (0) c05d (0)\n001 3 33fe 2293 2b80 | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 2 6271 62c0 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 2 55a2 5bf6 | 4 55a2 (0) 5b87 (0) 5b93 (0) 5bf6 (0)\n004 2 4853 4e4e | 2 4e4e (0) 4853 (0)\n005 1 404b | 1 404b (0)\n============ DEPTH: 6 ==========================================\n006 1 46af | 1 46af (0)\n007 1 4541 | 1 4541 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","private_key":"1fdc1683e025dbb4aabcc2b580cac31c8d7bd3862f5eaa0786c55ba1d5fe2e3a","name":"node_4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","services":["streamer"],"enable_msg_events":true,"port":35969},"up":true}},{"node":{"info":{"id":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","name":"node_5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","enode":"enode://d7953737b7f648f15413610ae2e027887e3ac47d3a49ff0c53b5813d980758bf1d3f12e711e824d7948bc24e2ba00d5558fccb7155232570ecd58236c2aa35ff@127.0.0.1:0","enr":"0xf88fb840f2731673fc9ef09cb16f3be083528cdc666e5d0e3ad5a8473aeda9cca202c5683d9af6f21212e6f6711983b993e9bcddb6b061addbacabed0e1ae01fd8061f9c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d7953737b7f648f15413610ae2e027887e3ac47d3a49ff0c53b5813d980758bf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W/ai/kgUErGyDwzCMloRGf2p40xN7z0fQCaojcDJkqw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5bf6a2\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d165 adfd bbbc | 35 d165 (0) dbef (0) d87b (0) dd48 (0)\n001 3 33fe 2293 2b80 | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 3 62c0 6049 75bf | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 5 4853 4e4e 404b 4541 | 6 4e4e (0) 4853 (0) 404b (0) 46af (0)\n004 1 55a2 | 1 55a2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 2 5b93 5b87 | 2 5b87 (0) 5b93 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","private_key":"fa8bc1f234fa77f91ac5a9338da6e6f227e45a18646baf568d4d6dfd6d1450ac","name":"node_5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","services":["streamer"],"enable_msg_events":true,"port":38467},"up":true}},{"node":{"info":{"id":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","name":"node_bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","enode":"enode://cc1d8b904cb61eeebf263eab856b6a39494abcc5f24a872d894cebb307123b3c21d4ad23093725c55431ea19b33f656d149a1546c5f4160410c2f15a3b8e96f0@127.0.0.1:0","enr":"0xf88fb840055d7f85d85a26105bc7165f2a6b6f5d76cdd64185015fc469f27b2f031c50ff47437f48acadbc971a934d387191f68159ab7cbbfcd0e9eadfffc11d84ba76150183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cc1d8b904cb61eeebf263eab856b6a39494abcc5f24a872d894cebb307123b3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"u7zMAYD+JgW+dI2uq7H8AubIhws383E1nzjuEU8Jdx8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bbbccc\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7a5c 46af 5bf6 | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 3 ec08 c034 d165 | 21 d165 (0) d87b (0) dbef (0) dd48 (0)\n002 2 9861 9637 | 6 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n003 3 aeff adfd a259 | 4 a259 (0) adfd (0) aeff (0) ab25 (0)\n004 1 b269 | 1 b269 (0)\n============ DEPTH: 5 ==========================================\n005 2 bc3e be5d | 2 bc3e (0) be5d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","private_key":"8e11dcf297e93d5064f7c16e21897f433b43b84640233484bdcb47c2986f8804","name":"node_bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","services":["streamer"],"enable_msg_events":true,"port":39121},"up":true}},{"node":{"info":{"id":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","name":"node_7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","enode":"enode://4aab8f1241e23af8e2dd0e60b55405d53a91654a387bd7cf812ae58bcd9d4a0402a8f608c6e0db8c43437c367f31326f3820f08d7afed4ee75622a2f05b37eaa@127.0.0.1:0","enr":"0xf88fb84038eea6fad2a04f841af87c2daf250d05a7047b23a61c49705e63401965b90bb16420d5734fe9622caa7b9e22f7c11e69f5c992a8d326d6f7addef874754fc92a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024aab8f1241e23af8e2dd0e60b55405d53a91654a387bd7cf812ae58bcd9d4a04","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"elxEaT3iCtw8U7EwL7AKqzKkYmWrx1Y726M/flxPnXQ=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7a5c44\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 d87b dbef c34b ec3e | 35 d165 (0) d87b (0) dbef (0) dd48 (0)\n001 5 10d5 041c 2b79 2293 | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 4 46af 4853 4e4e 5b93 | 10 4e4e (0) 4853 (0) 404b (0) 46af (0)\n============ DEPTH: 3 ==========================================\n003 3 62c0 6271 6049 | 3 6049 (0) 62c0 (0) 6271 (0)\n004 1 75bf | 1 75bf (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","private_key":"d779095ed5a31b33c8a0b0b0198e6417edf79f53b2a14a0eb5eb1e1e7369f12e","name":"node_7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","services":["streamer"],"enable_msg_events":true,"port":35791},"up":true}},{"node":{"info":{"id":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","name":"node_f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","enode":"enode://5901c788ea558d95661b2e50b68ca1e5e3c79c6293c1bcc73361993fa647db34891c6bc5d5952c43bc105ee6eb5d115a6eef3f26c87229b10777f2d86b12f587@127.0.0.1:0","enr":"0xf88fb840288340dcdbed401c8ce3bde43d0216d5df3e47dcc1c7d7d0a0d0ca4cc681176764d55a2920e5817f97fae70545a30a44acbfc65d43eb435f829b28d2655444590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035901c788ea558d95661b2e50b68ca1e5e3c79c6293c1bcc73361993fa647db34","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9vMY4lokxEnnJ8YMYQcZqqNtC6+CajpJMa1oSr+by7o=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f6f318\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2f1a 404b 6271 7a5c | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 2 a259 ab25 | 14 a259 (0) adfd (0) aeff (0) ab25 (0)\n002 2 c67d dd48 | 12 d165 (0) dbef (0) d87b (0) dd48 (0)\n003 2 ec08 ec3e | 3 e59a (0) ec3e (0) ec08 (0)\n004 2 ff06 fef2 | 2 fef2 (0) ff06 (0)\n============ DEPTH: 5 ==========================================\n005 3 f090 f16d f1e1 | 3 f1e1 (0) f16d (0) f090 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","private_key":"4d482c4424098c2a71c88f47c73227e568fcab0f63d5a6a716f3e716773f19b4","name":"node_f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","services":["streamer"],"enable_msg_events":true,"port":45669},"up":true}},{"node":{"info":{"id":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","name":"node_627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","enode":"enode://2ee80aae24fb663157cb638843b9fb21700a01f5ea5dcec4c69214f2b80eec02717985080fed1618333c85522a39caf9a7ba76b52ba0f480ff3ebb8186f5a69c@127.0.0.1:0","enr":"0xf88fb840fa1436482f2747ab816902e843a51484a4cbc4152e7ec2ad801cae3ded5c889236cca1756f6f103cc630767f9ff82a3a2f4e736ea92418c62499f129946c4bbb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022ee80aae24fb663157cb638843b9fb21700a01f5ea5dcec4c69214f2b80eec02","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YnEFlXqgtYepuhsPJz/BlAO2lVlA55SjWa3onNfUDfs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 627105\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 de4f c62e f6f3 | 35 a259 (0) adfd (0) aeff (0) ab25 (0)\n001 3 1a93 27c2 33fe | 14 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n002 3 4443 55a2 5b87 | 10 55a2 (0) 5b87 (0) 5b93 (0) 5bf6 (0)\n003 2 75bf 7a5c | 2 75bf (0) 7a5c (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 6049 | 1 6049 (0)\n007 0 | 0\n008 1 62c0 | 1 62c0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","private_key":"23966103833d36e192d35e9cfe2670b5319f5499072ede1f11cedd9024940533","name":"node_627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","services":["streamer"],"enable_msg_events":true,"port":32927},"up":true}},{"node":{"info":{"id":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","name":"node_c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","enode":"enode://a5b7729faa9896d27289883c8cec64d7eb741cd7cb745f93db938d30ad11655e5e6d8db4b9a81aba84c7112ea14816c7726c946678e0554b909627c400069fce@127.0.0.1:0","enr":"0xf88fb840e2e531e37debff2425fab0e7db5ecc75f9746078803605fb200a96a2a92984c5671e0f4b88fc7cdc89c9c09b97f9ef3f5a97d6a1be898e5e0594bf71e977c1280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a5b7729faa9896d27289883c8cec64d7eb741cd7cb745f93db938d30ad11655e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xi5LIwLNYvV4yMZHrcOkr/7232WlI2MChl24WJfvwBU=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c62e4b\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2293 33fe 4853 6271 | 29 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n001 3 b269 8934 9637 | 14 a259 (0) adfd (0) aeff (0) ab25 (0)\n002 4 f1e1 e59a ec3e ec08 | 9 e59a (0) ec3e (0) ec08 (0) fef2 (0)\n003 2 d87b dbef | 5 d87b (0) dbef (0) dd48 (0) de4f (0)\n004 2 ce82 c851 | 2 c851 (0) ce82 (0)\n============ DEPTH: 5 ==========================================\n005 3 c034 c05d c34b | 3 c34b (0) c05d (0) c034 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 c67d | 1 c67d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","private_key":"d56adf646d4edd18118697876a2b6c8f969d89f806dd57944e91d7ea8678c854","name":"node_c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","services":["streamer"],"enable_msg_events":true,"port":42935},"up":true}},{"node":{"info":{"id":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","name":"node_9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","enode":"enode://b2038dcdc21c0342ed4add7724ca7f5c70acbda4803e675e7a927cddf0d0acd0f8c470e2424aed644fe6369b849182c846e00a92c6ccb376fe303c1a46818595@127.0.0.1:0","enr":"0xf88fb840198e6a345712a2e48389ef9eb36c43f88bb2b34aa5711694ec4d386a7517b5cf5223d928910d5887731c99bcc03fcf179cb74267e67df478cae4059bab7e31740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b2038dcdc21c0342ed4add7724ca7f5c70acbda4803e675e7a927cddf0d0acd0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ljf6XsgL1ASjZv6G96iaVzUpgzCXwTARSzAVdUiGVF0=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9637fa\npopulation: 12 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 55a2 2b80 0f03 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 2 ce82 c62e | 21 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n002 2 a259 bbbc | 8 b269 (0) bc3e (0) be5d (0) bbbc (0)\n003 3 83aa 8cb7 8934 | 3 8cb7 (0) 8934 (0) 83aa (0)\n============ DEPTH: 4 ==========================================\n004 1 9861 | 1 9861 (0)\n005 1 9009 | 1 9009 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","private_key":"6cb0afbaa74888bcc3ca1555cc1235945258f49c75828c56a9e5c4d47637bbc2","name":"node_9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","services":["streamer"],"enable_msg_events":true,"port":41485},"up":true}},{"node":{"info":{"id":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","name":"node_0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","enode":"enode://287e97ae6cca5147329515ea229510ab6fbbed836fcf6267080988eb4521ca19fca56a67c19b8cdcc1818525d01765fdfa986478d2d22e10dc38f511bf9f66c1@127.0.0.1:0","enr":"0xf88fb8400a5646e83f67d36a442e286b23ed0eb1938e670917068d01ce00c8b6a1a44f471b7807fd83e22f4eb89c4398eeae14885b253e135d5d201bea3b4af9af1c89240183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103287e97ae6cca5147329515ea229510ab6fbbed836fcf6267080988eb4521ca19","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DwOlu1HD9ZlGnP6eXaChC40GulAaieGAB3p18cWXFGc=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0f03a5\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8cb7 9637 | 35 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n001 3 62c0 6049 404b | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 2b80 27c2 2293 | 6 33fe (0) 2293 (0) 27c2 (0) 2b79 (0)\n003 4 12b8 10d5 1a93 1dd4 | 4 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n004 1 041c | 1 041c (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 0d7f | 1 0d7f (0)\n007 1 0e8f | 1 0e8f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","private_key":"f3151faafed66691b7c7fe654fb8b3e32de80b36c07bfaf63b9ce5d571749b79","name":"node_0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","services":["streamer"],"enable_msg_events":true,"port":38513},"up":true}},{"node":{"info":{"id":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","name":"node_404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","enode":"enode://35c2c08791cc1c705a6126041e3383cba8baf51922829224bd290662116349bb20ac4774bbbeca9adf7266b8731664ad8255a17469fde0fdeffc60b1287b0b5a@127.0.0.1:0","enr":"0xf88fb840f7059937b3fb094126531a32fa1c349cd67da70cefdb5158e95ef285d03af1ec44ff0691cbeb5bc2a09af995303f9a5a61923166d8f92f1811559758e6c8be700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10235c2c08791cc1c705a6126041e3383cba8baf51922829224bd290662116349bb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QEtwxqxylyz9nnzxFcfwQ70V0OS5qVm/wpJMci63Evc=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 404b70\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f090 f6f3 ff06 | 35 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n001 2 2f1a 0f03 | 14 33fe (0) 2293 (0) 27c2 (0) 2b80 (0)\n002 2 62c0 6049 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 3 55a2 5bf6 5b93 | 4 55a2 (0) 5bf6 (0) 5b87 (0) 5b93 (0)\n004 2 4853 4e4e | 2 4e4e (0) 4853 (0)\n============ DEPTH: 5 ==========================================\n005 3 46af 4541 4443 | 3 46af (0) 4443 (0) 4541 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","private_key":"39ac08b99ed5a6af6a54d2ac5321be553f9143d2695a8505e15e42661d1e037e","name":"node_404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","services":["streamer"],"enable_msg_events":true,"port":40259},"up":true}},{"node":{"info":{"id":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","name":"node_2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","enode":"enode://13799436c7d312b56cc9e0e3efc7a244cd310752235ed2d531f3756fb4c329b8f4beed1ae628979c46857255291e4a89eca3d777309d735ccd52a1fd086eb37a@127.0.0.1:0","enr":"0xf88fb840a18583a1a4a283a6cb8ec25c1bf4c3f964e23314193307d2b5cb271cde21b81b48c60cf629544c76de4d3e4616a1311dfc70306df454ce056bfa7231738b81580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10213799436c7d312b56cc9e0e3efc7a244cd310752235ed2d531f3756fb4c329b8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LxoVw5vLDpU/jBYJM/aePdopuDRXV0LE9DLrOExd2d8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2f1a15\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f090 f6f3 ab25 | 35 f6f3 (0) f090 (0) f1e1 (0) f16d (0)\n001 4 62c0 6049 4853 404b | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 1dd4 1a93 12b8 | 8 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n003 1 33fe | 1 33fe (0)\n004 2 27c2 2293 | 2 2293 (0) 27c2 (0)\n============ DEPTH: 5 ==========================================\n005 2 2b79 2b80 | 2 2b80 (0) 2b79 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","private_key":"edc9fc2f574b8ae4c0f349dcfca0fb04cfdf47fc9405889b34be78c770fc4acf","name":"node_2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","services":["streamer"],"enable_msg_events":true,"port":45277},"up":true}},{"node":{"info":{"id":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","name":"node_ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","enode":"enode://d7dddfa4efbb58706320eaf3223ec745504d5d8d4b2bc5385b5dc670985287398ee138b1cb976bc08fe72de2b0b59452a0194bce9614f4df7c5e9faf58ef85d4@127.0.0.1:0","enr":"0xf88fb840d1e80f4b38afbcd783a882fe818fc87a0fc6df4a9e49d2d21e51e3494648bf771a06c6b548b8e2242ea69ad4c3677834df3e83510ddc5010347390435467866d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d7dddfa4efbb58706320eaf3223ec745504d5d8d4b2bc5385b5dc67098528739","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qyVcQOObqP0vtDn/JtE1qrOUT7kVnlQ3D0/nNZBtAxM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ab255c\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 041c 2f1a | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 dd48 f090 f6f3 | 21 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n002 2 8cb7 8934 | 6 8934 (0) 8cb7 (0) 83aa (0) 9009 (0)\n003 3 b269 be5d bc3e | 4 b269 (0) bc3e (0) be5d (0) bbbc (0)\n004 1 a259 | 1 a259 (0)\n============ DEPTH: 5 ==========================================\n005 2 aeff adfd | 2 adfd (0) aeff (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","private_key":"e097903ff73cba0125e376909f8f08ea09638c36b5e540c8b86d2c0370445bf7","name":"node_ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","services":["streamer"],"enable_msg_events":true,"port":40173},"up":true}},{"node":{"info":{"id":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","name":"node_041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","enode":"enode://bf082dde14615af13c8a4cd17d9d4aba390cb871d34006a5e4e27eeac55c37ed4b160b1c7fa573b079291477f5c34df7389fb207202d36cb020bb1e11b1770ae@127.0.0.1:0","enr":"0xf88fb840ee4895d2879885f7fcb08b7d5d3a2ebdb4617198888190d13eed5f53b6e2c48518e2429a8c73ab55c0f5bfb46f4144cf3d97557bf7a6065d62c6bf38af64d1f90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bf082dde14615af13c8a4cd17d9d4aba390cb871d34006a5e4e27eeac55c37ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BBxKP5QlNuZ68IfaMFQD4moZ4DDc9RRzpZdDF1OivsI=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 041c4a\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dd48 c034 8cb7 ab25 | 35 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n001 6 4541 5b87 55a2 62c0 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 2b80 2293 33fe | 6 33fe (0) 2293 (0) 27c2 (0) 2b80 (0)\n003 4 1dd4 1a93 12b8 10d5 | 4 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n============ DEPTH: 4 ==========================================\n004 3 0d7f 0f03 0e8f | 3 0d7f (0) 0e8f (0) 0f03 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","private_key":"0c395ad41017794ece1bb20e02f995d3d71b784e80b6972127d60e11b9416033","name":"node_041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","services":["streamer"],"enable_msg_events":true,"port":45519},"up":true}},{"node":{"info":{"id":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","name":"node_c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","enode":"enode://56c5533688bc45c78eab8abe6fdbcc89c9ff51b6b2e78b4aa94c1e9d24f9269468c3d7061b1898f46535308665012ae49ce7768fe52a097e0f29eba58264f339@127.0.0.1:0","enr":"0xf88fb8402ff8750dfe7251a484fddf76d16ae3c3704a2faf12eb06a51b8f7409190bb26958d90e58f0a89ef2e488bb66c090ec33b0434b315fc7d2aafca5ac24482e5deb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10356c5533688bc45c78eab8abe6fdbcc89c9ff51b6b2e78b4aa94c1e9d24f92694","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wDRxluyH9R+XIpFAtdZgFc//J4HMGv9tPiB8P6NTJzI=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c03471\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6049 041c | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 b269 bc3e bbbc | 14 b269 (0) bc3e (0) be5d (0) bbbc (0)\n002 2 ff06 fef2 | 9 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n003 2 de4f d165 | 5 dd48 (0) de4f (0) d87b (0) dbef (0)\n004 2 c851 ce82 | 2 ce82 (0) c851 (0)\n005 2 c62e c67d | 2 c67d (0) c62e (0)\n============ DEPTH: 6 ==========================================\n006 1 c34b | 1 c34b (0)\n007 0 | 0\n008 0 | 0\n009 1 c05d | 1 c05d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","private_key":"5a906a787cb78df16ad69dfd4eefb997694bce2b8b171b223cd01db89f2cfe56","name":"node_c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","services":["streamer"],"enable_msg_events":true,"port":42833},"up":true}},{"node":{"info":{"id":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","name":"node_d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","enode":"enode://d3715cf48dd521184951b76f82e30bef59b728fb780c33aafac3b501ec3a082cabdd4fbf1d191b0fc6fd4e329aca56f96d8820b1d3d7c38ff169bb66398379ef@127.0.0.1:0","enr":"0xf88fb84082fc9a1da6b7ab89a49f98c25a59627c4f54319e0d439c5f8605a75ddf74b1f0099cb2a276f366bd085ef8f6fbfbc4ae9b86b4530d0a31ce50fe3cbd8c98c6670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d3715cf48dd521184951b76f82e30bef59b728fb780c33aafac3b501ec3a082c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0WUT8w1IXTF1MhwaCqWlJcEVrhPDlff6Pesc9NHsabw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d16513\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5bf6 1a93 12b8 | 29 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n001 2 bbbc 9861 | 14 b269 (0) bc3e (0) be5d (0) bbbc (0)\n002 3 f090 ff06 fef2 | 9 fef2 (0) ff06 (0) f6f3 (0) f090 (0)\n003 5 ce82 c67d c34b c05d | 7 ce82 (0) c851 (0) c67d (0) c62e (0)\n============ DEPTH: 4 ==========================================\n004 4 dd48 de4f d87b dbef | 4 dd48 (0) de4f (0) d87b (0) dbef (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","private_key":"18698a5fd9c496b1d243f171696350d10fc3580717073a40f6d99520412f83d5","name":"node_d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","services":["streamer"],"enable_msg_events":true,"port":45987},"up":true}},{"node":{"info":{"id":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","name":"node_9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","enode":"enode://17306034b66dfcdbc97a6f9ba35033107edc8cbb03353fe5e6eb8df030ac6752cd0ed1f6edfcd7b57c456a10519e1563141ab10a463ab00d6c46cc315805d60f@127.0.0.1:0","enr":"0xf88fb84064b8824d317bdfdbd6d0f8e6d48f0b8a8faef43af8108d93c63e8d5b3b0239bd0221d18dbfe9bc21d49506094150e4abc556274dca3f62cf87b393001cdfbbab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10317306034b66dfcdbc97a6f9ba35033107edc8cbb03353fe5e6eb8df030ac6752","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mGHXyrFf13zlRKoEb52vYa9/fHjaf4TJ07wcGfny4HE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9861d7\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 2b80 55a2 4541 | 29 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n001 4 f16d f090 ce82 d165 | 21 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n002 3 bbbc a259 aeff | 8 b269 (0) bc3e (0) be5d (0) bbbc (0)\n003 3 83aa 8cb7 8934 | 3 8934 (0) 8cb7 (0) 83aa (0)\n============ DEPTH: 4 ==========================================\n004 2 9637 9009 | 2 9009 (0) 9637 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","private_key":"4df06f9461343c2fda87c2dad86b4b3cf8a4f9ca58c88bae635d03da92ea006b","name":"node_9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","services":["streamer"],"enable_msg_events":true,"port":46151},"up":true}},{"node":{"info":{"id":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","name":"node_45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","enode":"enode://a686970d89c6c9d2e4c69d94f1b6694d904581304de0fc9efb180891260b3099a5b46700b2aa72d09afb7266ef786abc5dada1f9b0fe5f3a78daec8cc6f66c53@127.0.0.1:0","enr":"0xf88fb840241ea258a71f40249cdf5e63289c8632db6eca503178586fa7803de62e853e4a3dd497f51b52eb68afac7dce913cf61574c069499d3a4f31f727f83262c49b180183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a686970d89c6c9d2e4c69d94f1b6694d904581304de0fc9efb180891260b3099","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RUEadILK5Q3R3Y2QE4oowNxhsEuqlZL5J/nUFbCXClM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 45411a\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ec08 9861 | 35 ce82 (0) c851 (0) c67d (0) c62e (0)\n001 3 041c 0d7f 0e8f | 14 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n002 2 6049 62c0 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 2 5bf6 55a2 | 4 55a2 (0) 5bf6 (0) 5b87 (0) 5b93 (0)\n004 2 4853 4e4e | 2 4e4e (0) 4853 (0)\n005 1 404b | 1 404b (0)\n============ DEPTH: 6 ==========================================\n006 1 46af | 1 46af (0)\n007 1 4443 | 1 4443 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","private_key":"e7b54819c42e18dc0898157b7f12a62003c3ca0b175bb3478c3e18364ad4d72d","name":"node_45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","services":["streamer"],"enable_msg_events":true,"port":39521},"up":true}},{"node":{"info":{"id":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","name":"node_ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","enode":"enode://d4e917601f1e529ba3150bc6547ed2baa812c622541b179807e35b3d19b6f024b3babc685cc9052d03ac6af21cd734b458f7010c55cf32997f230b64626a5a37@127.0.0.1:0","enr":"0xf88fb8406a26e3870ba17f1f806d807b45527a32c7fb63b96a757f20b191a4b827cb4f840cbfeef46ad28b8d65bb14e1677cff14604cd8e288cf6f25367dac70f3fc1e740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d4e917601f1e529ba3150bc6547ed2baa812c622541b179807e35b3d19b6f024","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7AhSQ2Rcbl/b7/sTfM0RkFO9ZV52sdmmteAiEYN2TkM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec0852\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6049 4e4e 4541 5b93 | 29 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n001 5 a259 b269 be5d bc3e | 14 b269 (0) bc3e (0) be5d (0) bbbc (0)\n002 8 d87b dd48 c851 ce82 | 12 ce82 (0) c851 (0) c67d (0) c62e (0)\n003 4 fef2 ff06 f6f3 f1e1 | 6 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n============ DEPTH: 4 ==========================================\n004 1 e59a | 1 e59a (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 ec3e | 1 ec3e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","private_key":"564658b59ef3923b2cfa270f76d2885719f4d8d5a4640218cef7fd7cc5803538","name":"node_ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","services":["streamer"],"enable_msg_events":true,"port":43959},"up":true}},{"node":{"info":{"id":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","name":"node_5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","enode":"enode://7cfb88f94a2ce6d8382ad72e15d58c728ccf68134cada4852553c46446caf2244b21821d261c193ef0f96bd15aa704cc0ff3c808d6f46572af769d98f5662856@127.0.0.1:0","enr":"0xf88fb8404835ccf9f26f0c1ced47b4f024d3eb722f652257cb4bbf0c7122ea46b1f338d061f8d1c3ff1e6a17350e0a573500841cd7eaa7b532e66ac094ad8f5e2642d0740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027cfb88f94a2ce6d8382ad72e15d58c728ccf68134cada4852553c46446caf224","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W5NjQdpwnRGzS23wB/OP/wOWt4WhT5RlOq+SHY5FCj8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5b9363\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bc3e b269 ec08 | 35 b269 (0) bc3e (0) be5d (0) bbbc (0)\n001 4 1dd4 0e8f 2293 27c2 | 14 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n002 3 62c0 6049 7a5c | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 3 4e4e 46af 404b | 6 404b (0) 46af (0) 4443 (0) 4541 (0)\n004 1 55a2 | 1 55a2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 5bf6 | 1 5bf6 (0)\n010 0 | 0\n011 1 5b87 | 1 5b87 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","private_key":"10d7b03ff60d1351f7b6be0726cb6c950befc858ef8f870ef7f19335efe1b2e9","name":"node_5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","services":["streamer"],"enable_msg_events":true,"port":41261},"up":true}},{"node":{"info":{"id":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","name":"node_27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","enode":"enode://643ed7e6dce73138a35c06ad2e7dd22b9fb60bfe8c62df0e78ba66158a01ee8c5105a61257adc96ceefe709d7f1a33501118a7f788cfc64a9ab1d5f8dabd02f0@127.0.0.1:0","enr":"0xf88fb8404d9287db19102ad4463ec35d232a539755701e2fa7d275048045a82a349c00ac7db9f3d723cc349a77840cb6643cf59aafffac21d27bfa52933fedcd68b91a4c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102643ed7e6dce73138a35c06ad2e7dd22b9fb60bfe8c62df0e78ba66158a01ee8c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J8I2WD3/cUowAKyvv9MwhWbIEnH4JerI9PDP+Dp/8Sc=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 27c236\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c05d c67d fef2 ff06 | 35 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n001 5 6271 7a5c 46af 4e4e | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 1dd4 10d5 0f03 | 8 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n003 1 33fe | 1 33fe (0)\n============ DEPTH: 4 ==========================================\n004 3 2b79 2b80 2f1a | 3 2f1a (0) 2b80 (0) 2b79 (0)\n005 1 2293 | 1 2293 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","private_key":"d83c8e0152983bd8a5e3e5bbbe5fcd0962af9a8d3c3e74b2766a616a662ce1fc","name":"node_27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","services":["streamer"],"enable_msg_events":true,"port":33423},"up":true}},{"node":{"info":{"id":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","name":"node_83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","enode":"enode://124f0cb5dff8cbe3f2b4879314e1c7e445847ab4107a0172bdb2cc3c8c117e31f5b7d10237c9a2e01cf4b308684c6ae532267b2316bec3efd66e418e51df05c4@127.0.0.1:0","enr":"0xf88fb840e0882134a9c0bab94463ea2fb53f1227c478c4b6573df8c6e0d225495bff145000ae070b7539cc26f159f626b7ce494e2f7830c5cb9a091059ccf0b950947b200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102124f0cb5dff8cbe3f2b4879314e1c7e445847ab4107a0172bdb2cc3c8c117e31","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g6rVuX4eqMQFN+VZPeSBDHs1+rFWBTQC3adY1unqkFU=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 83aad5\npopulation: 26 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5b87 4853 0e8f 1dd4 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 10 f16d f1e1 fef2 e59a | 21 ce82 (0) c851 (0) c67d (0) c62e (0)\n002 5 aeff adfd be5d bc3e | 8 b269 (0) bc3e (0) be5d (0) bbbc (0)\n003 3 9861 9009 9637 | 3 9637 (0) 9009 (0) 9861 (0)\n============ DEPTH: 4 ==========================================\n004 2 8cb7 8934 | 2 8cb7 (0) 8934 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","private_key":"cb01a75bc3c400c6de710019b74759a8aa1dd7e7362e86928ef1ea2b04805e0f","name":"node_83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","services":["streamer"],"enable_msg_events":true,"port":45083},"up":true}},{"node":{"info":{"id":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","name":"node_48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","enode":"enode://8cd9a1d7a69bf057290a9f420a465a9e82ca398b542cb8cbd444121f06a56a50a1488496a7786bc41fa750eebde2519b30e91d6a254979aafe5b362f291b3342@127.0.0.1:0","enr":"0xf88fb8405c96c6659930b28d8e7fc70e709db26a72cfb94922dbf7d4cfb4fac0083d70037a3eb75c1117b50851f09570ca994003cebee249134d8c8f7f1604ba717afaac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028cd9a1d7a69bf057290a9f420a465a9e82ca398b542cb8cbd444121f06a56a50","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SFNKU4/XCMDmFsvfqUhZYEi32qd+8J3WnBZSpfbQXvw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48534a\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c62e c851 ce82 83aa | 35 ce82 (0) c851 (0) c62e (0) c67d (0)\n001 3 2f1a 33fe 12b8 | 14 33fe (0) 2f1a (0) 2b80 (0) 2b79 (0)\n002 3 7a5c 62c0 6049 | 5 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n003 3 55a2 5bf6 5b87 | 4 55a2 (0) 5bf6 (0) 5b87 (0) 5b93 (0)\n============ DEPTH: 4 ==========================================\n004 4 404b 4443 4541 46af | 4 404b (0) 46af (0) 4443 (0) 4541 (0)\n005 1 4e4e | 1 4e4e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","private_key":"8b7949320c5ad8130070a34702abd57dc0f7b7ddd7da1abd2b8a3aabad87dca1","name":"node_48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","services":["streamer"],"enable_msg_events":true,"port":38627},"up":true}},{"node":{"info":{"id":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","name":"node_12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","enode":"enode://149300b78ce42863b2bff34e21322a35ae2558dfe528efca3cbcc8b9a90003d8cba8a3cb24dba7d83d923e4565689cef7d48c1988c109bb94b1bc92bf348c5dd@127.0.0.1:0","enr":"0xf88fb840731cd5d3da6e6990435abc04b71ca41ee0c7e99f6f7baf78f4f4dd25cc64f546516fdf07f114321703f8ad413ff912c769f3e636e3f2435ad48390bf3325da4f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103149300b78ce42863b2bff34e21322a35ae2558dfe528efca3cbcc8b9a90003d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Erh2ng6ZYBHO/0iaP1a6jlVdVFtprMtbQ5berXM1qNs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 12b876\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d165 aeff | 35 ce82 (0) c851 (0) c62e (0) c67d (0)\n001 3 62c0 6049 4853 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 2 2b79 2f1a | 6 33fe (0) 2f1a (0) 2b80 (0) 2b79 (0)\n003 4 041c 0f03 0e8f 0d7f | 4 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n============ DEPTH: 4 ==========================================\n004 2 1a93 1dd4 | 2 1a93 (0) 1dd4 (0)\n005 0 | 0\n006 1 10d5 | 1 10d5 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","private_key":"2508a321d22ccd27c53ebf00259ba720d9dee11266d3f043f356c7a542bf5213","name":"node_12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","services":["streamer"],"enable_msg_events":true,"port":38733},"up":true}},{"node":{"info":{"id":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","name":"node_aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","enode":"enode://680e1e24fb480dd22e272d12a2154d05d2da6969852d46f6b506b4a1282fb34600add98e4ca61da2fb843cf9cda458b570644726887f2050db271b98b1c0db17@127.0.0.1:0","enr":"0xf88fb8408aac439c83ee5ca37fe399d1d5b6c1e934d183768e15180da3383420881be7c53b0a80526aadd31a64143fd0a5260c48f9d7d5737a91adacae76980c9c76f9110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103680e1e24fb480dd22e272d12a2154d05d2da6969852d46f6b506b4a1282fb346","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rv+IpcdJczcH+ZuHbB7PfbcbMqaRbPm70mavPmn5ToI=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aeff88\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 62c0 6049 12b8 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 dd48 ce82 ec3e | 21 ce82 (0) c851 (0) c62e (0) c67d (0)\n002 3 8934 83aa 9861 | 6 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n003 2 bbbc b269 | 4 b269 (0) bbbc (0) bc3e (0) be5d (0)\n004 1 a259 | 1 a259 (0)\n============ DEPTH: 5 ==========================================\n005 1 ab25 | 1 ab25 (0)\n006 1 adfd | 1 adfd (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","private_key":"6362a429c515516bd38d57f294a819e354a5c339c513bbaab341d2c5a7f13394","name":"node_aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","services":["streamer"],"enable_msg_events":true,"port":40299},"up":true}},{"node":{"info":{"id":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","name":"node_ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","enode":"enode://78e0de844f3eb1a777d730bab86c1a0b567be81f22b68a37e6982ea9125e90bd7bc29f61d61244aa891f590fbfd8b5007806f51cf694267bb8e3b97a08572afb@127.0.0.1:0","enr":"0xf88fb840ee54b5b6a8c22c569f160e440cf7be54568f91bb8830054e562bf3befdd1d714319c55af25103db7e6a23762cbe773952246ac5142ec549a063fbea2b66725470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10378e0de844f3eb1a777d730bab86c1a0b567be81f22b68a37e6982ea9125e90bd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7D6E+Aq3HfCaRMecjUr42mj98919vOdFE2O4qhZjBJM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec3e84\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 4e4e 6049 7a5c 75bf | 29 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n001 4 8934 be5d a259 aeff | 14 8934 (0) 8cb7 (0) 83aa (0) 9637 (0)\n002 5 dd48 de4f c62e ce82 | 12 ce82 (0) c851 (0) c62e (0) c67d (0)\n003 5 fef2 ff06 f6f3 f16d | 6 ff06 (0) fef2 (0) f6f3 (0) f090 (0)\n============ DEPTH: 4 ==========================================\n004 1 e59a | 1 e59a (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 ec08 | 1 ec08 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","private_key":"9cd9fa1a605cd0ed1669a0dd7bdedc839592f58445855d00f026f10b963dcafc","name":"node_ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","services":["streamer"],"enable_msg_events":true,"port":36709},"up":true}},{"node":{"info":{"id":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","name":"node_2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","enode":"enode://e5b1f4c67a9ddf4aa86df910ed695036a223dd512855d568edab958376cdd219581d2630660fde2afdc7ee817e216363ceb5fe859fe22b1cac314f5ca41d5c6a@127.0.0.1:0","enr":"0xf88fb840d2019a30e5ccc8ec4bcbdee28917513d1f3af8f8d0a0ca778e4198ff0de51ae22ac27b43f7d4c6a255487960932f592d5cde6b85398068b56960e6b05ee82faa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e5b1f4c67a9ddf4aa86df910ed695036a223dd512855d568edab958376cdd219","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"IpOx6ftE7m2znbk2YpH8C04obDVVR3UN4Z6Wwy4Cvfk=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2293b1\npopulation: 22 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8934 c62e c05d ec3e | 35 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n001 6 75bf 7a5c 46af 4443 | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 7 10d5 1dd4 1a93 041c | 8 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n003 1 33fe | 1 33fe (0)\n============ DEPTH: 4 ==========================================\n004 3 2b80 2b79 2f1a | 3 2f1a (0) 2b80 (0) 2b79 (0)\n005 1 27c2 | 1 27c2 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","private_key":"a7e22c8e32897aa84673ffac362e3ce8b479502494dc0749e76bdfd84a0adb9c","name":"node_2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","services":["streamer"],"enable_msg_events":true,"port":42613},"up":true}},{"node":{"info":{"id":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","name":"node_0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","enode":"enode://0c0ef588e8b1199c6721bf84dcb2c30de56f14db707cb02e310a245b8b3ce5c62ae119bc2950db881cc79b4bc1a2386f24bc14b0b3b7ba4e2e2f37b5a1cff032@127.0.0.1:0","enr":"0xf88fb8403221a6d46572817f3fc0af52de678dc02fff0e264b852ad32144056b20ebe5eb256f63a332afe90b856b498ea1e44ba84e339efbe95ed453fbb8bf7eb3be2f0e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c0ef588e8b1199c6721bf84dcb2c30de56f14db707cb02e310a245b8b3ce5c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Do+z4ldGp/GPM+McECAOXsIetUrVkrrVNpubWE/oDhs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e8fb3\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8cb7 8934 83aa f16d | 35 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n001 3 4541 5b87 5b93 | 15 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n002 2 33fe 2293 | 6 33fe (0) 2f1a (0) 2b80 (0) 2b79 (0)\n003 4 10d5 12b8 1a93 1dd4 | 4 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n004 1 041c | 1 041c (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 0d7f | 1 0d7f (0)\n007 1 0f03 | 1 0f03 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","private_key":"e4fb6f87c8b9945ae6a519e730732fdde0730aca6c9f6337c91d93cd6c1c2480","name":"node_0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","services":["streamer"],"enable_msg_events":true,"port":42649},"up":true}},{"node":{"info":{"id":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","name":"node_f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","enode":"enode://d53eecb3d3f3d9ff017ec25bcdfcb2f3ce3232f6231b66d85ed3be04cf3f6cc65c8dde5e8fe596ad8525a3e57a7f32f6978897df1999e44a5d45eb5cd6b8e9a7@127.0.0.1:0","enr":"0xf88fb8406945726d8a4e02936737ad2da763a772efedf913a0000b71b47a1f44d9a385ea6b033e2dfc7fd4744edcf9516d7af9601eff2844b8039d985f9b575cd4a993dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d53eecb3d3f3d9ff017ec25bcdfcb2f3ce3232f6231b66d85ed3be04cf3f6cc6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8W3GW1ip+lBgZ0ynQVMYkf1Etj2axeq+oYV0UEnkdMo=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f16dc6\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 75bf 0d7f 0e8f | 29 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n001 3 8934 83aa 9861 | 14 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n002 2 ce82 dbef | 12 ce82 (0) c851 (0) c62e (0) c67d (0)\n003 2 e59a ec3e | 3 ec08 (0) ec3e (0) e59a (0)\n004 2 fef2 ff06 | 2 ff06 (0) fef2 (0)\n005 1 f6f3 | 1 f6f3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f090 | 1 f090 (0)\n008 1 f1e1 | 1 f1e1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","private_key":"6e17a7cb8b4de986f9326d40d3f75a0548c328b5dcee6251d75d9660ff38b25f","name":"node_f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","services":["streamer"],"enable_msg_events":true,"port":36431},"up":true}},{"node":{"info":{"id":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","name":"node_dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","enode":"enode://a8545ee5288608aa97011ceaad769754e2fef8de716fde9f03da6fd3443dee98a58ad2f20866d444df2aff3ebb9178512cbe0a88c70c13d763ad2f21a2d31518@127.0.0.1:0","enr":"0xf88fb840a5d951670a83dfbad4108b1a6e4daad3ec8234952811451a02187bb09cecbb095ae0eb3bb7f2c41e5a07f629cc716628c546b82b93c5895b8749b0af44aa53440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a8545ee5288608aa97011ceaad769754e2fef8de716fde9f03da6fd3443dee98","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2+/TIuTzfz4UKtFRoIyL13hPsNskkySv9Hn1tmMhLnY=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dbefd3\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7a5c 75bf 62c0 | 29 75bf (0) 7a5c (0) 6049 (0) 6271 (0)\n001 3 83aa 8cb7 8934 | 14 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n002 2 e59a f16d | 9 ec08 (0) ec3e (0) e59a (0) ff06 (0)\n003 3 c67d c62e c34b | 7 ce82 (0) c851 (0) c62e (0) c67d (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 de4f dd48 | 2 dd48 (0) de4f (0)\n006 1 d87b | 1 d87b (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","private_key":"8537c2f509c410459184963d560347c250fc3f2631bcc456ac9b79da484bc101","name":"node_dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","services":["streamer"],"enable_msg_events":true,"port":35725},"up":true}},{"node":{"info":{"id":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","name":"node_c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","enode":"enode://0245124f48570389a2866e65303f7d57c8a4254666fb9e7ec6e6f3ace35f5e45ca64226350e6b6445dfd1091d1394796df617f005159041b940524f8adda73a1@127.0.0.1:0","enr":"0xf88fb8404535d47dbfda01f3c3a68b4bd60c11c4768d1649b38384b158512d85b4e5cc43499e0e607bddd4361d5b54a390b17ae72e26d3080276c9d687c9efae40f005860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030245124f48570389a2866e65303f7d57c8a4254666fb9e7ec6e6f3ace35f5e45","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"w0vS4gn8EeJ/geE1lUXyjIFnhxJ7QYEdwXEPpOU/zvo=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c34bd2\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 75bf 7a5c 62c0 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 83aa 8cb7 8934 | 14 83aa (0) 8934 (0) 8cb7 (0) 9637 (0)\n002 2 ec08 f090 | 9 ec08 (0) ec3e (0) e59a (0) ff06 (0)\n003 2 d165 dbef | 5 d165 (0) dd48 (0) de4f (0) d87b (0)\n004 2 c851 ce82 | 2 ce82 (0) c851 (0)\n005 2 c67d c62e | 2 c62e (0) c67d (0)\n============ DEPTH: 6 ==========================================\n006 2 c05d c034 | 2 c034 (0) c05d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","private_key":"ecb3f67dada43226ea1f5c5c177ca97188784e759b87b5d7701b36bbbcee941b","name":"node_c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","services":["streamer"],"enable_msg_events":true,"port":38173},"up":true}},{"node":{"info":{"id":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","name":"node_f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","enode":"enode://796dd862e2916c5900370aa18abb58eb7ba061bd52bf8bb48806ac1deec33d5f6627fbd4cdccb07ca96c2661bc2e8b28c2899f2dc77b58affcbb938e197868b7@127.0.0.1:0","enr":"0xf88fb84022132521c6b77045f87c62858e909b70e05b1eb03074a66cdbf5ddd612c6497c0d7965fa4bf8da77b47dd9876098ae4e83e897a656a7fead1080c84ad489a9800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103796dd862e2916c5900370aa18abb58eb7ba061bd52bf8bb48806ac1deec33d5f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8JDZCflPaXDQdJSBFeT0bmfk+1c19TeIntKxaf8r02g=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f090d9\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 404b 2f1a 2b79 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 2 9861 ab25 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 2 d165 c34b | 12 d165 (0) dd48 (0) de4f (0) d87b (0)\n003 2 e59a ec3e | 3 ec08 (0) ec3e (0) e59a (0)\n004 2 fef2 ff06 | 2 ff06 (0) fef2 (0)\n005 1 f6f3 | 1 f6f3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 f1e1 f16d | 2 f1e1 (0) f16d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","private_key":"3dfe370e85ca228b6903e2d360a8514dce89675639f3a9264664edb96fdca3dc","name":"node_f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","services":["streamer"],"enable_msg_events":true,"port":41687},"up":true}},{"node":{"info":{"id":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","name":"node_2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","enode":"enode://370dcdd12168f383c15bd0ec87531e7bdaa52736c12bcea00741789b1751854b7e14b84fc913da88db24c127860eef70289cd36c30e870b2e60ae232f705b520@127.0.0.1:0","enr":"0xf88fb8403028d93ddd84c729bf844b16597a912772cc40c7db867507dad911da33bfe6d55295b0a2878cb609e92f19940ef46dd3702138aec69e6760ec1467fbce88f9fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102370dcdd12168f383c15bd0ec87531e7bdaa52736c12bcea00741789b1751854b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"K3kPvKjadMfelxW0kZzgPNzxSkYIZxzUc5srmaBS5jY=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2b790f\npopulation: 12 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 8934 83aa f090 | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 2 7a5c 5b87 | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 2 0d7f 12b8 | 8 041c (0) 0e8f (0) 0f03 (0) 0d7f (0)\n003 1 33fe | 1 33fe (0)\n004 2 2293 27c2 | 2 27c2 (0) 2293 (0)\n============ DEPTH: 5 ==========================================\n005 1 2f1a | 1 2f1a (0)\n006 0 | 0\n007 0 | 0\n008 1 2b80 | 1 2b80 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","private_key":"d4f121c855c9e92f96585641e9e11a9f25db6aa8086675165215c749e9931cc6","name":"node_2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","services":["streamer"],"enable_msg_events":true,"port":39687},"up":true}},{"node":{"info":{"id":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","name":"node_5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","enode":"enode://c1760651e80b5c22381bc3145277a8ea0e69ca9ccb7eec2abbf5d25763af1434adb24df08ef0563f360c47e13df5274f4a306c6c58d563001c737b1a6e8f6077@127.0.0.1:0","enr":"0xf88fb84049138c3a1759cf719d4a36e6e0af5ed94ddcc90a5151a6bf2f2c4a1ab71fb59e1c02d825fd42a203c2b2638a1e777ba95a1f07e2a1b276029d6f689aa0dd9c6f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c1760651e80b5c22381bc3145277a8ea0e69ca9ccb7eec2abbf5d25763af1434","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W4dHjOb5aYjVctJJFAymcW9mrsj24ENef4vp/KXtOKA=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5b8747\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 adfd 8cb7 8934 83aa | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 4 1dd4 0e8f 041c 2b79 | 14 041c (0) 0e8f (0) 0f03 (0) 0d7f (0)\n002 2 6271 75bf | 5 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n003 2 46af 4853 | 6 404b (0) 46af (0) 4443 (0) 4541 (0)\n004 1 55a2 | 1 55a2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 5bf6 | 1 5bf6 (0)\n010 0 | 0\n011 1 5b93 | 1 5b93 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","private_key":"8d3cdf3d5a28844fd7e67364be1e82e3718d8f5eb3b28b7c219f3bfd3a4482ff","name":"node_5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","services":["streamer"],"enable_msg_events":true,"port":45565},"up":true}},{"node":{"info":{"id":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","name":"node_c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","enode":"enode://8efe3d05a04ad75bac960e82749f90285a60965cbabf117520172a430cee7e1beabe22d9402056d1fcd0bd54060e8aef112a62ab850079d330d861bcdd7816cb@127.0.0.1:0","enr":"0xf88fb8405e37f5ab79e815ac91da5441a580c06abf98a4ea7d3ed49b9aaa5dd4b5c8356a4a4a3a5f0f457122d3ef8ef8d3d0ab266d55390d8c1dec965faa04061944e7180183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038efe3d05a04ad75bac960e82749f90285a60965cbabf117520172a430cee7e1b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yFEfiJbTxCJtXYyGAJbGqQg5/OUAp3uDBDlfW0gzsoQ=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8511f\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1dd4 1a93 4853 5b87 | 29 1a93 (0) 1dd4 (0) 10d5 (0) 12b8 (0)\n001 2 8cb7 83aa | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 3 e59a ec08 ec3e | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 dd48 d87b | 5 d165 (0) de4f (0) dd48 (0) dbef (0)\n============ DEPTH: 4 ==========================================\n004 5 c34b c034 c05d c62e | 5 c62e (0) c67d (0) c034 (0) c05d (0)\n005 1 ce82 | 1 ce82 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","private_key":"7edb500de3d27c2f1c20281b4a363269e854385d629b21f00110159d97b3607e","name":"node_c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","services":["streamer"],"enable_msg_events":true,"port":44825},"up":true}},{"node":{"info":{"id":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","name":"node_d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","enode":"enode://df025390a37a450f77f57f29730f1cdcf861dafe454be915480b15a7618c3dd0fa0614cd563fafc92b49c299f8ca1a67fa45a5e339ef81f7eb0313063ec7fcd7@127.0.0.1:0","enr":"0xf88fb840f20d1eb7eba00a7c4cad26a78536b6a072c53c985418b4cca4a279004d36316d3b04274929a19f4967819c2b69986716fdb97b7224be8c43b3152c9a09b6f1450183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df025390a37a450f77f57f29730f1cdcf861dafe454be915480b15a7618c3dd0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2HumV1dpaAWPzIZXnD9SqniQWQmwqUOTivYhxu2Z++o=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d87ba6\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6049 7a5c 75bf | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 8cb7 8934 83aa | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 2 ec08 f1e1 | 9 ec08 (0) ec3e (0) e59a (0) ff06 (0)\n003 2 c62e c851 | 7 c62e (0) c67d (0) c034 (0) c05d (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 de4f dd48 | 2 de4f (0) dd48 (0)\n006 1 dbef | 1 dbef (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","private_key":"93f0687cbba5779fbb6cb10ab57fdb2d731263d9454254b0d068517de95318c3","name":"node_d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","services":["streamer"],"enable_msg_events":true,"port":42845},"up":true}},{"node":{"info":{"id":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","name":"node_f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","enode":"enode://484250cb629a55eb8908406ea682b88bd1095dbc5c8b47d7dcf788b58af2aca80bcc8048c730f61123f714da50af301fbf0bb5544d6a12265dd64f6d6caa7622@127.0.0.1:0","enr":"0xf88fb840c0b62c373941d77a9db85a25dd2254d9ed63ab322b5103757f67b539c0637fa45e0227414a8f3c80030c5c4f3c63066f12d2f43a348b054df1baec631a2b24ab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102484250cb629a55eb8908406ea682b88bd1095dbc5c8b47d7dcf788b58af2aca8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8eFRvu8MIllmmslQElqgBLArpweL8thySKS30lxiWF4=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f1e151\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0d7f 10d5 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 adfd 83aa 8cb7 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 3 c67d c62e d87b | 12 c62e (0) c67d (0) c34b (0) c034 (0)\n003 2 e59a ec08 | 3 ec08 (0) ec3e (0) e59a (0)\n004 2 ff06 fef2 | 2 ff06 (0) fef2 (0)\n005 1 f6f3 | 1 f6f3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f090 | 1 f090 (0)\n008 1 f16d | 1 f16d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","private_key":"acc2b5405b67970f8bd4ed395c8d529244748d6ac6a154cb9ff921ece215fb88","name":"node_f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","services":["streamer"],"enable_msg_events":true,"port":41401},"up":true}},{"node":{"info":{"id":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","name":"node_10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","enode":"enode://89a7090143be61d5f0802e125024559acf78c2f4425833355773894fb50f276b8fdda028da973cf879caedfc187dd1addcdf96518411c22acaa2481c2e286f0e@127.0.0.1:0","enr":"0xf88fb8406fe88139d195b80e137f45124e24df45a21c7cd29b132466d90f172da4a4bc3827089aa2a8a2e90d2dffe86715fe8fa4fcb3e92946b1d1ba13c05fced90ccdf10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10289a7090143be61d5f0802e125024559acf78c2f4425833355773894fb50f276b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ENV5UjrLrTDj5Q1hDw0ykfdRhIZ3PI2UBIVr8TSRKL8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 10d579\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 fef2 f1e1 | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 3 6049 7a5c 75bf | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 3 33fe 2293 27c2 | 6 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n003 3 0f03 0e8f 041c | 4 041c (0) 0e8f (0) 0f03 (0) 0d7f (0)\n============ DEPTH: 4 ==========================================\n004 2 1a93 1dd4 | 2 1a93 (0) 1dd4 (0)\n005 0 | 0\n006 1 12b8 | 1 12b8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","private_key":"aed9b1cd2e417b73e0eafef6d800fb05144bbd30fde59e856931febfceef38fa","name":"node_10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","services":["streamer"],"enable_msg_events":true,"port":36265},"up":true}},{"node":{"info":{"id":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","name":"node_fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","enode":"enode://336313478a56abfa3294828046976fbf1cb48cdea139aa491ca1cd88448e89b3740139f57abadcff5bc46002f2e491114ae0145b2dd38143675777c06d03ef60@127.0.0.1:0","enr":"0xf88fb840aa6cf0fb83fdcdc187e00d76cbbbcb8be6d3beceab21d139ad8b0e8380aafaa62f686200f97847175179cad675ea37ee3c5b6db44cd6241386602d8d410691ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102336313478a56abfa3294828046976fbf1cb48cdea139aa491ca1cd88448e89b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/vJ6NgQIF56v1RTfxxAW898IW8sug7vetfueXNGTVpY=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fef27a\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 75bf 7a5c 27c2 10d5 | 29 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n001 3 83aa 8934 8cb7 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 3 d165 c034 c05d | 12 d165 (0) de4f (0) dd48 (0) dbef (0)\n003 3 e59a ec3e ec08 | 3 ec08 (0) ec3e (0) e59a (0)\n============ DEPTH: 4 ==========================================\n004 4 f090 f1e1 f16d f6f3 | 4 f6f3 (0) f090 (0) f16d (0) f1e1 (0)\n005 0 | 0\n006 0 | 0\n007 1 ff06 | 1 ff06 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","private_key":"49a6d4a219bf4b1ad421bd6639b794b3f12fabb5f218155ca4722238da50e33f","name":"node_fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","services":["streamer"],"enable_msg_events":true,"port":45845},"up":true}},{"node":{"info":{"id":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","name":"node_c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","enode":"enode://611dae74107d3503af1ac4fa2d17a00533063b2247085dd393337640911e8c5ca30c1e485845c6dc12c408705af5ecfcfc593bb6503d859b9ddd51eb2b40fa71@127.0.0.1:0","enr":"0xf88fb8401cb70183d2bfd84ae541dc21ef3417ac61c4e11bc8d80f2adc3b475b1ea5011a7767542e90a84bd5e76da6acfe25c5d8b7c0236a7b7ff85fc81506fbe874e1b00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103611dae74107d3503af1ac4fa2d17a00533063b2247085dd393337640911e8c5c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wF2dkZnBsb+Er0uIabNpIDgvA1DVjdUQBwDNDSfxZas=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c05d9d\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 33fe 27c2 2293 | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 3 8934 83aa be5d | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 2 ec08 fef2 | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 d165 de4f | 5 d165 (0) de4f (0) dd48 (0) dbef (0)\n004 2 c851 ce82 | 2 ce82 (0) c851 (0)\n005 2 c67d c62e | 2 c62e (0) c67d (0)\n============ DEPTH: 6 ==========================================\n006 1 c34b | 1 c34b (0)\n007 0 | 0\n008 0 | 0\n009 1 c034 | 1 c034 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","private_key":"d8106f622a5e169381999bd3370e0a0ee143ac4bd5f679a957c78402600e345b","name":"node_c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","services":["streamer"],"enable_msg_events":true,"port":41355},"up":true}},{"node":{"info":{"id":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","name":"node_be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","enode":"enode://1461c352c31d8c7158d0bae6915d42f1353f1b5608ebca9ab6ef2bc08035155f3fb075962f54495806fe9b8cd85a22b42ac099cbf299571ff5e5ba91271a2f17@127.0.0.1:0","enr":"0xf88fb840a191693ed026822c26a8b3823cb888fc5e2607612bcfe9d4a6ee5ede28060aef2608c9121b792343c21884f298aa1dcff8431d0acf48205f66a6cd156b4089360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031461c352c31d8c7158d0bae6915d42f1353f1b5608ebca9ab6ef2bc08035155f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vl2g60vHbAyjpjQjVo2/ok04VJmUWwaDCKKHTtQkPrM=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be5da0\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 27c2 33fe 4e4e | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 3 ec3e ec08 c05d | 21 ec08 (0) ec3e (0) e59a (0) f090 (0)\n002 3 83aa 8934 8cb7 | 6 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n003 2 ab25 a259 | 4 a259 (0) ab25 (0) aeff (0) adfd (0)\n004 1 b269 | 1 b269 (0)\n============ DEPTH: 5 ==========================================\n005 1 bbbc | 1 bbbc (0)\n006 1 bc3e | 1 bc3e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","private_key":"9d95c4e61d120dc2c67a63e93da0b69a257ae7dd8ca30eda036335366d1508de","name":"node_be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","services":["streamer"],"enable_msg_events":true,"port":36717},"up":true}},{"node":{"info":{"id":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","name":"node_4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","enode":"enode://41e5ef400615590acfce1feaa4f723da88b7fee03c125e8feeb03201c364a22a14bfab06b86ce8c50bbf67843d5c300284b03c113f769c22ec8d0c0efa7bdb88@127.0.0.1:0","enr":"0xf88fb840d9ed9f340c2d0edc3d9f2fb6dc8cab0028f8ad74cb6931445c8752a95d3d1f0905c1ba22a04418eeb093a35bafd184eff3faa6fd110606e175e07ece0216c8930183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10241e5ef400615590acfce1feaa4f723da88b7fee03c125e8feeb03201c364a22a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Tk7V+Q3FOZ4zYtJpHLVYevhieuVCxSTi8qEpQouRqJs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4e4ed5\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e59a ec3e ec08 be5d | 35 ec08 (0) ec3e (0) e59a (0) f090 (0)\n001 3 27c2 33fe 0d7f | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 2 7a5c 75bf | 5 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n003 2 5bf6 5b93 | 4 5bf6 (0) 5b87 (0) 5b93 (0) 55a2 (0)\n============ DEPTH: 4 ==========================================\n004 4 46af 4541 4443 404b | 4 404b (0) 4443 (0) 4541 (0) 46af (0)\n005 1 4853 | 1 4853 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","private_key":"30dde001235a31362e50d4c106edd3ceaf6526ef026eca049fedc0a8fc0b96e1","name":"node_4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","services":["streamer"],"enable_msg_events":true,"port":42507},"up":true}},{"node":{"info":{"id":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","name":"node_0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","enode":"enode://91e81df107a4406cac255c8d4ba60fd18e5dcd96fd1cb877eb7024c046b695df3f48d299aeef695da5d4fea7069487cc20c4c48c1fd27528eb3f2f627b952342@127.0.0.1:0","enr":"0xf88fb8401644e0ac4bf24a23935aa075cfd9c4d6d785825325cbf7a21768c96abc96a92e5f47057330b9c09e916850fddfb4b3d689a4a0b98ba012c7b01e0123da1726900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10291e81df107a4406cac255c8d4ba60fd18e5dcd96fd1cb877eb7024c046b695df","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DX9KZirMctL+2ZnhOIDNEHDXu4aKku40OlLc+EzwY5U=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d7f4a\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 dd48 f16d f1e1 8cb7 | 35 f1e1 (0) f16d (0) f090 (0) f6f3 (0)\n001 3 55a2 4541 4e4e | 15 7a5c (0) 75bf (0) 6049 (0) 6271 (0)\n002 2 2b79 2293 | 6 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n003 2 1a93 12b8 | 4 10d5 (0) 12b8 (0) 1a93 (0) 1dd4 (0)\n004 1 041c | 1 041c (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 0e8f 0f03 | 2 0f03 (0) 0e8f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","private_key":"52ff6622d57b5556228f56e411af84d7d5e876ec0b0ef9a3910cf4dacf19295a","name":"node_0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","services":["streamer"],"enable_msg_events":true,"port":35159},"up":true}},{"node":{"info":{"id":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","name":"node_adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","enode":"enode://b05e0fa469e2a12f94369fc64122362af6019a567958df1faa114a1d2c667a835201b99b789eff01bddf4da25a4801ca96f3eaa056156808eeff5f4ecbd9cd36@127.0.0.1:0","enr":"0xf88fb840e775dd44d761e5b3b2c18b047cd086b5c5ca6dbba08ba0744c495cde6f289bf958930628ace3e04c30d4347c0ed18bcc9d021bcc5bfa395a05423d6042f5fe600183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b05e0fa469e2a12f94369fc64122362af6019a567958df1faa114a1d2c667a83","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rf0mQdjlet4ua4AsvrDAtzNkMKZ9HR86vFFStN8Ga5E=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: adfd26\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5b87 5bf6 0d7f | 29 5bf6 (0) 5b87 (0) 5b93 (0) 55a2 (0)\n001 2 f1e1 ff06 | 21 f1e1 (0) f16d (0) f090 (0) f6f3 (0)\n002 3 8934 83aa 9009 | 6 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n003 3 bbbc bc3e b269 | 4 b269 (0) bbbc (0) be5d (0) bc3e (0)\n004 1 a259 | 1 a259 (0)\n============ DEPTH: 5 ==========================================\n005 1 ab25 | 1 ab25 (0)\n006 1 aeff | 1 aeff (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","private_key":"0315f5fb99c9777433fed108cc4c6deb7db717796e405b5e6a3aa389299b87b4","name":"node_adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","services":["streamer"],"enable_msg_events":true,"port":35001},"up":true}},{"node":{"info":{"id":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","name":"node_9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","enode":"enode://093522f714ffd69ed9f6db15bb1cde0bc555925225a9e372b375bd301de6cb9d950b7b8c0b78c4de65bbeee2cd2ac0dcb1901f0bc3de835e1a24d76ca813c2ae@127.0.0.1:0","enr":"0xf88fb840c1c3fa0a54f8946b866c65b93538aac7322c9d5b26aff75c0dd8033fde1dde1627786a0478d2407b93c96f661b093b4a13d1aa4b5bd03a067492d76988b6a6800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102093522f714ffd69ed9f6db15bb1cde0bc555925225a9e372b375bd301de6cb9d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kAnO8yucxC6XuBK6OjW5d9pdNzmQu5UhpRbflGZAHV0=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9009ce\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 27c2 33fe 62c0 | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 3 ce82 de4f ff06 | 21 d165 (0) de4f (0) dd48 (0) dbef (0)\n002 2 bc3e adfd | 8 b269 (0) bbbc (0) be5d (0) bc3e (0)\n003 3 83aa 8934 8cb7 | 3 83aa (0) 8934 (0) 8cb7 (0)\n============ DEPTH: 4 ==========================================\n004 1 9861 | 1 9861 (0)\n005 1 9637 | 1 9637 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","private_key":"1bc6fe30378e57ca0c15b6f6f5f2d74ba8cdafbe43f76592ab80c52dc0f52728","name":"node_9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","services":["streamer"],"enable_msg_events":true,"port":35487},"up":true}},{"node":{"info":{"id":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","name":"node_62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","enode":"enode://c81f541ba227667d8becb3345c579943bfbb3a8bcd62b439cb005efda334f6c8c1d6d2af9fa49dad450a5875a0646b9a04f7083c19087bd7c433ab3db9094628@127.0.0.1:0","enr":"0xf88fb8403f4920feda458e968679a926fd71a565a684927ea66ae2650f2db9bd6c6ee43e1fc9cd1d73b370ecd2ba7c6b42518f316edc250d1e926c34b391d1b6480cdb330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c81f541ba227667d8becb3345c579943bfbb3a8bcd62b439cb005efda334f6c8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YsCWkN1xeE4GtDjXxWJW4Ql8Bf5+uDuQ/lsCd6S4hWg=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 62c096\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 de4f dbef c34b e59a | 35 d165 (0) de4f (0) dd48 (0) dbef (0)\n001 6 0f03 041c 12b8 1a93 | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 7 4853 404b 4443 4541 | 10 5b87 (0) 5b93 (0) 5bf6 (0) 55a2 (0)\n003 2 75bf 7a5c | 2 7a5c (0) 75bf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 6049 | 1 6049 (0)\n007 0 | 0\n008 1 6271 | 1 6271 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","private_key":"269dd3ac6136b86cb9f66421970333cf6b067b5e2ad659c74a12a454391a781b","name":"node_62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","services":["streamer"],"enable_msg_events":true,"port":43131},"up":true}},{"node":{"info":{"id":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","name":"node_e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","enode":"enode://f5fe3b4e018db5568948b9ef30185053e250d458a82b652689af29835dd52c49183ff839f32d445eb8106cc99df2f214878755161589f635c59336b92e24fdad@127.0.0.1:0","enr":"0xf88fb840a740cd0c6245b675fe0d492a0d4d735796337ec26f5662c4f9da84de9e48a03f5558dc622db428dea3a93145610b4c70871ada7d76383a1148c2343ac86a40bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f5fe3b4e018db5568948b9ef30185053e250d458a82b652689af29835dd52c49","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5Zp0tlcJzZ521NUx0HioowVQYe3cTVFa/7/A+ZyuIqw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e59a74\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1dd4 4e4e 6049 62c0 | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 4 a259 83aa 8934 8cb7 | 14 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n002 5 c62e c851 ce82 de4f | 12 d165 (0) dbef (0) d87b (0) de4f (0)\n003 4 fef2 f16d f1e1 f090 | 6 f090 (0) f1e1 (0) f16d (0) f6f3 (0)\n============ DEPTH: 4 ==========================================\n004 2 ec3e ec08 | 2 ec08 (0) ec3e (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","private_key":"6e4dcbf79fca1a42fc07f76fb66b645ff15ad89bf3b5ee627bc4294089d2770b","name":"node_e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","services":["streamer"],"enable_msg_events":true,"port":41179},"up":true}},{"node":{"info":{"id":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","name":"node_1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","enode":"enode://091c7d3991885b5205a7ad94190d2c5ca8169b7a2b7cee4fd6892d2dbe13ae3471441239ab4accb7bcd14852193c18d5617b8862678cc87887b11e6d41649b11@127.0.0.1:0","enr":"0xf88fb840c63763385c1eda51cd29a392364bf9f8be18399e4f9607b47bab1b59152f0587723422ca8629675ecacc5ffa0aeb859c37e02ffc2af0369b0979891a56d18e5d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103091c7d3991885b5205a7ad94190d2c5ca8169b7a2b7cee4fd6892d2dbe13ae34","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HdTCyNrGRlJrGv0YfzJnEtp17Xpxdmi/yJx3A6lk1IA=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1dd4c2\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8934 83aa c851 e59a | 35 83aa (0) 8934 (0) 8cb7 (0) 9861 (0)\n001 3 5b87 5b93 75bf | 15 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n002 4 2f1a 2293 27c2 33fe | 6 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n003 3 041c 0f03 0e8f | 4 041c (0) 0d7f (0) 0f03 (0) 0e8f (0)\n============ DEPTH: 4 ==========================================\n004 2 10d5 12b8 | 2 12b8 (0) 10d5 (0)\n005 1 1a93 | 1 1a93 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","private_key":"15434ad1577984b2ae25fc53d127261f8a1d1b643edf1cfe7f49714a1ed8619b","name":"node_1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","services":["streamer"],"enable_msg_events":true,"port":46023},"up":true}},{"node":{"info":{"id":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","name":"node_75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","enode":"enode://5196fd22b79e08c920e19716c9cf53c83634acda9a39d03f9e09e1241417eb955553103a82a5e58351a4696f61b7910bb9ce0e40105fef8f988d891d2b37b63d@127.0.0.1:0","enr":"0xf88fb840924cb202bf2e42bbe4204422d11630c955bb55e1c35949af2ab69a72a890f7c00a9429df6f78ec5295745029133eccea9fdd9c81b7ff637c884cd01bc527398b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035196fd22b79e08c920e19716c9cf53c83634acda9a39d03f9e09e1241417eb95","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"db+IG2rL9RLyq89C5dhqwy5d2EnnpBbjknWXmitr9Do=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 75bf88\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f16d fef2 ec3e c34b | 35 e59a (0) ec08 (0) ec3e (0) f090 (0)\n001 3 2293 10d5 1dd4 | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 3 4e4e 5bf6 5b87 | 10 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n============ DEPTH: 3 ==========================================\n003 3 6049 62c0 6271 | 3 6271 (0) 62c0 (0) 6049 (0)\n004 1 7a5c | 1 7a5c (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","private_key":"1d04f36e8b1b0b6d54f6361f0951803d47e9635eca0750c712509153f7ecf942","name":"node_75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","services":["streamer"],"enable_msg_events":true,"port":35973},"up":true}},{"node":{"info":{"id":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","name":"node_a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","enode":"enode://a475a32447cded8bbb47d0d8fe2373bdd01422752a81c31c2845b8f630c501c57e5e1df81ac50100e84cc9c7c29c7a5217d80933bb076ae900c4e9b39b8d3192@127.0.0.1:0","enr":"0xf88fb840c305671d9a97ae99f8a21d0af8cb920e8343e1157f891978be2c6593c9ccd2b606f3d350e8f146686ba9e55de1988b02886a36cb7782c11fbed93a7a1987a3ff0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a475a32447cded8bbb47d0d8fe2373bdd01422752a81c31c2845b8f630c501c5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"olkE+YxzoJo3A09XnYZBP+Mf2aBSoD10Jmdg1OpzuOk=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a25904\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6049 75bf | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 4 ec3e ec08 e59a f6f3 | 21 e59a (0) ec08 (0) ec3e (0) f090 (0)\n002 2 9637 9861 | 6 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n003 3 b269 bbbc be5d | 4 b269 (0) bbbc (0) be5d (0) bc3e (0)\n============ DEPTH: 4 ==========================================\n004 3 ab25 aeff adfd | 3 ab25 (0) aeff (0) adfd (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","private_key":"9c19a3fae05635da15fc8499e2d30b15ab154d5aebd6e911ffe18c8b9bdf7e06","name":"node_a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","services":["streamer"],"enable_msg_events":true,"port":37579},"up":true}},{"node":{"info":{"id":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","name":"node_604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","enode":"enode://f7775a8758c3725f763c0806ba1d52f74e6b312de69eaf6ed8cc0c7a88625c53e47053e304eb9b567843da94010ca4447b98699a541ba1425f0aa147e444b86e@127.0.0.1:0","enr":"0xf88fb8403f292e1bf244a35875921965cd6bb6dd93bb0241082ee3ebf32a0ed161c646941d2ff14e735c34f9cda2916a1e96e9f80b22d2c60195d45433c614157e330c900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f7775a8758c3725f763c0806ba1d52f74e6b312de69eaf6ed8cc0c7a88625c53","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YEli8AZKyWEqGbRZlk9y2ifFR8cKW/Evuf8++cBsWkE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 604962\npopulation: 27 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 c034 d87b de4f ec3e | 35 e59a (0) ec08 (0) ec3e (0) f090 (0)\n001 7 1a93 10d5 12b8 0f03 | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 6 5b93 5bf6 4853 404b | 10 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n003 2 75bf 7a5c | 2 7a5c (0) 75bf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 62c0 6271 | 2 6271 (0) 62c0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","private_key":"d43fc183927a1d97aee7b09b4977f66657a79a7132440f1085e72dac4f111b29","name":"node_604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","services":["streamer"],"enable_msg_events":true,"port":36711},"up":true}},{"node":{"info":{"id":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","name":"node_46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","enode":"enode://51afc950250580c6016fe6e1cc591b90a31257d89b57df0cee54184ed0fe09c1e5777398b9ea7cbf355e475dff29a8a57cf7af461f2544f09595281730b0421b@127.0.0.1:0","enr":"0xf88fb840c55fc03f59e481c9056bb420d743110b252edb232b677c6eded69cb1f9de070f214517d43e7bd121063ff69d83b53ef77f2cb60ea36ee3fd501c4ce5f941c5d00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10351afc950250580c6016fe6e1cc591b90a31257d89b57df0cee54184ed0fe09c1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rq+9e3Hp9VeBNe9Xxumvrx7ekUJf1YB9ayV+R/k9gwo=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 46afbd\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bbbc b269 c67d | 35 b269 (0) bbbc (0) be5d (0) bc3e (0)\n001 3 2293 27c2 33fe | 14 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n002 2 7a5c 6049 | 5 7a5c (0) 75bf (0) 6271 (0) 62c0 (0)\n003 2 5b93 5b87 | 4 5b93 (0) 5b87 (0) 5bf6 (0) 55a2 (0)\n004 2 4e4e 4853 | 2 4853 (0) 4e4e (0)\n005 1 404b | 1 404b (0)\n============ DEPTH: 6 ==========================================\n006 2 4443 4541 | 2 4541 (0) 4443 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","private_key":"c83d6d9cc57a48d84d57d3c6bb8bea3f077d62d280265de50dcd32e06d248f03","name":"node_46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","services":["streamer"],"enable_msg_events":true,"port":34261},"up":true}},{"node":{"info":{"id":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","name":"node_c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","enode":"enode://9f5e3ba7425458e07339268d779ab9edafb03e2b1b67169a1123d0c6082374c60f34ef62398c7fff491e9a586e010737c16cc6fee1c969b773e5d9036bb2d2d5@127.0.0.1:0","enr":"0xf88fb840331107dbd5f067ec688710841e8f2feb84a5139e0b4b8b5fc9e775a99353e7c160a1dfa9939df3d039103b453a571a574a36f7ba55ed3f64ea23917b4f1d48570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039f5e3ba7425458e07339268d779ab9edafb03e2b1b67169a1123d0c6082374c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xn2ygvie5cf+M8zrbWBmcsBPJz+SR0ePMjyCJ/cJty0=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c67db2\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 27c2 33fe 46af | 29 33fe (0) 27c2 (0) 2293 (0) 2f1a (0)\n001 2 b269 8cb7 | 14 b269 (0) bbbc (0) be5d (0) bc3e (0)\n002 3 ec08 f1e1 f6f3 | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 d165 dbef | 5 d165 (0) dbef (0) d87b (0) de4f (0)\n004 2 ce82 c851 | 2 c851 (0) ce82 (0)\n============ DEPTH: 5 ==========================================\n005 3 c05d c034 c34b | 3 c34b (0) c034 (0) c05d (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 c62e | 1 c62e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","private_key":"c5f0dbfaf1bc89108010b5a6b4fdd44434a9c6f91328d5eadbbfa0108072ccb8","name":"node_c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","services":["streamer"],"enable_msg_events":true,"port":36251},"up":true}},{"node":{"info":{"id":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","name":"node_8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","enode":"enode://de0a8da74b3df44a50a35257ac834a3fe752fa615fb7d9b39d2c716b9b5f7edc32874d826d50224f2e37fb1a07f7526070f08674414124367465abf02cbf5ff4@127.0.0.1:0","enr":"0xf88fb840189409bc37dbd9a8810613dce78f7b24e5c24579fe5ede271045352b0a50969802f6e75f3b631cb61f415fbb4a7a68e994cb620ba81be2ece91909c5f01e673f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102de0a8da74b3df44a50a35257ac834a3fe752fa615fb7d9b39d2c716b9b5f7edc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jLfaTvIVjQfCIsDwjex/m1gDdiP0ZYJLQRmp8lsxoAU=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8cb7da\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5b87 041c 0d7f 0e8f | 29 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n001 9 e59a fef2 f1e1 c851 | 21 ec08 (0) ec3e (0) e59a (0) f090 (0)\n002 2 ab25 be5d | 8 b269 (0) bbbc (0) be5d (0) bc3e (0)\n003 3 9861 9637 9009 | 3 9861 (0) 9637 (0) 9009 (0)\n============ DEPTH: 4 ==========================================\n004 1 83aa | 1 83aa (0)\n005 1 8934 | 1 8934 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","private_key":"6cb4589e98325b9101a5f706969483cdb93fe451d2fe83dcbec1e6fde1986836","name":"node_8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","services":["streamer"],"enable_msg_events":true,"port":38013},"up":true}},{"node":{"info":{"id":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","name":"node_dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","enode":"enode://89555a99503427e59874c6cfce334350add1c85b4b935dad096d2755bb8bda4223becd8f73fc3bda4dc5239d7407dac529cf3f943d1129f29af26dc8c10b04d9@127.0.0.1:0","enr":"0xf88fb8402389226733f4287a4f18cdd6b9ca854dded27d7f7c9cdf1fe5f0ff2b60a3e75a1ea809d39554ccd2b2c97c0b8cff5ea61d51f91c69e821da8b45ed186c4833570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10389555a99503427e59874c6cfce334350add1c85b4b935dad096d2755bb8bda42","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3UgRJxAH+QtkpRt1ivx+vIxa8wbLahuIzNwsyI/ZaEs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dd4811\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0d7f 041c 2b80 | 29 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n001 3 aeff ab25 8cb7 | 14 ab25 (0) aeff (0) adfd (0) a259 (0)\n002 3 ec3e ec08 f6f3 | 9 ec08 (0) ec3e (0) e59a (0) f090 (0)\n003 2 ce82 c851 | 7 c851 (0) ce82 (0) c34b (0) c034 (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 d87b dbef | 2 dbef (0) d87b (0)\n006 1 de4f | 1 de4f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","private_key":"4a8e7f4ee986a36520c7faff2f4957ba20b7db18fd59de5604f3889db1eb8dd9","name":"node_dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","services":["streamer"],"enable_msg_events":true,"port":33135},"up":true}},{"node":{"info":{"id":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","name":"node_2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","enode":"enode://f6640b5930abb9a111010f89da0b40002e956167f60a2bd769b53430ab64bdce724abbd610813dc99a92fbe4e15cc33c164bb6ae05e965490ebd84c5cfecf306@127.0.0.1:0","enr":"0xf88fb840f9d875b3913769d2201f5c0a0b1dddddb9416184e14f986671f98b799fb7bc7c3b1853a972ca0dce95c27a7f6195e3f8fd87da8e9708d9ce4b224e940a2d319b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f6640b5930abb9a111010f89da0b40002e956167f60a2bd769b53430ab64bdce","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"K4BPbSojVEHPC1tSp/sqqGLIRRDtSC8KWuySxNiatIQ=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2b804f\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9637 9861 dd48 | 35 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n001 3 4443 5bf6 55a2 | 15 6049 (0) 6271 (0) 62c0 (0) 7a5c (0)\n002 2 041c 0f03 | 8 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n003 1 33fe | 1 33fe (0)\n004 2 2293 27c2 | 2 27c2 (0) 2293 (0)\n============ DEPTH: 5 ==========================================\n005 1 2f1a | 1 2f1a (0)\n006 0 | 0\n007 0 | 0\n008 1 2b79 | 1 2b79 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","private_key":"482d8c479e055a2cd97d27a00578bfbe177ae0ca405f9b3a2a08e55ad11f0da8","name":"node_2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","services":["streamer"],"enable_msg_events":true,"port":42125},"up":true}},{"node":{"info":{"id":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","name":"node_55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","enode":"enode://0e1f60835d710b5bce7825c96b4002cfe63ef0308ad175b5e4e4bcf6fbf5187d01c5b296ce5a87affae58239bbbd0d8bbd425a558e2d5eee41d6cddbea15b939@127.0.0.1:0","enr":"0xf88fb84058ce2d6dde0e4febc7e1b9b68901a2399228ed0dc3972db83041f6511414997e295b9340c70b1cb50884a5dd3f193a346b3aac3f8d2d860c2ef0066ad6315cbe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030e1f60835d710b5bce7825c96b4002cfe63ef0308ad175b5e4e4bcf6fbf5187d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VaJDtL33j/JGBTPFIWILEbTOqmejyWdg4qn6zGcn9Q8=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 55a243\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9637 9861 ce82 | 35 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n001 3 0d7f 041c 2b80 | 14 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n002 2 6271 62c0 | 5 6049 (0) 62c0 (0) 6271 (0) 7a5c (0)\n003 4 4853 404b 4541 4443 | 6 46af (0) 4541 (0) 4443 (0) 404b (0)\n============ DEPTH: 4 ==========================================\n004 3 5b87 5b93 5bf6 | 3 5b87 (0) 5b93 (0) 5bf6 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","private_key":"22bc669edb33e88cc2edf332fe24eeb77672294a38ee9ad3fa4a1cc3a2b6c916","name":"node_55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","services":["streamer"],"enable_msg_events":true,"port":35969},"up":true}},{"node":{"info":{"id":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","name":"node_ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","enode":"enode://a7e3b7f8243c44f711eaa63305c75e94cc5c280f85bba57a8153591777c08edd2c46d54768f3e3be5682ceb74a4b7d51c3404faadcead2f9abf0fca9e08496d9@127.0.0.1:0","enr":"0xf88fb84089be519b3e126e4daefeb96ab3a6fad77d8957bcec90ad01848bdae2a1158d7b0625a8ca5453dbac3b83c87abe19b7ee6d9db1a0a469dd9455c871eddc751eef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a7e3b7f8243c44f711eaa63305c75e94cc5c280f85bba57a8153591777c08edd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zoK5gFv6We8/GLRtXi2MRRPhM/hlAN+DtV4TMxrkKYw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ce82b9\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1a93 4443 4853 55a2 | 29 33fe (0) 2293 (0) 27c2 (0) 2f1a (0)\n001 5 aeff 83aa 9861 9009 | 14 9861 (0) 9637 (0) 9009 (0) 83aa (0)\n002 4 f16d e59a ec3e ec08 | 9 e59a (0) ec3e (0) ec08 (0) f090 (0)\n003 2 d165 dd48 | 5 d165 (0) dbef (0) d87b (0) de4f (0)\n============ DEPTH: 4 ==========================================\n004 5 c62e c67d c34b c034 | 5 c34b (0) c034 (0) c05d (0) c67d (0)\n005 1 c851 | 1 c851 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","private_key":"755137d90f904038ad62a2a3a4c884831de662050430fc5bc44c0e776122f890","name":"node_ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","services":["streamer"],"enable_msg_events":true,"port":34417},"up":true}},{"node":{"info":{"id":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","name":"node_1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","enode":"enode://6441a0fb862b2ad19dca82baf54880795e459ccb977d3dec2f5945041080887d4e18924c1f76a70f0cc6aa5e516d4bff2813cba7fd94f9f5990af5d7ba081ba2@127.0.0.1:0","enr":"0xf88fb84089526e1437560f8885e8dec6fdcb7f89033526e82f59e94698507fa850c9e19a3fb9333403aa92eb996e936774dcf266d18fc8c2210f28637ab27102e7f5d0390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026441a0fb862b2ad19dca82baf54880795e459ccb977d3dec2f5945041080887d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GpMQvGFQXQjEWOq6DnzRtcHnpk4A/LogNNoaF6L6oVw=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1a9310\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 bc3e d165 c851 ce82 | 35 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n001 3 6049 6271 62c0 | 15 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n002 3 2f1a 2293 33fe | 6 33fe (0) 2293 (0) 27c2 (0) 2f1a (0)\n003 4 041c 0e8f 0f03 0d7f | 4 041c (0) 0d7f (0) 0e8f (0) 0f03 (0)\n============ DEPTH: 4 ==========================================\n004 2 10d5 12b8 | 2 12b8 (0) 10d5 (0)\n005 1 1dd4 | 1 1dd4 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","private_key":"3d1bc8c36e5611d1524cba438ab612087f7fe9210a0ddb9f80b7bb94bebf28d0","name":"node_1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","services":["streamer"],"enable_msg_events":true,"port":38755},"up":true}},{"node":{"info":{"id":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","name":"node_bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","enode":"enode://c8fb04e5496759ed67612814155cdc9e564c33e6151e1328db3e3d733ef3be481febd2026453482338b6cf323c0293a196cc120abffb4ee215877ecce683dcea@127.0.0.1:0","enr":"0xf88fb8409592035288ec2ea45833c8d7fcd2795780db3698a74d8f87077300514fcd2205330b0bab53a6dfebdf54779337d6761e4bf024cc5038e4dd4a9f7941eb7d19570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c8fb04e5496759ed67612814155cdc9e564c33e6151e1328db3e3d733ef3be48","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vD4H7gmLrdc5xOm5ZSdfb79jMfdraSCJYErEQCXPC8w=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bc3e07\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6049 5b93 1a93 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 3 ec08 c034 de4f | 21 e59a (0) ec3e (0) ec08 (0) f1e1 (0)\n002 2 83aa 9009 | 6 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n003 2 ab25 adfd | 4 aeff (0) adfd (0) ab25 (0) a259 (0)\n004 1 b269 | 1 b269 (0)\n============ DEPTH: 5 ==========================================\n005 1 bbbc | 1 bbbc (0)\n006 1 be5d | 1 be5d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","private_key":"aedc9b1c86a50c21ebc168086896d03dc0ff1d2d366426a35678be1bb1f8cd46","name":"node_bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","services":["streamer"],"enable_msg_events":true,"port":38905},"up":true}},{"node":{"info":{"id":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","name":"node_de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","enode":"enode://9f62e657f5258fdc9d473a088077877e003e1ad5e336214b8517cafa34581a7b83eeb731bdaeaee23b09a1739c0c1cbfc75fd0715b014baf301c3ce66dea9210@127.0.0.1:0","enr":"0xf88fb8403b3bfb23ac7a5fe81b2cac041477fe3f148ec11dce658a17042c6be5047af9766810b4b7d33d10350eef6ae57c979f6400cdb549c72f79b6d1938b73ed206c5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029f62e657f5258fdc9d473a088077877e003e1ad5e336214b8517cafa34581a7b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3k8Wi3tnDBNI2AHbcNmp5/pE3XKQMLpcBd+WI5Z8QLE=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: de4f16\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6049 6271 62c0 | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 2 9009 bc3e | 14 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n002 3 ec3e e59a ff06 | 9 e59a (0) ec3e (0) ec08 (0) f1e1 (0)\n003 2 c034 c05d | 7 ce82 (0) c851 (0) c34b (0) c034 (0)\n004 1 d165 | 1 d165 (0)\n============ DEPTH: 5 ==========================================\n005 2 d87b dbef | 2 d87b (0) dbef (0)\n006 1 dd48 | 1 dd48 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","private_key":"56f97537df39cd2e28da49629a002972b36e5ac32df3a117fa710b9cabe52aa8","name":"node_de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","services":["streamer"],"enable_msg_events":true,"port":46139},"up":true}},{"node":{"info":{"id":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","name":"node_ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","enode":"enode://cb17dde808303f1bbd012517614e105867070959f82e17c94a6af3d5ac085fb14656af8db156f67f5f64480d8221e11c6f8b172b785e6e9c57848833f437b8d8@127.0.0.1:0","enr":"0xf88fb840d2fed0376fa9577d9adabbeb81ace57c4cbf4073222b71a010f99d6b9c4228fc2ad8ec5bcefbfce0225b7f05d0e59e4b02c99cec57387ef602959f4b90d9ed820183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cb17dde808303f1bbd012517614e105867070959f82e17c94a6af3d5ac085fb1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/wbWzDUh0gwKm813nIcvV2AjyOqvrXKJhkFAsxOlxHs=","hive":"\n=========================================================================\nThu Feb 28 18:02:46 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ff06d6\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 404b 27c2 33fe | 29 6049 (0) 62c0 (0) 6271 (0) 75bf (0)\n001 2 9009 adfd | 14 9861 (0) 9009 (0) 9637 (0) 83aa (0)\n002 3 c034 d165 de4f | 12 ce82 (0) c851 (0) c34b (0) c05d (0)\n003 2 ec3e ec08 | 3 e59a (0) ec3e (0) ec08 (0)\n============ DEPTH: 4 ==========================================\n004 4 f6f3 f090 f1e1 f16d | 4 f1e1 (0) f16d (0) f090 (0) f6f3 (0)\n005 0 | 0\n006 0 | 0\n007 1 fef2 | 1 fef2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","private_key":"a519551fcbce37d32e6dbc7b4489172d0fb096ebd57e6ee332422c809ae61862","name":"node_ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","services":["streamer"],"enable_msg_events":true,"port":45295},"up":true}}],"conns":[{"one":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","other":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","other":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"9637fa5ec80bd404a366fe86f7a89a573529833097c130114b3015754886545d","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","up":true},{"one":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","up":true},{"one":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"12b8769e0e996011ceff489a3f56ba8e555d545b69accb5b4396dead7335a8db","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","other":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"a25904f98c73a09a37034f579d86413fe31fd9a052a03d74266760d4ea73b8e9","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"9861d7cab15fd77ce544aa046f9daf61af7f7c78da7f84c9d3bc1c19f9f2e071","up":true},{"one":"2b790fbca8da74c7de9715b4919ce03cdcf14a4608671cd4739b2b99a052e636","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"10d579523acbad30e3e50d610f0d3291f7518486773c8d9404856bf1349128bf","other":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"bbbccc0180fe2605be748daeabb1fc02e6c8870b37f371359f38ee114f09771f","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"041c4a3f942536e67af087da305403e26a19e030dcf51473a597431753a2bec2","other":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","up":true},{"one":"2b804f6d2a235441cf0b5b52a7fb2aa862c84510ed482f0a5aec92c4d89ab484","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"9009cef32b9cc42e97b812ba3a35b977da5d373990bb9521a516df9466401d5d","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","other":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","other":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ff06d6cc3521d20c0a9bcd779c872f576023c8eaafad7289864140b313a5c47b","other":"f6f318e25a24c449e727c60c610719aaa36d0baf826a3a4931ad684abf9bcbba","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"0e8fb3e25746a7f18f33e31c10200e5ec21eb54ad592bad5369b9b584fe80e1b","other":"5b87478ce6f96988d572d249140ca6716f66aec8f6e0435e7f8be9fca5ed38a0","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"75bf881b6acbf512f2abcf42e5d86ac32e5dd849e7a416e39275979a2b6bf43a","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"627105957aa0b587a9ba1b0f273fc19403b6955940e794a359ade89cd7d40dfb","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"0f03a5bb51c3f599469cfe9e5da0a10b8d06ba501a89e180077a75f1c5971467","other":"1a9310bc61505d08c458eaba0e7cd1b5c1e7a64e00fcba2034da1a17a2faa15c","up":true},{"one":"f090d909f94f6970d074948115e4f46e67e4fb5735f537889ed2b169ff2bd368","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"0d7f4a662acc72d2fed999e13880cd1070d7bb868a92ee343a52dcf84cf06395","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"b2697a3f2de6ea0d13586a655463782509691d6f05d90f45fd08823e7eaf5a0b","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"aeff88a5c749733707f99b876c1ecf7db71b32a6916cf9bbd266af3e69f94e82","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"45411a7482cae50dd1dd8d90138a28c0dc61b04baa9592f927f9d415b0970a53","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"33fe6d6970690e8d9e2b08ff234cb1eaf336baa53b398511cd078dcce2c8b2da","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","other":"dbefd322e4f37f3e142ad151a08c8bd7784fb0db249324aff479f5b663212e76","up":true},{"one":"f1e151beef0c2259669ac950125aa004b02ba7078bf2d87248a4b7d25c62585e","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"2f1a15c39bcb0e953f8c160933f69e3dda29b834575742c4f432eb384c5dd9df","other":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","up":true},{"one":"27c236583dff714a3000acafbfd3308566c81271f825eac8f4f0cff83a7ff127","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"dd4811271007f90b64a51b758afc7ebc8c5af306cb6a1b88ccdc2cc88fd9684b","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","other":"c8511f8896d3c4226d5d8c860096c6a90839fce500a77b8304395f5b4833b284","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"4e4ed5f90dc5399e3362d2691cb5587af8627ae542c524e2f2a129428b91a89b","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","other":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","up":true},{"one":"62c09690dd71784e06b438d7c56256e1097c05fe7eb83b90fe5b0277a4b88568","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","other":"c67db282f89ee5c7fe33cceb6d606672c04f273f9247478f323c8227f709b72d","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"55a243b4bdf78ff2460533c521620b11b4ceaa67a3c96760e2a9facc6727f50f","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"8cb7da4ef2158d07c222c0f08dec7f9b58037623f465824b4119a9f25b31a005","up":true},{"one":"1dd4c2c8dac646526b1afd187f326712da75ed7a717668bfc89c7703a964d480","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"f16dc65b58a9fa5060674ca741531891fd44b63d9ac5eabea185745049e474ca","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"d87ba657576968058fcc86579c3f52aa78905909b0a943938af621c6ed99fbea","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","other":"2293b1e9fb44ee6db39db9366291fc0b4e286c355547750de19e96c32e02bdf9","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"83aad5b97e1ea8c40537e5593de4810c7b35fab156053402dda758d6e9ea9055","up":true},{"one":"c62e4b2302cd62f578c8c647adc3a4affef6df65a5236302865db85897efc015","other":"ce82b9805bfa59ef3f18b46d5e2d8c4513e133f86500df83b55e13331ae4298c","up":true},{"one":"604962f0064ac9612a19b459964f72da27c547c70a5bf12fb9ff3ef9c06c5a41","other":"5b936341da709d11b34b6df007f38fff0396b785a14f94653aaf921d8e450a3f","up":true},{"one":"48534a538fd708c0e616cbdfa948596048b7daa77ef09dd69c1652a5f6d05efc","other":"4443b3497092c9f200fe7d43c32a533f8fc9fa7129226e1e2c7fd5f7f27e1711","up":true},{"one":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","up":true},{"one":"ab255c40e39ba8fd2fb439ff26d135aab3944fb9159e54370f4fe735906d0313","other":"be5da0eb4bc76c0ca3a63423568dbfa24d385499945b068308a2874ed4243eb3","up":true},{"one":"404b70c6ac72972cfd9e7cf115c7f043bd15d0e4b9a959bfc2924c722eb712f7","other":"5bf6a2fe481412b1b20f0cc2325a1119fda9e34c4def3d1f4026a88dc0c992ac","up":true},{"one":"46afbd7b71e9f5578135ef57c6e9afaf1ede91425fd5807d6b257e47f93d830a","other":"7a5c44693de20adc3c53b1302fb00aab32a46265abc7563bdba33f7e5c4f9d74","up":true},{"one":"c34bd2e209fc11e27f81e1359545f28c816787127b41811dc1710fa4e53fcefa","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true},{"one":"e59a74b65709cd9e76d4d531d078a8a3055061eddc4d515affbfc0f99cae22ac","other":"fef27a360408179eafd514dfc71016f3df085bcb2e83bbdeb5fb9e5cd1935696","up":true},{"one":"8934ee6bbfc9c912a5a5fb004eb3df0b65313e22e8ceb8dc3f3e13d10853228f","other":"adfd2641d8e57ade2e6b802cbeb0c0b7336430a67d1d1f3abc5152b4df066b91","up":true},{"one":"bc3e07ee098badd739c4e9b965275f6fbf6331f76b692089604ac44025cf0bcc","other":"c0347196ec87f51f97229140b5d66015cfff2781cc1aff6d3e207c3fa3532732","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"ec085243645c6e5fdbeffb137ccd119053bd655e76b1d9a6b5e0221183764e43","up":true},{"one":"de4f168b7b670c1348d801db70d9a9e7fa44dd729030ba5c05df9623967c40b1","other":"ec3e84f80ab71df09a44c79c8d4af8da68fdf3dd7dbce7451363b8aa16630493","up":true},{"one":"c05d9d9199c1b1bf84af4b8869b36920382f0350d58dd5100700cd0d27f165ab","other":"d16513f30d485d3175321c1a0aa5a525c115ae13c395f7fa3deb1cf4d1ec69bc","up":true}]} \ No newline at end of file diff --git a/swarm/network_test.go b/swarm/network_test.go deleted file mode 100644 index 1a8c992a3a..0000000000 --- a/swarm/network_test.go +++ /dev/null @@ -1,562 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swarm - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - "math/rand" - "os" - "strings" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/sctx" - "github.com/ethereum/go-ethereum/swarm/testutil" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/mattn/go-colorable" -) - -var ( - loglevel = flag.Int("loglevel", 2, "verbosity of logs") - longrunning = flag.Bool("longrunning", false, "do run long-running tests") - waitKademlia = flag.Bool("waitkademlia", false, "wait for healthy kademlia before checking files availability") -) - -func init() { - rand.Seed(time.Now().UnixNano()) - - flag.Parse() - - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) -} - -// TestSwarmNetwork runs a series of test simulations with -// static and dynamic Swarm nodes in network simulation, by -// uploading files to every node and retrieving them. -func TestSwarmNetwork(t *testing.T) { - var tests = []testSwarmNetworkCase{ - { - name: "10_nodes", - steps: []testSwarmNetworkStep{ - { - nodeCount: 10, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 45 * time.Second, - }, - }, - { - name: "10_nodes_skip_check", - steps: []testSwarmNetworkStep{ - { - nodeCount: 10, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 45 * time.Second, - SkipCheck: true, - }, - }, - { - name: "dec_inc_node_count", - steps: []testSwarmNetworkStep{ - { - nodeCount: 3, - }, - { - nodeCount: 1, - }, - { - nodeCount: 5, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 90 * time.Second, - }, - }, - } - - if *longrunning { - tests = append(tests, longRunningCases()...) - } else if testutil.RaceEnabled { - tests = shortCaseForRace() - - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - testSwarmNetwork(t, tc.options, tc.steps...) - }) - } -} - -type testSwarmNetworkCase struct { - name string - steps []testSwarmNetworkStep - options *testSwarmNetworkOptions -} - -// testSwarmNetworkStep is the configuration -// for the state of the simulation network. -type testSwarmNetworkStep struct { - // number of swarm nodes that must be in the Up state - nodeCount int -} - -// testSwarmNetworkOptions contains optional parameters for running -// testSwarmNetwork. -type testSwarmNetworkOptions struct { - Timeout time.Duration - SkipCheck bool -} - -func longRunningCases() []testSwarmNetworkCase { - return []testSwarmNetworkCase{ - { - name: "50_nodes", - steps: []testSwarmNetworkStep{ - { - nodeCount: 50, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 3 * time.Minute, - }, - }, - { - name: "50_nodes_skip_check", - steps: []testSwarmNetworkStep{ - { - nodeCount: 50, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 3 * time.Minute, - SkipCheck: true, - }, - }, - { - name: "inc_node_count", - steps: []testSwarmNetworkStep{ - { - nodeCount: 2, - }, - { - nodeCount: 5, - }, - { - nodeCount: 10, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 90 * time.Second, - }, - }, - { - name: "dec_node_count", - steps: []testSwarmNetworkStep{ - { - nodeCount: 10, - }, - { - nodeCount: 6, - }, - { - nodeCount: 3, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 90 * time.Second, - }, - }, - { - name: "inc_dec_node_count", - steps: []testSwarmNetworkStep{ - { - nodeCount: 3, - }, - { - nodeCount: 5, - }, - { - nodeCount: 25, - }, - { - nodeCount: 10, - }, - { - nodeCount: 4, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 5 * time.Minute, - }, - }, - { - name: "inc_dec_node_count_skip_check", - steps: []testSwarmNetworkStep{ - { - nodeCount: 3, - }, - { - nodeCount: 5, - }, - { - nodeCount: 25, - }, - { - nodeCount: 10, - }, - { - nodeCount: 4, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 5 * time.Minute, - SkipCheck: true, - }, - }, - } -} - -func shortCaseForRace() []testSwarmNetworkCase { - // As for now, Travis with -race can only run 8 nodes - return []testSwarmNetworkCase{ - { - name: "8_nodes", - steps: []testSwarmNetworkStep{ - { - nodeCount: 8, - }, - }, - options: &testSwarmNetworkOptions{ - Timeout: 1 * time.Minute, - }, - }, - } -} - -// file represents the file uploaded on a particular node. -type file struct { - addr storage.Address - data string - nodeID enode.ID -} - -// check represents a reference to a file that is retrieved -// from a particular node. -type check struct { - key string - nodeID enode.ID -} - -// testSwarmNetwork is a helper function used for testing different -// static and dynamic Swarm network simulations. -// It is responsible for: -// - Setting up a Swarm network simulation, and updates the number of nodes within the network on every step according to steps. -// - Uploading a unique file to every node on every step. -// - May wait for Kademlia on every node to be healthy. -// - Checking if a file is retrievable from all nodes. -func testSwarmNetwork(t *testing.T, o *testSwarmNetworkOptions, steps ...testSwarmNetworkStep) { - t.Helper() - - if o == nil { - o = new(testSwarmNetworkOptions) - } - - sim := simulation.New(map[string]simulation.ServiceFunc{ - "swarm": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { - config := api.NewConfig() - - dir, err := ioutil.TempDir("", "swarm-network-test-node") - if err != nil { - return nil, nil, err - } - cleanup = func() { - err := os.RemoveAll(dir) - if err != nil { - log.Error("cleaning up swarm temp dir", "err", err) - } - } - - config.Path = dir - - privkey, err := crypto.GenerateKey() - if err != nil { - return nil, cleanup, err - } - nodekey, err := crypto.GenerateKey() - if err != nil { - return nil, cleanup, err - } - - config.Init(privkey, nodekey) - config.DeliverySkipCheck = o.SkipCheck - config.Port = "" - - swarm, err := NewSwarm(config, nil) - if err != nil { - return nil, cleanup, err - } - bucket.Store(simulation.BucketKeyKademlia, swarm.bzz.Hive.Kademlia) - log.Info("new swarm", "bzzKey", config.BzzKey, "baseAddr", fmt.Sprintf("%x", swarm.bzz.BaseAddr())) - return swarm, cleanup, nil - }, - }) - defer sim.Close() - - ctx := context.Background() - if o.Timeout > 0 { - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, o.Timeout) - defer cancel() - } - - files := make([]file, 0) - - for i, step := range steps { - log.Debug("test sync step", "n", i+1, "nodes", step.nodeCount) - - change := step.nodeCount - len(sim.UpNodeIDs()) - - if change > 0 { - _, err := sim.AddNodesAndConnectChain(change) - if err != nil { - t.Fatal(err) - } - } else if change < 0 { - _, err := sim.StopRandomNodes(-change) - if err != nil { - t.Fatal(err) - } - } else { - t.Logf("step %v: no change in nodes", i) - continue - } - - var checkStatusM sync.Map - var nodeStatusM sync.Map - var totalFoundCount uint64 - - result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { - nodeIDs := sim.UpNodeIDs() - rand.Shuffle(len(nodeIDs), func(i, j int) { - nodeIDs[i], nodeIDs[j] = nodeIDs[j], nodeIDs[i] - }) - for _, id := range nodeIDs { - key, data, err := uploadFile(sim.Service("swarm", id).(*Swarm)) - if err != nil { - return err - } - log.Trace("file uploaded", "node", id, "key", key.String()) - files = append(files, file{ - addr: key, - data: data, - nodeID: id, - }) - } - - if *waitKademlia { - if _, err := sim.WaitTillHealthy(ctx); err != nil { - return err - } - } - - // File retrieval check is repeated until all uploaded files are retrieved from all nodes - // or until the timeout is reached. - for { - if retrieve(sim, files, &checkStatusM, &nodeStatusM, &totalFoundCount) == 0 { - return nil - } - } - }) - - if result.Error != nil { - t.Fatal(result.Error) - } - log.Debug("done: test sync step", "n", i+1, "nodes", step.nodeCount) - } -} - -// uploadFile, uploads a short file to the swarm instance -// using the api.Put method. -func uploadFile(swarm *Swarm) (storage.Address, string, error) { - b := make([]byte, 8) - _, err := rand.Read(b) - if err != nil { - return nil, "", err - } - // File data is very short, but it is ensured that its - // uniqueness is very certain. - data := fmt.Sprintf("test content %s %x", time.Now().Round(0), b) - ctx := context.TODO() - k, wait, err := putString(ctx, swarm.api, data, "text/plain", false) - if err != nil { - return nil, "", err - } - if wait != nil { - err = wait(ctx) - } - return k, data, err -} - -// retrieve is the function that is used for checking the availability of -// uploaded files in testSwarmNetwork test helper function. -func retrieve( - sim *simulation.Simulation, - files []file, - checkStatusM *sync.Map, - nodeStatusM *sync.Map, - totalFoundCount *uint64, -) (missing uint64) { - rand.Shuffle(len(files), func(i, j int) { - files[i], files[j] = files[j], files[i] - }) - - var totalWg sync.WaitGroup - errc := make(chan error) - - nodeIDs := sim.UpNodeIDs() - - totalCheckCount := len(nodeIDs) * len(files) - - for _, id := range nodeIDs { - if _, ok := nodeStatusM.Load(id); ok { - continue - } - start := time.Now() - var checkCount uint64 - var foundCount uint64 - - totalWg.Add(1) - - var wg sync.WaitGroup - - swarm := sim.Service("swarm", id).(*Swarm) - for _, f := range files { - - checkKey := check{ - key: f.addr.String(), - nodeID: id, - } - if n, ok := checkStatusM.Load(checkKey); ok && n.(int) == 0 { - continue - } - - checkCount++ - wg.Add(1) - go func(f file, id enode.ID) { - defer wg.Done() - - log.Debug("api get: check file", "node", id.String(), "key", f.addr.String(), "total files found", atomic.LoadUint64(totalFoundCount)) - - r, _, _, _, err := swarm.api.Get(context.TODO(), api.NOOPDecrypt, f.addr, "/") - if err != nil { - errc <- fmt.Errorf("api get: node %s, key %s, kademlia %s: %v", id, f.addr, swarm.bzz.Hive, err) - return - } - d, err := ioutil.ReadAll(r) - if err != nil { - errc <- fmt.Errorf("api get: read response: node %s, key %s: kademlia %s: %v", id, f.addr, swarm.bzz.Hive, err) - return - } - data := string(d) - if data != f.data { - errc <- fmt.Errorf("file contend missmatch: node %s, key %s, expected %q, got %q", id, f.addr, f.data, data) - return - } - checkStatusM.Store(checkKey, 0) - atomic.AddUint64(&foundCount, 1) - log.Info("api get: file found", "node", id.String(), "key", f.addr.String(), "content", data, "files found", atomic.LoadUint64(&foundCount)) - }(f, id) - } - - go func(id enode.ID) { - defer totalWg.Done() - wg.Wait() - - atomic.AddUint64(totalFoundCount, foundCount) - - if foundCount == checkCount { - log.Info("all files are found for node", "id", id.String(), "duration", time.Since(start)) - nodeStatusM.Store(id, 0) - return - } - log.Debug("files missing for node", "id", id.String(), "check", checkCount, "found", foundCount) - }(id) - - } - - go func() { - totalWg.Wait() - close(errc) - }() - - var errCount int - for err := range errc { - if err != nil { - errCount++ - } - log.Warn(err.Error()) - } - - log.Info("check stats", "total check count", totalCheckCount, "total files found", atomic.LoadUint64(totalFoundCount), "total errors", errCount) - - return uint64(totalCheckCount) - atomic.LoadUint64(totalFoundCount) -} - -// putString provides singleton manifest creation on top of api.API -func putString(ctx context.Context, a *api.API, content string, contentType string, toEncrypt bool) (k storage.Address, wait func(context.Context) error, err error) { - r := strings.NewReader(content) - tag, err := a.Tags.New("unnamed-tag", 0) - - log.Trace("created new tag", "uid", tag.Uid) - - cCtx := sctx.SetTag(ctx, tag.Uid) - key, waitContent, err := a.Store(cCtx, r, int64(len(content)), toEncrypt) - if err != nil { - return nil, nil, err - } - manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType) - r = strings.NewReader(manifest) - key, waitManifest, err := a.Store(cCtx, r, int64(len(manifest)), toEncrypt) - if err != nil { - return nil, nil, err - } - tag.DoneSplit(key) - return key, func(ctx context.Context) error { - err := waitContent(ctx) - if err != nil { - return err - } - return waitManifest(ctx) - }, nil -} diff --git a/swarm/pot/address.go b/swarm/pot/address.go deleted file mode 100644 index 91cada2e88..0000000000 --- a/swarm/pot/address.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package pot see doc.go -package pot - -import ( - "encoding/binary" - "fmt" - "math/rand" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/common" -) - -var ( - zerosBin = Address{}.Bin() -) - -// Address is an alias for common.Hash -type Address common.Hash - -// NewAddressFromBytes constructs an Address from a byte slice -func NewAddressFromBytes(b []byte) Address { - h := common.Hash{} - copy(h[:], b) - return Address(h) -} - -func (a Address) String() string { - return fmt.Sprintf("%x", a[:]) -} - -// MarshalJSON Address serialisation -func (a *Address) MarshalJSON() (out []byte, err error) { - return []byte(`"` + a.String() + `"`), nil -} - -// UnmarshalJSON Address deserialisation -func (a *Address) UnmarshalJSON(value []byte) error { - *a = Address(common.HexToHash(string(value[1 : len(value)-1]))) - return nil -} - -// Bin returns the string form of the binary representation of an address (only first 8 bits) -func (a Address) Bin() string { - return ToBin(a[:]) -} - -// ToBin converts a byteslice to the string binary representation -func ToBin(a []byte) string { - var bs []string - for _, b := range a { - bs = append(bs, fmt.Sprintf("%08b", b)) - } - return strings.Join(bs, "") -} - -// Bytes returns the Address as a byte slice -func (a Address) Bytes() []byte { - return a[:] -} - -// ProxCmp compares the distances a->target and b->target. -// Returns -1 if a is closer to target, 1 if b is closer to target -// and 0 if they are equal. -func ProxCmp(a, x, y interface{}) int { - return proxCmp(ToBytes(a), ToBytes(x), ToBytes(y)) -} - -func proxCmp(a, x, y []byte) int { - for i := range a { - dx := x[i] ^ a[i] - dy := y[i] ^ a[i] - if dx > dy { - return 1 - } else if dx < dy { - return -1 - } - } - return 0 -} - -// RandomAddressAt (address, prox) generates a random address -// at proximity order prox relative to address -// if prox is negative a random address is generated -func RandomAddressAt(self Address, prox int) (addr Address) { - addr = self - pos := -1 - if prox >= 0 { - pos = prox / 8 - trans := prox % 8 - transbytea := byte(0) - for j := 0; j <= trans; j++ { - transbytea |= 1 << uint8(7-j) - } - flipbyte := byte(1 << uint8(7-trans)) - transbyteb := transbytea ^ byte(255) - randbyte := byte(rand.Intn(255)) - addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb - } - for i := pos + 1; i < len(addr); i++ { - addr[i] = byte(rand.Intn(255)) - } - - return -} - -// RandomAddress generates a random address -func RandomAddress() Address { - return RandomAddressAt(Address{}, -1) -} - -// NewAddressFromString creates a byte slice from a string in binary representation -func NewAddressFromString(s string) []byte { - ha := [32]byte{} - - t := s + zerosBin[:len(zerosBin)-len(s)] - for i := 0; i < 4; i++ { - n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64) - if err != nil { - panic("wrong format: " + err.Error()) - } - binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], n) - } - return ha[:] -} - -// BytesAddress is an interface for elements addressable by a byte slice -type BytesAddress interface { - Address() []byte -} - -// ToBytes turns the Val into bytes -func ToBytes(v Val) []byte { - if v == nil { - return nil - } - b, ok := v.([]byte) - if !ok { - ba, ok := v.(BytesAddress) - if !ok { - panic(fmt.Sprintf("unsupported value type %T", v)) - } - b = ba.Address() - } - return b -} - -// DefaultPof returns a proximity order comparison operator function -func DefaultPof(max int) func(one, other Val, pos int) (int, bool) { - return func(one, other Val, pos int) (int, bool) { - po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos) - if po >= max { - eq = true - po = max - } - return po, eq - } -} - -// proximityOrder returns two parameters: -// 1. relative proximity order of the arguments one & other; -// 2. boolean indicating whether the full match occurred (one == other). -func proximityOrder(one, other []byte, pos int) (int, bool) { - for i := pos / 8; i < len(one); i++ { - if one[i] == other[i] { - continue - } - oxo := one[i] ^ other[i] - start := 0 - if i == pos/8 { - start = pos % 8 - } - for j := start; j < 8; j++ { - if (oxo>>uint8(7-j))&0x01 != 0 { - return i*8 + j, false - } - } - } - return len(one) * 8, true -} - -// Label displays the node's key in binary format -func Label(v Val) string { - if v == nil { - return "" - } - if s, ok := v.(fmt.Stringer); ok { - return s.String() - } - if b, ok := v.([]byte); ok { - return ToBin(b) - } - panic(fmt.Sprintf("unsupported value type %T", v)) -} diff --git a/swarm/pot/doc.go b/swarm/pot/doc.go deleted file mode 100644 index cb6faea57b..0000000000 --- a/swarm/pot/doc.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/* -Package pot (proximity order tree) implements a container similar to a binary tree. -The elements are generic Val interface types. - -Each fork in the trie is itself a value. Values of the subtree contained under -a node all share the same order when compared to other elements in the tree. - -Example of proximity order is the length of the common prefix over bitvectors. -(which is equivalent to the reverse rank of order of magnitude of the MSB first X -OR distance over finite set of integers). - -Methods take a comparison operator (pof, proximity order function) to compare two -value types. The default pof assumes Val to be or project to a byte slice using -the reverse rank on the MSB first XOR logarithmic distance. - -If the address space if limited, equality is defined as the maximum proximity order. - -The container offers applicative (functional) style methods on PO trees: -* adding/removing en element -* swap (value based add/remove) -* merging two PO trees (union) - -as well as iterator accessors that respect proximity order - -When synchronicity of membership if not 100% requirement (e.g. used as a database -of network connections), applicative structures have the advantage that nodes -are immutable therefore manipulation does not need locking allowing for -concurrent retrievals. -For the use case where the entire container is supposed to allow changes by -concurrent routines, - -Pot -* retrieval, insertion and deletion by key involves log(n) pointer lookups -* for any item retrieval (defined as common prefix on the binary key) -* provide synchronous iterators respecting proximity ordering wrt any item -* provide asynchronous iterator (for parallel execution of operations) over n items -* allows cheap iteration over ranges -* asymmetric concurrent merge (union) - -Note: -* as is, union only makes sense for set representations since which of two values -with equal keys survives is random -* intersection is not implemented -* simple get accessor is not implemented (but derivable from EachNeighbour) - -Pinned value on the node implies no need to copy keys of the item type. - -Note that -* the same set of values allows for a large number of alternative -POT representations. -* values on the top are accessed faster than lower ones and the steps needed to -retrieve items has a logarithmic distribution. - -As a consequence one can organise the tree so that items that need faster access -are torwards the top. In particular for any subset where popularity has a power -distriution that is independent of proximity order (content addressed storage of -chunks), it is in principle possible to create a pot where the steps needed to -access an item is inversely proportional to its popularity. -Such organisation is not implemented as yet. - -TODO: -* overwrite-style merge -* intersection -* access frequency based optimisations - -*/ -package pot diff --git a/swarm/pot/pot.go b/swarm/pot/pot.go deleted file mode 100644 index 7e3967f3f9..0000000000 --- a/swarm/pot/pot.go +++ /dev/null @@ -1,787 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package pot see doc.go -package pot - -import ( - "fmt" - "sync" -) - -const ( - maxkeylen = 256 -) - -// Pot is the node type (same for root, branching node and leaf) -type Pot struct { - pin Val - bins []*Pot - size int - po int -} - -// Val is the element type for Pots -type Val interface{} - -// Pof is the proximity order comparison operator function -type Pof func(Val, Val, int) (int, bool) - -// NewPot constructor. Requires a value of type Val to pin -// and po to point to a span in the Val key -// The pinned item counts towards the size -func NewPot(v Val, po int) *Pot { - var size int - if v != nil { - size++ - } - return &Pot{ - pin: v, - po: po, - size: size, - } -} - -// Pin returns the pinned element (key) of the Pot -func (t *Pot) Pin() Val { - return t.pin -} - -// Size returns the number of values in the Pot -func (t *Pot) Size() int { - if t == nil { - return 0 - } - return t.size -} - -// Add inserts a new value into the Pot and -// returns the proximity order of v and a boolean -// indicating if the item was found -// Add called on (t, v) returns a new Pot that contains all the elements of t -// plus the value v, using the applicative add -// the second return value is the proximity order of the inserted element -// the third is boolean indicating if the item was found -func Add(t *Pot, val Val, pof Pof) (*Pot, int, bool) { - return add(t, val, pof) -} - -func (t *Pot) clone() *Pot { - return &Pot{ - pin: t.pin, - size: t.size, - po: t.po, - bins: t.bins, - } -} - -func add(t *Pot, val Val, pof Pof) (*Pot, int, bool) { - var r *Pot - if t == nil || t.pin == nil { - r = t.clone() - r.pin = val - r.size++ - return r, 0, false - } - po, found := pof(t.pin, val, t.po) - if found { - r = t.clone() - r.pin = val - return r, po, true - } - - var p *Pot - var i, j int - size := t.size - for i < len(t.bins) { - n := t.bins[i] - if n.po == po { - p, _, found = add(n, val, pof) - if !found { - size++ - } - j++ - break - } - if n.po > po { - break - } - i++ - j++ - } - if p == nil { - size++ - p = &Pot{ - pin: val, - size: 1, - po: po, - } - } - - bins := append([]*Pot{}, t.bins[:i]...) - bins = append(bins, p) - bins = append(bins, t.bins[j:]...) - r = &Pot{ - pin: t.pin, - size: size, - po: t.po, - bins: bins, - } - - return r, po, found -} - -// Remove deletes element v from the Pot t and returns three parameters: -// 1. new Pot that contains all the elements of t minus the element v; -// 2. proximity order of the removed element v; -// 3. boolean indicating whether the item was found. -func Remove(t *Pot, v Val, pof Pof) (*Pot, int, bool) { - return remove(t, v, pof) -} - -func remove(t *Pot, val Val, pof Pof) (r *Pot, po int, found bool) { - size := t.size - po, found = pof(t.pin, val, t.po) - if found { - size-- - if size == 0 { - return &Pot{}, po, true - } - i := len(t.bins) - 1 - last := t.bins[i] - r = &Pot{ - pin: last.pin, - bins: append(t.bins[:i], last.bins...), - size: size, - po: t.po, - } - return r, t.po, true - } - - var p *Pot - var i, j int - for i < len(t.bins) { - n := t.bins[i] - if n.po == po { - p, po, found = remove(n, val, pof) - if found { - size-- - } - j++ - break - } - if n.po > po { - return t, po, false - } - i++ - j++ - } - bins := t.bins[:i] - if p != nil && p.pin != nil { - bins = append(bins, p) - } - bins = append(bins, t.bins[j:]...) - r = &Pot{ - pin: t.pin, - size: size, - po: t.po, - bins: bins, - } - return r, po, found -} - -// Swap called on (k, f) looks up the item at k -// and applies the function f to the value v at k or to nil if the item is not found -// if f(v) returns nil, the element is removed -// if f(v) returns v' <> v then v' is inserted into the Pot -// if (v) == v the Pot is not changed -// it panics if Pof(f(v), k) show that v' and v are not key-equal -func Swap(t *Pot, k Val, pof Pof, f func(v Val) Val) (r *Pot, po int, found bool, change bool) { - var val Val - if t.pin == nil { - val = f(nil) - if val == nil { - return nil, 0, false, false - } - return NewPot(val, t.po), 0, false, true - } - size := t.size - po, found = pof(k, t.pin, t.po) - if found { - val = f(t.pin) - // remove element - if val == nil { - size-- - if size == 0 { - r = &Pot{ - po: t.po, - } - // return empty pot - return r, po, true, true - } - // actually remove pin, by merging last bin - i := len(t.bins) - 1 - last := t.bins[i] - r = &Pot{ - pin: last.pin, - bins: append(t.bins[:i], last.bins...), - size: size, - po: t.po, - } - return r, po, true, true - } - // element found but no change - if val == t.pin { - return t, po, true, false - } - // actually modify the pinned element, but no change in structure - r = t.clone() - r.pin = val - return r, po, true, true - } - - // recursive step - var p *Pot - n, i := t.getPos(po) - if n != nil { - p, po, found, change = Swap(n, k, pof, f) - // recursive no change - if !change { - return t, po, found, false - } - // recursive change - bins := append([]*Pot{}, t.bins[:i]...) - if p.size == 0 { - size-- - } else { - size += p.size - n.size - bins = append(bins, p) - } - i++ - if i < len(t.bins) { - bins = append(bins, t.bins[i:]...) - } - r = t.clone() - r.bins = bins - r.size = size - return r, po, found, true - } - // key does not exist - val = f(nil) - if val == nil { - // and it should not be created - return t, po, false, false - } - // otherwise check val if equal to k - if _, eq := pof(val, k, po); !eq { - panic("invalid value") - } - /// - size++ - p = &Pot{ - pin: val, - size: 1, - po: po, - } - - bins := append([]*Pot{}, t.bins[:i]...) - bins = append(bins, p) - if i < len(t.bins) { - bins = append(bins, t.bins[i:]...) - } - r = t.clone() - r.bins = bins - r.size = size - return r, po, found, true -} - -// Union called on (t0, t1, pof) returns the union of t0 and t1 -// calculates the union using the applicative union -// the second return value is the number of common elements -func Union(t0, t1 *Pot, pof Pof) (*Pot, int) { - return union(t0, t1, pof) -} - -func union(t0, t1 *Pot, pof Pof) (*Pot, int) { - if t0 == nil || t0.size == 0 { - return t1, 0 - } - if t1 == nil || t1.size == 0 { - return t0, 0 - } - var pin Val - var bins []*Pot - var mis []int - wg := &sync.WaitGroup{} - wg.Add(1) - pin0 := t0.pin - pin1 := t1.pin - bins0 := t0.bins - bins1 := t1.bins - var i0, i1 int - var common int - - po, eq := pof(pin0, pin1, 0) - - for { - l0 := len(bins0) - l1 := len(bins1) - var n0, n1 *Pot - var p0, p1 int - var a0, a1 bool - - for { - - if !a0 && i0 < l0 && bins0[i0] != nil && bins0[i0].po <= po { - n0 = bins0[i0] - p0 = n0.po - a0 = p0 == po - } else { - a0 = true - } - - if !a1 && i1 < l1 && bins1[i1] != nil && bins1[i1].po <= po { - n1 = bins1[i1] - p1 = n1.po - a1 = p1 == po - } else { - a1 = true - } - if a0 && a1 { - break - } - - switch { - case (p0 < p1 || a1) && !a0: - bins = append(bins, n0) - i0++ - n0 = nil - case (p1 < p0 || a0) && !a1: - bins = append(bins, n1) - i1++ - n1 = nil - case p1 < po: - bl := len(bins) - bins = append(bins, nil) - ml := len(mis) - mis = append(mis, 0) - // wg.Add(1) - // go func(b, m int, m0, m1 *Pot) { - // defer wg.Done() - // bins[b], mis[m] = union(m0, m1, pof) - // }(bl, ml, n0, n1) - bins[bl], mis[ml] = union(n0, n1, pof) - i0++ - i1++ - n0 = nil - n1 = nil - } - } - - if eq { - common++ - pin = pin1 - break - } - - i := i0 - if len(bins0) > i && bins0[i].po == po { - i++ - } - var size0 int - for _, n := range bins0[i:] { - size0 += n.size - } - np := &Pot{ - pin: pin0, - bins: bins0[i:], - size: size0 + 1, - po: po, - } - - bins2 := []*Pot{np} - if n0 == nil { - pin0 = pin1 - po = maxkeylen + 1 - eq = true - common-- - - } else { - bins2 = append(bins2, n0.bins...) - pin0 = pin1 - pin1 = n0.pin - po, eq = pof(pin0, pin1, n0.po) - - } - bins0 = bins1 - bins1 = bins2 - i0 = i1 - i1 = 0 - - } - - wg.Done() - wg.Wait() - for _, c := range mis { - common += c - } - n := &Pot{ - pin: pin, - bins: bins, - size: t0.size + t1.size - common, - po: t0.po, - } - return n, common -} - -// Each is a synchronous iterator over the elements of pot with function f. -func (t *Pot) Each(f func(Val) bool) bool { - return t.each(f) -} - -// each is a synchronous iterator over the elements of pot with function f. -// the iteration ends if the function return false or there are no more elements. -func (t *Pot) each(f func(Val) bool) bool { - if t == nil || t.size == 0 { - return false - } - for _, n := range t.bins { - if !n.each(f) { - return false - } - } - return f(t.pin) -} - -// eachFrom is a synchronous iterator over the elements of pot with function f, -// starting from certain proximity order po, which is passed as a second parameter. -// the iteration ends if the function return false or there are no more elements. -func (t *Pot) eachFrom(f func(Val) bool, po int) bool { - if t == nil || t.size == 0 { - return false - } - _, beg := t.getPos(po) - for i := beg; i < len(t.bins); i++ { - if !t.bins[i].each(f) { - return false - } - } - return f(t.pin) -} - -// EachBin iterates over bins of the pivot node and offers iterators to the caller on each -// subtree passing the proximity order and the size -// the iteration continues until the function's return value is false -// or there are no more subtries -func (t *Pot) EachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val) bool) bool) bool) { - t.eachBin(val, pof, po, f) -} - -func (t *Pot) eachBin(val Val, pof Pof, po int, f func(int, int, func(func(val Val) bool) bool) bool) { - if t == nil || t.size == 0 { - return - } - spr, _ := pof(t.pin, val, t.po) - _, lim := t.getPos(spr) - var size int - var n *Pot - for i := 0; i < lim; i++ { - n = t.bins[i] - size += n.size - if n.po < po { - continue - } - if !f(n.po, n.size, n.each) { - return - } - } - if lim == len(t.bins) { - if spr >= po { - f(spr, 1, func(g func(Val) bool) bool { - return g(t.pin) - }) - } - return - } - - n = t.bins[lim] - - spo := spr - if n.po == spr { - spo++ - size += n.size - } - if spr >= po { - if !f(spr, t.size-size, func(g func(Val) bool) bool { - return t.eachFrom(func(v Val) bool { - return g(v) - }, spo) - }) { - return - } - } - if n.po == spr { - n.eachBin(val, pof, po, f) - } - -} - -// EachNeighbour is a synchronous iterator over neighbours of any target val -// the order of elements retrieved reflect proximity order to the target -// TODO: add maximum proxbin to start range of iteration -func (t *Pot) EachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool { - return t.eachNeighbour(val, pof, f) -} - -func (t *Pot) eachNeighbour(val Val, pof Pof, f func(Val, int) bool) bool { - if t == nil || t.size == 0 { - return false - } - var next bool - l := len(t.bins) - var n *Pot - ir := l - il := l - po, eq := pof(t.pin, val, t.po) - if !eq { - n, il = t.getPos(po) - if n != nil { - next = n.eachNeighbour(val, pof, f) - if !next { - return false - } - ir = il - } else { - ir = il - 1 - } - } - - next = f(t.pin, po) - if !next { - return false - } - - for i := l - 1; i > ir; i-- { - next = t.bins[i].each(func(v Val) bool { - return f(v, po) - }) - if !next { - return false - } - } - - for i := il - 1; i >= 0; i-- { - n := t.bins[i] - next = n.each(func(v Val) bool { - return f(v, n.po) - }) - if !next { - return false - } - } - return true -} - -// EachNeighbourAsync called on (val, max, maxPos, f, wait) is an asynchronous iterator -// over elements not closer than maxPos wrt val. -// val does not need to be match an element of the Pot, but if it does, and -// maxPos is keylength than it is included in the iteration -// Calls to f are parallelised, the order of calls is undefined. -// proximity order is respected in that there is no element in the Pot that -// is not visited if a closer node is visited. -// The iteration is finished when max number of nearest nodes is visited -// or if the entire there are no nodes not closer than maxPos that is not visited -// if wait is true, the iterator returns only if all calls to f are finished -// TODO: implement minPos for proper prox range iteration -func (t *Pot) EachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(Val, int), wait bool) { - if max > t.size { - max = t.size - } - var wg *sync.WaitGroup - if wait { - wg = &sync.WaitGroup{} - } - t.eachNeighbourAsync(val, pof, max, maxPos, f, wg) - if wait { - wg.Wait() - } -} - -func (t *Pot) eachNeighbourAsync(val Val, pof Pof, max int, maxPos int, f func(Val, int), wg *sync.WaitGroup) (extra int) { - l := len(t.bins) - - po, eq := pof(t.pin, val, t.po) - - // if po is too close, set the pivot branch (pom) to maxPos - pom := po - if pom > maxPos { - pom = maxPos - } - n, il := t.getPos(pom) - ir := il - // if pivot branch exists and po is not too close, iterate on the pivot branch - if pom == po { - if n != nil { - - m := n.size - if max < m { - m = max - } - max -= m - - extra = n.eachNeighbourAsync(val, pof, m, maxPos, f, wg) - - } else { - if !eq { - ir-- - } - } - } else { - extra++ - max-- - if n != nil { - il++ - } - // before checking max, add up the extra elements - // on the close branches that are skipped (if po is too close) - for i := l - 1; i >= il; i-- { - s := t.bins[i] - m := s.size - if max < m { - m = max - } - max -= m - extra += m - } - } - - var m int - if pom == po { - - m, max, extra = need(1, max, extra) - if m <= 0 { - return - } - - if wg != nil { - wg.Add(1) - } - go func() { - if wg != nil { - defer wg.Done() - } - f(t.pin, po) - }() - - // otherwise iterats - for i := l - 1; i > ir; i-- { - n := t.bins[i] - - m, max, extra = need(n.size, max, extra) - if m <= 0 { - return - } - - if wg != nil { - wg.Add(m) - } - go func(pn *Pot, pm int) { - pn.each(func(v Val) bool { - if wg != nil { - defer wg.Done() - } - f(v, po) - pm-- - return pm > 0 - }) - }(n, m) - - } - } - - // iterate branches that are farther tham pom with their own po - for i := il - 1; i >= 0; i-- { - n := t.bins[i] - // the first time max is less than the size of the entire branch - // wait for the pivot thread to release extra elements - m, max, extra = need(n.size, max, extra) - if m <= 0 { - return - } - - if wg != nil { - wg.Add(m) - } - go func(pn *Pot, pm int) { - pn.each(func(v Val) bool { - if wg != nil { - defer wg.Done() - } - f(v, pn.po) - pm-- - return pm > 0 - }) - }(n, m) - - } - return max + extra -} - -// getPos called on (n) returns the forking node at PO n and its index if it exists -// otherwise nil -// caller is supposed to hold the lock -func (t *Pot) getPos(po int) (n *Pot, i int) { - for i, n = range t.bins { - if po > n.po { - continue - } - if po < n.po { - return nil, i - } - return n, i - } - return nil, len(t.bins) -} - -// need called on (m, max, extra) uses max m out of extra, and then max -// if needed, returns the adjusted counts -func need(m, max, extra int) (int, int, int) { - if m <= extra { - return m, max, extra - m - } - max += extra - m - if max <= 0 { - return m + max, 0, 0 - } - return m, max, 0 -} - -func (t *Pot) String() string { - return t.sstring("") -} - -func (t *Pot) sstring(indent string) string { - if t == nil { - return "" - } - var s string - indent += " " - s += fmt.Sprintf("%v%v (%v) %v \n", indent, t.pin, t.po, t.size) - for _, n := range t.bins { - s += fmt.Sprintf("%v%v\n", indent, n.sstring(indent)) - } - return s -} diff --git a/swarm/pot/pot_test.go b/swarm/pot/pot_test.go deleted file mode 100644 index 83d604919f..0000000000 --- a/swarm/pot/pot_test.go +++ /dev/null @@ -1,741 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package pot - -import ( - "errors" - "fmt" - "math/rand" - "runtime" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/log" -) - -const ( - maxEachNeighbourTests = 420 - maxEachNeighbour = 420 - maxSwap = 420 - maxSwapTests = 420 -) - -// func init() { -// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) -// } - -type testAddr struct { - a []byte - i int -} - -func newTestAddr(s string, i int) *testAddr { - return &testAddr{NewAddressFromString(s), i} -} - -func (a *testAddr) Address() []byte { - return a.a -} - -func (a *testAddr) String() string { - return Label(a.a) -} - -func randomTestAddr(n int, i int) *testAddr { - v := RandomAddress().Bin()[:n] - return newTestAddr(v, i) -} - -func randomtestAddr(n int, i int) *testAddr { - v := RandomAddress().Bin()[:n] - return newTestAddr(v, i) -} - -func indexes(t *Pot) (i []int) { - t.Each(func(v Val) bool { - a := v.(*testAddr) - i = append(i, a.i) - return true - }) - return i -} - -func testAdd(t *Pot, pof Pof, j int, values ...string) (_ *Pot, n int, f bool) { - for i, val := range values { - t, n, f = Add(t, newTestAddr(val, i+j), pof) - } - return t, n, f -} - -// removing non-existing element from pot -func TestPotRemoveNonExisting(t *testing.T) { - pof := DefaultPof(8) - n := NewPot(newTestAddr("00111100", 0), 0) - n, _, _ = Remove(n, newTestAddr("00000101", 0), pof) - exp := "00111100" - got := Label(n.Pin()) - if got[:8] != exp { - t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got[:8]) - } -} - -// this test creates hierarchical pot tree, and therefore any child node will have -// child_po = parent_po + 1. -// then removes a node from the middle of the tree. -func TestPotRemoveSameBin(t *testing.T) { - pof := DefaultPof(8) - n := NewPot(newTestAddr("11111111", 0), 0) - n, _, _ = testAdd(n, pof, 1, "00000000", "01000000", "01100000", "01110000", "01111000") - n, _, _ = Remove(n, newTestAddr("01110000", 0), pof) - inds := indexes(n) - goti := n.Size() - expi := 5 - if goti != expi { - t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) - } - inds = indexes(n) - got := fmt.Sprintf("%v", inds) - exp := "[5 3 2 1 0]" - if got != exp { - t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) - } -} - -// this test creates a flat pot tree (all the elements are leafs of one root), -// and therefore they all have the same po. -// then removes an arbitrary element from the pot. -func TestPotRemoveDifferentBins(t *testing.T) { - pof := DefaultPof(8) - n := NewPot(newTestAddr("11111111", 0), 0) - n, _, _ = testAdd(n, pof, 1, "00000000", "10000000", "11000000", "11100000", "11110000") - n, _, _ = Remove(n, newTestAddr("11100000", 0), pof) - inds := indexes(n) - goti := n.Size() - expi := 5 - if goti != expi { - t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) - } - inds = indexes(n) - got := fmt.Sprintf("%v", inds) - exp := "[1 2 3 5 0]" - if got != exp { - t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) - } - n, _, _ = testAdd(n, pof, 4, "11100000") - inds = indexes(n) - got = fmt.Sprintf("%v", inds) - exp = "[1 2 3 4 5 0]" - if got != exp { - t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) - } -} - -func TestPotAdd(t *testing.T) { - pof := DefaultPof(8) - n := NewPot(newTestAddr("00111100", 0), 0) - // Pin set correctly - exp := "00111100" - got := Label(n.Pin())[:8] - if got != exp { - t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got) - } - // check size - goti := n.Size() - expi := 1 - if goti != expi { - t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) - } - - n, _, _ = testAdd(n, pof, 1, "01111100", "00111100", "01111100", "00011100") - // check size - goti = n.Size() - expi = 3 - if goti != expi { - t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) - } - inds := indexes(n) - got = fmt.Sprintf("%v", inds) - exp = "[3 4 2]" - if got != exp { - t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) - } -} - -func TestPotRemove(t *testing.T) { - pof := DefaultPof(8) - n := NewPot(newTestAddr("00111100", 0), 0) - n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) - exp := "" - got := Label(n.Pin()) - if got != exp { - t.Fatalf("incorrect pinned value. Expected %v, got %v", exp, got) - } - n, _, _ = testAdd(n, pof, 1, "00000000", "01111100", "00111100", "00011100") - n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) - goti := n.Size() - expi := 3 - if goti != expi { - t.Fatalf("incorrect number of elements in Pot. Expected %v, got %v", expi, goti) - } - inds := indexes(n) - got = fmt.Sprintf("%v", inds) - exp = "[2 4 1]" - if got != exp { - t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) - } - n, _, _ = Remove(n, newTestAddr("00111100", 0), pof) // remove again same element - inds = indexes(n) - got = fmt.Sprintf("%v", inds) - if got != exp { - t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) - } - n, _, _ = Remove(n, newTestAddr("00000000", 0), pof) // remove the first element - inds = indexes(n) - got = fmt.Sprintf("%v", inds) - exp = "[2 4]" - if got != exp { - t.Fatalf("incorrect indexes in iteration over Pot. Expected %v, got %v", exp, got) - } -} - -func TestPotSwap(t *testing.T) { - for i := 0; i < maxSwapTests; i++ { - alen := maxkeylen - pof := DefaultPof(alen) - max := rand.Intn(maxSwap) - - n := NewPot(nil, 0) - var m []*testAddr - var found bool - for j := 0; j < 2*max; { - v := randomtestAddr(alen, j) - n, _, found = Add(n, v, pof) - if !found { - m = append(m, v) - j++ - } - } - k := make(map[string]*testAddr) - for j := 0; j < max; { - v := randomtestAddr(alen, 1) - _, found := k[Label(v)] - if !found { - k[Label(v)] = v - j++ - } - } - for _, v := range k { - m = append(m, v) - } - f := func(v Val) Val { - tv := v.(*testAddr) - if tv.i < max { - return nil - } - tv.i = 0 - return v - } - for _, val := range m { - n, _, _, _ = Swap(n, val, pof, func(v Val) Val { - if v == nil { - return val - } - return f(v) - }) - } - sum := 0 - n.Each(func(v Val) bool { - if v == nil { - return true - } - sum++ - tv := v.(*testAddr) - if tv.i > 1 { - t.Fatalf("item value incorrect, expected 0, got %v", tv.i) - } - return true - }) - if sum != 2*max { - t.Fatalf("incorrect number of elements. expected %v, got %v", 2*max, sum) - } - if sum != n.Size() { - t.Fatalf("incorrect size. expected %v, got %v", sum, n.Size()) - } - } -} - -func checkPo(val Val, pof Pof) func(Val, int) error { - return func(v Val, po int) error { - // check the po - exp, _ := pof(val, v, 0) - if po != exp { - return fmt.Errorf("incorrect prox order for item %v in neighbour iteration for %v. Expected %v, got %v", v, val, exp, po) - } - return nil - } -} - -func checkOrder(val Val) func(Val, int) error { - po := maxkeylen - return func(v Val, p int) error { - if po < p { - return fmt.Errorf("incorrect order for item %v in neighbour iteration for %v. PO %v > %v (previous max)", v, val, p, po) - } - po = p - return nil - } -} - -func checkValues(m map[string]bool, val Val) func(Val, int) error { - return func(v Val, po int) error { - duplicate, ok := m[Label(v)] - if !ok { - return fmt.Errorf("alien value %v", v) - } - if duplicate { - return fmt.Errorf("duplicate value returned: %v", v) - } - m[Label(v)] = true - return nil - } -} - -var errNoCount = errors.New("not count") - -func testPotEachNeighbour(n *Pot, pof Pof, val Val, expCount int, fs ...func(Val, int) error) error { - var err error - var count int - n.EachNeighbour(val, pof, func(v Val, po int) bool { - for _, f := range fs { - err = f(v, po) - if err != nil { - return err.Error() == errNoCount.Error() - } - } - count++ - return count != expCount - }) - if err == nil && count < expCount { - return fmt.Errorf("not enough neighbours returned, expected %v, got %v", expCount, count) - } - return err -} - -const ( - mergeTestCount = 5 - mergeTestChoose = 5 -) - -func TestPotMergeCommon(t *testing.T) { - vs := make([]*testAddr, mergeTestCount) - for i := 0; i < maxEachNeighbourTests; i++ { - alen := maxkeylen - pof := DefaultPof(alen) - - for j := 0; j < len(vs); j++ { - vs[j] = randomtestAddr(alen, j) - } - max0 := rand.Intn(mergeTestChoose) + 1 - max1 := rand.Intn(mergeTestChoose) + 1 - n0 := NewPot(nil, 0) - n1 := NewPot(nil, 0) - log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1)) - m := make(map[string]bool) - var found bool - for j := 0; j < max0; { - r := rand.Intn(max0) - v := vs[r] - n0, _, found = Add(n0, v, pof) - if !found { - m[Label(v)] = false - j++ - } - } - expAdded := 0 - - for j := 0; j < max1; { - r := rand.Intn(max1) - v := vs[r] - n1, _, found = Add(n1, v, pof) - if !found { - j++ - } - _, found = m[Label(v)] - if !found { - expAdded++ - m[Label(v)] = false - } - } - if i < 6 { - continue - } - expSize := len(m) - log.Trace(fmt.Sprintf("%v-0: pin: %v, size: %v", i, n0.Pin(), max0)) - log.Trace(fmt.Sprintf("%v-1: pin: %v, size: %v", i, n1.Pin(), max1)) - log.Trace(fmt.Sprintf("%v: merged tree size: %v, newly added: %v", i, expSize, expAdded)) - n, common := Union(n0, n1, pof) - added := n1.Size() - common - size := n.Size() - - if expSize != size { - t.Fatalf("%v: incorrect number of elements in merged pot, expected %v, got %v\n%v", i, expSize, size, n) - } - if expAdded != added { - t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added) - } - if !checkDuplicates(n) { - t.Fatalf("%v: merged pot contains duplicates: \n%v", i, n) - } - for k := range m { - _, _, found = Add(n, newTestAddr(k, 0), pof) - if !found { - t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v", i, size, added, k) - } - } - } -} - -func TestPotMergeScale(t *testing.T) { - for i := 0; i < maxEachNeighbourTests; i++ { - alen := maxkeylen - pof := DefaultPof(alen) - max0 := rand.Intn(maxEachNeighbour) + 1 - max1 := rand.Intn(maxEachNeighbour) + 1 - n0 := NewPot(nil, 0) - n1 := NewPot(nil, 0) - log.Trace(fmt.Sprintf("round %v: %v - %v", i, max0, max1)) - m := make(map[string]bool) - var found bool - for j := 0; j < max0; { - v := randomtestAddr(alen, j) - n0, _, found = Add(n0, v, pof) - if !found { - m[Label(v)] = false - j++ - } - } - expAdded := 0 - - for j := 0; j < max1; { - v := randomtestAddr(alen, j) - n1, _, found = Add(n1, v, pof) - if !found { - j++ - } - _, found = m[Label(v)] - if !found { - expAdded++ - m[Label(v)] = false - } - } - if i < 6 { - continue - } - expSize := len(m) - log.Trace(fmt.Sprintf("%v-0: pin: %v, size: %v", i, n0.Pin(), max0)) - log.Trace(fmt.Sprintf("%v-1: pin: %v, size: %v", i, n1.Pin(), max1)) - log.Trace(fmt.Sprintf("%v: merged tree size: %v, newly added: %v", i, expSize, expAdded)) - n, common := Union(n0, n1, pof) - added := n1.Size() - common - size := n.Size() - - if expSize != size { - t.Fatalf("%v: incorrect number of elements in merged pot, expected %v, got %v", i, expSize, size) - } - if expAdded != added { - t.Fatalf("%v: incorrect number of added elements in merged pot, expected %v, got %v", i, expAdded, added) - } - if !checkDuplicates(n) { - t.Fatalf("%v: merged pot contains duplicates", i) - } - for k := range m { - _, _, found = Add(n, newTestAddr(k, 0), pof) - if !found { - t.Fatalf("%v: merged pot (size:%v, added: %v) missing element %v", i, size, added, k) - } - } - } -} - -func checkDuplicates(t *Pot) bool { - po := -1 - for _, c := range t.bins { - if c == nil { - return false - } - if c.po <= po || !checkDuplicates(c) { - return false - } - po = c.po - } - return true -} - -func TestPotEachNeighbourSync(t *testing.T) { - for i := 0; i < maxEachNeighbourTests; i++ { - alen := maxkeylen - pof := DefaultPof(maxkeylen) - max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2 - pin := randomTestAddr(alen, 0) - n := NewPot(pin, 0) - m := make(map[string]bool) - m[Label(pin)] = false - for j := 1; j <= max; j++ { - v := randomTestAddr(alen, j) - n, _, _ = Add(n, v, pof) - m[Label(v)] = false - } - - size := n.Size() - if size < 2 { - continue - } - count := rand.Intn(size/2) + size/2 - val := randomTestAddr(alen, max+1) - log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v", i, n.Pin(), size, val, count)) - err := testPotEachNeighbour(n, pof, val, count, checkPo(val, pof), checkOrder(val), checkValues(m, val)) - if err != nil { - t.Fatal(err) - } - minPoFound := alen - maxPoNotFound := 0 - for k, found := range m { - po, _ := pof(val, newTestAddr(k, 0), 0) - if found { - if po < minPoFound { - minPoFound = po - } - } else { - if po > maxPoNotFound { - maxPoNotFound = po - } - } - } - if minPoFound < maxPoNotFound { - t.Fatalf("incorrect neighbours returned: found one with PO %v < there was one not found with PO %v", minPoFound, maxPoNotFound) - } - } -} - -func TestPotEachNeighbourAsync(t *testing.T) { - for i := 0; i < maxEachNeighbourTests; i++ { - max := rand.Intn(maxEachNeighbour/2) + maxEachNeighbour/2 - alen := maxkeylen - pof := DefaultPof(alen) - n := NewPot(randomTestAddr(alen, 0), 0) - size := 1 - var found bool - for j := 1; j <= max; j++ { - v := randomTestAddr(alen, j) - n, _, found = Add(n, v, pof) - if !found { - size++ - } - } - if size != n.Size() { - t.Fatal(n) - } - if size < 2 { - continue - } - count := rand.Intn(size/2) + size/2 - val := randomTestAddr(alen, max+1) - - mu := sync.Mutex{} - m := make(map[string]bool) - maxPos := rand.Intn(alen) - log.Trace(fmt.Sprintf("%v: pin: %v, size: %v, val: %v, count: %v, maxPos: %v", i, n.Pin(), size, val, count, maxPos)) - msize := 0 - remember := func(v Val, po int) error { - if po > maxPos { - return errNoCount - } - m[Label(v)] = true - msize++ - return nil - } - if i == 0 { - continue - } - testPotEachNeighbour(n, pof, val, count, remember) - d := 0 - forget := func(v Val, po int) { - mu.Lock() - defer mu.Unlock() - d++ - delete(m, Label(v)) - } - - n.EachNeighbourAsync(val, pof, count, maxPos, forget, true) - if d != msize { - t.Fatalf("incorrect number of neighbour calls in async iterator. expected %v, got %v", msize, d) - } - if len(m) != 0 { - t.Fatalf("incorrect neighbour calls in async iterator. %v items missed:\n%v", len(m), n) - } - } -} - -func benchmarkEachNeighbourSync(t *testing.B, max, count int, d time.Duration) { - t.ReportAllocs() - alen := maxkeylen - pof := DefaultPof(alen) - pin := randomTestAddr(alen, 0) - n := NewPot(pin, 0) - var found bool - for j := 1; j <= max; { - v := randomTestAddr(alen, j) - n, _, found = Add(n, v, pof) - if !found { - j++ - } - } - t.ResetTimer() - for i := 0; i < t.N; i++ { - val := randomTestAddr(alen, max+1) - m := 0 - n.EachNeighbour(val, pof, func(v Val, po int) bool { - time.Sleep(d) - m++ - return m != count - }) - } - t.StopTimer() - stats := new(runtime.MemStats) - runtime.ReadMemStats(stats) -} - -func benchmarkEachNeighbourAsync(t *testing.B, max, count int, d time.Duration) { - t.ReportAllocs() - alen := maxkeylen - pof := DefaultPof(alen) - pin := randomTestAddr(alen, 0) - n := NewPot(pin, 0) - var found bool - for j := 1; j <= max; { - v := randomTestAddr(alen, j) - n, _, found = Add(n, v, pof) - if !found { - j++ - } - } - t.ResetTimer() - for i := 0; i < t.N; i++ { - val := randomTestAddr(alen, max+1) - n.EachNeighbourAsync(val, pof, count, alen, func(v Val, po int) { - time.Sleep(d) - }, true) - } - t.StopTimer() - stats := new(runtime.MemStats) - runtime.ReadMemStats(stats) -} - -func BenchmarkEachNeighbourSync_3_1_0(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 10, 1*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_1_0(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 10, 1*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_2_0(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 100, 1*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_2_0(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 100, 1*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_3_0(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 1000, 1*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_3_0(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 1000, 1*time.Microsecond) -} - -func BenchmarkEachNeighbourSync_3_1_1(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 10, 2*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_1_1(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 10, 2*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_2_1(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 100, 2*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_2_1(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 100, 2*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_3_1(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 1000, 2*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_3_1(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 1000, 2*time.Microsecond) -} - -func BenchmarkEachNeighbourSync_3_1_2(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 10, 4*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_1_2(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 10, 4*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_2_2(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 100, 4*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_2_2(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 100, 4*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_3_2(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 1000, 4*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_3_2(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 1000, 4*time.Microsecond) -} - -func BenchmarkEachNeighbourSync_3_1_3(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 10, 8*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_1_3(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 10, 8*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_2_3(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 100, 8*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_2_3(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 100, 8*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_3_3(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 1000, 8*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_3_3(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 1000, 8*time.Microsecond) -} - -func BenchmarkEachNeighbourSync_3_1_4(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 10, 16*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_1_4(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 10, 16*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_2_4(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 100, 16*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_2_4(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 100, 16*time.Microsecond) -} -func BenchmarkEachNeighbourSync_3_3_4(t *testing.B) { - benchmarkEachNeighbourSync(t, 1000, 1000, 16*time.Microsecond) -} -func BenchmarkEachNeighboursAsync_3_3_4(t *testing.B) { - benchmarkEachNeighbourAsync(t, 1000, 1000, 16*time.Microsecond) -} diff --git a/swarm/pss/ARCHITECTURE.md b/swarm/pss/ARCHITECTURE.md deleted file mode 100644 index 279e895ab7..0000000000 --- a/swarm/pss/ARCHITECTURE.md +++ /dev/null @@ -1,144 +0,0 @@ -# Postal Service over Swarm - -Pss provides devp2p functionality for swarm nodes without the need for a direct tcp connection between them. - -Messages are encapsulated in a devp2p message structure `PssMsg`. These capsules are forwarded from node to node using ordinary tcp devp2p until they reach their destination: The node or nodes who can successfully decrypt the message. - -| Layer | Contents | -|-----------|-----------------| -| PssMsg: | Address, Expiry | -| Envelope: | Topic | -| Payload: | e(data) | - -Routing of messages is done using swarm's own kademlia routing. Optionally routing can be turned off, forcing the message to be sent to all peers, similar to the behavior of the whisper protocol. - -Pss is intended for messages of limited size, typically a couple of Kbytes at most. The messages themselves can be anything at all; complex data structures or non-descript byte sequences. - -For the current state and roadmap of pss development please see https://github.com/ethersphere/swarm/wiki/swarm-dev-progress. - -Please report issues on https://github.com/ethersphere/go-ethereum - -Feel free to ask questions in https://gitter.im/ethersphere/pss - -## STATUS OF THIS DOCUMENT - -`pss` is under active development, and the first implementation is yet to be merged to the Ethereum main branch. Expect things to change. - -## CORE INTERFACES - -The pss core provides low level control of key handling and message exchange. - -### TOPICS - -An encrypted envelope of a pss message always contains a Topic. This is pss' way of determining which message handlers to dispatch messages to. The topic of a message is only visible for the node(s) who can decrypt the message. - -This "topic" is not like the subject of an email message, but a hash-like arbitrary 4 byte value. A valid topic can be generated using the `pss_*ToTopic` API methods. - -### IDENTITY AND ENCRYPTION - -Pss aims to achieve perfect darkness. That means that the minimum requirement for two nodes to communicate using pss is a shared secret. This secret can be an arbitrary byte slice, or a ECDSA keypair. The end recipient of a message is defined as the node that can successfully decrypt that message using stored keys. - -A node's public key is derived from the private key passed to the `pss` constructor. Pss (currently) has no PKI. - -Peer keys can manually be added to the pss node through its API calls `pss_setPeerPublicKey` and `pss_setSymmetricKey`. Keys are always coupled with a topic, and the keys will only be valid for these topics. - -### CONNECTIONS - -A "connection" in pss is a purely virtual construct. There is no mechanisms in place to ensure that the remote peer actually is there. In fact, "adding" a peer involves merely the node's opinion that the peer is there. It may issue messages to that remote peer to a directly connected peer, which in turn passes it on. But if it is not present on the network - or if there is no route to it - the message will never reach its destination through mere forwarding. - -Since pss itself never requires a confirmation from a peer of whether a message is received or not, one could argue that pss shows `UDP`-like behavior. - -It is also important to note that if the wrong (partial) address is set for a particular key/topic combination, the message may never reach that peer. The further left in the address byte slice the error lies, the less likely it is that delivery will occur. - - -### EXCHANGE - -Message exchange in `pss` *requires* end-to-end encryption. - -The API methods `pss_sendSym` and `pss_sendAsym` sends an arbitrary byte slice with a specific topic to a pss peer using the respective encryption scheme. The key passed to the send method must be associated with a topic in the pss key store prior to sending, or the send method will fail. - -Return values from the send methods do *not* indicate whether the message was successfully delivered to the pss peer. It *only* indicates whether or not the message could be passed on to the network. If the message could not be forwarded to any peers, the method will fail. - -Keep in mind that symmetric encryption is less resource-intensive than asymmetric encryption. The former should be used for nodes with high message volumes. - -## EXTENSIONS - -### HANDSHAKE - -Pss offers an optional Diffie-Hellman handshake mechanism. Handshake functionality is activated per topic, and can be deactivated per topic even while the node is running. - -Handshakes are activated in the code implementation of the node by running `SetHandshakeController()` on the pss node instance BEFORE starting the node service. The methods exposed by the HandshakeController's API gives the possibility to initiate, remove and check the state of handshakes and associated keys. - -See the `HandshakeAPI` section in `godoc` for details. - -### DEVP2P PROTOCOLS - -The `Protocol` convenience structure is provided to mimic devp2p-type protocols over pss. In theory this makes it possible to reuse protocol code written for devp2p with a minimum of effort. - -#### OUTGOING CONNECTIONS - -In order to message a peer using this layer, a `Protocol` object must first be instantiated. When this is done, peers can be added using the protocol's `AddPeer()` method. The peer's key/topic combination must be in the pss key store before the peer can be aded. - -Adding a peer in effect "runs" the protocol on that peer, and adds an internal mapping between a topic and that peer, and enables sending and receiving messages using the usual io-construct of devp2p. It does not actually *transmit* anything to the peer, it merely represents the node's opinion that a connection with the peer exists. (See CONNECTION above). - -#### INCOMING CONNECTIONS - -An incoming connection is nothing more than an actual PssMsg appearing with a certain Topic. If a Handler has been registered to that Topic, the message will be passed to it. This constitutes a "new" connection if: - -- The pss node never called AddPeer with this combination of remote peer address and topic, and - -- The pss node never received a PssMsg from this remote peer with this specific Topic before. - -If it is a "new" connection, the protocol will be "run" on the remote peer, as if the peer was added via the API. - -As with the `AddPeer()` method, the key/topic of the originating peer must exist in the pss key store. - -#### TOPICS IN DEVP2P - -The `ProtocolTopic()` method should be used to determine the correct topic to use for a pss `Protocol` instance. - -## EXAMPLES - -Coming. Please refer to the tests for now. - -## PSS INTERNALS - -Pss implements the node.Service interface. It depends on a working kademlia overlay for routing. - -### DECRYPTION - -When processing an incoming message, `pss` detects whether it is encrypted symmetrically or asymmetrically. - -When decrypting symmetrically, `pss` iterates through all stored keys, and attempts to decrypt with each key in order. - -pss keeps a *cache* of these keys. The cache will only store a certain amount of keys, and the iterator will return keys in the order of most recently used key first. Abandoned keys will be garbage collected. - -### ROUTING - -(please refer to swarm kademlia routing for an explanation of the routing algorithm used for pss) - -`pss` uses *address hinting* for routing. The address hint is an arbitrary-length MSB byte slice of the peer's swarm overlay address. It can be the whole address, part of the address, or even an empty byte slice. The slice will be matched to the MSB slice of the same length of all devp2p peers in the routing stage. - -If an empty byte slice is passed, all devp2p peers will match the address hint, and the message will be forwarded to everyone. This is equivalent to `whisper` routing, and makes it difficult to perform traffic analysis based on who messages are forwarded to. - -A node will also forward to everyone if the address hint provided is in its proximity bin, both to provide saturation to increase chances of delivery, and also for recipient obfuscation to thwart traffic analysis attacks. The recipient node(s) will always forward to all its peers. - -### CACHING - -pss implements a simple caching mechanism for messages, using the swarm FileStore for storage of the messages and generation of the digest keys used in the cache table. The caching is intended to alleviate the following: - -- save messages so that they can be delivered later if the recipient was not online at the time of sending. - -- drop an identical message to the same recipient if received within a given time interval - -- prevent backwards routing of messages - -the latter may occur if only one entry is in the receiving node's kademlia, or if the proximity of the current node recipient hinted by the address is so close that the message will be forwarded to everyone. In these cases the forwarder will be provided as the "nearest node" to the final recipient. The cache keeps the address of who the message was forwarded from, and if the cache lookup matches, the message will be dropped. - -### DEVP2P PROTOCOLS - -When implementing devp2p protocols, topics are derived from protocols' name and version. The Protocol provides a generic Handler that be passed to Pss.Register. This makes it possible to use the same message handler code for pss that is used for directly connected peers in devp2p. - -Under the hood, pss implements its own MsgReadWriter, which bridges MsgReadWriter.WriteMsg with Pss.SendRaw, and deftly adds an InjectMsg method which pipes incoming messages to appear on the MsgReadWriter.ReadMsg channel. - - diff --git a/swarm/pss/README.md b/swarm/pss/README.md deleted file mode 100644 index aea871251f..0000000000 --- a/swarm/pss/README.md +++ /dev/null @@ -1,318 +0,0 @@ -# Postal Services over Swarm - -`pss` enables message relay over swarm. This means nodes can send messages to each other without being directly connected with each other, while taking advantage of the efficient routing algorithms that swarm uses for transporting and storing data. - -### CONTENTS - -* Status of this document -* Core concepts -* Caveat -* Examples -* API - * Retrieve node information - * Receive messages - * Send messages using public key encryption - * Send messages using symmetric encryption - * Querying peer keys - * Handshakes - -### STATUS OF THIS DOCUMENT - -`pss` is under active development, and the first implementation is yet to be merged to the Ethereum main branch. Expect things to change. - -Details on swarm routing and encryption schemes out of scope of this document. - -Please refer to [ARCHITECTURE.md](ARCHITECTURE.md) for in-depth topics concerning `pss`. - -## CORE CONCEPTS - -Three things are required to send a `pss` message: - -1. Encryption key -2. Topic -3. Message payload - -Encryption key can be a public key or a 32 byte symmetric key. It must be coupled with a peer address in the node prior to sending. - -Topic is the initial 4 bytes of a hash value. - -Message payload is an arbitrary byte slice of data. - -Upon sending the message it is encrypted and passed on from peer to peer. Any node along the route that can successfully decrypt the message is regarded as a recipient. Recipients continue to pass on the message to their peers, to make traffic analysis attacks more difficult. - -The Address that is coupled with the encryption keys are used for routing the message. This does *not* need to be a full addresses; the network will route the message to the best of its ability with the information that is available. If *no* address is given (zero-length byte slice), routing is effectively deactivated, and the message is passed to all peers by all peers. - -## CAVEAT - -`pss` connectivity resembles UDP. This means there is no delivery guarantee for a message. Furthermore there is no strict definition of what a connection between two nodes communicating via `pss` is. Reception acknowledgements and keepalive-schemes is the responsibility of the application. - -Due to the inherent properties of the `swarm` routing algorithm, a node may receive the same message more than once. Message deduplication *cannot be guaranteed* by `pss`, and must be handled in the application layer to ensure predictable results. - -## EXAMPLES - -The code tutorial [p2p programming in go-ethereum](https://github.com/nolash/go-ethereum-p2p-demo) by [@nolash](https://github.com/nolash) provides step-by-step code examples for usage of `pss` API with `go-ethereum` nodes. - -A quite unpolished example using `javascript` is available here: [https://github.com/nolash/pss-js/tree/withcrypt](https://github.com/nolash/pss-js/tree/withcrypt) - -## API - -The `pss` API is available through IPC and Websockets. There is currently no `web3.js` implementation, as this does not support message subscription. - -For `golang` clients, please use the `rpc.Client` provided by the `go-ethereum` repository. The return values may have special types in `golang`. Please refer to `godoc` for details. - -### RETRIEVE NODE INFORMATION - -#### pss_getPublicKey - -Retrieves the public key of the node, in hex format - -``` -parameters: -none - -returns: -1. publickey (hex) -``` - -#### pss_baseAddr - -Retrieves the swarm overlay address of the node, in hex format - -``` -parameters: -none - -returns: -1. swarm overlay address (hex) -``` - -#### pss_stringToTopic - -Creates a deterministic 4 byte topic value from input, returned in hex format - -``` -parameters: -1. topic string (string) - -returns: -1. pss topic (hex) -``` - -### RECEIVE MESSAGES - -#### pss_subscribe - -Creates a subscription. Received messages with matching topic will be passed to subscription client. - -``` -parameters: -1. string("receive") -2. topic (4 bytes in hex) - -returns: -1. subscription handle `base64(byte)` `rpc.ClientSubscription` -``` - -In `golang` as special method is used: - -`rpc.Client.Subscribe(context.Context, "pss", chan pss.APIMsg, "receive", pss.Topic)` - -Incoming messages are encapsulated in an object (`pss.APIMsg` in `golang`) with the following members: - -``` -1. Msg (hex) - the message payload -2. Asymmetric (bool) - true if message used public key encryption -3. Key (string) - the encryption key used -``` - -### SEND MESSAGE USING PUBLIC KEY ENCRYPTION - -#### pss_setPeerPublicKey - -Register a peer's public key. This is done once for every topic that will be used with the peer. Address can be anything from 0 to 32 bytes inclusive of the peer's swarm overlay address. - -``` -parameters: -1. public key of peer (hex) -2. topic (4 bytes in hex) -3. address of peer (hex) - -returns: -none -``` - -#### pss_sendAsym - -Encrypts the message using the provided public key, and signs it using the node's private key. It then wraps it in an envelope containing the topic, and sends it to the network. - -``` -parameters: -1. public key of peer (hex) -2. topic (4 bytes in hex) -3. message (hex) - -returns: -none -``` - -### SEND MESSAGE USING SYMMETRIC ENCRYPTION - -#### pss_setSymmetricKey - -Register a symmetric key shared with a peer. This is done once for every topic that will be used with the peer. Address can be anything from 0 to 32 bytes inclusive of the peer's swarm overlay address. - -If the fourth parameter is false, the key will *not* be added to the list of symmetric keys used for decryption attempts. - -``` -parameters: -1. symmetric key (hex) -2. topic (4 bytes in hex) -3. address of peer (hex) -4. use for decryption (bool) - -returns: -1. symmetric key id (string) -``` - -#### pss_sendSym - -Encrypts the message using the provided symmetric key, wraps it in an envelope containing the topic, and sends it to the network. - -``` -parameters: -1. symmetric key id (string) -2. topic (4 bytes in hex) -3. message (hex) - -returns: -none -``` - -### QUERY PEER KEYS - -#### pss_GetSymmetricAddressHint - -Return the swarm overlay address associated with the peer registered with the given symmetric key and topic combination. - -``` -parameters: -1. topic (4 bytes in hex) -2. symmetric key id (string) - -returns: -1. peer address (hex) -``` - -#### pss_GetAsymmetricAddressHint - -Return the swarm overlay address associated with the peer registered with the given symmetric key and topic combination. - -``` -parameters: -1. topic (4 bytes in hex) -2. public key in hex form (string) - -returns: -1. peer address (hex) -``` - -### HANDSHAKES - -Convenience implementation of Diffie-Hellman handshakes using ephemeral symmetric keys. Peers keep separate sets of keys for incoming and outgoing communications. - -*This functionality is an optional feature in `pss`. It is compiled in by default, but can be omitted by providing the `nopsshandshake` build tag.* - -#### pss_addHandshake - -Activate handshake functionality on the specified topic. - -``` -parameters: -1. topic (4 bytes in hex) - -returns: -none -``` - -#### pss_removeHandshake - -Remove handshake functionality on the specified topic. - -``` -parameters: -1. topic (4 bytes in hex) - -returns: -none -``` - -#### pss_handshake - -Instantiate handshake with peer, refreshing symmetric encryption keys. - -If parameter 3 is false, the returned array will be empty. - -``` -parameters: -1. public key of peer in hex format (string) -2. topic (4 bytes in hex) -3. block calls until keys are received (bool) -4. flush existing incoming keys (bool) - -returns: -1. list of symmetric keys (string[]) -``` - -#### pss_getHandshakeKeys - -Get valid symmetric encryption keys for a specified peer and topic. - -parameters: -1. public key of peer in hex format (string) -2. topic (4 bytes in hex) -3. include keys for incoming messages (bool) -4. include keys for outgoing messages (bool) - -returns: -1. list of symmetric keys (string[]) - -#### pss_getHandshakeKeyCapacity - -Get amount of remaining messages the specified key is valid for. - -``` -parameters: -1. symmetric key id (string) - -returns: -1. number of messages (uint16) -``` - -#### pss_getHandshakePublicKey - -Get the peer's public key associated with the specified symmetric key. - -``` -parameters: -1. symmetric key id (string) - -returns: -1. Associated public key in hex format (string) -``` - -#### pss_releaseHandshakeKey - -Invalidate the specified key. - -Normally, the key will be kept for a grace period to allow for decryption of delayed messages. If instant removal is set, this grace period is omitted, and the key removed instantaneously. - -``` -parameters: -1. public key of peer in hex format (string) -2. topic (4 bytes in hex) -3. symmetric key id to release (string) -4. remove keys instantly (bool) - -returns: -1. whether key was successfully removed (bool) -``` diff --git a/swarm/pss/api.go b/swarm/pss/api.go deleted file mode 100644 index 4556d7b7c4..0000000000 --- a/swarm/pss/api.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package pss - -import ( - "context" - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/log" -) - -// Wrapper for receiving pss messages when using the pss API -// providing access to sender of message -type APIMsg struct { - Msg hexutil.Bytes - Asymmetric bool - Key string -} - -// Additional public methods accessible through API for pss -type API struct { - *Pss -} - -func NewAPI(ps *Pss) *API { - return &API{Pss: ps} -} - -// Creates a new subscription for the caller. Enables external handling of incoming messages. -// -// A new handler is registered in pss for the supplied topic -// -// All incoming messages to the node matching this topic will be encapsulated in the APIMsg -// struct and sent to the subscriber -func (pssapi *API) Receive(ctx context.Context, topic Topic, raw bool, prox bool) (*rpc.Subscription, error) { - notifier, supported := rpc.NotifierFromContext(ctx) - if !supported { - return nil, fmt.Errorf("Subscribe not supported") - } - - psssub := notifier.CreateSubscription() - - hndlr := NewHandler(func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - apimsg := &APIMsg{ - Msg: hexutil.Bytes(msg), - Asymmetric: asymmetric, - Key: keyid, - } - if err := notifier.Notify(psssub.ID, apimsg); err != nil { - log.Warn(fmt.Sprintf("notification on pss sub topic rpc (sub %v) msg %v failed!", psssub.ID, msg)) - } - return nil - }) - if raw { - hndlr.caps.raw = true - } - if prox { - hndlr.caps.prox = true - } - - deregf := pssapi.Register(&topic, hndlr) - go func() { - defer deregf() - select { - case err := <-psssub.Err(): - log.Warn(fmt.Sprintf("caught subscription error in pss sub topic %x: %v", topic, err)) - case <-notifier.Closed(): - log.Warn(fmt.Sprintf("rpc sub notifier closed")) - } - }() - - return psssub, nil -} - -func (pssapi *API) GetAddress(topic Topic, asymmetric bool, key string) (PssAddress, error) { - var addr PssAddress - if asymmetric { - peer, ok := pssapi.Pss.pubKeyPool[key][topic] - if !ok { - return nil, fmt.Errorf("pubkey/topic pair %x/%x doesn't exist", key, topic) - } - addr = peer.address - } else { - peer, ok := pssapi.Pss.symKeyPool[key][topic] - if !ok { - return nil, fmt.Errorf("symkey/topic pair %x/%x doesn't exist", key, topic) - } - addr = peer.address - - } - return addr, nil -} - -// Retrieves the node's base address in hex form -func (pssapi *API) BaseAddr() (PssAddress, error) { - return PssAddress(pssapi.Pss.BaseAddr()), nil -} - -// Retrieves the node's public key in hex form -func (pssapi *API) GetPublicKey() (keybytes hexutil.Bytes) { - key := pssapi.Pss.PublicKey() - keybytes = crypto.FromECDSAPub(key) - return keybytes -} - -// Set Public key to associate with a particular Pss peer -func (pssapi *API) SetPeerPublicKey(pubkey hexutil.Bytes, topic Topic, addr PssAddress) error { - pk, err := crypto.UnmarshalPubkey(pubkey) - if err != nil { - return fmt.Errorf("Cannot unmarshal pubkey: %x", pubkey) - } - err = pssapi.Pss.SetPeerPublicKey(pk, topic, addr) - if err != nil { - return fmt.Errorf("Invalid key: %x", pk) - } - return nil -} - -func (pssapi *API) GetSymmetricKey(symkeyid string) (hexutil.Bytes, error) { - symkey, err := pssapi.Pss.GetSymmetricKey(symkeyid) - return hexutil.Bytes(symkey), err -} - -func (pssapi *API) GetSymmetricAddressHint(topic Topic, symkeyid string) (PssAddress, error) { - return pssapi.Pss.symKeyPool[symkeyid][topic].address, nil -} - -func (pssapi *API) GetAsymmetricAddressHint(topic Topic, pubkeyid string) (PssAddress, error) { - return pssapi.Pss.pubKeyPool[pubkeyid][topic].address, nil -} - -func (pssapi *API) StringToTopic(topicstring string) (Topic, error) { - topicbytes := BytesToTopic([]byte(topicstring)) - if topicbytes == rawTopic { - return rawTopic, errors.New("Topic string hashes to 0x00000000 and cannot be used") - } - return topicbytes, nil -} - -func (pssapi *API) SendAsym(pubkeyhex string, topic Topic, msg hexutil.Bytes) error { - if err := validateMsg(msg); err != nil { - return err - } - return pssapi.Pss.SendAsym(pubkeyhex, topic, msg[:]) -} - -func (pssapi *API) SendSym(symkeyhex string, topic Topic, msg hexutil.Bytes) error { - if err := validateMsg(msg); err != nil { - return err - } - return pssapi.Pss.SendSym(symkeyhex, topic, msg[:]) -} - -func (pssapi *API) SendRaw(addr hexutil.Bytes, topic Topic, msg hexutil.Bytes) error { - if err := validateMsg(msg); err != nil { - return err - } - return pssapi.Pss.SendRaw(PssAddress(addr), topic, msg[:]) -} - -func (pssapi *API) GetPeerTopics(pubkeyhex string) ([]Topic, error) { - topics, _, err := pssapi.Pss.GetPublickeyPeers(pubkeyhex) - return topics, err - -} - -func (pssapi *API) GetPeerAddress(pubkeyhex string, topic Topic) (PssAddress, error) { - return pssapi.Pss.getPeerAddress(pubkeyhex, topic) -} - -func validateMsg(msg []byte) error { - if len(msg) == 0 { - return errors.New("invalid message length") - } - return nil -} diff --git a/swarm/pss/client/client.go b/swarm/pss/client/client.go deleted file mode 100644 index 5ee387aa79..0000000000 --- a/swarm/pss/client/client.go +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build !noclient,!noprotocol - -package client - -import ( - "context" - "errors" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/pss" -) - -const ( - handshakeRetryTimeout = 1000 - handshakeRetryCount = 3 -) - -// The pss client provides devp2p emulation over pss RPC API, -// giving access to pss methods from a different process -type Client struct { - BaseAddrHex string - - // peers - peerPool map[pss.Topic]map[string]*pssRPCRW - protos map[pss.Topic]*p2p.Protocol - - // rpc connections - rpc *rpc.Client - subs []*rpc.ClientSubscription - - // channels - topicsC chan []byte - quitC chan struct{} - - poolMu sync.Mutex -} - -// implements p2p.MsgReadWriter -type pssRPCRW struct { - *Client - topic string - msgC chan []byte - addr pss.PssAddress - pubKeyId string - lastSeen time.Time - closed bool -} - -func (c *Client) newpssRPCRW(pubkeyid string, addr pss.PssAddress, topicobj pss.Topic) (*pssRPCRW, error) { - topic := topicobj.String() - err := c.rpc.Call(nil, "pss_setPeerPublicKey", pubkeyid, topic, hexutil.Encode(addr[:])) - if err != nil { - return nil, fmt.Errorf("setpeer %s %s: %v", topic, pubkeyid, err) - } - return &pssRPCRW{ - Client: c, - topic: topic, - msgC: make(chan []byte), - addr: addr, - pubKeyId: pubkeyid, - }, nil -} - -func (rw *pssRPCRW) ReadMsg() (p2p.Msg, error) { - msg := <-rw.msgC - log.Trace("pssrpcrw read", "msg", msg) - pmsg, err := pss.ToP2pMsg(msg) - if err != nil { - return p2p.Msg{}, err - } - - return pmsg, nil -} - -// If only one message slot left -// then new is requested through handshake -// if buffer is empty, handshake request blocks until return -// after which pointer is changed to first new key in buffer -// will fail if: -// - any api calls fail -// - handshake retries are exhausted without reply, -// - send fails -func (rw *pssRPCRW) WriteMsg(msg p2p.Msg) error { - log.Trace("got writemsg pssclient", "msg", msg) - if rw.closed { - return fmt.Errorf("connection closed") - } - rlpdata := make([]byte, msg.Size) - msg.Payload.Read(rlpdata) - pmsg, err := rlp.EncodeToBytes(pss.ProtocolMsg{ - Code: msg.Code, - Size: msg.Size, - Payload: rlpdata, - }) - if err != nil { - return err - } - - // Get the keys we have - var symkeyids []string - err = rw.Client.rpc.Call(&symkeyids, "pss_getHandshakeKeys", rw.pubKeyId, rw.topic, false, true) - if err != nil { - return err - } - - // Check the capacity of the first key - var symkeycap uint16 - if len(symkeyids) > 0 { - err = rw.Client.rpc.Call(&symkeycap, "pss_getHandshakeKeyCapacity", symkeyids[0]) - if err != nil { - return err - } - } - - err = rw.Client.rpc.Call(nil, "pss_sendSym", symkeyids[0], rw.topic, hexutil.Encode(pmsg)) - if err != nil { - return err - } - - // If this is the last message it is valid for, initiate new handshake - if symkeycap == 1 { - var retries int - var sync bool - // if it's the only remaining key, make sure we don't continue until we have new ones for further writes - if len(symkeyids) == 1 { - sync = true - } - // initiate handshake - _, err := rw.handshake(retries, sync, false) - if err != nil { - log.Warn("failing", "err", err) - return err - } - } - return nil -} - -// retry and synchronicity wrapper for handshake api call -// returns first new symkeyid upon successful execution -func (rw *pssRPCRW) handshake(retries int, sync bool, flush bool) (string, error) { - - var symkeyids []string - var i int - // request new keys - // if the key buffer was depleted, make this as a blocking call and try several times before giving up - for i = 0; i < 1+retries; i++ { - log.Debug("handshake attempt pssrpcrw", "pubkeyid", rw.pubKeyId, "topic", rw.topic, "sync", sync) - err := rw.Client.rpc.Call(&symkeyids, "pss_handshake", rw.pubKeyId, rw.topic, sync, flush) - if err == nil { - var keyid string - if sync { - keyid = symkeyids[0] - } - return keyid, nil - } - if i-1+retries > 1 { - time.Sleep(time.Millisecond * handshakeRetryTimeout) - } - } - - return "", fmt.Errorf("handshake failed after %d attempts", i) -} - -// Custom constructor -// -// Provides direct access to the rpc object -func NewClient(rpcurl string) (*Client, error) { - rpcclient, err := rpc.Dial(rpcurl) - if err != nil { - return nil, err - } - - client, err := NewClientWithRPC(rpcclient) - if err != nil { - return nil, err - } - return client, nil -} - -// Main constructor -// -// The 'rpcclient' parameter allows passing a in-memory rpc client to act as the remote websocket RPC. -func NewClientWithRPC(rpcclient *rpc.Client) (*Client, error) { - client := newClient() - client.rpc = rpcclient - err := client.rpc.Call(&client.BaseAddrHex, "pss_baseAddr") - if err != nil { - return nil, fmt.Errorf("cannot get pss node baseaddress: %v", err) - } - return client, nil -} - -func newClient() (client *Client) { - client = &Client{ - quitC: make(chan struct{}), - peerPool: make(map[pss.Topic]map[string]*pssRPCRW), - protos: make(map[pss.Topic]*p2p.Protocol), - } - return -} - -// Mounts a new devp2p protcool on the pss connection -// -// the protocol is aliased as a "pss topic" -// uses normal devp2p send and incoming message handler routines from the p2p/protocols package -// -// when an incoming message is received from a peer that is not yet known to the client, -// this peer object is instantiated, and the protocol is run on it. -func (c *Client) RunProtocol(ctx context.Context, proto *p2p.Protocol) error { - topicobj := pss.BytesToTopic([]byte(fmt.Sprintf("%s:%d", proto.Name, proto.Version))) - topichex := topicobj.String() - msgC := make(chan pss.APIMsg) - c.peerPool[topicobj] = make(map[string]*pssRPCRW) - sub, err := c.rpc.Subscribe(ctx, "pss", msgC, "receive", topichex, false, false) - if err != nil { - return fmt.Errorf("pss event subscription failed: %v", err) - } - c.subs = append(c.subs, sub) - err = c.rpc.Call(nil, "pss_addHandshake", topichex) - if err != nil { - return fmt.Errorf("pss handshake activation failed: %v", err) - } - - // dispatch incoming messages - go func() { - for { - select { - case msg := <-msgC: - // we only allow sym msgs here - if msg.Asymmetric { - continue - } - // we get passed the symkeyid - // need the symkey itself to resolve to peer's pubkey - var pubkeyid string - err = c.rpc.Call(&pubkeyid, "pss_getHandshakePublicKey", msg.Key) - if err != nil || pubkeyid == "" { - log.Trace("proto err or no pubkey", "err", err, "symkeyid", msg.Key) - continue - } - // if we don't have the peer on this protocol already, create it - // this is more or less the same as AddPssPeer, less the handshake initiation - if c.peerPool[topicobj][pubkeyid] == nil { - var addrhex string - err := c.rpc.Call(&addrhex, "pss_getAddress", topichex, false, msg.Key) - if err != nil { - log.Trace(err.Error()) - continue - } - addrbytes, err := hexutil.Decode(addrhex) - if err != nil { - log.Trace(err.Error()) - break - } - addr := pss.PssAddress(addrbytes) - rw, err := c.newpssRPCRW(pubkeyid, addr, topicobj) - if err != nil { - break - } - c.peerPool[topicobj][pubkeyid] = rw - p := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%v", addr), []p2p.Cap{}) - go proto.Run(p, c.peerPool[topicobj][pubkeyid]) - } - go func() { - c.peerPool[topicobj][pubkeyid].msgC <- msg.Msg - }() - case <-c.quitC: - return - } - } - }() - - c.protos[topicobj] = proto - return nil -} - -// Always call this to ensure that we exit cleanly -func (c *Client) Close() error { - for _, s := range c.subs { - s.Unsubscribe() - } - return nil -} - -// Add a pss peer (public key) and run the protocol on it -// -// client.RunProtocol with matching topic must have been -// run prior to adding the peer, or this method will -// return an error. -// -// The key must exist in the key store of the pss node -// before the peer is added. The method will return an error -// if it is not. -func (c *Client) AddPssPeer(pubkeyid string, addr []byte, spec *protocols.Spec) error { - topic := pss.ProtocolTopic(spec) - if c.peerPool[topic] == nil { - return errors.New("addpeer on unset topic") - } - if c.peerPool[topic][pubkeyid] == nil { - rw, err := c.newpssRPCRW(pubkeyid, addr, topic) - if err != nil { - return err - } - _, err = rw.handshake(handshakeRetryCount, true, true) - if err != nil { - return err - } - c.poolMu.Lock() - c.peerPool[topic][pubkeyid] = rw - c.poolMu.Unlock() - p := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%v", addr), []p2p.Cap{}) - go c.protos[topic].Run(p, c.peerPool[topic][pubkeyid]) - } - return nil -} - -// Remove a pss peer -// -// TODO: underlying cleanup -func (c *Client) RemovePssPeer(pubkeyid string, spec *protocols.Spec) { - log.Debug("closing pss client peer", "pubkey", pubkeyid, "protoname", spec.Name, "protoversion", spec.Version) - c.poolMu.Lock() - defer c.poolMu.Unlock() - topic := pss.ProtocolTopic(spec) - c.peerPool[topic][pubkeyid].closed = true - delete(c.peerPool[topic], pubkeyid) -} diff --git a/swarm/pss/client/client_test.go b/swarm/pss/client/client_test.go deleted file mode 100644 index 1bd340cf04..0000000000 --- a/swarm/pss/client/client_test.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package client - -import ( - "bytes" - "context" - "flag" - "fmt" - "math/rand" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/pss" - "github.com/ethereum/go-ethereum/swarm/state" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" -) - -type protoCtrl struct { - C chan bool - protocol *pss.Protocol - run func(*p2p.Peer, p2p.MsgReadWriter) error -} - -var ( - debugdebugflag = flag.Bool("vv", false, "veryverbose") - debugflag = flag.Bool("v", false, "verbose") - w *whisper.Whisper - wapi *whisper.PublicWhisperAPI - // custom logging - psslogmain log.Logger - pssprotocols map[string]*protoCtrl - sendLimit = uint16(256) -) - -var services = newServices() - -func init() { - flag.Parse() - rand.Seed(time.Now().Unix()) - - adapters.RegisterServices(services) - - loglevel := log.LvlInfo - if *debugflag { - loglevel = log.LvlDebug - } else if *debugdebugflag { - loglevel = log.LvlTrace - } - - psslogmain = log.New("psslog", "*") - hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) - hf := log.LvlFilterHandler(loglevel, hs) - h := log.CallerFileHandler(hf) - log.Root().SetHandler(h) - - w = whisper.New(&whisper.DefaultConfig) - wapi = whisper.NewPublicWhisperAPI(w) - - pssprotocols = make(map[string]*protoCtrl) -} - -// ping pong exchange across one expired symkey -func TestClientHandshake(t *testing.T) { - sendLimit = 3 - - clients, err := setupNetwork(2) - if err != nil { - t.Fatal(err) - } - - lpsc, err := NewClientWithRPC(clients[0]) - if err != nil { - t.Fatal(err) - } - rpsc, err := NewClientWithRPC(clients[1]) - if err != nil { - t.Fatal(err) - } - lpssping := &pss.Ping{ - OutC: make(chan bool), - InC: make(chan bool), - Pong: false, - } - rpssping := &pss.Ping{ - OutC: make(chan bool), - InC: make(chan bool), - Pong: false, - } - lproto := pss.NewPingProtocol(lpssping) - rproto := pss.NewPingProtocol(rpssping) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - err = lpsc.RunProtocol(ctx, lproto) - if err != nil { - t.Fatal(err) - } - err = rpsc.RunProtocol(ctx, rproto) - if err != nil { - t.Fatal(err) - } - topic := pss.PingTopic.String() - - var loaddr string - err = clients[0].Call(&loaddr, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 1 baseaddr fail: %v", err) - } - var roaddr string - err = clients[1].Call(&roaddr, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 2 baseaddr fail: %v", err) - } - - var lpubkey string - err = clients[0].Call(&lpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 1 pubkey fail: %v", err) - } - var rpubkey string - err = clients[1].Call(&rpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 2 pubkey fail: %v", err) - } - - err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddr) - if err != nil { - t.Fatal(err) - } - err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddr) - if err != nil { - t.Fatal(err) - } - - time.Sleep(time.Second) - - roaddrbytes, err := hexutil.Decode(roaddr) - if err != nil { - t.Fatal(err) - } - err = lpsc.AddPssPeer(rpubkey, roaddrbytes, pss.PingProtocol) - if err != nil { - t.Fatal(err) - } - - time.Sleep(time.Second) - - for i := uint16(0); i <= sendLimit; i++ { - lpssping.OutC <- false - got := <-rpssping.InC - log.Warn("ok", "idx", i, "got", got) - time.Sleep(time.Second) - } - - rw := lpsc.peerPool[pss.PingTopic][rpubkey] - lpsc.RemovePssPeer(rpubkey, pss.PingProtocol) - if err := rw.WriteMsg(p2p.Msg{ - Size: 3, - Payload: bytes.NewReader([]byte("foo")), - }); err == nil { - t.Fatalf("expected error on write") - } -} - -func setupNetwork(numnodes int) (clients []*rpc.Client, err error) { - nodes := make([]*simulations.Node, numnodes) - clients = make([]*rpc.Client, numnodes) - if numnodes < 2 { - return nil, fmt.Errorf("Minimum two nodes in network") - } - adapter := adapters.NewSimAdapter(services) - net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - ID: "0", - DefaultService: "bzz", - }) - for i := 0; i < numnodes; i++ { - nodeconf := adapters.RandomNodeConfig() - nodeconf.Services = []string{"bzz", "pss"} - nodes[i], err = net.NewNodeWithConfig(nodeconf) - if err != nil { - return nil, fmt.Errorf("error creating node 1: %v", err) - } - err = net.Start(nodes[i].ID()) - if err != nil { - return nil, fmt.Errorf("error starting node 1: %v", err) - } - if i > 0 { - err = net.Connect(nodes[i].ID(), nodes[i-1].ID()) - if err != nil { - return nil, fmt.Errorf("error connecting nodes: %v", err) - } - } - clients[i], err = nodes[i].Client() - if err != nil { - return nil, fmt.Errorf("create node 1 rpc client fail: %v", err) - } - } - if numnodes > 2 { - err = net.Connect(nodes[0].ID(), nodes[len(nodes)-1].ID()) - if err != nil { - return nil, fmt.Errorf("error connecting first and last nodes") - } - } - return clients, nil -} - -func newServices() adapters.Services { - stateStore := state.NewInmemoryStore() - kademlias := make(map[enode.ID]*network.Kademlia) - kademlia := func(id enode.ID) *network.Kademlia { - if k, ok := kademlias[id]; ok { - return k - } - params := network.NewKadParams() - params.NeighbourhoodSize = 2 - params.MaxBinSize = 3 - params.MinBinSize = 1 - params.MaxRetries = 1000 - params.RetryExponent = 2 - params.RetryInterval = 1000000 - kademlias[id] = network.NewKademlia(id[:], params) - return kademlias[id] - } - return adapters.Services{ - "pss": func(ctx *adapters.ServiceContext) (node.Service, error) { - ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctxlocal) - if err != nil { - return nil, err - } - privkey, err := w.GetPrivateKey(keys) - if err != nil { - return nil, err - } - psparams := pss.NewPssParams().WithPrivateKey(privkey) - pskad := kademlia(ctx.Config.ID) - ps, err := pss.NewPss(pskad, psparams) - if err != nil { - return nil, err - } - pshparams := pss.NewHandshakeParams() - pshparams.SymKeySendLimit = sendLimit - err = pss.SetHandshakeController(ps, pshparams) - if err != nil { - return nil, fmt.Errorf("handshake controller fail: %v", err) - } - return ps, nil - }, - "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { - addr := network.NewAddr(ctx.Config.Node()) - hp := network.NewHiveParams() - hp.Discovery = false - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - return network.NewBzz(config, kademlia(ctx.Config.ID), stateStore, nil, nil), nil - }, - } -} diff --git a/swarm/pss/client/doc.go b/swarm/pss/client/doc.go deleted file mode 100644 index 080af45a9a..0000000000 --- a/swarm/pss/client/doc.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// simple abstraction for implementing pss functionality -// -// the pss client library aims to simplify usage of the p2p.protocols package over pss -// -// IO is performed using the ordinary p2p.MsgReadWriter interface, which transparently communicates with a pss node via RPC using websockets as transport layer, using methods in the PssAPI class in the swarm/pss package -// -// -// Minimal-ish usage example (requires a running pss node with websocket RPC): -// -// -// import ( -// "context" -// "fmt" -// "os" -// pss "github.com/ethereum/go-ethereum/swarm/pss/client" -// "github.com/ethereum/go-ethereum/p2p/protocols" -// "github.com/ethereum/go-ethereum/p2p" -// "github.com/ethereum/go-ethereum/swarm/pot" -// "github.com/ethereum/go-ethereum/swarm/log" -// ) -// -// type FooMsg struct { -// Bar int -// } -// -// -// func fooHandler (msg interface{}) error { -// foomsg, ok := msg.(*FooMsg) -// if ok { -// log.Debug("Yay, just got a message", "msg", foomsg) -// } -// return errors.New(fmt.Sprintf("Unknown message")) -// } -// -// spec := &protocols.Spec{ -// Name: "foo", -// Version: 1, -// MaxMsgSize: 1024, -// Messages: []interface{}{ -// FooMsg{}, -// }, -// } -// -// proto := &p2p.Protocol{ -// Name: spec.Name, -// Version: spec.Version, -// Length: uint64(len(spec.Messages)), -// Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { -// pp := protocols.NewPeer(p, rw, spec) -// return pp.Run(fooHandler) -// }, -// } -// -// func implementation() { -// cfg := pss.NewClientConfig() -// psc := pss.NewClient(context.Background(), nil, cfg) -// err := psc.Start() -// if err != nil { -// log.Crit("can't start pss client") -// os.Exit(1) -// } -// -// log.Debug("connected to pss node", "bzz addr", psc.BaseAddr) -// -// err = psc.RunProtocol(proto) -// if err != nil { -// log.Crit("can't start protocol on pss websocket") -// os.Exit(1) -// } -// -// addr := pot.RandomAddress() // should be a real address, of course -// psc.AddPssPeer(addr, spec) -// -// // use the protocol for something -// -// psc.Stop() -// } -// -// BUG(test): TestIncoming test times out due to deadlock issues in the swarm hive -package client diff --git a/swarm/pss/doc.go b/swarm/pss/doc.go deleted file mode 100644 index 462c82aaad..0000000000 --- a/swarm/pss/doc.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Pss provides devp2p functionality for swarm nodes without the need for a direct tcp connection between them. -// -// Messages are encapsulated in a devp2p message structure `PssMsg`. These capsules are forwarded from node to node using ordinary tcp devp2p until it reaches its destination: The node or nodes who can successfully decrypt the message. -// -// Routing of messages is done using swarm's own kademlia routing. Optionally routing can be turned off, forcing the message to be sent to all peers, similar to the behavior of the whisper protocol. -// -// Pss is intended for messages of limited size, typically a couple of Kbytes at most. The messages themselves can be anything at all; complex data structures or non-descript byte sequences. -// -// Documentation can be found in the README file. -// -// For the current state and roadmap of pss development please see https://github.com/ethersphere/swarm/wiki/swarm-dev-progress. -// -// Please report issues on https://github.com/ethersphere/go-ethereum -// -// Feel free to ask questions in https://gitter.im/ethersphere/pss -// -// TOPICS -// -// An encrypted envelope of a pss messages always contains a Topic. This is pss' way of determining what action to take on the message. The topic is only visible for the node(s) who can decrypt the message. -// -// This "topic" is not like the subject of an email message, but a hash-like arbitrary 4 byte value. A valid topic can be generated using the `pss_*ToTopic` API methods. -// -// IDENTITY IN PSS -// -// Pss aims to achieve perfect darkness. That means that the minimum requirement for two nodes to communicate using pss is a shared secret. This secret can be an arbitrary byte slice, or a ECDSA keypair. -// -// Peer keys can manually be added to the pss node through its API calls `pss_setPeerPublicKey` and `pss_setSymmetricKey`. Keys are always coupled with a topic, and the keys will only be valid for these topics. -// -// CONNECTIONS -// -// A "connection" in pss is a purely virtual construct. There is no mechanisms in place to ensure that the remote peer actually is there. In fact, "adding" a peer involves merely the node's opinion that the peer is there. It may issue messages to that remote peer to a directly connected peer, which in turn passes it on. But if it is not present on the network - or if there is no route to it - the message will never reach its destination through mere forwarding. -// -// When implementing the devp2p protocol stack, the "adding" of a remote peer is a prerequisite for the side actually initiating the protocol communication. Adding a peer in effect "runs" the protocol on that peer, and adds an internal mapping between a topic and that peer. It also enables sending and receiving messages using the main io-construct in devp2p - the p2p.MsgReadWriter. -// -// Under the hood, pss implements its own MsgReadWriter, which bridges MsgReadWriter.WriteMsg with Pss.SendRaw, and deftly adds an InjectMsg method which pipes incoming messages to appear on the MsgReadWriter.ReadMsg channel. -// -// An incoming connection is nothing more than an actual PssMsg appearing with a certain Topic. If a Handler har been registered to that Topic, the message will be passed to it. This constitutes a "new" connection if: -// -// - The pss node never called AddPeer with this combination of remote peer address and topic, and -// -// - The pss node never received a PssMsg from this remote peer with this specific Topic before. -// -// If it is a "new" connection, the protocol will be "run" on the remote peer, in the same manner as if it was pre-emptively added. -// -package pss diff --git a/swarm/pss/forwarding_test.go b/swarm/pss/forwarding_test.go deleted file mode 100644 index 746d4dc404..0000000000 --- a/swarm/pss/forwarding_test.go +++ /dev/null @@ -1,357 +0,0 @@ -package pss - -import ( - "fmt" - "math/rand" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/pot" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" -) - -type testCase struct { - name string - recipient []byte - peers []pot.Address - expected []int - exclusive bool - nFails int - success bool - errors string -} - -var testCases []testCase - -// the purpose of this test is to see that pss.forward() function correctly -// selects the peers for message forwarding, depending on the message address -// and kademlia constellation. -func TestForwardBasic(t *testing.T) { - baseAddrBytes := make([]byte, 32) - for i := 0; i < len(baseAddrBytes); i++ { - baseAddrBytes[i] = 0xFF - } - var c testCase - base := pot.NewAddressFromBytes(baseAddrBytes) - var peerAddresses []pot.Address - const depth = 10 - for i := 0; i <= depth; i++ { - // add two peers for each proximity order - a := pot.RandomAddressAt(base, i) - peerAddresses = append(peerAddresses, a) - a = pot.RandomAddressAt(base, i) - peerAddresses = append(peerAddresses, a) - } - - // skip one level, add one peer at one level deeper. - // as a result, we will have an edge case of three peers in nearest neighbours' bin. - peerAddresses = append(peerAddresses, pot.RandomAddressAt(base, depth+2)) - - kad := network.NewKademlia(base[:], network.NewKadParams()) - ps := createPss(t, kad) - defer ps.Stop() - addPeers(kad, peerAddresses) - - const firstNearest = depth * 2 // shallowest peer in the nearest neighbours' bin - nearestNeighbours := []int{firstNearest, firstNearest + 1, firstNearest + 2} - var all []int // indices of all the peers - for i := 0; i < len(peerAddresses); i++ { - all = append(all, i) - } - - for i := 0; i < len(peerAddresses); i++ { - // send msg directly to the known peers (recipient address == peer address) - c = testCase{ - name: fmt.Sprintf("Send direct to known, id: [%d]", i), - recipient: peerAddresses[i][:], - peers: peerAddresses, - expected: []int{i}, - exclusive: false, - } - testCases = append(testCases, c) - } - - for i := 0; i < firstNearest; i++ { - // send random messages with proximity orders, corresponding to PO of each bin, - // with one peer being closer to the recipient address - a := pot.RandomAddressAt(peerAddresses[i], 64) - c = testCase{ - name: fmt.Sprintf("Send random to each PO, id: [%d]", i), - recipient: a[:], - peers: peerAddresses, - expected: []int{i}, - exclusive: false, - } - testCases = append(testCases, c) - } - - for i := 0; i < firstNearest; i++ { - // send random messages with proximity orders, corresponding to PO of each bin, - // with random proximity relative to the recipient address - po := i / 2 - a := pot.RandomAddressAt(base, po) - c = testCase{ - name: fmt.Sprintf("Send direct to known, id: [%d]", i), - recipient: a[:], - peers: peerAddresses, - expected: []int{po * 2, po*2 + 1}, - exclusive: true, - } - testCases = append(testCases, c) - } - - for i := firstNearest; i < len(peerAddresses); i++ { - // recipient address falls into the nearest neighbours' bin - a := pot.RandomAddressAt(base, i) - c = testCase{ - name: fmt.Sprintf("recipient address falls into the nearest neighbours' bin, id: [%d]", i), - recipient: a[:], - peers: peerAddresses, - expected: nearestNeighbours, - exclusive: false, - } - testCases = append(testCases, c) - } - - // send msg with proximity order much deeper than the deepest nearest neighbour - a2 := pot.RandomAddressAt(base, 77) - c = testCase{ - name: "proximity order much deeper than the deepest nearest neighbour", - recipient: a2[:], - peers: peerAddresses, - expected: nearestNeighbours, - exclusive: false, - } - testCases = append(testCases, c) - - // test with partial addresses - const part = 12 - - for i := 0; i < firstNearest; i++ { - // send messages with partial address falling into different proximity orders - po := i / 2 - if i%8 != 0 { - c = testCase{ - name: fmt.Sprintf("partial address falling into different proximity orders, id: [%d]", i), - recipient: peerAddresses[i][:i], - peers: peerAddresses, - expected: []int{po * 2, po*2 + 1}, - exclusive: true, - } - testCases = append(testCases, c) - } - c = testCase{ - name: fmt.Sprintf("extended partial address falling into different proximity orders, id: [%d]", i), - recipient: peerAddresses[i][:part], - peers: peerAddresses, - expected: []int{po * 2, po*2 + 1}, - exclusive: true, - } - testCases = append(testCases, c) - } - - for i := firstNearest; i < len(peerAddresses); i++ { - // partial address falls into the nearest neighbours' bin - c = testCase{ - name: fmt.Sprintf("partial address falls into the nearest neighbours' bin, id: [%d]", i), - recipient: peerAddresses[i][:part], - peers: peerAddresses, - expected: nearestNeighbours, - exclusive: false, - } - testCases = append(testCases, c) - } - - // partial address with proximity order deeper than any of the nearest neighbour - a3 := pot.RandomAddressAt(base, part) - c = testCase{ - name: "partial address with proximity order deeper than any of the nearest neighbour", - recipient: a3[:part], - peers: peerAddresses, - expected: nearestNeighbours, - exclusive: false, - } - testCases = append(testCases, c) - - // special cases where partial address matches a large group of peers - - // zero bytes of address is given, msg should be delivered to all the peers - c = testCase{ - name: "zero bytes of address is given", - recipient: []byte{}, - peers: peerAddresses, - expected: all, - exclusive: false, - } - testCases = append(testCases, c) - - // luminous radius of 8 bits, proximity order 8 - indexAtPo8 := 16 - c = testCase{ - name: "luminous radius of 8 bits", - recipient: []byte{0xFF}, - peers: peerAddresses, - expected: all[indexAtPo8:], - exclusive: false, - } - testCases = append(testCases, c) - - // luminous radius of 256 bits, proximity order 8 - a4 := pot.Address{} - a4[0] = 0xFF - c = testCase{ - name: "luminous radius of 256 bits", - recipient: a4[:], - peers: peerAddresses, - expected: []int{indexAtPo8, indexAtPo8 + 1}, - exclusive: true, - } - testCases = append(testCases, c) - - // check correct behaviour in case send fails - for i := 2; i < firstNearest-3; i += 2 { - po := i / 2 - // send random messages with proximity orders, corresponding to PO of each bin, - // with different numbers of failed attempts. - // msg should be received by only one of the deeper peers. - a := pot.RandomAddressAt(base, po) - c = testCase{ - name: fmt.Sprintf("Send direct to known, id: [%d]", i), - recipient: a[:], - peers: peerAddresses, - expected: all[i+1:], - exclusive: true, - nFails: rand.Int()%3 + 2, - } - testCases = append(testCases, c) - } - - for _, c := range testCases { - testForwardMsg(t, ps, &c) - } -} - -// this function tests the forwarding of a single message. the recipient address is passed as param, -// along with addresses of all peers, and indices of those peers which are expected to receive the message. -func testForwardMsg(t *testing.T, ps *Pss, c *testCase) { - recipientAddr := c.recipient - peers := c.peers - expected := c.expected - exclusive := c.exclusive - nFails := c.nFails - tries := 0 // number of previous failed tries - - resultMap := make(map[pot.Address]int) - - defer func() { sendFunc = sendMsg }() - sendFunc = func(_ *Pss, sp *network.Peer, _ *PssMsg) bool { - if tries < nFails { - tries++ - return false - } - a := pot.NewAddressFromBytes(sp.Address()) - resultMap[a]++ - return true - } - - msg := newTestMsg(recipientAddr) - ps.forward(msg) - - // check test results - var fail bool - precision := len(recipientAddr) - if precision > 4 { - precision = 4 - } - s := fmt.Sprintf("test [%s]\nmsg address: %x..., radius: %d", c.name, recipientAddr[:precision], 8*len(recipientAddr)) - - // false negatives (expected message didn't reach peer) - if exclusive { - var cnt int - for _, i := range expected { - a := peers[i] - cnt += resultMap[a] - resultMap[a] = 0 - } - if cnt != 1 { - s += fmt.Sprintf("\n%d messages received by %d peers with indices: [%v]", cnt, len(expected), expected) - fail = true - } - } else { - for _, i := range expected { - a := peers[i] - received := resultMap[a] - if received != 1 { - s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", i, a[:4], received) - fail = true - } - resultMap[a] = 0 - } - } - - // false positives (unexpected message reached peer) - for k, v := range resultMap { - if v != 0 { - // find the index of the false positive peer - var j int - for j = 0; j < len(peers); j++ { - if peers[j] == k { - break - } - } - s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", j, k[:4], v) - fail = true - } - } - - if fail { - t.Fatal(s) - } -} - -func addPeers(kad *network.Kademlia, addresses []pot.Address) { - for _, a := range addresses { - p := newTestDiscoveryPeer(a, kad) - kad.On(p) - } -} - -func createPss(t *testing.T, kad *network.Kademlia) *Pss { - privKey, err := crypto.GenerateKey() - pssp := NewPssParams().WithPrivateKey(privKey) - ps, err := NewPss(kad, pssp) - if err != nil { - t.Fatal(err.Error()) - } - return ps -} - -func newTestDiscoveryPeer(addr pot.Address, kad *network.Kademlia) *network.Peer { - rw := &p2p.MsgPipeRW{} - p := p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{}) - pp := protocols.NewPeer(p, rw, &protocols.Spec{}) - bp := &network.BzzPeer{ - Peer: pp, - BzzAddr: &network.BzzAddr{ - OAddr: addr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", addr[:])), - }, - } - return network.NewPeer(bp, kad) -} - -func newTestMsg(addr []byte) *PssMsg { - msg := newPssMsg(&msgParams{}) - msg.To = addr[:] - msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix()) - msg.Payload = &whisper.Envelope{ - Topic: [4]byte{}, - Data: []byte("i have nothing to hide"), - } - return msg -} diff --git a/swarm/pss/handshake.go b/swarm/pss/handshake.go deleted file mode 100644 index ec3bffa30a..0000000000 --- a/swarm/pss/handshake.go +++ /dev/null @@ -1,592 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build !nopsshandshake - -package pss - -import ( - "context" - "errors" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/log" -) - -const ( - IsActiveHandshake = true -) - -var ( - ctrlSingleton *HandshakeController -) - -const ( - defaultSymKeyRequestTimeout = 1000 * 8 // max wait ms to receive a response to a handshake symkey request - defaultSymKeyExpiryTimeout = 1000 * 10 // ms to wait before allowing garbage collection of an expired symkey - defaultSymKeySendLimit = 256 // amount of messages a symkey is valid for - defaultSymKeyCapacity = 4 // max number of symkeys to store/send simultaneously -) - -// symmetric key exchange message payload -type handshakeMsg struct { - From []byte - Limit uint16 - Keys [][]byte - Request uint8 - Topic Topic -} - -// internal representation of an individual symmetric key -type handshakeKey struct { - symKeyID *string - pubKeyID *string - limit uint16 - count uint16 - expiredAt time.Time -} - -// container for all in- and outgoing keys -// for one particular peer (public key) and topic -type handshake struct { - outKeys []handshakeKey - inKeys []handshakeKey -} - -// Initialization parameters for the HandshakeController -// -// SymKeyRequestExpiry: Timeout for waiting for a handshake reply -// (default 8000 ms) -// -// SymKeySendLimit: Amount of messages symmetric keys issues by -// this node is valid for (default 256) -// -// SymKeyCapacity: Ideal (and maximum) amount of symmetric keys -// held per direction per peer (default 4) -type HandshakeParams struct { - SymKeyRequestTimeout time.Duration - SymKeyExpiryTimeout time.Duration - SymKeySendLimit uint16 - SymKeyCapacity uint8 -} - -// Sane defaults for HandshakeController initialization -func NewHandshakeParams() *HandshakeParams { - return &HandshakeParams{ - SymKeyRequestTimeout: defaultSymKeyRequestTimeout * time.Millisecond, - SymKeyExpiryTimeout: defaultSymKeyExpiryTimeout * time.Millisecond, - SymKeySendLimit: defaultSymKeySendLimit, - SymKeyCapacity: defaultSymKeyCapacity, - } -} - -// Singleton object enabling semi-automatic Diffie-Hellman -// exchange of ephemeral symmetric keys -type HandshakeController struct { - pss *Pss - keyC map[string]chan []string // adds a channel to report when a handshake succeeds - keyCMu sync.Mutex // protects keyC map - lock sync.Mutex - symKeyRequestTimeout time.Duration - symKeyExpiryTimeout time.Duration - symKeySendLimit uint16 - symKeyCapacity uint8 - symKeyIndex map[string]*handshakeKey - handshakes map[string]map[Topic]*handshake - deregisterFuncs map[Topic]func() -} - -// Attach HandshakeController to pss node -// -// Must be called before starting the pss node service -func SetHandshakeController(pss *Pss, params *HandshakeParams) error { - ctrl := &HandshakeController{ - pss: pss, - keyC: make(map[string]chan []string), - symKeyRequestTimeout: params.SymKeyRequestTimeout, - symKeyExpiryTimeout: params.SymKeyExpiryTimeout, - symKeySendLimit: params.SymKeySendLimit, - symKeyCapacity: params.SymKeyCapacity, - symKeyIndex: make(map[string]*handshakeKey), - handshakes: make(map[string]map[Topic]*handshake), - deregisterFuncs: make(map[Topic]func()), - } - api := &HandshakeAPI{ - namespace: "pss", - ctrl: ctrl, - } - pss.addAPI(rpc.API{ - Namespace: api.namespace, - Version: "0.2", - Service: api, - Public: true, - }) - ctrlSingleton = ctrl - return nil -} - -// Return all unexpired symmetric keys from store by -// peer (public key), topic and specified direction -func (ctl *HandshakeController) validKeys(pubkeyid string, topic *Topic, in bool) (validkeys []*string) { - ctl.lock.Lock() - defer ctl.lock.Unlock() - now := time.Now() - if _, ok := ctl.handshakes[pubkeyid]; !ok { - return []*string{} - } else if _, ok := ctl.handshakes[pubkeyid][*topic]; !ok { - return []*string{} - } - var keystore *[]handshakeKey - if in { - keystore = &(ctl.handshakes[pubkeyid][*topic].inKeys) - } else { - keystore = &(ctl.handshakes[pubkeyid][*topic].outKeys) - } - - for _, key := range *keystore { - if key.limit <= key.count { - ctl.releaseKeyNoLock(*key.symKeyID, topic) - } else if !key.expiredAt.IsZero() && key.expiredAt.Before(now) { - ctl.releaseKeyNoLock(*key.symKeyID, topic) - } else { - validkeys = append(validkeys, key.symKeyID) - } - } - return -} - -// Add all given symmetric keys with validity limits to store by -// peer (public key), topic and specified direction -func (ctl *HandshakeController) updateKeys(pubkeyid string, topic *Topic, in bool, symkeyids []string, limit uint16) { - ctl.lock.Lock() - defer ctl.lock.Unlock() - if _, ok := ctl.handshakes[pubkeyid]; !ok { - ctl.handshakes[pubkeyid] = make(map[Topic]*handshake) - - } - if ctl.handshakes[pubkeyid][*topic] == nil { - ctl.handshakes[pubkeyid][*topic] = &handshake{} - } - var keystore *[]handshakeKey - expire := time.Now() - if in { - keystore = &(ctl.handshakes[pubkeyid][*topic].inKeys) - } else { - keystore = &(ctl.handshakes[pubkeyid][*topic].outKeys) - expire = expire.Add(time.Millisecond * ctl.symKeyExpiryTimeout) - } - for _, storekey := range *keystore { - storekey.expiredAt = expire - } - for i := 0; i < len(symkeyids); i++ { - storekey := handshakeKey{ - symKeyID: &symkeyids[i], - pubKeyID: &pubkeyid, - limit: limit, - } - *keystore = append(*keystore, storekey) - ctl.pss.mx.Lock() - ctl.pss.symKeyPool[*storekey.symKeyID][*topic].protected = true - ctl.pss.mx.Unlock() - } - for i := 0; i < len(*keystore); i++ { - ctl.symKeyIndex[*(*keystore)[i].symKeyID] = &((*keystore)[i]) - } -} - -func (ctl *HandshakeController) releaseKey(symkeyid string, topic *Topic) bool { - ctl.lock.Lock() - defer ctl.lock.Unlock() - return ctl.releaseKeyNoLock(symkeyid, topic) -} - -// Expire a symmetric key, making it eligible for garbage collection -func (ctl *HandshakeController) releaseKeyNoLock(symkeyid string, topic *Topic) bool { - if ctl.symKeyIndex[symkeyid] == nil { - log.Debug("no symkey", "symkeyid", symkeyid) - return false - } - ctl.symKeyIndex[symkeyid].expiredAt = time.Now() - log.Debug("handshake release", "symkeyid", symkeyid) - return true -} - -// Checks all symmetric keys in given direction(s) by -// specified peer (public key) and topic for expiry. -// Expired means: -// - expiry timestamp is set, and grace period is exceeded -// - message validity limit is reached -func (ctl *HandshakeController) cleanHandshake(pubkeyid string, topic *Topic, in bool, out bool) int { - ctl.lock.Lock() - defer ctl.lock.Unlock() - var deletecount int - var deletes []string - now := time.Now() - handshake := ctl.handshakes[pubkeyid][*topic] - log.Debug("handshake clean", "pubkey", pubkeyid, "topic", topic) - if in { - for i, key := range handshake.inKeys { - if key.expiredAt.Before(now) || (key.expiredAt.IsZero() && key.limit <= key.count) { - log.Trace("handshake in clean remove", "symkeyid", *key.symKeyID) - deletes = append(deletes, *key.symKeyID) - handshake.inKeys[deletecount] = handshake.inKeys[i] - deletecount++ - } - } - handshake.inKeys = handshake.inKeys[:len(handshake.inKeys)-deletecount] - } - if out { - deletecount = 0 - for i, key := range handshake.outKeys { - if key.expiredAt.Before(now) && (key.expiredAt.IsZero() && key.limit <= key.count) { - log.Trace("handshake out clean remove", "symkeyid", *key.symKeyID) - deletes = append(deletes, *key.symKeyID) - handshake.outKeys[deletecount] = handshake.outKeys[i] - deletecount++ - } - } - handshake.outKeys = handshake.outKeys[:len(handshake.outKeys)-deletecount] - } - for _, keyid := range deletes { - delete(ctl.symKeyIndex, keyid) - ctl.pss.symKeyPool[keyid][*topic].protected = false - } - return len(deletes) -} - -// Runs cleanHandshake() on all peers and topics -func (ctl *HandshakeController) clean() { - peerpubkeys := ctl.handshakes - for pubkeyid, peertopics := range peerpubkeys { - for topic := range peertopics { - ctl.cleanHandshake(pubkeyid, &topic, true, true) - } - } -} - -func (ctl *HandshakeController) getSymKey(symkeyid string) *handshakeKey { - ctl.lock.Lock() - defer ctl.lock.Unlock() - return ctl.symKeyIndex[symkeyid] -} - -// Passed as a PssMsg handler for the topic handshake is activated on -// Handles incoming key exchange messages and -// counts message usage by symmetric key (expiry limit control) -// Only returns error if key handler fails -func (ctl *HandshakeController) handler(msg []byte, p *p2p.Peer, asymmetric bool, symkeyid string) error { - if asymmetric { - keymsg := &handshakeMsg{} - err := rlp.DecodeBytes(msg, keymsg) - if err == nil { - err := ctl.handleKeys(symkeyid, keymsg) - if err != nil { - log.Error("handlekeys fail", "error", err) - } - return err - } - return nil - } - return ctl.registerSymKeyUse(symkeyid) -} - -func (ctl *HandshakeController) registerSymKeyUse(symkeyid string) error { - ctl.lock.Lock() - defer ctl.lock.Unlock() - - symKey, ok := ctl.symKeyIndex[symkeyid] - if !ok { - return nil - } - - if symKey.count >= symKey.limit { - return fmt.Errorf("symetric key expired (id: %s)", symkeyid) - } - symKey.count++ - - receiver := common.ToHex(crypto.FromECDSAPub(ctl.pss.PublicKey())) - log.Trace("increment symkey recv use", "symsymkeyid", symkeyid, "count", symKey.count, "limit", symKey.limit, "receiver", receiver) - - return nil -} - -// Handle incoming key exchange message -// Add keys received from peer to store -// and enerate and send the amount of keys requested by peer -// -// TODO: -// - flood guard -// - keylength check -// - update address hint if: -// 1) leftmost bytes in new address do not match stored -// 2) else, if new address is longer -func (ctl *HandshakeController) handleKeys(pubkeyid string, keymsg *handshakeMsg) error { - // new keys from peer - if len(keymsg.Keys) > 0 { - log.Debug("received handshake keys", "pubkeyid", pubkeyid, "from", keymsg.From, "count", len(keymsg.Keys)) - var sendsymkeyids []string - for _, key := range keymsg.Keys { - sendsymkey := make([]byte, len(key)) - copy(sendsymkey, key) - sendsymkeyid, err := ctl.pss.setSymmetricKey(sendsymkey, keymsg.Topic, PssAddress(keymsg.From), false, false) - if err != nil { - return err - } - sendsymkeyids = append(sendsymkeyids, sendsymkeyid) - } - if len(sendsymkeyids) > 0 { - ctl.updateKeys(pubkeyid, &keymsg.Topic, false, sendsymkeyids, keymsg.Limit) - - ctl.alertHandshake(pubkeyid, sendsymkeyids) - } - } - - // peer request for keys - if keymsg.Request > 0 { - _, err := ctl.sendKey(pubkeyid, &keymsg.Topic, keymsg.Request) - if err != nil { - return err - } - } - - return nil -} - -// Send key exchange to peer (public key) valid for `topic` -// Will send number of keys specified by `keycount` with -// validity limits specified in `msglimit` -// If number of valid outgoing keys is less than the ideal/max -// amount, a request is sent for the amount of keys to make up -// the difference -func (ctl *HandshakeController) sendKey(pubkeyid string, topic *Topic, keycount uint8) ([]string, error) { - - var requestcount uint8 - to := PssAddress{} - if _, ok := ctl.pss.pubKeyPool[pubkeyid]; !ok { - return []string{}, errors.New("Invalid public key") - } else if psp, ok := ctl.pss.pubKeyPool[pubkeyid][*topic]; ok { - to = psp.address - } - - recvkeys := make([][]byte, keycount) - recvkeyids := make([]string, keycount) - ctl.lock.Lock() - if _, ok := ctl.handshakes[pubkeyid]; !ok { - ctl.handshakes[pubkeyid] = make(map[Topic]*handshake) - } - ctl.lock.Unlock() - - // check if buffer is not full - outkeys := ctl.validKeys(pubkeyid, topic, false) - if len(outkeys) < int(ctl.symKeyCapacity) { - //requestcount = uint8(self.symKeyCapacity - uint8(len(outkeys))) - requestcount = ctl.symKeyCapacity - } - // return if there's nothing to be accomplished - if requestcount == 0 && keycount == 0 { - return []string{}, nil - } - - // generate new keys to send - for i := 0; i < len(recvkeyids); i++ { - var err error - recvkeyids[i], err = ctl.pss.GenerateSymmetricKey(*topic, to, true) - if err != nil { - return []string{}, fmt.Errorf("set receive symkey fail (pubkey %x topic %x): %v", pubkeyid, topic, err) - } - recvkeys[i], err = ctl.pss.GetSymmetricKey(recvkeyids[i]) - if err != nil { - return []string{}, fmt.Errorf("GET Generated outgoing symkey fail (pubkey %x topic %x): %v", pubkeyid, topic, err) - } - } - ctl.updateKeys(pubkeyid, topic, true, recvkeyids, ctl.symKeySendLimit) - - // encode and send the message - recvkeymsg := &handshakeMsg{ - From: ctl.pss.BaseAddr(), - Keys: recvkeys, - Request: requestcount, - Limit: ctl.symKeySendLimit, - Topic: *topic, - } - log.Debug("sending our symkeys", "pubkey", pubkeyid, "symkeys", recvkeyids, "limit", ctl.symKeySendLimit, "requestcount", requestcount, "keycount", len(recvkeys)) - recvkeybytes, err := rlp.EncodeToBytes(recvkeymsg) - if err != nil { - return []string{}, fmt.Errorf("rlp keymsg encode fail: %v", err) - } - // if the send fails it means this public key is not registered for this particular address AND topic - err = ctl.pss.SendAsym(pubkeyid, *topic, recvkeybytes) - if err != nil { - return []string{}, fmt.Errorf("Send symkey failed: %v", err) - } - return recvkeyids, nil -} - -// Enables callback for keys received from a key exchange request -func (ctl *HandshakeController) alertHandshake(pubkeyid string, symkeys []string) chan []string { - ctl.keyCMu.Lock() - defer ctl.keyCMu.Unlock() - if len(symkeys) > 0 { - if _, ok := ctl.keyC[pubkeyid]; ok { - ctl.keyC[pubkeyid] <- symkeys - close(ctl.keyC[pubkeyid]) - delete(ctl.keyC, pubkeyid) - } - return nil - } - if _, ok := ctl.keyC[pubkeyid]; !ok { - ctl.keyC[pubkeyid] = make(chan []string) - } - return ctl.keyC[pubkeyid] -} - -type HandshakeAPI struct { - namespace string - ctrl *HandshakeController -} - -// Initiate a handshake session for a peer (public key) and topic -// combination. -// -// If `sync` is set, the call will block until keys are received from peer, -// or if the handshake request times out -// -// If `flush` is set, the max amount of keys will be sent to the peer -// regardless of how many valid keys that currently exist in the store. -// -// Returns list of symmetric key ids that can be passed to pss.GetSymmetricKey() -// for retrieval of the symmetric key bytes themselves. -// -// Fails if the incoming symmetric key store is already full (and `flush` is false), -// or if the underlying key dispatcher fails -func (api *HandshakeAPI) Handshake(pubkeyid string, topic Topic, sync bool, flush bool) (keys []string, err error) { - var hsc chan []string - var keycount uint8 - if flush { - keycount = api.ctrl.symKeyCapacity - } else { - validkeys := api.ctrl.validKeys(pubkeyid, &topic, false) - keycount = api.ctrl.symKeyCapacity - uint8(len(validkeys)) - } - if keycount == 0 { - return keys, errors.New("Incoming symmetric key store is already full") - } - if sync { - hsc = api.ctrl.alertHandshake(pubkeyid, []string{}) - } - _, err = api.ctrl.sendKey(pubkeyid, &topic, keycount) - if err != nil { - return keys, err - } - if sync { - ctx, cancel := context.WithTimeout(context.Background(), api.ctrl.symKeyRequestTimeout) - defer cancel() - select { - case keys = <-hsc: - log.Trace("sync handshake response receive", "key", keys) - case <-ctx.Done(): - return []string{}, errors.New("timeout") - } - } - return keys, nil -} - -// Activate handshake functionality on a topic -func (api *HandshakeAPI) AddHandshake(topic Topic) error { - api.ctrl.deregisterFuncs[topic] = api.ctrl.pss.Register(&topic, NewHandler(api.ctrl.handler)) - return nil -} - -// Deactivate handshake functionality on a topic -func (api *HandshakeAPI) RemoveHandshake(topic *Topic) error { - if _, ok := api.ctrl.deregisterFuncs[*topic]; ok { - api.ctrl.deregisterFuncs[*topic]() - } - return nil -} - -// Returns all valid symmetric keys in store per peer (public key) -// and topic. -// -// The `in` and `out` parameters indicate for which direction(s) -// symmetric keys will be returned. -// If both are false, no keys (and no error) will be returned. -func (api *HandshakeAPI) GetHandshakeKeys(pubkeyid string, topic Topic, in bool, out bool) (keys []string, err error) { - if in { - for _, inkey := range api.ctrl.validKeys(pubkeyid, &topic, true) { - keys = append(keys, *inkey) - } - } - if out { - for _, outkey := range api.ctrl.validKeys(pubkeyid, &topic, false) { - keys = append(keys, *outkey) - } - } - return keys, nil -} - -// Returns the amount of messages the specified symmetric key -// is still valid for under the handshake scheme -func (api *HandshakeAPI) GetHandshakeKeyCapacity(symkeyid string) (uint16, error) { - storekey := api.ctrl.getSymKey(symkeyid) - if storekey == nil { - return 0, fmt.Errorf("invalid symkey id %s", symkeyid) - } - return storekey.limit - storekey.count, nil -} - -// Returns the byte representation of the public key in ascii hex -// associated with the given symmetric key -func (api *HandshakeAPI) GetHandshakePublicKey(symkeyid string) (string, error) { - storekey := api.ctrl.getSymKey(symkeyid) - if storekey == nil { - return "", fmt.Errorf("invalid symkey id %s", symkeyid) - } - return *storekey.pubKeyID, nil -} - -// Manually expire the given symkey -// -// If `flush` is set, garbage collection will be performed before returning. -// -// Returns true on successful removal, false otherwise -func (api *HandshakeAPI) ReleaseHandshakeKey(pubkeyid string, topic Topic, symkeyid string, flush bool) (removed bool, err error) { - removed = api.ctrl.releaseKey(symkeyid, &topic) - if removed && flush { - api.ctrl.cleanHandshake(pubkeyid, &topic, true, true) - } - return -} - -// Send symmetric message under the handshake scheme -// -// Overloads the pss.SendSym() API call, adding symmetric key usage count -// for message expiry control -func (api *HandshakeAPI) SendSym(symkeyid string, topic Topic, msg hexutil.Bytes) (err error) { - err = api.ctrl.pss.SendSym(symkeyid, topic, msg[:]) - if otherErr := api.ctrl.registerSymKeyUse(symkeyid); otherErr != nil { - return otherErr - } - return err -} diff --git a/swarm/pss/handshake_none.go b/swarm/pss/handshake_none.go deleted file mode 100644 index a09674be39..0000000000 --- a/swarm/pss/handshake_none.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build nopsshandshake - -package pss - -const ( - IsActiveHandshake = false -) - -func NewHandshakeParams() interface{} { - return nil -} diff --git a/swarm/pss/handshake_test.go b/swarm/pss/handshake_test.go deleted file mode 100644 index e47e4be194..0000000000 --- a/swarm/pss/handshake_test.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package pss - -import ( - "strconv" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/log" -) - -// asymmetrical key exchange between two directly connected peers -// full address, partial address (8 bytes) and empty address -func TestHandshake(t *testing.T) { - t.Skip("Handshakes have not been maintained for a longer period, and have started to fail. They should be reviewed and possible removed.") - t.Run("32", testHandshake) - t.Run("8", testHandshake) - t.Run("0", testHandshake) -} - -func testHandshake(t *testing.T) { - - // how much of the address we will use - useHandshake = true - var addrsize int64 - var err error - addrsizestring := strings.Split(t.Name(), "/") - addrsize, _ = strconv.ParseInt(addrsizestring[1], 10, 0) - - // set up two nodes directly connected - // (we are not testing pss routing here) - clients, err := setupNetwork(2, true) - if err != nil { - t.Fatal(err) - } - - var topic string - err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") - if err != nil { - t.Fatal(err) - } - - var loaddr string - err = clients[0].Call(&loaddr, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 1 baseaddr fail: %v", err) - } - // "0x" = 2 bytes + addrsize address bytes which in hex is 2x length - loaddr = loaddr[:2+(addrsize*2)] - var roaddr string - err = clients[1].Call(&roaddr, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 2 baseaddr fail: %v", err) - } - roaddr = roaddr[:2+(addrsize*2)] - log.Debug("addresses", "left", loaddr, "right", roaddr) - - // retrieve public key from pss instance - // set this public key reciprocally - var lpubkey string - err = clients[0].Call(&lpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 1 pubkey fail: %v", err) - } - var rpubkey string - err = clients[1].Call(&rpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 2 pubkey fail: %v", err) - } - - time.Sleep(time.Millisecond * 1000) // replace with hive healthy code - - // give each node its peer's public key - err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddr) - if err != nil { - t.Fatal(err) - } - err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddr) - if err != nil { - t.Fatal(err) - } - - // perform the handshake - // after this each side will have defaultSymKeyBufferCapacity symkeys each for in- and outgoing messages: - // L -> request 4 keys -> R - // L <- send 4 keys, request 4 keys <- R - // L -> send 4 keys -> R - // the call will fill the array with symkeys L needs for sending to R - err = clients[0].Call(nil, "pss_addHandshake", topic) - if err != nil { - t.Fatal(err) - } - err = clients[1].Call(nil, "pss_addHandshake", topic) - if err != nil { - t.Fatal(err) - } - - var lhsendsymkeyids []string - err = clients[0].Call(&lhsendsymkeyids, "pss_handshake", rpubkey, topic, true, true) - if err != nil { - t.Fatal(err) - } - - // make sure the r-node gets its keys - time.Sleep(time.Second) - - // check if we have 6 outgoing keys stored, and they match what was received from R - var lsendsymkeyids []string - err = clients[0].Call(&lsendsymkeyids, "pss_getHandshakeKeys", rpubkey, topic, false, true) - if err != nil { - t.Fatal(err) - } - m := 0 - for _, hid := range lhsendsymkeyids { - for _, lid := range lsendsymkeyids { - if lid == hid { - m++ - } - } - } - if m != defaultSymKeyCapacity { - t.Fatalf("buffer size mismatch, expected %d, have %d: %v", defaultSymKeyCapacity, m, lsendsymkeyids) - } - - // check if in- and outgoing keys on l-node and r-node match up and are in opposite categories (l recv = r send, l send = r recv) - var rsendsymkeyids []string - err = clients[1].Call(&rsendsymkeyids, "pss_getHandshakeKeys", lpubkey, topic, false, true) - if err != nil { - t.Fatal(err) - } - var lrecvsymkeyids []string - err = clients[0].Call(&lrecvsymkeyids, "pss_getHandshakeKeys", rpubkey, topic, true, false) - if err != nil { - t.Fatal(err) - } - var rrecvsymkeyids []string - err = clients[1].Call(&rrecvsymkeyids, "pss_getHandshakeKeys", lpubkey, topic, true, false) - if err != nil { - t.Fatal(err) - } - - // get outgoing symkeys in byte form from both sides - var lsendsymkeys []string - for _, id := range lsendsymkeyids { - var key string - err = clients[0].Call(&key, "pss_getSymmetricKey", id) - if err != nil { - t.Fatal(err) - } - lsendsymkeys = append(lsendsymkeys, key) - } - var rsendsymkeys []string - for _, id := range rsendsymkeyids { - var key string - err = clients[1].Call(&key, "pss_getSymmetricKey", id) - if err != nil { - t.Fatal(err) - } - rsendsymkeys = append(rsendsymkeys, key) - } - - // get incoming symkeys in byte form from both sides and compare - var lrecvsymkeys []string - for _, id := range lrecvsymkeyids { - var key string - err = clients[0].Call(&key, "pss_getSymmetricKey", id) - if err != nil { - t.Fatal(err) - } - match := false - for _, otherkey := range rsendsymkeys { - if otherkey == key { - match = true - } - } - if !match { - t.Fatalf("no match right send for left recv key %s", id) - } - lrecvsymkeys = append(lrecvsymkeys, key) - } - var rrecvsymkeys []string - for _, id := range rrecvsymkeyids { - var key string - err = clients[1].Call(&key, "pss_getSymmetricKey", id) - if err != nil { - t.Fatal(err) - } - match := false - for _, otherkey := range lsendsymkeys { - if otherkey == key { - match = true - } - } - if !match { - t.Fatalf("no match left send for right recv key %s", id) - } - rrecvsymkeys = append(rrecvsymkeys, key) - } - - // send new handshake request, should send no keys - err = clients[0].Call(nil, "pss_handshake", rpubkey, topic, false) - if err == nil { - t.Fatal("expected full symkey buffer error") - } - - // expire one key, send new handshake request - err = clients[0].Call(nil, "pss_releaseHandshakeKey", rpubkey, topic, lsendsymkeyids[0], true) - if err != nil { - t.Fatalf("release left send key %s fail: %v", lsendsymkeyids[0], err) - } - - var newlhsendkeyids []string - - // send new handshake request, should now receive one key - // check that it is not in previous right recv key array - err = clients[0].Call(&newlhsendkeyids, "pss_handshake", rpubkey, topic, true, false) - if err != nil { - t.Fatalf("handshake send fail: %v", err) - } else if len(newlhsendkeyids) != defaultSymKeyCapacity { - t.Fatalf("wrong receive count, expected 1, got %d", len(newlhsendkeyids)) - } - - var newlrecvsymkey string - err = clients[0].Call(&newlrecvsymkey, "pss_getSymmetricKey", newlhsendkeyids[0]) - if err != nil { - t.Fatal(err) - } - var rmatchsymkeyid *string - for i, id := range rrecvsymkeyids { - var key string - err = clients[1].Call(&key, "pss_getSymmetricKey", id) - if err != nil { - t.Fatal(err) - } - if newlrecvsymkey == key { - rmatchsymkeyid = &rrecvsymkeyids[i] - } - } - if rmatchsymkeyid != nil { - t.Fatalf("right sent old key id %s in second handshake", *rmatchsymkeyid) - } - - // clean the pss core keystore. Should clean the key released earlier - var cleancount int - clients[0].Call(&cleancount, "psstest_clean") - if cleancount > 1 { - t.Fatalf("pss clean count mismatch; expected 1, got %d", cleancount) - } -} diff --git a/swarm/pss/keystore.go b/swarm/pss/keystore.go deleted file mode 100644 index 5c44cb2453..0000000000 --- a/swarm/pss/keystore.go +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package pss - -import ( - "crypto/ecdsa" - "errors" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/log" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" -) - -type KeyStore struct { - w *whisper.Whisper // key and encryption backend - - mx sync.RWMutex - pubKeyPool map[string]map[Topic]*pssPeer // mapping of hex public keys to peer address by topic. - symKeyPool map[string]map[Topic]*pssPeer // mapping of symkeyids to peer address by topic. - symKeyDecryptCache []*string // fast lookup of symkeys recently used for decryption; last used is on top of stack - symKeyDecryptCacheCursor int // modular cursor pointing to last used, wraps on symKeyDecryptCache array -} - -func loadKeyStore() *KeyStore { - return &KeyStore{ - w: whisper.New(&whisper.DefaultConfig), - - pubKeyPool: make(map[string]map[Topic]*pssPeer), - symKeyPool: make(map[string]map[Topic]*pssPeer), - symKeyDecryptCache: make([]*string, defaultSymKeyCacheCapacity), - } -} - -func (ks *KeyStore) isSymKeyStored(key string) bool { - ks.mx.RLock() - defer ks.mx.RUnlock() - var ok bool - _, ok = ks.symKeyPool[key] - return ok -} - -func (ks *KeyStore) isPubKeyStored(key string) bool { - ks.mx.RLock() - defer ks.mx.RUnlock() - var ok bool - _, ok = ks.pubKeyPool[key] - return ok -} - -func (ks *KeyStore) getPeerSym(symkeyid string, topic Topic) (*pssPeer, bool) { - ks.mx.RLock() - defer ks.mx.RUnlock() - psp, ok := ks.symKeyPool[symkeyid][topic] - return psp, ok -} - -func (ks *KeyStore) getPeerPub(pubkeyid string, topic Topic) (*pssPeer, bool) { - ks.mx.RLock() - defer ks.mx.RUnlock() - psp, ok := ks.pubKeyPool[pubkeyid][topic] - return psp, ok -} - -// Links a peer ECDSA public key to a topic. -// This is required for asymmetric message exchange on the given topic. -// The value in `address` will be used as a routing hint for the public key / topic association. -func (ks *KeyStore) SetPeerPublicKey(pubkey *ecdsa.PublicKey, topic Topic, address PssAddress) error { - if err := validateAddress(address); err != nil { - return err - } - pubkeybytes := crypto.FromECDSAPub(pubkey) - if len(pubkeybytes) == 0 { - return fmt.Errorf("invalid public key: %v", pubkey) - } - pubkeyid := common.ToHex(pubkeybytes) - psp := &pssPeer{ - address: address, - } - ks.mx.Lock() - if _, ok := ks.pubKeyPool[pubkeyid]; !ok { - ks.pubKeyPool[pubkeyid] = make(map[Topic]*pssPeer) - } - ks.pubKeyPool[pubkeyid][topic] = psp - ks.mx.Unlock() - log.Trace("added pubkey", "pubkeyid", pubkeyid, "topic", topic, "address", address) - return nil -} - -// adds a symmetric key to the pss key pool, and optionally adds the key to the -// collection of keys used to attempt symmetric decryption of incoming messages -func (ks *KeyStore) addSymmetricKeyToPool(keyid string, topic Topic, address PssAddress, addtocache bool, protected bool) { - psp := &pssPeer{ - address: address, - protected: protected, - } - ks.mx.Lock() - if _, ok := ks.symKeyPool[keyid]; !ok { - ks.symKeyPool[keyid] = make(map[Topic]*pssPeer) - } - ks.symKeyPool[keyid][topic] = psp - ks.mx.Unlock() - if addtocache { - ks.symKeyDecryptCacheCursor++ - ks.symKeyDecryptCache[ks.symKeyDecryptCacheCursor%cap(ks.symKeyDecryptCache)] = &keyid - } -} - -// Returns all recorded topic and address combination for a specific public key -func (ks *KeyStore) GetPublickeyPeers(keyid string) (topic []Topic, address []PssAddress, err error) { - ks.mx.RLock() - defer ks.mx.RUnlock() - for t, peer := range ks.pubKeyPool[keyid] { - topic = append(topic, t) - address = append(address, peer.address) - } - return topic, address, nil -} - -func (ks *KeyStore) getPeerAddress(keyid string, topic Topic) (PssAddress, error) { - ks.mx.RLock() - defer ks.mx.RUnlock() - if peers, ok := ks.pubKeyPool[keyid]; ok { - if t, ok := peers[topic]; ok { - return t.address, nil - } - } - return nil, fmt.Errorf("peer with pubkey %s, topic %x not found", keyid, topic) -} - -// Attempt to decrypt, validate and unpack a symmetrically encrypted message. -// If successful, returns the unpacked whisper ReceivedMessage struct -// encapsulating the decrypted message, and the whisper backend id -// of the symmetric key used to decrypt the message. -// It fails if decryption of the message fails or if the message is corrupted. -func (ks *KeyStore) processSym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, PssAddress, error) { - metrics.GetOrRegisterCounter("pss.process.sym", nil).Inc(1) - - for i := ks.symKeyDecryptCacheCursor; i > ks.symKeyDecryptCacheCursor-cap(ks.symKeyDecryptCache) && i > 0; i-- { - symkeyid := ks.symKeyDecryptCache[i%cap(ks.symKeyDecryptCache)] - symkey, err := ks.w.GetSymKey(*symkeyid) - if err != nil { - continue - } - recvmsg, err := envelope.OpenSymmetric(symkey) - if err != nil { - continue - } - if !recvmsg.ValidateAndParse() { - return nil, "", nil, errors.New("symmetrically encrypted message has invalid signature or is corrupt") - } - var from PssAddress - ks.mx.RLock() - if ks.symKeyPool[*symkeyid][Topic(envelope.Topic)] != nil { - from = ks.symKeyPool[*symkeyid][Topic(envelope.Topic)].address - } - ks.mx.RUnlock() - ks.symKeyDecryptCacheCursor++ - ks.symKeyDecryptCache[ks.symKeyDecryptCacheCursor%cap(ks.symKeyDecryptCache)] = symkeyid - return recvmsg, *symkeyid, from, nil - } - return nil, "", nil, errors.New("could not decrypt message") -} - -// Attempt to decrypt, validate and unpack an asymmetrically encrypted message. -// If successful, returns the unpacked whisper ReceivedMessage struct -// encapsulating the decrypted message, and the byte representation of -// the public key used to decrypt the message. -// It fails if decryption of message fails, or if the message is corrupted. -func (ks *Pss) processAsym(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, PssAddress, error) { - metrics.GetOrRegisterCounter("pss.process.asym", nil).Inc(1) - - recvmsg, err := envelope.OpenAsymmetric(ks.privateKey) - if err != nil { - return nil, "", nil, fmt.Errorf("could not decrypt message: %s", err) - } - // check signature (if signed), strip padding - if !recvmsg.ValidateAndParse() { - return nil, "", nil, errors.New("invalid message") - } - pubkeyid := common.ToHex(crypto.FromECDSAPub(recvmsg.Src)) - var from PssAddress - ks.mx.RLock() - if ks.pubKeyPool[pubkeyid][Topic(envelope.Topic)] != nil { - from = ks.pubKeyPool[pubkeyid][Topic(envelope.Topic)].address - } - ks.mx.RUnlock() - return recvmsg, pubkeyid, from, nil -} - -// Symkey garbage collection -// a key is removed if: -// - it is not marked as protected -// - it is not in the incoming decryption cache -func (ks *Pss) cleanKeys() (count int) { - ks.mx.Lock() - defer ks.mx.Unlock() - for keyid, peertopics := range ks.symKeyPool { - var expiredtopics []Topic - for topic, psp := range peertopics { - if psp.protected { - continue - } - - var match bool - for i := ks.symKeyDecryptCacheCursor; i > ks.symKeyDecryptCacheCursor-cap(ks.symKeyDecryptCache) && i > 0; i-- { - cacheid := ks.symKeyDecryptCache[i%cap(ks.symKeyDecryptCache)] - if *cacheid == keyid { - match = true - } - } - if !match { - expiredtopics = append(expiredtopics, topic) - } - } - for _, topic := range expiredtopics { - delete(ks.symKeyPool[keyid], topic) - log.Trace("symkey cleanup deletion", "symkeyid", keyid, "topic", topic, "val", ks.symKeyPool[keyid]) - count++ - } - } - return count -} - -// Automatically generate a new symkey for a topic and address hint -func (ks *KeyStore) GenerateSymmetricKey(topic Topic, address PssAddress, addToCache bool) (string, error) { - keyid, err := ks.w.GenerateSymKey() - if err == nil { - ks.addSymmetricKeyToPool(keyid, topic, address, addToCache, false) - } - return keyid, err -} - -// Returns a symmetric key byte sequence stored in the whisper backend by its unique id. -// Passes on the error value from the whisper backend. -func (ks *KeyStore) GetSymmetricKey(symkeyid string) ([]byte, error) { - return ks.w.GetSymKey(symkeyid) -} - -// Links a peer symmetric key (arbitrary byte sequence) to a topic. -// -// This is required for symmetrically encrypted message exchange on the given topic. -// -// The key is stored in the whisper backend. -// -// If addtocache is set to true, the key will be added to the cache of keys -// used to attempt symmetric decryption of incoming messages. -// -// Returns a string id that can be used to retrieve the key bytes -// from the whisper backend (see pss.GetSymmetricKey()) -func (ks *KeyStore) SetSymmetricKey(key []byte, topic Topic, address PssAddress, addtocache bool) (string, error) { - if err := validateAddress(address); err != nil { - return "", err - } - return ks.setSymmetricKey(key, topic, address, addtocache, true) -} - -func (ks *KeyStore) setSymmetricKey(key []byte, topic Topic, address PssAddress, addtocache bool, protected bool) (string, error) { - keyid, err := ks.w.AddSymKeyDirect(key) - if err == nil { - ks.addSymmetricKeyToPool(keyid, topic, address, addtocache, protected) - } - return keyid, err -} diff --git a/swarm/pss/notify/notify.go b/swarm/pss/notify/notify.go deleted file mode 100644 index e9d40dc321..0000000000 --- a/swarm/pss/notify/notify.go +++ /dev/null @@ -1,394 +0,0 @@ -package notify - -import ( - "crypto/ecdsa" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/pss" -) - -const ( - // sent from requester to updater to request start of notifications - MsgCodeStart = iota - - // sent from updater to requester, contains a notification plus a new symkey to replace the old - MsgCodeNotifyWithKey - - // sent from updater to requester, contains a notification - MsgCodeNotify - - // sent from requester to updater to request stop of notifications (currently unused) - MsgCodeStop - MsgCodeMax -) - -const ( - DefaultAddressLength = 1 - symKeyLength = 32 // this should be gotten from source -) - -var ( - // control topic is used before symmetric key issuance completes - controlTopic = pss.Topic{0x00, 0x00, 0x00, 0x01} -) - -// when code is MsgCodeStart, Payload is address -// when code is MsgCodeNotifyWithKey, Payload is notification | symkey -// when code is MsgCodeNotify, Payload is notification -// when code is MsgCodeStop, Payload is address -type Msg struct { - Code byte - Name []byte - Payload []byte - namestring string -} - -// NewMsg creates a new notification message object -func NewMsg(code byte, name string, payload []byte) *Msg { - return &Msg{ - Code: code, - Name: []byte(name), - Payload: payload, - namestring: name, - } -} - -// NewMsgFromPayload decodes a serialized message payload into a new notification message object -func NewMsgFromPayload(payload []byte) (*Msg, error) { - msg := &Msg{} - err := rlp.DecodeBytes(payload, msg) - if err != nil { - return nil, err - } - msg.namestring = string(msg.Name) - return msg, nil -} - -// a notifier has one sendBin entry for each address space it sends messages to -type sendBin struct { - address pss.PssAddress - symKeyId string - count int -} - -// represents a single notification service -// only subscription address bins that match the address of a notification client have entries. -type notifier struct { - bins map[string]*sendBin - topic pss.Topic // identifies the resource for pss receiver - threshold int // amount of address bytes used in bins - updateC <-chan []byte - quitC chan struct{} -} - -func (n *notifier) removeSubscription() { - n.quitC <- struct{}{} -} - -// represents an individual subscription made by a public key at a specific address/neighborhood -type subscription struct { - pubkeyId string - address pss.PssAddress - handler func(string, []byte) error -} - -// Controller is the interface to control, add and remove notification services and subscriptions -type Controller struct { - pss *pss.Pss - notifiers map[string]*notifier - subscriptions map[string]*subscription - mu sync.Mutex -} - -// NewController creates a new Controller object -func NewController(ps *pss.Pss) *Controller { - ctrl := &Controller{ - pss: ps, - notifiers: make(map[string]*notifier), - subscriptions: make(map[string]*subscription), - } - ctrl.pss.Register(&controlTopic, pss.NewHandler(ctrl.Handler)) - return ctrl -} - -// IsActive is used to check if a notification service exists for a specified id string -// Returns true if exists, false if not -func (c *Controller) IsActive(name string) bool { - c.mu.Lock() - defer c.mu.Unlock() - return c.isActive(name) -} - -func (c *Controller) isActive(name string) bool { - _, ok := c.notifiers[name] - return ok -} - -// Subscribe is used by a client to request notifications from a notification service provider -// It will create a MsgCodeStart message and send asymmetrically to the provider using its public key and routing address -// The handler function is a callback that will be called when notifications are received -// Fails if the request pss cannot be sent or if the update message could not be serialized -func (c *Controller) Subscribe(name string, pubkey *ecdsa.PublicKey, address pss.PssAddress, handler func(string, []byte) error) error { - c.mu.Lock() - defer c.mu.Unlock() - msg := NewMsg(MsgCodeStart, name, c.pss.BaseAddr()) - c.pss.SetPeerPublicKey(pubkey, controlTopic, address) - pubkeyId := hexutil.Encode(crypto.FromECDSAPub(pubkey)) - smsg, err := rlp.EncodeToBytes(msg) - if err != nil { - return err - } - err = c.pss.SendAsym(pubkeyId, controlTopic, smsg) - if err != nil { - return err - } - c.subscriptions[name] = &subscription{ - pubkeyId: pubkeyId, - address: address, - handler: handler, - } - return nil -} - -// Unsubscribe, perhaps unsurprisingly, undoes the effects of Subscribe -// Fails if the subscription does not exist, if the request pss cannot be sent or if the update message could not be serialized -func (c *Controller) Unsubscribe(name string) error { - c.mu.Lock() - defer c.mu.Unlock() - sub, ok := c.subscriptions[name] - if !ok { - return fmt.Errorf("Unknown subscription '%s'", name) - } - msg := NewMsg(MsgCodeStop, name, sub.address) - smsg, err := rlp.EncodeToBytes(msg) - if err != nil { - return err - } - err = c.pss.SendAsym(sub.pubkeyId, controlTopic, smsg) - if err != nil { - return err - } - delete(c.subscriptions, name) - return nil -} - -// NewNotifier is used by a notification service provider to create a new notification service -// It takes a name as identifier for the resource, a threshold indicating the granularity of the subscription address bin -// It then starts an event loop which listens to the supplied update channel and executes notifications on channel receives -// Fails if a notifier already is registered on the name -//func (c *Controller) NewNotifier(name string, threshold int, contentFunc func(string) ([]byte, error)) error { -func (c *Controller) NewNotifier(name string, threshold int, updateC <-chan []byte) (func(), error) { - c.mu.Lock() - if c.isActive(name) { - c.mu.Unlock() - return nil, fmt.Errorf("Notification service %s already exists in controller", name) - } - quitC := make(chan struct{}) - c.notifiers[name] = ¬ifier{ - bins: make(map[string]*sendBin), - topic: pss.BytesToTopic([]byte(name)), - threshold: threshold, - updateC: updateC, - quitC: quitC, - //contentFunc: contentFunc, - } - c.mu.Unlock() - go func() { - for { - select { - case <-quitC: - return - case data := <-updateC: - c.notify(name, data) - } - } - }() - - return c.notifiers[name].removeSubscription, nil -} - -// RemoveNotifier is used to stop a notification service. -// It cancels the event loop listening to the notification provider's update channel -func (c *Controller) RemoveNotifier(name string) error { - c.mu.Lock() - defer c.mu.Unlock() - currentNotifier, ok := c.notifiers[name] - if !ok { - return fmt.Errorf("Unknown notification service %s", name) - } - currentNotifier.removeSubscription() - delete(c.notifiers, name) - return nil -} - -// Notify is called by a notification service provider to issue a new notification -// It takes the name of the notification service and the data to be sent. -// It fails if a notifier with this name does not exist or if data could not be serialized -// Note that it does NOT fail on failure to send a message -func (c *Controller) notify(name string, data []byte) error { - c.mu.Lock() - defer c.mu.Unlock() - if !c.isActive(name) { - return fmt.Errorf("Notification service %s doesn't exist", name) - } - msg := NewMsg(MsgCodeNotify, name, data) - smsg, err := rlp.EncodeToBytes(msg) - if err != nil { - return err - } - for _, m := range c.notifiers[name].bins { - log.Debug("sending pss notify", "name", name, "addr", fmt.Sprintf("%x", m.address), "topic", fmt.Sprintf("%x", c.notifiers[name].topic), "data", data) - go func(m *sendBin) { - err = c.pss.SendSym(m.symKeyId, c.notifiers[name].topic, smsg) - if err != nil { - log.Warn("Failed to send notify to addr %x: %v", m.address, err) - } - }(m) - } - return nil -} - -// check if we already have the bin -// if we do, retrieve the symkey from it and increment the count -// if we dont make a new symkey and a new bin entry -func (c *Controller) addToBin(ntfr *notifier, address []byte) (symKeyId string, pssAddress pss.PssAddress, err error) { - - // parse the address from the message and truncate if longer than our bins threshold - if len(address) > ntfr.threshold { - address = address[:ntfr.threshold] - } - - pssAddress = pss.PssAddress(address) - hexAddress := fmt.Sprintf("%x", address) - currentBin, ok := ntfr.bins[hexAddress] - if ok { - currentBin.count++ - symKeyId = currentBin.symKeyId - } else { - symKeyId, err = c.pss.GenerateSymmetricKey(ntfr.topic, pssAddress, false) - if err != nil { - return "", nil, err - } - ntfr.bins[hexAddress] = &sendBin{ - address: address, - symKeyId: symKeyId, - count: 1, - } - } - return symKeyId, pssAddress, nil -} - -func (c *Controller) handleStartMsg(msg *Msg, keyid string) (err error) { - - keyidbytes, err := hexutil.Decode(keyid) - if err != nil { - return err - } - pubkey, err := crypto.UnmarshalPubkey(keyidbytes) - if err != nil { - return err - } - - // if name is not registered for notifications we will not react - currentNotifier, ok := c.notifiers[msg.namestring] - if !ok { - return fmt.Errorf("Subscribe attempted on unknown resource '%s'", msg.namestring) - } - - // add to or open new bin - symKeyId, pssAddress, err := c.addToBin(currentNotifier, msg.Payload) - if err != nil { - return err - } - - // add to address book for send initial notify - symkey, err := c.pss.GetSymmetricKey(symKeyId) - if err != nil { - return err - } - err = c.pss.SetPeerPublicKey(pubkey, controlTopic, pssAddress) - if err != nil { - return err - } - - // TODO this is set to zero-length byte pending decision on protocol for initial message, whether it should include message or not, and how to trigger the initial message so that current state of Swarm feed is sent upon subscription - notify := []byte{} - replyMsg := NewMsg(MsgCodeNotifyWithKey, msg.namestring, make([]byte, len(notify)+symKeyLength)) - copy(replyMsg.Payload, notify) - copy(replyMsg.Payload[len(notify):], symkey) - sReplyMsg, err := rlp.EncodeToBytes(replyMsg) - if err != nil { - return err - } - return c.pss.SendAsym(keyid, controlTopic, sReplyMsg) -} - -func (c *Controller) handleNotifyWithKeyMsg(msg *Msg) error { - symkey := msg.Payload[len(msg.Payload)-symKeyLength:] - topic := pss.BytesToTopic(msg.Name) - - // \TODO keep track of and add actual address - updaterAddr := pss.PssAddress([]byte{}) - c.pss.SetSymmetricKey(symkey, topic, updaterAddr, true) - c.pss.Register(&topic, pss.NewHandler(c.Handler)) - return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload[:len(msg.Payload)-symKeyLength]) -} - -func (c *Controller) handleStopMsg(msg *Msg) error { - // if name is not registered for notifications we will not react - currentNotifier, ok := c.notifiers[msg.namestring] - if !ok { - return fmt.Errorf("Unsubscribe attempted on unknown resource '%s'", msg.namestring) - } - - // parse the address from the message and truncate if longer than our bins' address length threshold - address := msg.Payload - if len(msg.Payload) > currentNotifier.threshold { - address = address[:currentNotifier.threshold] - } - - // remove the entry from the bin if it exists, and remove the bin if it's the last remaining one - hexAddress := fmt.Sprintf("%x", address) - currentBin, ok := currentNotifier.bins[hexAddress] - if !ok { - return fmt.Errorf("found no active bin for address %s", hexAddress) - } - currentBin.count-- - if currentBin.count == 0 { // if no more clients in this bin, remove it - delete(currentNotifier.bins, hexAddress) - } - return nil -} - -// Handler is the pss topic handler to be used to process notification service messages -// It should be registered in the pss of both to any notification service provides and clients using the service -func (c *Controller) Handler(smsg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - c.mu.Lock() - defer c.mu.Unlock() - log.Debug("notify controller handler", "keyid", keyid) - - // see if the message is valid - msg, err := NewMsgFromPayload(smsg) - if err != nil { - return err - } - - switch msg.Code { - case MsgCodeStart: - return c.handleStartMsg(msg, keyid) - case MsgCodeNotifyWithKey: - return c.handleNotifyWithKeyMsg(msg) - case MsgCodeNotify: - return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload) - case MsgCodeStop: - return c.handleStopMsg(msg) - } - - return fmt.Errorf("Invalid message code: %d", msg.Code) -} diff --git a/swarm/pss/notify/notify_test.go b/swarm/pss/notify/notify_test.go deleted file mode 100644 index cda069b9e1..0000000000 --- a/swarm/pss/notify/notify_test.go +++ /dev/null @@ -1,265 +0,0 @@ -package notify - -import ( - "bytes" - "context" - "flag" - "fmt" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/pss" - "github.com/ethereum/go-ethereum/swarm/state" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" -) - -var ( - loglevel = flag.Int("l", 3, "loglevel") - psses map[string]*pss.Pss - w *whisper.Whisper - wapi *whisper.PublicWhisperAPI -) - -func init() { - flag.Parse() - hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) - hf := log.LvlFilterHandler(log.Lvl(*loglevel), hs) - h := log.CallerFileHandler(hf) - log.Root().SetHandler(h) - - w = whisper.New(&whisper.DefaultConfig) - wapi = whisper.NewPublicWhisperAPI(w) - psses = make(map[string]*pss.Pss) -} - -// Creates a client node and notifier node -// Client sends pss notifications requests -// notifier sends initial notification with symmetric key, and -// second notification symmetrically encrypted -func TestStart(t *testing.T) { - adapter := adapters.NewSimAdapter(newServices(false)) - net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - ID: "0", - DefaultService: "bzz", - }) - defer net.Shutdown() - leftNodeConf := adapters.RandomNodeConfig() - leftNodeConf.Services = []string{"bzz", "pss"} - leftNode, err := net.NewNodeWithConfig(leftNodeConf) - if err != nil { - t.Fatal(err) - } - err = net.Start(leftNode.ID()) - if err != nil { - t.Fatal(err) - } - - rightNodeConf := adapters.RandomNodeConfig() - rightNodeConf.Services = []string{"bzz", "pss"} - rightNode, err := net.NewNodeWithConfig(rightNodeConf) - if err != nil { - t.Fatal(err) - } - err = net.Start(rightNode.ID()) - if err != nil { - t.Fatal(err) - } - - err = net.Connect(rightNode.ID(), leftNode.ID()) - if err != nil { - t.Fatal(err) - } - - leftRpc, err := leftNode.Client() - if err != nil { - t.Fatal(err) - } - - rightRpc, err := rightNode.Client() - if err != nil { - t.Fatal(err) - } - - var leftAddr string - err = leftRpc.Call(&leftAddr, "pss_baseAddr") - if err != nil { - t.Fatal(err) - } - - var rightAddr string - err = rightRpc.Call(&rightAddr, "pss_baseAddr") - if err != nil { - t.Fatal(err) - } - - var leftPub string - err = leftRpc.Call(&leftPub, "pss_getPublicKey") - if err != nil { - t.Fatal(err) - } - - var rightPub string - err = rightRpc.Call(&rightPub, "pss_getPublicKey") - if err != nil { - t.Fatal(err) - } - - rsrcName := "foo.eth" - rsrcTopic := pss.BytesToTopic([]byte(rsrcName)) - - // wait for kademlia table to populate - time.Sleep(time.Second) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) - defer cancel() - rmsgC := make(chan *pss.APIMsg) - rightSub, err := rightRpc.Subscribe(ctx, "pss", rmsgC, "receive", controlTopic, false, false) - if err != nil { - t.Fatal(err) - } - defer rightSub.Unsubscribe() - - updateC := make(chan []byte) - var updateMsg []byte - ctrlClient := NewController(psses[rightPub]) - ctrlNotifier := NewController(psses[leftPub]) - ctrlNotifier.NewNotifier("foo.eth", 2, updateC) - - pubkeybytes, err := hexutil.Decode(leftPub) - if err != nil { - t.Fatal(err) - } - pubkey, err := crypto.UnmarshalPubkey(pubkeybytes) - if err != nil { - t.Fatal(err) - } - addrbytes, err := hexutil.Decode(leftAddr) - if err != nil { - t.Fatal(err) - } - - copyOfUpdateMsg := make([]byte, len(updateMsg)) - copy(copyOfUpdateMsg, updateMsg) - ctrlClientError := make(chan error, 1) - ctrlClient.Subscribe(rsrcName, pubkey, addrbytes, func(s string, b []byte) error { - if s != "foo.eth" || !bytes.Equal(copyOfUpdateMsg, b) { - ctrlClientError <- fmt.Errorf("unexpected result in client handler: '%s':'%x'", s, b) - } else { - log.Info("client handler receive", "s", s, "b", b) - } - return nil - }) - - var inMsg *pss.APIMsg - select { - case inMsg = <-rmsgC: - case err := <-ctrlClientError: - t.Fatal(err) - case <-ctx.Done(): - t.Fatal(ctx.Err()) - } - - dMsg, err := NewMsgFromPayload(inMsg.Msg) - if err != nil { - t.Fatal(err) - } - if dMsg.namestring != rsrcName { - t.Fatalf("expected name '%s', got '%s'", rsrcName, dMsg.namestring) - } - if !bytes.Equal(dMsg.Payload[:len(updateMsg)], updateMsg) { - t.Fatalf("expected payload first %d bytes '%x', got '%x'", len(updateMsg), updateMsg, dMsg.Payload[:len(updateMsg)]) - } - if len(updateMsg)+symKeyLength != len(dMsg.Payload) { - t.Fatalf("expected payload length %d, have %d", len(updateMsg)+symKeyLength, len(dMsg.Payload)) - } - - rightSubUpdate, err := rightRpc.Subscribe(ctx, "pss", rmsgC, "receive", rsrcTopic, false, false) - if err != nil { - t.Fatal(err) - } - defer rightSubUpdate.Unsubscribe() - - updateMsg = []byte("plugh") - updateC <- updateMsg - select { - case inMsg = <-rmsgC: - case <-ctx.Done(): - log.Error("timed out waiting for msg", "topic", fmt.Sprintf("%x", rsrcTopic)) - t.Fatal(ctx.Err()) - } - dMsg, err = NewMsgFromPayload(inMsg.Msg) - if err != nil { - t.Fatal(err) - } - if dMsg.namestring != rsrcName { - t.Fatalf("expected name %s, got %s", rsrcName, dMsg.namestring) - } - if !bytes.Equal(dMsg.Payload, updateMsg) { - t.Fatalf("expected payload '%x', got '%x'", updateMsg, dMsg.Payload) - } - -} - -func newServices(allowRaw bool) adapters.Services { - stateStore := state.NewInmemoryStore() - kademlias := make(map[enode.ID]*network.Kademlia) - kademlia := func(id enode.ID) *network.Kademlia { - if k, ok := kademlias[id]; ok { - return k - } - params := network.NewKadParams() - params.NeighbourhoodSize = 2 - params.MaxBinSize = 3 - params.MinBinSize = 1 - params.MaxRetries = 1000 - params.RetryExponent = 2 - params.RetryInterval = 1000000 - kademlias[id] = network.NewKademlia(id[:], params) - return kademlias[id] - } - return adapters.Services{ - "pss": func(ctx *adapters.ServiceContext) (node.Service, error) { - ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctxlocal) - if err != nil { - return nil, err - } - privkey, err := w.GetPrivateKey(keys) - if err != nil { - return nil, err - } - pssp := pss.NewPssParams().WithPrivateKey(privkey) - pssp.MsgTTL = time.Second * 30 - pssp.AllowRaw = allowRaw - pskad := kademlia(ctx.Config.ID) - ps, err := pss.NewPss(pskad, pssp) - if err != nil { - return nil, err - } - //psses[common.ToHex(crypto.FromECDSAPub(&privkey.PublicKey))] = ps - psses[hexutil.Encode(crypto.FromECDSAPub(&privkey.PublicKey))] = ps - return ps, nil - }, - "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { - addr := network.NewAddr(ctx.Config.Node()) - hp := network.NewHiveParams() - hp.Discovery = false - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - return network.NewBzz(config, kademlia(ctx.Config.ID), stateStore, nil, nil), nil - }, - } -} diff --git a/swarm/pss/ping.go b/swarm/pss/ping.go deleted file mode 100644 index ff635f40a4..0000000000 --- a/swarm/pss/ping.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build !nopssprotocol,!nopssping - -package pss - -import ( - "context" - "errors" - "time" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/swarm/log" -) - -// Generic ping protocol implementation for -// pss devp2p protocol emulation -type PingMsg struct { - Created time.Time - Pong bool // set if message is pong reply -} - -type Ping struct { - Pong bool // toggle pong reply upon ping receive - OutC chan bool // trigger ping - InC chan bool // optional, report back to calling code -} - -func (p *Ping) pingHandler(ctx context.Context, msg interface{}) error { - var pingmsg *PingMsg - var ok bool - if pingmsg, ok = msg.(*PingMsg); !ok { - return errors.New("invalid msg") - } - log.Debug("ping handler", "msg", pingmsg, "outc", p.OutC) - if p.InC != nil { - p.InC <- pingmsg.Pong - } - if p.Pong && !pingmsg.Pong { - p.OutC <- true - } - return nil -} - -var PingProtocol = &protocols.Spec{ - Name: "psstest", - Version: 1, - MaxMsgSize: 1024, - Messages: []interface{}{ - PingMsg{}, - }, -} - -var PingTopic = ProtocolTopic(PingProtocol) - -func NewPingProtocol(ping *Ping) *p2p.Protocol { - return &p2p.Protocol{ - Name: PingProtocol.Name, - Version: PingProtocol.Version, - Length: uint64(PingProtocol.MaxMsgSize), - Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { - quitC := make(chan struct{}) - pp := protocols.NewPeer(p, rw, PingProtocol) - log.Trace("running pss vprotocol", "peer", p, "outc", ping.OutC) - go func() { - for { - select { - case ispong := <-ping.OutC: - pp.Send(context.TODO(), &PingMsg{ - Created: time.Now(), - Pong: ispong, - }) - case <-quitC: - } - } - }() - err := pp.Run(ping.pingHandler) - quitC <- struct{}{} - return err - }, - } -} diff --git a/swarm/pss/protocol.go b/swarm/pss/protocol.go deleted file mode 100644 index 7f186f6153..0000000000 --- a/swarm/pss/protocol.go +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build !nopssprotocol - -package pss - -import ( - "bytes" - "fmt" - "sync" - "time" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/swarm/log" -) - -const ( - IsActiveProtocol = true -) - -// Convenience wrapper for devp2p protocol messages for transport over pss -type ProtocolMsg struct { - Code uint64 - Size uint32 - Payload []byte - ReceivedAt time.Time -} - -// Creates a ProtocolMsg -func NewProtocolMsg(code uint64, msg interface{}) ([]byte, error) { - - rlpdata, err := rlp.EncodeToBytes(msg) - if err != nil { - return nil, err - } - - // TODO verify that nested structs cannot be used in rlp - smsg := &ProtocolMsg{ - Code: code, - Size: uint32(len(rlpdata)), - Payload: rlpdata, - } - - return rlp.EncodeToBytes(smsg) -} - -// Protocol options to be passed to a new Protocol instance -// -// The parameters specify which encryption schemes to allow -type ProtocolParams struct { - Asymmetric bool - Symmetric bool -} - -// PssReadWriter bridges pss send/receive with devp2p protocol send/receive -// -// Implements p2p.MsgReadWriter -type PssReadWriter struct { - *Pss - LastActive time.Time - rw chan p2p.Msg - spec *protocols.Spec - topic *Topic - sendFunc func(string, Topic, []byte) error - key string - closed bool -} - -// Implements p2p.MsgReader -func (prw *PssReadWriter) ReadMsg() (p2p.Msg, error) { - msg := <-prw.rw - log.Trace(fmt.Sprintf("pssrw readmsg: %v", msg)) - return msg, nil -} - -// Implements p2p.MsgWriter -func (prw *PssReadWriter) WriteMsg(msg p2p.Msg) error { - log.Trace("pssrw writemsg", "msg", msg) - if prw.closed { - return fmt.Errorf("connection closed") - } - rlpdata := make([]byte, msg.Size) - msg.Payload.Read(rlpdata) - pmsg, err := rlp.EncodeToBytes(ProtocolMsg{ - Code: msg.Code, - Size: msg.Size, - Payload: rlpdata, - }) - if err != nil { - return err - } - return prw.sendFunc(prw.key, *prw.topic, pmsg) -} - -// Injects a p2p.Msg into the MsgReadWriter, so that it appears on the associated p2p.MsgReader -func (prw *PssReadWriter) injectMsg(msg p2p.Msg) error { - log.Trace(fmt.Sprintf("pssrw injectmsg: %v", msg)) - prw.rw <- msg - return nil -} - -// Convenience object for emulation devp2p over pss -type Protocol struct { - *Pss - proto *p2p.Protocol - topic *Topic - spec *protocols.Spec - pubKeyRWPool map[string]p2p.MsgReadWriter - symKeyRWPool map[string]p2p.MsgReadWriter - Asymmetric bool - Symmetric bool - RWPoolMu sync.Mutex -} - -// Activates devp2p emulation over a specific pss topic -// -// One or both encryption schemes must be specified. If -// only one is specified, the protocol will not be valid -// for the other, and will make the message handler -// return errors -func RegisterProtocol(ps *Pss, topic *Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol, options *ProtocolParams) (*Protocol, error) { - if !options.Asymmetric && !options.Symmetric { - return nil, fmt.Errorf("specify at least one of asymmetric or symmetric messaging mode") - } - pp := &Protocol{ - Pss: ps, - proto: targetprotocol, - topic: topic, - spec: spec, - pubKeyRWPool: make(map[string]p2p.MsgReadWriter), - symKeyRWPool: make(map[string]p2p.MsgReadWriter), - Asymmetric: options.Asymmetric, - Symmetric: options.Symmetric, - } - return pp, nil -} - -// Generic handler for incoming messages over devp2p emulation -// -// To be passed to pss.Register() -// -// Will run the protocol on a new incoming peer, provided that -// the encryption key of the message has a match in the internal -// pss keypool -// -// Fails if protocol is not valid for the message encryption scheme, -// if adding a new peer fails, or if the message is not a serialized -// p2p.Msg (which it always will be if it is sent from this object). -func (p *Protocol) Handle(msg []byte, peer *p2p.Peer, asymmetric bool, keyid string) error { - var vrw *PssReadWriter - if p.Asymmetric != asymmetric && p.Symmetric == !asymmetric { - return fmt.Errorf("invalid protocol encryption") - } else if (!p.isActiveSymKey(keyid, *p.topic) && !asymmetric) || - (!p.isActiveAsymKey(keyid, *p.topic) && asymmetric) { - - rw, err := p.AddPeer(peer, *p.topic, asymmetric, keyid) - if err != nil { - return err - } else if rw == nil { - return fmt.Errorf("handle called on nil MsgReadWriter for new key " + keyid) - } - vrw = rw.(*PssReadWriter) - } - - pmsg, err := ToP2pMsg(msg) - if err != nil { - return fmt.Errorf("could not decode pssmsg") - } - if asymmetric { - if p.pubKeyRWPool[keyid] == nil { - return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid) - } - vrw = p.pubKeyRWPool[keyid].(*PssReadWriter) - } else { - if p.symKeyRWPool[keyid] == nil { - return fmt.Errorf("handle called on nil MsgReadWriter for key " + keyid) - } - vrw = p.symKeyRWPool[keyid].(*PssReadWriter) - } - vrw.injectMsg(pmsg) - return nil -} - -// check if (peer) symmetric key is currently registered with this topic -func (p *Protocol) isActiveSymKey(key string, topic Topic) bool { - return p.symKeyRWPool[key] != nil -} - -// check if (peer) asymmetric key is currently registered with this topic -func (p *Protocol) isActiveAsymKey(key string, topic Topic) bool { - return p.pubKeyRWPool[key] != nil -} - -// Creates a serialized (non-buffered) version of a p2p.Msg, used in the specialized internal p2p.MsgReadwriter implementations -func ToP2pMsg(msg []byte) (p2p.Msg, error) { - payload := &ProtocolMsg{} - if err := rlp.DecodeBytes(msg, payload); err != nil { - return p2p.Msg{}, fmt.Errorf("pss protocol handler unable to decode payload as p2p message: %v", err) - } - - return p2p.Msg{ - Code: payload.Code, - Size: uint32(len(payload.Payload)), - ReceivedAt: time.Now(), - Payload: bytes.NewBuffer(payload.Payload), - }, nil -} - -// Runs an emulated pss Protocol on the specified peer, -// linked to a specific topic -// `key` and `asymmetric` specifies what encryption key -// to link the peer to. -// The key must exist in the pss store prior to adding the peer. -func (p *Protocol) AddPeer(peer *p2p.Peer, topic Topic, asymmetric bool, key string) (p2p.MsgReadWriter, error) { - rw := &PssReadWriter{ - Pss: p.Pss, - rw: make(chan p2p.Msg), - spec: p.spec, - topic: p.topic, - key: key, - } - if asymmetric { - rw.sendFunc = p.Pss.SendAsym - } else { - rw.sendFunc = p.Pss.SendSym - } - if asymmetric { - if !p.Pss.isPubKeyStored(key) { - return nil, fmt.Errorf("asym key does not exist: %s", key) - } - p.RWPoolMu.Lock() - p.pubKeyRWPool[key] = rw - p.RWPoolMu.Unlock() - } else { - if !p.Pss.isSymKeyStored(key) { - return nil, fmt.Errorf("symkey does not exist: %s", key) - } - p.RWPoolMu.Lock() - p.symKeyRWPool[key] = rw - p.RWPoolMu.Unlock() - } - go func() { - err := p.proto.Run(peer, rw) - log.Warn(fmt.Sprintf("pss vprotocol quit on %v topic %v: %v", peer, topic, err)) - }() - return rw, nil -} - -func (p *Protocol) RemovePeer(asymmetric bool, key string) { - log.Debug("closing pss peer", "asym", asymmetric, "key", key) - p.RWPoolMu.Lock() - defer p.RWPoolMu.Unlock() - if asymmetric { - rw := p.pubKeyRWPool[key].(*PssReadWriter) - rw.closed = true - delete(p.pubKeyRWPool, key) - } else { - rw := p.symKeyRWPool[key].(*PssReadWriter) - rw.closed = true - delete(p.symKeyRWPool, key) - } -} - -// Uniform translation of protocol specifiers to topic -func ProtocolTopic(spec *protocols.Spec) Topic { - return BytesToTopic([]byte(fmt.Sprintf("%s:%d", spec.Name, spec.Version))) -} diff --git a/swarm/pss/protocol_none.go b/swarm/pss/protocol_none.go deleted file mode 100644 index c92be3f902..0000000000 --- a/swarm/pss/protocol_none.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build nopssprotocol - -package pss - -const ( - IsActiveProtocol = false -) diff --git a/swarm/pss/protocol_test.go b/swarm/pss/protocol_test.go deleted file mode 100644 index 520c48a202..0000000000 --- a/swarm/pss/protocol_test.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package pss - -import ( - "bytes" - "context" - "fmt" - "strconv" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/log" -) - -type protoCtrl struct { - C chan bool - protocol *Protocol - run func(*p2p.Peer, p2p.MsgReadWriter) error -} - -// simple ping pong protocol test for the pss devp2p emulation -func TestProtocol(t *testing.T) { - t.Run("32", testProtocol) - t.Run("8", testProtocol) - t.Run("0", testProtocol) -} - -func testProtocol(t *testing.T) { - - // address hint size - var addrsize int64 - paramstring := strings.Split(t.Name(), "/") - addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) - log.Info("protocol test", "addrsize", addrsize) - - topic := PingTopic.String() - - clients, err := setupNetwork(2, false) - if err != nil { - t.Fatal(err) - } - var loaddrhex string - err = clients[0].Call(&loaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 1 baseaddr fail: %v", err) - } - loaddrhex = loaddrhex[:2+(addrsize*2)] - var roaddrhex string - err = clients[1].Call(&roaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 2 baseaddr fail: %v", err) - } - roaddrhex = roaddrhex[:2+(addrsize*2)] - lnodeinfo := &p2p.NodeInfo{} - err = clients[0].Call(&lnodeinfo, "admin_nodeInfo") - if err != nil { - t.Fatalf("rpc nodeinfo node 11 fail: %v", err) - } - - var lpubkey string - err = clients[0].Call(&lpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 1 pubkey fail: %v", err) - } - var rpubkey string - err = clients[1].Call(&rpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 2 pubkey fail: %v", err) - } - - time.Sleep(time.Millisecond * 1000) // replace with hive healthy code - - lmsgC := make(chan APIMsg) - lctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false) - if err != nil { - t.Fatal(err) - } - defer lsub.Unsubscribe() - rmsgC := make(chan APIMsg) - rctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) - if err != nil { - t.Fatal(err) - } - defer rsub.Unsubscribe() - - // set reciprocal public keys - err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddrhex) - if err != nil { - t.Fatal(err) - } - err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddrhex) - if err != nil { - t.Fatal(err) - } - - // add right peer's public key as protocol peer on left - p := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%x", common.FromHex(loaddrhex)), []p2p.Cap{}) - _, err = pssprotocols[lnodeinfo.ID].protocol.AddPeer(p, PingTopic, true, rpubkey) - if err != nil { - t.Fatal(err) - } - - // sends ping asym, checks delivery - pssprotocols[lnodeinfo.ID].C <- false - select { - case <-lmsgC: - log.Debug("lnode ok") - case cerr := <-lctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - return - } - select { - case <-rmsgC: - log.Debug("rnode ok") - case cerr := <-lctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - } - - // sends ping asym, checks delivery - pssprotocols[lnodeinfo.ID].C <- false - select { - case <-lmsgC: - log.Debug("lnode ok") - case cerr := <-lctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - } - select { - case <-rmsgC: - log.Debug("rnode ok") - case cerr := <-lctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - } - rw := pssprotocols[lnodeinfo.ID].protocol.pubKeyRWPool[rpubkey] - pssprotocols[lnodeinfo.ID].protocol.RemovePeer(true, rpubkey) - if err := rw.WriteMsg(p2p.Msg{ - Size: 3, - Payload: bytes.NewReader([]byte("foo")), - }); err == nil { - t.Fatalf("expected error on write") - } -} diff --git a/swarm/pss/prox_test.go b/swarm/pss/prox_test.go deleted file mode 100644 index 908a0d3302..0000000000 --- a/swarm/pss/prox_test.go +++ /dev/null @@ -1,467 +0,0 @@ -package pss - -import ( - "context" - "crypto/ecdsa" - "encoding/binary" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/simulation" - "github.com/ethereum/go-ethereum/swarm/pot" - "github.com/ethereum/go-ethereum/swarm/state" -) - -// needed to make the enode id of the receiving node available to the handler for triggers -type handlerContextFunc func(*testData, *adapters.NodeConfig) *handler - -// struct to notify reception of messages to simulation driver -// TODO To make code cleaner: -// - consider a separate pss unwrap to message event in sim framework (this will make eventual message propagation analysis with pss easier/possible in the future) -// - consider also test api calls to inspect handling results of messages -type handlerNotification struct { - id enode.ID - serial uint64 -} - -type testData struct { - sim *simulation.Simulation - kademlias map[enode.ID]*network.Kademlia - nodeAddresses map[enode.ID][]byte // make predictable overlay addresses from the generated random enode ids - senders map[int]enode.ID // originating nodes of the messages (intention is to choose as far as possible from the receiving neighborhood) - recipientAddresses [][]byte - - requiredMsgCount int - requiredMsgs map[enode.ID][]uint64 // message serials we expect respective nodes to receive - allowedMsgs map[enode.ID][]uint64 // message serials we expect respective nodes to receive - - notifications []handlerNotification // notification queue - totalMsgCount int - handlerDone bool // set to true on termination of the simulation run - mu sync.Mutex -} - -var ( - pof = pot.DefaultPof(256) // generate messages and index them - topic = BytesToTopic([]byte{0xf3, 0x9e, 0x06, 0x82}) -) - -func (td *testData) pushNotification(val handlerNotification) { - td.mu.Lock() - td.notifications = append(td.notifications, val) - td.mu.Unlock() -} - -func (td *testData) popNotification() (first handlerNotification, exist bool) { - td.mu.Lock() - if len(td.notifications) > 0 { - exist = true - first = td.notifications[0] - td.notifications = td.notifications[1:] - } - td.mu.Unlock() - return first, exist -} - -func (td *testData) getMsgCount() int { - td.mu.Lock() - defer td.mu.Unlock() - return td.totalMsgCount -} - -func (td *testData) incrementMsgCount() int { - td.mu.Lock() - defer td.mu.Unlock() - td.totalMsgCount++ - return td.totalMsgCount -} - -func (td *testData) isDone() bool { - td.mu.Lock() - defer td.mu.Unlock() - return td.handlerDone -} - -func (td *testData) setDone() { - td.mu.Lock() - defer td.mu.Unlock() - td.handlerDone = true -} - -func newTestData() *testData { - return &testData{ - kademlias: make(map[enode.ID]*network.Kademlia), - nodeAddresses: make(map[enode.ID][]byte), - requiredMsgs: make(map[enode.ID][]uint64), - allowedMsgs: make(map[enode.ID][]uint64), - senders: make(map[int]enode.ID), - } -} - -func (td *testData) getKademlia(nodeId *enode.ID) (*network.Kademlia, error) { - kadif, ok := td.sim.NodeItem(*nodeId, simulation.BucketKeyKademlia) - if !ok { - return nil, fmt.Errorf("no kademlia entry for %v", nodeId) - } - kad, ok := kadif.(*network.Kademlia) - if !ok { - return nil, fmt.Errorf("invalid kademlia entry for %v", nodeId) - } - return kad, nil -} - -func (td *testData) init(msgCount int) error { - log.Debug("TestProxNetwork start") - - for _, nodeId := range td.sim.NodeIDs() { - kad, err := td.getKademlia(&nodeId) - if err != nil { - return err - } - td.nodeAddresses[nodeId] = kad.BaseAddr() - } - - for i := 0; i < int(msgCount); i++ { - msgAddr := pot.RandomAddress() // we choose message addresses randomly - td.recipientAddresses = append(td.recipientAddresses, msgAddr.Bytes()) - smallestPo := 256 - var targets []enode.ID - var closestPO int - - // loop through all nodes and find the required and allowed recipients of each message - // (for more information, please see the comment to the main test function) - for _, nod := range td.sim.Net.GetNodes() { - po, _ := pof(td.recipientAddresses[i], td.nodeAddresses[nod.ID()], 0) - depth := td.kademlias[nod.ID()].NeighbourhoodDepth() - - // only nodes with closest IDs (wrt the msg address) will be required recipients - if po > closestPO { - closestPO = po - targets = nil - targets = append(targets, nod.ID()) - } else if po == closestPO { - targets = append(targets, nod.ID()) - } - - if po >= depth { - td.allowedMsgs[nod.ID()] = append(td.allowedMsgs[nod.ID()], uint64(i)) - } - - // a node with the smallest PO (wrt msg) will be the sender, - // in order to increase the distance the msg must travel - if po < smallestPo { - smallestPo = po - td.senders[i] = nod.ID() - } - } - - td.requiredMsgCount += len(targets) - for _, id := range targets { - td.requiredMsgs[id] = append(td.requiredMsgs[id], uint64(i)) - } - - log.Debug("nn for msg", "targets", len(targets), "msgidx", i, "msg", common.Bytes2Hex(msgAddr[:8]), "sender", td.senders[i], "senderpo", smallestPo) - } - log.Debug("recipientAddresses to receive", "count", td.requiredMsgCount) - return nil -} - -// Here we test specific functionality of the pss, setting the prox property of -// the handler. The tests generate a number of messages with random addresses. -// Then, for each message it calculates which nodes have the msg address -// within its nearest neighborhood depth, and stores those nodes as possible -// recipients. Those nodes that are the closest to the message address (nodes -// belonging to the deepest PO wrt the msg address) are stored as required -// recipients. The difference between allowed and required recipients results -// from the fact that the nearest neighbours are not necessarily reciprocal. -// Upon sending the messages, the test verifies that the respective message is -// passed to the message handlers of these required recipients. The test fails -// if a message is handled by recipient which is not listed among the allowed -// recipients of this particular message. It also fails after timeout, if not -// all the required recipients have received their respective messages. -// -// For example, if proximity order of certain msg address is 4, and node X -// has PO=5 wrt the message address, and nodes Y and Z have PO=6, then: -// nodes Y and Z will be considered required recipients of the msg, -// whereas nodes X, Y and Z will be allowed recipients. -func TestProxNetwork(t *testing.T) { - t.Run("16_nodes,_16_messages,_16_seconds", func(t *testing.T) { - testProxNetwork(t, 16, 16, 16*time.Second) - }) -} - -func TestProxNetworkLong(t *testing.T) { - if !*longrunning { - t.Skip("run with --longrunning flag to run extensive network tests") - } - t.Run("8_nodes,_100_messages,_30_seconds", func(t *testing.T) { - testProxNetwork(t, 8, 100, 30*time.Second) - }) - t.Run("16_nodes,_100_messages,_30_seconds", func(t *testing.T) { - testProxNetwork(t, 16, 100, 30*time.Second) - }) - t.Run("32_nodes,_100_messages,_60_seconds", func(t *testing.T) { - testProxNetwork(t, 32, 100, 1*time.Minute) - }) - t.Run("64_nodes,_100_messages,_60_seconds", func(t *testing.T) { - testProxNetwork(t, 64, 100, 1*time.Minute) - }) - t.Run("128_nodes,_100_messages,_120_seconds", func(t *testing.T) { - testProxNetwork(t, 128, 100, 2*time.Minute) - }) -} - -func testProxNetwork(t *testing.T, nodeCount int, msgCount int, timeout time.Duration) { - td := newTestData() - handlerContextFuncs := make(map[Topic]handlerContextFunc) - handlerContextFuncs[topic] = nodeMsgHandler - services := newProxServices(td, true, handlerContextFuncs, td.kademlias) - td.sim = simulation.New(services) - defer td.sim.Close() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - filename := fmt.Sprintf("testdata/snapshot_%d.json", nodeCount) - err := td.sim.UploadSnapshot(ctx, filename) - if err != nil { - t.Fatal(err) - } - err = td.init(msgCount) // initialize the test data - if err != nil { - t.Fatal(err) - } - wrapper := func(c context.Context, _ *simulation.Simulation) error { - return testRoutine(td, c) - } - result := td.sim.Run(ctx, wrapper) // call the main test function - if result.Error != nil { - timedOut := result.Error == context.DeadlineExceeded - if !timedOut || td.getMsgCount() < td.requiredMsgCount { - t.Fatal(result.Error) - } - } -} - -func (td *testData) sendAllMsgs() error { - nodes := make(map[int]*rpc.Client) - for i := range td.recipientAddresses { - nodeClient, err := td.sim.Net.GetNode(td.senders[i]).Client() - if err != nil { - return err - } - nodes[i] = nodeClient - } - - for i, msg := range td.recipientAddresses { - log.Debug("sending msg", "idx", i, "from", td.senders[i]) - nodeClient := nodes[i] - var uvarByte [8]byte - binary.PutUvarint(uvarByte[:], uint64(i)) - nodeClient.Call(nil, "pss_sendRaw", hexutil.Encode(msg), hexutil.Encode(topic[:]), hexutil.Encode(uvarByte[:])) - } - return nil -} - -func isMoreTimeLeft(ctx context.Context) bool { - select { - case <-ctx.Done(): - return false - default: - return true - } -} - -// testRoutine is the main test function, called by Simulation.Run() -func testRoutine(td *testData, ctx context.Context) error { - - hasMoreRound := func(err error, hadMessage bool) bool { - return err == nil && (hadMessage || isMoreTimeLeft(ctx)) - } - - if err := td.sendAllMsgs(); err != nil { - return err - } - - var err error - received := 0 - hadMessage := false - - for oneMoreRound := true; oneMoreRound; oneMoreRound = hasMoreRound(err, hadMessage) { - message, hadMessage := td.popNotification() - - if !isMoreTimeLeft(ctx) { - // Stop handlers from sending more messages. - // Note: only best effort, race is possible. - td.setDone() - } - - if hadMessage { - if td.isAllowedMessage(message) { - received++ - log.Debug("msg received", "msgs_received", received, "total_expected", td.requiredMsgCount, "id", message.id, "serial", message.serial) - } else { - err = fmt.Errorf("message %d received by wrong recipient %v", message.serial, message.id) - } - } else { - time.Sleep(32 * time.Millisecond) - } - } - - if err != nil { - return err - } - - if td.getMsgCount() < td.requiredMsgCount { - return ctx.Err() - } - return nil -} - -func (td *testData) isAllowedMessage(n handlerNotification) bool { - // check if message serial is in expected messages for this recipient - for _, s := range td.allowedMsgs[n.id] { - if n.serial == s { - return true - } - } - return false -} - -func (td *testData) removeAllowedMessage(id enode.ID, index int) { - last := len(td.allowedMsgs[id]) - 1 - td.allowedMsgs[id][index] = td.allowedMsgs[id][last] - td.allowedMsgs[id] = td.allowedMsgs[id][:last] -} - -func nodeMsgHandler(td *testData, config *adapters.NodeConfig) *handler { - return &handler{ - f: func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - if td.isDone() { - return nil // terminate if simulation is over - } - - td.incrementMsgCount() - - // using simple serial in message body, makes it easy to keep track of who's getting what - serial, c := binary.Uvarint(msg) - if c <= 0 { - log.Crit(fmt.Sprintf("corrupt message received by %x (uvarint parse returned %d)", config.ID, c)) - } - - td.pushNotification(handlerNotification{id: config.ID, serial: serial}) - return nil - }, - caps: &handlerCaps{ - raw: true, // we use raw messages for simplicity - prox: true, - }, - } -} - -// an adaptation of the same services setup as in pss_test.go -// replaces pss_test.go when those tests are rewritten to the new swarm/network/simulation package -func newProxServices(td *testData, allowRaw bool, handlerContextFuncs map[Topic]handlerContextFunc, kademlias map[enode.ID]*network.Kademlia) map[string]simulation.ServiceFunc { - stateStore := state.NewInmemoryStore() - kademlia := func(id enode.ID, bzzkey []byte) *network.Kademlia { - if k, ok := kademlias[id]; ok { - return k - } - params := network.NewKadParams() - params.MaxBinSize = 3 - params.MinBinSize = 1 - params.MaxRetries = 1000 - params.RetryExponent = 2 - params.RetryInterval = 1000000 - kademlias[id] = network.NewKademlia(bzzkey, params) - return kademlias[id] - } - return map[string]simulation.ServiceFunc{ - "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - var err error - var bzzPrivateKey *ecdsa.PrivateKey - // normally translation of enode id to swarm address is concealed by the network package - // however, we need to keep track of it in the test driver as well. - // if the translation in the network package changes, that can cause these tests to unpredictably fail - // therefore we keep a local copy of the translation here - addr := network.NewAddr(ctx.Config.Node()) - bzzPrivateKey, err = simulation.BzzPrivateKeyFromConfig(ctx.Config) - if err != nil { - return nil, nil, err - } - addr.OAddr = network.PrivateKeyToBzzKey(bzzPrivateKey) - b.Store(simulation.BucketKeyBzzPrivateKey, bzzPrivateKey) - hp := network.NewHiveParams() - hp.Discovery = false - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - bzzKey := network.PrivateKeyToBzzKey(bzzPrivateKey) - pskad := kademlia(ctx.Config.ID, bzzKey) - b.Store(simulation.BucketKeyKademlia, pskad) - return network.NewBzz(config, kademlia(ctx.Config.ID, addr.OAddr), stateStore, nil, nil), nil, nil - }, - "pss": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { - // execadapter does not exec init() - initTest() - - // create keys in whisper and set up the pss object - ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second*3) - defer cancel() - keys, err := wapi.NewKeyPair(ctxlocal) - privkey, err := w.GetPrivateKey(keys) - pssp := NewPssParams().WithPrivateKey(privkey) - pssp.AllowRaw = allowRaw - bzzPrivateKey, err := simulation.BzzPrivateKeyFromConfig(ctx.Config) - if err != nil { - return nil, nil, err - } - bzzKey := network.PrivateKeyToBzzKey(bzzPrivateKey) - pskad := kademlia(ctx.Config.ID, bzzKey) - b.Store(simulation.BucketKeyKademlia, pskad) - ps, err := NewPss(pskad, pssp) - if err != nil { - return nil, nil, err - } - - // register the handlers we've been passed - var deregisters []func() - for tpc, hndlrFunc := range handlerContextFuncs { - deregisters = append(deregisters, ps.Register(&tpc, hndlrFunc(td, ctx.Config))) - } - - // if handshake mode is set, add the controller - // TODO: This should be hooked to the handshake test file - if useHandshake { - SetHandshakeController(ps, NewHandshakeParams()) - } - - // we expose some api calls for cheating - ps.addAPI(rpc.API{ - Namespace: "psstest", - Version: "0.3", - Service: NewAPITest(ps), - Public: false, - }) - - // return Pss and cleanups - return ps, func() { - // run the handler deregister functions in reverse order - for i := len(deregisters); i > 0; i-- { - deregisters[i-1]() - } - }, nil - }, - } -} diff --git a/swarm/pss/pss.go b/swarm/pss/pss.go deleted file mode 100644 index 0d02c9b8de..0000000000 --- a/swarm/pss/pss.go +++ /dev/null @@ -1,857 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package pss - -import ( - "bytes" - "context" - "crypto/ecdsa" - "crypto/rand" - "errors" - "fmt" - "hash" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/pot" - "github.com/ethereum/go-ethereum/swarm/storage" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" - "golang.org/x/crypto/sha3" -) - -const ( - defaultPaddingByteSize = 16 - DefaultMsgTTL = time.Second * 120 - defaultDigestCacheTTL = time.Second * 10 - defaultSymKeyCacheCapacity = 512 - digestLength = 32 // byte length of digest used for pss cache (currently same as swarm chunk hash) - defaultWhisperWorkTime = 3 - defaultWhisperPoW = 0.0000000001 - defaultMaxMsgSize = 1024 * 1024 - defaultCleanInterval = time.Second * 60 * 10 - defaultOutboxCapacity = 100000 - pssProtocolName = "pss" - pssVersion = 2 - hasherCount = 8 -) - -var ( - addressLength = len(pot.Address{}) -) - -// cache is used for preventing backwards routing -// will also be instrumental in flood guard mechanism -// and mailbox implementation -type pssCacheEntry struct { - expiresAt time.Time -} - -// abstraction to enable access to p2p.protocols.Peer.Send -type senderPeer interface { - Info() *p2p.PeerInfo - ID() enode.ID - Address() []byte - Send(context.Context, interface{}) error -} - -// per-key peer related information -// member `protected` prevents garbage collection of the instance -type pssPeer struct { - lastSeen time.Time - address PssAddress - protected bool -} - -// Pss configuration parameters -type PssParams struct { - MsgTTL time.Duration - CacheTTL time.Duration - privateKey *ecdsa.PrivateKey - SymKeyCacheCapacity int - AllowRaw bool // If true, enables sending and receiving messages without builtin pss encryption -} - -// Sane defaults for Pss -func NewPssParams() *PssParams { - return &PssParams{ - MsgTTL: DefaultMsgTTL, - CacheTTL: defaultDigestCacheTTL, - SymKeyCacheCapacity: defaultSymKeyCacheCapacity, - } -} - -func (params *PssParams) WithPrivateKey(privatekey *ecdsa.PrivateKey) *PssParams { - params.privateKey = privatekey - return params -} - -// Toplevel pss object, takes care of message sending, receiving, decryption and encryption, message handler dispatchers and message forwarding. -// -// Implements node.Service -type Pss struct { - *network.Kademlia // we can get the Kademlia address from this - *KeyStore - - privateKey *ecdsa.PrivateKey // pss can have it's own independent key - auxAPIs []rpc.API // builtins (handshake, test) can add APIs - - // sending and forwarding - fwdPool map[string]*protocols.Peer // keep track of all peers sitting on the pssmsg routing layer - fwdPoolMu sync.RWMutex - fwdCache map[pssDigest]pssCacheEntry // checksum of unique fields from pssmsg mapped to expiry, cache to determine whether to drop msg - fwdCacheMu sync.RWMutex - cacheTTL time.Duration // how long to keep messages in fwdCache (not implemented) - msgTTL time.Duration - paddingByteSize int - capstring string - outbox chan *PssMsg - - // message handling - handlers map[Topic]map[*handler]bool // topic and version based pss payload handlers. See pss.Handle() - handlersMu sync.RWMutex - hashPool sync.Pool - topicHandlerCaps map[Topic]*handlerCaps // caches capabilities of each topic's handlers - topicHandlerCapsMu sync.RWMutex - - // process - quitC chan struct{} -} - -func (p *Pss) String() string { - return fmt.Sprintf("pss: addr %x, pubkey %v", p.BaseAddr(), common.ToHex(crypto.FromECDSAPub(&p.privateKey.PublicKey))) -} - -// Creates a new Pss instance. -// -// In addition to params, it takes a swarm network Kademlia -// and a FileStore storage for message cache storage. -func NewPss(k *network.Kademlia, params *PssParams) (*Pss, error) { - if params.privateKey == nil { - return nil, errors.New("missing private key for pss") - } - cap := p2p.Cap{ - Name: pssProtocolName, - Version: pssVersion, - } - ps := &Pss{ - Kademlia: k, - KeyStore: loadKeyStore(), - - privateKey: params.privateKey, - quitC: make(chan struct{}), - - fwdPool: make(map[string]*protocols.Peer), - fwdCache: make(map[pssDigest]pssCacheEntry), - cacheTTL: params.CacheTTL, - msgTTL: params.MsgTTL, - paddingByteSize: defaultPaddingByteSize, - capstring: cap.String(), - outbox: make(chan *PssMsg, defaultOutboxCapacity), - - handlers: make(map[Topic]map[*handler]bool), - topicHandlerCaps: make(map[Topic]*handlerCaps), - - hashPool: sync.Pool{ - New: func() interface{} { - return sha3.NewLegacyKeccak256() - }, - }, - } - - for i := 0; i < hasherCount; i++ { - hashfunc := storage.MakeHashFunc(storage.DefaultHash)() - ps.hashPool.Put(hashfunc) - } - - return ps, nil -} - -///////////////////////////////////////////////////////////////////// -// SECTION: node.Service interface -///////////////////////////////////////////////////////////////////// - -func (p *Pss) Start(srv *p2p.Server) error { - go func() { - ticker := time.NewTicker(defaultCleanInterval) - cacheTicker := time.NewTicker(p.cacheTTL) - defer ticker.Stop() - defer cacheTicker.Stop() - for { - select { - case <-cacheTicker.C: - p.cleanFwdCache() - case <-ticker.C: - p.cleanKeys() - case <-p.quitC: - return - } - } - }() - go func() { - for { - select { - case msg := <-p.outbox: - err := p.forward(msg) - if err != nil { - log.Error(err.Error()) - metrics.GetOrRegisterCounter("pss.forward.err", nil).Inc(1) - } - case <-p.quitC: - return - } - } - }() - log.Info("Started Pss") - log.Info("Loaded EC keys", "pubkey", common.ToHex(crypto.FromECDSAPub(p.PublicKey())), "secp256", common.ToHex(crypto.CompressPubkey(p.PublicKey()))) - return nil -} - -func (p *Pss) Stop() error { - log.Info("Pss shutting down") - close(p.quitC) - return nil -} - -var pssSpec = &protocols.Spec{ - Name: pssProtocolName, - Version: pssVersion, - MaxMsgSize: defaultMaxMsgSize, - Messages: []interface{}{ - PssMsg{}, - }, -} - -func (p *Pss) Protocols() []p2p.Protocol { - return []p2p.Protocol{ - { - Name: pssSpec.Name, - Version: pssSpec.Version, - Length: pssSpec.Length(), - Run: p.Run, - }, - } -} - -func (p *Pss) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - pp := protocols.NewPeer(peer, rw, pssSpec) - p.fwdPoolMu.Lock() - p.fwdPool[peer.Info().ID] = pp - p.fwdPoolMu.Unlock() - return pp.Run(p.handlePssMsg) -} - -func (p *Pss) APIs() []rpc.API { - apis := []rpc.API{ - { - Namespace: "pss", - Version: "1.0", - Service: NewAPI(p), - Public: true, - }, - } - apis = append(apis, p.auxAPIs...) - return apis -} - -// add API methods to the pss API -// must be run before node is started -func (p *Pss) addAPI(api rpc.API) { - p.auxAPIs = append(p.auxAPIs, api) -} - -// Returns the swarm Kademlia address of the pss node -func (p *Pss) BaseAddr() []byte { - return p.Kademlia.BaseAddr() -} - -// Returns the pss node's public key -func (p *Pss) PublicKey() *ecdsa.PublicKey { - return &p.privateKey.PublicKey -} - -///////////////////////////////////////////////////////////////////// -// SECTION: Message handling -///////////////////////////////////////////////////////////////////// - -func (p *Pss) getTopicHandlerCaps(topic Topic) (hc *handlerCaps, found bool) { - p.topicHandlerCapsMu.RLock() - defer p.topicHandlerCapsMu.RUnlock() - hc, found = p.topicHandlerCaps[topic] - return -} - -func (p *Pss) setTopicHandlerCaps(topic Topic, hc *handlerCaps) { - p.topicHandlerCapsMu.Lock() - defer p.topicHandlerCapsMu.Unlock() - p.topicHandlerCaps[topic] = hc -} - -// Links a handler function to a Topic -// -// All incoming messages with an envelope Topic matching the -// topic specified will be passed to the given Handler function. -// -// There may be an arbitrary number of handler functions per topic. -// -// Returns a deregister function which needs to be called to -// deregister the handler, -func (p *Pss) Register(topic *Topic, hndlr *handler) func() { - p.handlersMu.Lock() - defer p.handlersMu.Unlock() - handlers := p.handlers[*topic] - if handlers == nil { - handlers = make(map[*handler]bool) - p.handlers[*topic] = handlers - log.Debug("registered handler", "capabilities", hndlr.caps) - } - if hndlr.caps == nil { - hndlr.caps = &handlerCaps{} - } - handlers[hndlr] = true - - capabilities, ok := p.getTopicHandlerCaps(*topic) - if !ok { - capabilities = &handlerCaps{} - p.setTopicHandlerCaps(*topic, capabilities) - } - - if hndlr.caps.raw { - capabilities.raw = true - } - if hndlr.caps.prox { - capabilities.prox = true - } - return func() { p.deregister(topic, hndlr) } -} - -func (p *Pss) deregister(topic *Topic, hndlr *handler) { - p.handlersMu.Lock() - defer p.handlersMu.Unlock() - handlers := p.handlers[*topic] - if len(handlers) > 1 { - delete(p.handlers, *topic) - // topic caps might have changed now that a handler is gone - caps := &handlerCaps{} - for h := range handlers { - if h.caps.raw { - caps.raw = true - } - if h.caps.prox { - caps.prox = true - } - } - p.setTopicHandlerCaps(*topic, caps) - return - } - delete(handlers, hndlr) -} - -// Filters incoming messages for processing or forwarding. -// Check if address partially matches -// If yes, it CAN be for us, and we process it -// Only passes error to pss protocol handler if payload is not valid pssmsg -func (p *Pss) handlePssMsg(ctx context.Context, msg interface{}) error { - metrics.GetOrRegisterCounter("pss.handlepssmsg", nil).Inc(1) - pssmsg, ok := msg.(*PssMsg) - if !ok { - return fmt.Errorf("invalid message type. Expected *PssMsg, got %T ", msg) - } - log.Trace("handler", "self", label(p.Kademlia.BaseAddr()), "topic", label(pssmsg.Payload.Topic[:])) - if int64(pssmsg.Expire) < time.Now().Unix() { - metrics.GetOrRegisterCounter("pss.expire", nil).Inc(1) - log.Warn("pss filtered expired message", "from", common.ToHex(p.Kademlia.BaseAddr()), "to", common.ToHex(pssmsg.To)) - return nil - } - if p.checkFwdCache(pssmsg) { - log.Trace("pss relay block-cache match (process)", "from", common.ToHex(p.Kademlia.BaseAddr()), "to", (common.ToHex(pssmsg.To))) - return nil - } - p.addFwdCache(pssmsg) - - psstopic := Topic(pssmsg.Payload.Topic) - - // raw is simplest handler contingency to check, so check that first - var isRaw bool - if pssmsg.isRaw() { - if capabilities, ok := p.getTopicHandlerCaps(psstopic); ok { - if !capabilities.raw { - log.Debug("No handler for raw message", "topic", psstopic) - return nil - } - } - isRaw = true - } - - // check if we can be recipient: - // - no prox handler on message and partial address matches - // - prox handler on message and we are in prox regardless of partial address match - // store this result so we don't calculate again on every handler - var isProx bool - if capabilities, ok := p.getTopicHandlerCaps(psstopic); ok { - isProx = capabilities.prox - } - isRecipient := p.isSelfPossibleRecipient(pssmsg, isProx) - if !isRecipient { - log.Trace("pss msg forwarding ===>", "pss", common.ToHex(p.BaseAddr()), "prox", isProx) - return p.enqueue(pssmsg) - } - - log.Trace("pss msg processing <===", "pss", common.ToHex(p.BaseAddr()), "prox", isProx, "raw", isRaw, "topic", label(pssmsg.Payload.Topic[:])) - if err := p.process(pssmsg, isRaw, isProx); err != nil { - qerr := p.enqueue(pssmsg) - if qerr != nil { - return fmt.Errorf("process fail: processerr %v, queueerr: %v", err, qerr) - } - } - return nil -} - -// Entry point to processing a message for which the current node can be the intended recipient. -// Attempts symmetric and asymmetric decryption with stored keys. -// Dispatches message to all handlers matching the message topic -func (p *Pss) process(pssmsg *PssMsg, raw bool, prox bool) error { - metrics.GetOrRegisterCounter("pss.process", nil).Inc(1) - - var err error - var recvmsg *whisper.ReceivedMessage - var payload []byte - var from PssAddress - var asymmetric bool - var keyid string - var keyFunc func(envelope *whisper.Envelope) (*whisper.ReceivedMessage, string, PssAddress, error) - - envelope := pssmsg.Payload - psstopic := Topic(envelope.Topic) - - if raw { - payload = pssmsg.Payload.Data - } else { - if pssmsg.isSym() { - keyFunc = p.processSym - } else { - asymmetric = true - keyFunc = p.processAsym - } - - recvmsg, keyid, from, err = keyFunc(envelope) - if err != nil { - return errors.New("Decryption failed") - } - payload = recvmsg.Payload - } - - if len(pssmsg.To) < addressLength || prox { - err = p.enqueue(pssmsg) - } - p.executeHandlers(psstopic, payload, from, raw, prox, asymmetric, keyid) - return err -} - -// copy all registered handlers for respective topic in order to avoid data race or deadlock -func (p *Pss) getHandlers(topic Topic) (ret []*handler) { - p.handlersMu.RLock() - defer p.handlersMu.RUnlock() - for k := range p.handlers[topic] { - ret = append(ret, k) - } - return ret -} - -func (p *Pss) executeHandlers(topic Topic, payload []byte, from PssAddress, raw bool, prox bool, asymmetric bool, keyid string) { - handlers := p.getHandlers(topic) - peer := p2p.NewPeer(enode.ID{}, fmt.Sprintf("%x", from), []p2p.Cap{}) - for _, h := range handlers { - if !h.caps.raw && raw { - log.Warn("norawhandler") - continue - } - if !h.caps.prox && prox { - log.Warn("noproxhandler") - continue - } - err := (h.f)(payload, peer, asymmetric, keyid) - if err != nil { - log.Warn("Pss handler failed", "err", err) - } - } -} - -// will return false if using partial address -func (p *Pss) isSelfRecipient(msg *PssMsg) bool { - return bytes.Equal(msg.To, p.Kademlia.BaseAddr()) -} - -// test match of leftmost bytes in given message to node's Kademlia address -func (p *Pss) isSelfPossibleRecipient(msg *PssMsg, prox bool) bool { - local := p.Kademlia.BaseAddr() - - // if a partial address matches we are possible recipient regardless of prox - // if not and prox is not set, we are surely not - if bytes.Equal(msg.To, local[:len(msg.To)]) { - - return true - } else if !prox { - return false - } - - depth := p.Kademlia.NeighbourhoodDepth() - po, _ := network.Pof(p.Kademlia.BaseAddr(), msg.To, 0) - log.Trace("selfpossible", "po", po, "depth", depth) - - return depth <= po -} - -///////////////////////////////////////////////////////////////////// -// SECTION: Message sending -///////////////////////////////////////////////////////////////////// - -func (p *Pss) enqueue(msg *PssMsg) error { - select { - case p.outbox <- msg: - return nil - default: - } - - metrics.GetOrRegisterCounter("pss.enqueue.outbox.full", nil).Inc(1) - return errors.New("outbox full") -} - -// Send a raw message (any encryption is responsibility of calling client) -// -// Will fail if raw messages are disallowed -func (p *Pss) SendRaw(address PssAddress, topic Topic, msg []byte) error { - if err := validateAddress(address); err != nil { - return err - } - pssMsgParams := &msgParams{ - raw: true, - } - payload := &whisper.Envelope{ - Data: msg, - Topic: whisper.TopicType(topic), - } - pssMsg := newPssMsg(pssMsgParams) - pssMsg.To = address - pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) - pssMsg.Payload = payload - p.addFwdCache(pssMsg) - err := p.enqueue(pssMsg) - if err != nil { - return err - } - - // if we have a proxhandler on this topic - // also deliver message to ourselves - if capabilities, ok := p.getTopicHandlerCaps(topic); ok { - if p.isSelfPossibleRecipient(pssMsg, true) && capabilities.prox { - return p.process(pssMsg, true, true) - } - } - return nil -} - -// Send a message using symmetric encryption -// -// Fails if the key id does not match any of the stored symmetric keys -func (p *Pss) SendSym(symkeyid string, topic Topic, msg []byte) error { - symkey, err := p.GetSymmetricKey(symkeyid) - if err != nil { - return fmt.Errorf("missing valid send symkey %s: %v", symkeyid, err) - } - psp, ok := p.getPeerSym(symkeyid, topic) - if !ok { - return fmt.Errorf("invalid topic '%s' for symkey '%s'", topic.String(), symkeyid) - } - return p.send(psp.address, topic, msg, false, symkey) -} - -// Send a message using asymmetric encryption -// -// Fails if the key id does not match any in of the stored public keys -func (p *Pss) SendAsym(pubkeyid string, topic Topic, msg []byte) error { - if _, err := crypto.UnmarshalPubkey(common.FromHex(pubkeyid)); err != nil { - return fmt.Errorf("Cannot unmarshal pubkey: %x", pubkeyid) - } - psp, ok := p.getPeerPub(pubkeyid, topic) - if !ok { - return fmt.Errorf("invalid topic '%s' for pubkey '%s'", topic.String(), pubkeyid) - } - return p.send(psp.address, topic, msg, true, common.FromHex(pubkeyid)) -} - -// Send is payload agnostic, and will accept any byte slice as payload -// It generates an whisper envelope for the specified recipient and topic, -// and wraps the message payload in it. -// TODO: Implement proper message padding -func (p *Pss) send(to []byte, topic Topic, msg []byte, asymmetric bool, key []byte) error { - metrics.GetOrRegisterCounter("pss.send", nil).Inc(1) - - if key == nil || bytes.Equal(key, []byte{}) { - return fmt.Errorf("Zero length key passed to pss send") - } - padding := make([]byte, p.paddingByteSize) - c, err := rand.Read(padding) - if err != nil { - return err - } else if c < p.paddingByteSize { - return fmt.Errorf("invalid padding length: %d", c) - } - wparams := &whisper.MessageParams{ - TTL: defaultWhisperTTL, - Src: p.privateKey, - Topic: whisper.TopicType(topic), - WorkTime: defaultWhisperWorkTime, - PoW: defaultWhisperPoW, - Payload: msg, - Padding: padding, - } - if asymmetric { - pk, err := crypto.UnmarshalPubkey(key) - if err != nil { - return fmt.Errorf("Cannot unmarshal pubkey: %x", key) - } - wparams.Dst = pk - } else { - wparams.KeySym = key - } - // set up outgoing message container, which does encryption and envelope wrapping - woutmsg, err := whisper.NewSentMessage(wparams) - if err != nil { - return fmt.Errorf("failed to generate whisper message encapsulation: %v", err) - } - // performs encryption. - // Does NOT perform / performs negligible PoW due to very low difficulty setting - // after this the message is ready for sending - envelope, err := woutmsg.Wrap(wparams) - if err != nil { - return fmt.Errorf("failed to perform whisper encryption: %v", err) - } - log.Trace("pssmsg whisper done", "env", envelope, "wparams payload", common.ToHex(wparams.Payload), "to", common.ToHex(to), "asym", asymmetric, "key", common.ToHex(key)) - - // prepare for devp2p transport - pssMsgParams := &msgParams{ - sym: !asymmetric, - } - pssMsg := newPssMsg(pssMsgParams) - pssMsg.To = to - pssMsg.Expire = uint32(time.Now().Add(p.msgTTL).Unix()) - pssMsg.Payload = envelope - err = p.enqueue(pssMsg) - if err != nil { - return err - } - if capabilities, ok := p.getTopicHandlerCaps(topic); ok { - if p.isSelfPossibleRecipient(pssMsg, true) && capabilities.prox { - return p.process(pssMsg, true, true) - } - } - return nil -} - -// sendFunc is a helper function that tries to send a message and returns true on success. -// It is set here for usage in production, and optionally overridden in tests. -var sendFunc = sendMsg - -// tries to send a message, returns true if successful -func sendMsg(p *Pss, sp *network.Peer, msg *PssMsg) bool { - var isPssEnabled bool - info := sp.Info() - for _, capability := range info.Caps { - if capability == p.capstring { - isPssEnabled = true - break - } - } - if !isPssEnabled { - log.Error("peer doesn't have matching pss capabilities, skipping", "peer", info.Name, "caps", info.Caps) - return false - } - - // get the protocol peer from the forwarding peer cache - p.fwdPoolMu.RLock() - pp := p.fwdPool[sp.Info().ID] - p.fwdPoolMu.RUnlock() - - err := pp.Send(context.TODO(), msg) - if err != nil { - metrics.GetOrRegisterCounter("pss.pp.send.error", nil).Inc(1) - log.Error(err.Error()) - } - - return err == nil -} - -// Forwards a pss message to the peer(s) based on recipient address according to the algorithm -// described below. The recipient address can be of any length, and the byte slice will be matched -// to the MSB slice of the peer address of the equivalent length. -// -// If the recipient address (or partial address) is within the neighbourhood depth of the forwarding -// node, then it will be forwarded to all the nearest neighbours of the forwarding node. In case of -// partial address, it should be forwarded to all the peers matching the partial address, if there -// are any; otherwise only to one peer, closest to the recipient address. In any case, if the message -// forwarding fails, the node should try to forward it to the next best peer, until the message is -// successfully forwarded to at least one peer. -func (p *Pss) forward(msg *PssMsg) error { - metrics.GetOrRegisterCounter("pss.forward", nil).Inc(1) - sent := 0 // number of successful sends - to := make([]byte, addressLength) - copy(to[:len(msg.To)], msg.To) - neighbourhoodDepth := p.Kademlia.NeighbourhoodDepth() - - // luminosity is the opposite of darkness. the more bytes are removed from the address, the higher is darkness, - // but the luminosity is less. here luminosity equals the number of bits given in the destination address. - luminosityRadius := len(msg.To) * 8 - - // proximity order function matching up to neighbourhoodDepth bits (po <= neighbourhoodDepth) - pof := pot.DefaultPof(neighbourhoodDepth) - - // soft threshold for msg broadcast - broadcastThreshold, _ := pof(to, p.BaseAddr(), 0) - if broadcastThreshold > luminosityRadius { - broadcastThreshold = luminosityRadius - } - - var onlySendOnce bool // indicates if the message should only be sent to one peer with closest address - - // if measured from the recipient address as opposed to the base address (see Kademlia.EachConn - // call below), then peers that fall in the same proximity bin as recipient address will appear - // [at least] one bit closer, but only if these additional bits are given in the recipient address. - if broadcastThreshold < luminosityRadius && broadcastThreshold < neighbourhoodDepth { - broadcastThreshold++ - onlySendOnce = true - } - - p.Kademlia.EachConn(to, addressLength*8, func(sp *network.Peer, po int) bool { - if po < broadcastThreshold && sent > 0 { - return false // stop iterating - } - if sendFunc(p, sp, msg) { - sent++ - if onlySendOnce { - return false - } - if po == addressLength*8 { - // stop iterating if successfully sent to the exact recipient (perfect match of full address) - return false - } - } - return true - }) - - // if we failed to send to anyone, re-insert message in the send-queue - if sent == 0 { - log.Debug("unable to forward to any peers") - if err := p.enqueue(msg); err != nil { - metrics.GetOrRegisterCounter("pss.forward.enqueue.error", nil).Inc(1) - log.Error(err.Error()) - return err - } - } - - // cache the message - p.addFwdCache(msg) - return nil -} - -///////////////////////////////////////////////////////////////////// -// SECTION: Caching -///////////////////////////////////////////////////////////////////// - -// cleanFwdCache is used to periodically remove expired entries from the forward cache -func (p *Pss) cleanFwdCache() { - metrics.GetOrRegisterCounter("pss.cleanfwdcache", nil).Inc(1) - p.fwdCacheMu.Lock() - defer p.fwdCacheMu.Unlock() - for k, v := range p.fwdCache { - if v.expiresAt.Before(time.Now()) { - delete(p.fwdCache, k) - } - } -} - -func label(b []byte) string { - return fmt.Sprintf("%04x", b[:2]) -} - -// add a message to the cache -func (p *Pss) addFwdCache(msg *PssMsg) error { - metrics.GetOrRegisterCounter("pss.addfwdcache", nil).Inc(1) - - var entry pssCacheEntry - var ok bool - - p.fwdCacheMu.Lock() - defer p.fwdCacheMu.Unlock() - - digest := p.digest(msg) - if entry, ok = p.fwdCache[digest]; !ok { - entry = pssCacheEntry{} - } - entry.expiresAt = time.Now().Add(p.cacheTTL) - p.fwdCache[digest] = entry - return nil -} - -// check if message is in the cache -func (p *Pss) checkFwdCache(msg *PssMsg) bool { - p.fwdCacheMu.Lock() - defer p.fwdCacheMu.Unlock() - - digest := p.digest(msg) - entry, ok := p.fwdCache[digest] - if ok { - if entry.expiresAt.After(time.Now()) { - log.Trace("unexpired cache", "digest", fmt.Sprintf("%x", digest)) - metrics.GetOrRegisterCounter("pss.checkfwdcache.unexpired", nil).Inc(1) - return true - } - metrics.GetOrRegisterCounter("pss.checkfwdcache.expired", nil).Inc(1) - } - return false -} - -// Digest of message -func (p *Pss) digest(msg *PssMsg) pssDigest { - return p.digestBytes(msg.serialize()) -} - -func (p *Pss) digestBytes(msg []byte) pssDigest { - hasher := p.hashPool.Get().(hash.Hash) - defer p.hashPool.Put(hasher) - hasher.Reset() - hasher.Write(msg) - digest := pssDigest{} - key := hasher.Sum(nil) - copy(digest[:], key[:digestLength]) - return digest -} - -func validateAddress(addr PssAddress) error { - if len(addr) > addressLength { - return errors.New("address too long") - } - return nil -} diff --git a/swarm/pss/pss_test.go b/swarm/pss/pss_test.go deleted file mode 100644 index 9884ffbe94..0000000000 --- a/swarm/pss/pss_test.go +++ /dev/null @@ -1,2092 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package pss - -import ( - "bytes" - "context" - "crypto/ecdsa" - "encoding/binary" - "encoding/hex" - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "math/rand" - "os" - "strconv" - "strings" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/pot" - "github.com/ethereum/go-ethereum/swarm/state" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" -) - -var ( - initOnce = sync.Once{} - loglevel = flag.Int("loglevel", 2, "logging verbosity") - longrunning = flag.Bool("longrunning", false, "do run long-running tests") - w *whisper.Whisper - wapi *whisper.PublicWhisperAPI - psslogmain log.Logger - pssprotocols map[string]*protoCtrl - useHandshake bool - noopHandlerFunc = func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - return nil - } -) - -func init() { - flag.Parse() - rand.Seed(time.Now().Unix()) - - adapters.RegisterServices(newServices(false)) - initTest() -} - -func initTest() { - initOnce.Do( - func() { - psslogmain = log.New("psslog", "*") - hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) - hf := log.LvlFilterHandler(log.Lvl(*loglevel), hs) - h := log.CallerFileHandler(hf) - log.Root().SetHandler(h) - - w = whisper.New(&whisper.DefaultConfig) - wapi = whisper.NewPublicWhisperAPI(w) - - pssprotocols = make(map[string]*protoCtrl) - }, - ) -} - -// test that topic conversion functions give predictable results -func TestTopic(t *testing.T) { - - api := &API{} - - topicstr := strings.Join([]string{PingProtocol.Name, strconv.Itoa(int(PingProtocol.Version))}, ":") - - // bytestotopic is the authoritative topic conversion source - topicobj := BytesToTopic([]byte(topicstr)) - - // string to topic and bytes to topic must match - topicapiobj, _ := api.StringToTopic(topicstr) - if topicobj != topicapiobj { - t.Fatalf("bytes and string topic conversion mismatch; %s != %s", topicobj, topicapiobj) - } - - // string representation of topichex - topichex := topicobj.String() - - // protocoltopic wrapper on pingtopic should be same as topicstring - // check that it matches - pingtopichex := PingTopic.String() - if topichex != pingtopichex { - t.Fatalf("protocol topic conversion mismatch; %s != %s", topichex, pingtopichex) - } - - // json marshal of topic - topicjsonout, err := topicobj.MarshalJSON() - if err != nil { - t.Fatal(err) - } - if string(topicjsonout)[1:len(topicjsonout)-1] != topichex { - t.Fatalf("topic json marshal mismatch; %s != \"%s\"", topicjsonout, topichex) - } - - // json unmarshal of topic - var topicjsonin Topic - topicjsonin.UnmarshalJSON(topicjsonout) - if topicjsonin != topicobj { - t.Fatalf("topic json unmarshal mismatch: %x != %x", topicjsonin, topicobj) - } -} - -// test bit packing of message control flags -func TestMsgParams(t *testing.T) { - var ctrl byte - ctrl |= pssControlRaw - p := newMsgParamsFromBytes([]byte{ctrl}) - m := newPssMsg(p) - if !m.isRaw() || m.isSym() { - t.Fatal("expected raw=true and sym=false") - } - ctrl |= pssControlSym - p = newMsgParamsFromBytes([]byte{ctrl}) - m = newPssMsg(p) - if !m.isRaw() || !m.isSym() { - t.Fatal("expected raw=true and sym=true") - } - ctrl &= 0xff &^ pssControlRaw - p = newMsgParamsFromBytes([]byte{ctrl}) - m = newPssMsg(p) - if m.isRaw() || !m.isSym() { - t.Fatal("expected raw=false and sym=true") - } -} - -// test if we can insert into cache, match items with cache and cache expiry -func TestCache(t *testing.T) { - var err error - to, _ := hex.DecodeString("08090a0b0c0d0e0f1011121314150001020304050607161718191a1b1c1d1e1f") - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctx) - privkey, err := w.GetPrivateKey(keys) - if err != nil { - t.Fatal(err) - } - ps := newTestPss(privkey, nil, nil) - defer ps.Stop() - pp := NewPssParams().WithPrivateKey(privkey) - data := []byte("foo") - datatwo := []byte("bar") - datathree := []byte("baz") - wparams := &whisper.MessageParams{ - TTL: defaultWhisperTTL, - Src: privkey, - Dst: &privkey.PublicKey, - Topic: whisper.TopicType(PingTopic), - WorkTime: defaultWhisperWorkTime, - PoW: defaultWhisperPoW, - Payload: data, - } - woutmsg, err := whisper.NewSentMessage(wparams) - env, err := woutmsg.Wrap(wparams) - msg := &PssMsg{ - Payload: env, - To: to, - } - wparams.Payload = datatwo - woutmsg, err = whisper.NewSentMessage(wparams) - envtwo, err := woutmsg.Wrap(wparams) - msgtwo := &PssMsg{ - Payload: envtwo, - To: to, - } - wparams.Payload = datathree - woutmsg, err = whisper.NewSentMessage(wparams) - envthree, err := woutmsg.Wrap(wparams) - msgthree := &PssMsg{ - Payload: envthree, - To: to, - } - - digest := ps.digest(msg) - if err != nil { - t.Fatalf("could not store cache msgone: %v", err) - } - digesttwo := ps.digest(msgtwo) - if err != nil { - t.Fatalf("could not store cache msgtwo: %v", err) - } - digestthree := ps.digest(msgthree) - if err != nil { - t.Fatalf("could not store cache msgthree: %v", err) - } - - if digest == digesttwo { - t.Fatalf("different msgs return same hash: %d", digesttwo) - } - - // check the cache - err = ps.addFwdCache(msg) - if err != nil { - t.Fatalf("write to pss expire cache failed: %v", err) - } - - if !ps.checkFwdCache(msg) { - t.Fatalf("message %v should have EXPIRE record in cache but checkCache returned false", msg) - } - - if ps.checkFwdCache(msgtwo) { - t.Fatalf("message %v should NOT have EXPIRE record in cache but checkCache returned true", msgtwo) - } - - time.Sleep(pp.CacheTTL + 1*time.Second) - err = ps.addFwdCache(msgthree) - if err != nil { - t.Fatalf("write to pss expire cache failed: %v", err) - } - - if ps.checkFwdCache(msg) { - t.Fatalf("message %v should have expired from cache but checkCache returned true", msg) - } - - if _, ok := ps.fwdCache[digestthree]; !ok { - t.Fatalf("unexpired message should be in the cache: %v", digestthree) - } - - if _, ok := ps.fwdCache[digesttwo]; ok { - t.Fatalf("expired message should have been cleared from the cache: %v", digesttwo) - } -} - -// matching of address hints; whether a message could be or is for the node -func TestAddressMatch(t *testing.T) { - - localaddr := network.RandomAddr().Over() - copy(localaddr[:8], []byte("deadbeef")) - remoteaddr := []byte("feedbeef") - kadparams := network.NewKadParams() - kad := network.NewKademlia(localaddr, kadparams) - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctx) - if err != nil { - t.Fatalf("Could not generate private key: %v", err) - } - privkey, err := w.GetPrivateKey(keys) - pssp := NewPssParams().WithPrivateKey(privkey) - ps, err := NewPss(kad, pssp) - if err != nil { - t.Fatal(err.Error()) - } - - pssmsg := &PssMsg{ - To: remoteaddr, - } - - // differ from first byte - if ps.isSelfRecipient(pssmsg) { - t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) - } - if ps.isSelfPossibleRecipient(pssmsg, false) { - t.Fatalf("isSelfPossibleRecipient true but %x != %x", remoteaddr[:8], localaddr[:8]) - } - - // 8 first bytes same - copy(remoteaddr[:4], localaddr[:4]) - if ps.isSelfRecipient(pssmsg) { - t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) - } - if !ps.isSelfPossibleRecipient(pssmsg, false) { - t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8]) - } - - // all bytes same - pssmsg.To = localaddr - if !ps.isSelfRecipient(pssmsg) { - t.Fatalf("isSelfRecipient false but %x == %x", remoteaddr, localaddr) - } - if !ps.isSelfPossibleRecipient(pssmsg, false) { - t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8]) - } - -} - -// test that message is handled by sender if a prox handler exists and sender is in prox of message -func TestProxShortCircuit(t *testing.T) { - - // sender node address - localAddr := network.RandomAddr().Over() - localPotAddr := pot.NewAddressFromBytes(localAddr) - - // set up kademlia - kadParams := network.NewKadParams() - kad := network.NewKademlia(localAddr, kadParams) - peerCount := kad.MinBinSize + 1 - - // set up pss - privKey, err := crypto.GenerateKey() - pssp := NewPssParams().WithPrivateKey(privKey) - ps, err := NewPss(kad, pssp) - if err != nil { - t.Fatal(err.Error()) - } - - // create kademlia peers, so we have peers both inside and outside minproxlimit - var peers []*network.Peer - proxMessageAddress := pot.RandomAddressAt(localPotAddr, peerCount).Bytes() - distantMessageAddress := pot.RandomAddressAt(localPotAddr, 0).Bytes() - - for i := 0; i < peerCount; i++ { - rw := &p2p.MsgPipeRW{} - ptpPeer := p2p.NewPeer(enode.ID{}, "wanna be with me? [ ] yes [ ] no", []p2p.Cap{}) - protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{}) - peerAddr := pot.RandomAddressAt(localPotAddr, i) - bzzPeer := &network.BzzPeer{ - Peer: protoPeer, - BzzAddr: &network.BzzAddr{ - OAddr: peerAddr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])), - }, - } - peer := network.NewPeer(bzzPeer, kad) - kad.On(peer) - peers = append(peers, peer) - } - - // register it marking prox capability - delivered := make(chan struct{}) - rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - log.Trace("in allowraw handler") - delivered <- struct{}{} - return nil - } - topic := BytesToTopic([]byte{0x2a}) - hndlrProxDereg := ps.Register(&topic, &handler{ - f: rawHandlerFunc, - caps: &handlerCaps{ - raw: true, - prox: true, - }, - }) - defer hndlrProxDereg() - - // send message too far away for sender to be in prox - // reception of this message should time out - errC := make(chan error) - go func() { - err := ps.SendRaw(distantMessageAddress, topic, []byte("foo")) - if err != nil { - errC <- err - } - }() - - ctx, cancel := context.WithTimeout(context.TODO(), time.Second) - defer cancel() - select { - case <-delivered: - t.Fatal("raw distant message delivered") - case err := <-errC: - t.Fatal(err) - case <-ctx.Done(): - } - - // send message that should be within sender prox - // this message should be delivered - go func() { - err := ps.SendRaw(proxMessageAddress, topic, []byte("bar")) - if err != nil { - errC <- err - } - }() - - ctx, cancel = context.WithTimeout(context.TODO(), time.Second) - defer cancel() - select { - case <-delivered: - case err := <-errC: - t.Fatal(err) - case <-ctx.Done(): - t.Fatal("raw timeout") - } - - // try the same prox message with sym and asym send - proxAddrPss := PssAddress(proxMessageAddress) - symKeyId, err := ps.GenerateSymmetricKey(topic, proxAddrPss, true) - go func() { - err := ps.SendSym(symKeyId, topic, []byte("baz")) - if err != nil { - errC <- err - } - }() - ctx, cancel = context.WithTimeout(context.TODO(), time.Second) - defer cancel() - select { - case <-delivered: - case err := <-errC: - t.Fatal(err) - case <-ctx.Done(): - t.Fatal("sym timeout") - } - - err = ps.SetPeerPublicKey(&privKey.PublicKey, topic, proxAddrPss) - if err != nil { - t.Fatal(err) - } - pubKeyId := hexutil.Encode(crypto.FromECDSAPub(&privKey.PublicKey)) - go func() { - err := ps.SendAsym(pubKeyId, topic, []byte("xyzzy")) - if err != nil { - errC <- err - } - }() - ctx, cancel = context.WithTimeout(context.TODO(), time.Second) - defer cancel() - select { - case <-delivered: - case err := <-errC: - t.Fatal(err) - case <-ctx.Done(): - t.Fatal("asym timeout") - } -} - -// verify that node can be set as recipient regardless of explicit message address match if minimum one handler of a topic is explicitly set to allow it -// note that in these tests we use the raw capability on handlers for convenience -func TestAddressMatchProx(t *testing.T) { - - // recipient node address - localAddr := network.RandomAddr().Over() - localPotAddr := pot.NewAddressFromBytes(localAddr) - - // set up kademlia - kadparams := network.NewKadParams() - kad := network.NewKademlia(localAddr, kadparams) - nnPeerCount := kad.MinBinSize - peerCount := nnPeerCount + 2 - - // set up pss - privKey, err := crypto.GenerateKey() - pssp := NewPssParams().WithPrivateKey(privKey) - ps, err := NewPss(kad, pssp) - if err != nil { - t.Fatal(err.Error()) - } - - // create kademlia peers, so we have peers both inside and outside minproxlimit - var peers []*network.Peer - for i := 0; i < peerCount; i++ { - rw := &p2p.MsgPipeRW{} - ptpPeer := p2p.NewPeer(enode.ID{}, "362436 call me anytime", []p2p.Cap{}) - protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{}) - peerAddr := pot.RandomAddressAt(localPotAddr, i) - bzzPeer := &network.BzzPeer{ - Peer: protoPeer, - BzzAddr: &network.BzzAddr{ - OAddr: peerAddr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])), - }, - } - peer := network.NewPeer(bzzPeer, kad) - kad.On(peer) - peers = append(peers, peer) - } - - // TODO: create a test in the network package to make a table with n peers where n-m are proxpeers - // meanwhile test regression for kademlia since we are compiling the test parameters from different packages - var proxes int - var conns int - depth := kad.NeighbourhoodDepth() - kad.EachConn(nil, peerCount, func(p *network.Peer, po int) bool { - conns++ - if po >= depth { - proxes++ - } - return true - }) - if proxes != nnPeerCount { - t.Fatalf("expected %d proxpeers, have %d", nnPeerCount, proxes) - } else if conns != peerCount { - t.Fatalf("expected %d peers total, have %d", peerCount, proxes) - } - - // remote address distances from localAddr to try and the expected outcomes if we use prox handler - remoteDistances := []int{ - 255, - nnPeerCount + 1, - nnPeerCount, - nnPeerCount - 1, - 0, - } - expects := []bool{ - true, - true, - true, - false, - false, - } - - // first the unit test on the method that calculates possible receipient using prox - for i, distance := range remoteDistances { - pssMsg := newPssMsg(&msgParams{}) - pssMsg.To = make([]byte, len(localAddr)) - copy(pssMsg.To, localAddr) - var byteIdx = distance / 8 - pssMsg.To[byteIdx] ^= 1 << uint(7-(distance%8)) - log.Trace(fmt.Sprintf("addrmatch %v", bytes.Equal(pssMsg.To, localAddr))) - if ps.isSelfPossibleRecipient(pssMsg, true) != expects[i] { - t.Fatalf("expected distance %d to be %v", distance, expects[i]) - } - } - - // we move up to higher level and test the actual message handler - // for each distance check if we are possible recipient when prox variant is used is set - - // this handler will increment a counter for every message that gets passed to the handler - var receives int - rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - log.Trace("in allowraw handler") - receives++ - return nil - } - - // register it marking prox capability - topic := BytesToTopic([]byte{0x2a}) - hndlrProxDereg := ps.Register(&topic, &handler{ - f: rawHandlerFunc, - caps: &handlerCaps{ - raw: true, - prox: true, - }, - }) - - // test the distances - var prevReceive int - for i, distance := range remoteDistances { - remotePotAddr := pot.RandomAddressAt(localPotAddr, distance) - remoteAddr := remotePotAddr.Bytes() - - var data [32]byte - rand.Read(data[:]) - pssMsg := newPssMsg(&msgParams{raw: true}) - pssMsg.To = remoteAddr - pssMsg.Expire = uint32(time.Now().Unix() + 4200) - pssMsg.Payload = &whisper.Envelope{ - Topic: whisper.TopicType(topic), - Data: data[:], - } - - log.Trace("withprox addrs", "local", localAddr, "remote", remoteAddr) - ps.handlePssMsg(context.TODO(), pssMsg) - if (!expects[i] && prevReceive != receives) || (expects[i] && prevReceive == receives) { - t.Fatalf("expected distance %d recipient %v when prox is set for handler", distance, expects[i]) - } - prevReceive = receives - } - - // now add a non prox-capable handler and test - ps.Register(&topic, &handler{ - f: rawHandlerFunc, - caps: &handlerCaps{ - raw: true, - }, - }) - receives = 0 - prevReceive = 0 - for i, distance := range remoteDistances { - remotePotAddr := pot.RandomAddressAt(localPotAddr, distance) - remoteAddr := remotePotAddr.Bytes() - - var data [32]byte - rand.Read(data[:]) - pssMsg := newPssMsg(&msgParams{raw: true}) - pssMsg.To = remoteAddr - pssMsg.Expire = uint32(time.Now().Unix() + 4200) - pssMsg.Payload = &whisper.Envelope{ - Topic: whisper.TopicType(topic), - Data: data[:], - } - - log.Trace("withprox addrs", "local", localAddr, "remote", remoteAddr) - ps.handlePssMsg(context.TODO(), pssMsg) - if (!expects[i] && prevReceive != receives) || (expects[i] && prevReceive == receives) { - t.Fatalf("expected distance %d recipient %v when prox is set for handler", distance, expects[i]) - } - prevReceive = receives - } - - // now deregister the prox capable handler, now none of the messages will be handled - hndlrProxDereg() - receives = 0 - - for _, distance := range remoteDistances { - remotePotAddr := pot.RandomAddressAt(localPotAddr, distance) - remoteAddr := remotePotAddr.Bytes() - - pssMsg := newPssMsg(&msgParams{raw: true}) - pssMsg.To = remoteAddr - pssMsg.Expire = uint32(time.Now().Unix() + 4200) - pssMsg.Payload = &whisper.Envelope{ - Topic: whisper.TopicType(topic), - Data: []byte(remotePotAddr.String()), - } - - log.Trace("noprox addrs", "local", localAddr, "remote", remoteAddr) - ps.handlePssMsg(context.TODO(), pssMsg) - if receives != 0 { - t.Fatalf("expected distance %d to not be recipient when prox is not set for handler", distance) - } - - } -} - -// verify that message queueing happens when it should, and that expired and corrupt messages are dropped -func TestMessageProcessing(t *testing.T) { - - t.Skip("Disabled due to probable faulty logic for outbox expectations") - // setup - privkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err.Error()) - } - - addr := make([]byte, 32) - addr[0] = 0x01 - ps := newTestPss(privkey, network.NewKademlia(addr, network.NewKadParams()), NewPssParams()) - defer ps.Stop() - - // message should pass - msg := newPssMsg(&msgParams{}) - msg.To = addr - msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix()) - msg.Payload = &whisper.Envelope{ - Topic: [4]byte{}, - Data: []byte{0x66, 0x6f, 0x6f}, - } - if err := ps.handlePssMsg(context.TODO(), msg); err != nil { - t.Fatal(err.Error()) - } - tmr := time.NewTimer(time.Millisecond * 100) - var outmsg *PssMsg - select { - case outmsg = <-ps.outbox: - case <-tmr.C: - default: - } - if outmsg != nil { - t.Fatalf("expected outbox empty after full address on msg, but had message %s", msg) - } - - // message should pass and queue due to partial length - msg.To = addr[0:1] - msg.Payload.Data = []byte{0x78, 0x79, 0x80, 0x80, 0x79} - if err := ps.handlePssMsg(context.TODO(), msg); err != nil { - t.Fatal(err.Error()) - } - tmr.Reset(time.Millisecond * 100) - outmsg = nil - select { - case outmsg = <-ps.outbox: - case <-tmr.C: - } - if outmsg == nil { - t.Fatal("expected message in outbox on encrypt fail, but empty") - } - outmsg = nil - select { - case outmsg = <-ps.outbox: - default: - } - if outmsg != nil { - t.Fatalf("expected only one queued message but also had message %v", msg) - } - - // full address mismatch should put message in queue - msg.To[0] = 0xff - if err := ps.handlePssMsg(context.TODO(), msg); err != nil { - t.Fatal(err.Error()) - } - tmr.Reset(time.Millisecond * 10) - outmsg = nil - select { - case outmsg = <-ps.outbox: - case <-tmr.C: - } - if outmsg == nil { - t.Fatal("expected message in outbox on address mismatch, but empty") - } - outmsg = nil - select { - case outmsg = <-ps.outbox: - default: - } - if outmsg != nil { - t.Fatalf("expected only one queued message but also had message %v", msg) - } - - // expired message should be dropped - msg.Expire = uint32(time.Now().Add(-time.Second).Unix()) - if err := ps.handlePssMsg(context.TODO(), msg); err != nil { - t.Fatal(err.Error()) - } - tmr.Reset(time.Millisecond * 10) - outmsg = nil - select { - case outmsg = <-ps.outbox: - case <-tmr.C: - default: - } - if outmsg != nil { - t.Fatalf("expected empty queue but have message %v", msg) - } - - // invalid message should return error - fckedupmsg := &struct { - pssMsg *PssMsg - }{ - pssMsg: &PssMsg{}, - } - if err := ps.handlePssMsg(context.TODO(), fckedupmsg); err == nil { - t.Fatalf("expected error from processMsg but error nil") - } - - // outbox full should return error - msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix()) - for i := 0; i < defaultOutboxCapacity; i++ { - ps.outbox <- msg - } - msg.Payload.Data = []byte{0x62, 0x61, 0x72} - err = ps.handlePssMsg(context.TODO(), msg) - if err == nil { - t.Fatal("expected error when mailbox full, but was nil") - } -} - -// set and generate pubkeys and symkeys -func TestKeys(t *testing.T) { - // make our key and init pss with it - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - ourkeys, err := wapi.NewKeyPair(ctx) - if err != nil { - t.Fatalf("create 'our' key fail") - } - ctx, cancel2 := context.WithTimeout(context.Background(), time.Second) - defer cancel2() - theirkeys, err := wapi.NewKeyPair(ctx) - if err != nil { - t.Fatalf("create 'their' key fail") - } - ourprivkey, err := w.GetPrivateKey(ourkeys) - if err != nil { - t.Fatalf("failed to retrieve 'our' private key") - } - theirprivkey, err := w.GetPrivateKey(theirkeys) - if err != nil { - t.Fatalf("failed to retrieve 'their' private key") - } - ps := newTestPss(ourprivkey, nil, nil) - defer ps.Stop() - - // set up peer with mock address, mapped to mocked publicaddress and with mocked symkey - addr := make(PssAddress, 32) - copy(addr, network.RandomAddr().Over()) - outkey := network.RandomAddr().Over() - topicobj := BytesToTopic([]byte("foo:42")) - ps.SetPeerPublicKey(&theirprivkey.PublicKey, topicobj, addr) - outkeyid, err := ps.SetSymmetricKey(outkey, topicobj, addr, false) - if err != nil { - t.Fatalf("failed to set 'our' outgoing symmetric key") - } - - // make a symmetric key that we will send to peer for encrypting messages to us - inkeyid, err := ps.GenerateSymmetricKey(topicobj, addr, true) - if err != nil { - t.Fatalf("failed to set 'our' incoming symmetric key") - } - - // get the key back from whisper, check that it's still the same - outkeyback, err := ps.w.GetSymKey(outkeyid) - if err != nil { - t.Fatalf(err.Error()) - } - inkey, err := ps.w.GetSymKey(inkeyid) - if err != nil { - t.Fatalf(err.Error()) - } - if !bytes.Equal(outkeyback, outkey) { - t.Fatalf("passed outgoing symkey doesnt equal stored: %x / %x", outkey, outkeyback) - } - - t.Logf("symout: %v", outkeyback) - t.Logf("symin: %v", inkey) - - // check that the key is stored in the peerpool - psp := ps.symKeyPool[inkeyid][topicobj] - if !bytes.Equal(psp.address, addr) { - t.Fatalf("inkey address does not match; %p != %p", psp.address, addr) - } -} - -// check that we can retrieve previously added public key entires per topic and peer -func TestGetPublickeyEntries(t *testing.T) { - - privkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - ps := newTestPss(privkey, nil, nil) - defer ps.Stop() - - peeraddr := network.RandomAddr().Over() - topicaddr := make(map[Topic]PssAddress) - topicaddr[Topic{0x13}] = peeraddr - topicaddr[Topic{0x2a}] = peeraddr[:16] - topicaddr[Topic{0x02, 0x9a}] = []byte{} - - remoteprivkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - remotepubkeybytes := crypto.FromECDSAPub(&remoteprivkey.PublicKey) - remotepubkeyhex := common.ToHex(remotepubkeybytes) - - pssapi := NewAPI(ps) - - for to, a := range topicaddr { - err = pssapi.SetPeerPublicKey(remotepubkeybytes, to, a) - if err != nil { - t.Fatal(err) - } - } - - intopic, err := pssapi.GetPeerTopics(remotepubkeyhex) - if err != nil { - t.Fatal(err) - } - -OUTER: - for _, tnew := range intopic { - for torig, addr := range topicaddr { - if bytes.Equal(torig[:], tnew[:]) { - inaddr, err := pssapi.GetPeerAddress(remotepubkeyhex, torig) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(addr, inaddr) { - t.Fatalf("Address mismatch for topic %x; got %x, expected %x", torig, inaddr, addr) - } - delete(topicaddr, torig) - continue OUTER - } - } - t.Fatalf("received topic %x did not match any existing topics", tnew) - } - - if len(topicaddr) != 0 { - t.Fatalf("%d topics were not matched", len(topicaddr)) - } -} - -// forwarding should skip peers that do not have matching pss capabilities -func TestPeerCapabilityMismatch(t *testing.T) { - - // create privkey for forwarder node - privkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - // initialize kad - baseaddr := network.RandomAddr() - kad := network.NewKademlia((baseaddr).Over(), network.NewKadParams()) - rw := &p2p.MsgPipeRW{} - - // one peer has a mismatching version of pss - wrongpssaddr := network.RandomAddr() - wrongpsscap := p2p.Cap{ - Name: pssProtocolName, - Version: 0, - } - nid := enode.ID{0x01} - wrongpsspeer := network.NewPeer(&network.BzzPeer{ - Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(wrongpssaddr.Over()), []p2p.Cap{wrongpsscap}), rw, nil), - BzzAddr: &network.BzzAddr{OAddr: wrongpssaddr.Over(), UAddr: nil}, - }, kad) - - // one peer doesn't even have pss (boo!) - nopssaddr := network.RandomAddr() - nopsscap := p2p.Cap{ - Name: "nopss", - Version: 1, - } - nid = enode.ID{0x02} - nopsspeer := network.NewPeer(&network.BzzPeer{ - Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(nopssaddr.Over()), []p2p.Cap{nopsscap}), rw, nil), - BzzAddr: &network.BzzAddr{OAddr: nopssaddr.Over(), UAddr: nil}, - }, kad) - - // add peers to kademlia and activate them - // it's safe so don't check errors - kad.Register(wrongpsspeer.BzzAddr) - kad.On(wrongpsspeer) - kad.Register(nopsspeer.BzzAddr) - kad.On(nopsspeer) - - // create pss - pssmsg := &PssMsg{ - To: []byte{}, - Expire: uint32(time.Now().Add(time.Second).Unix()), - Payload: &whisper.Envelope{}, - } - ps := newTestPss(privkey, kad, nil) - defer ps.Stop() - - // run the forward - // it is enough that it completes; trying to send to incapable peers would create segfault - ps.forward(pssmsg) - -} - -// verifies that message handlers for raw messages only are invoked when minimum one handler for the topic exists in which raw messages are explicitly allowed -func TestRawAllow(t *testing.T) { - - // set up pss like so many times before - privKey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - baseAddr := network.RandomAddr() - kad := network.NewKademlia((baseAddr).Over(), network.NewKadParams()) - ps := newTestPss(privKey, kad, nil) - defer ps.Stop() - topic := BytesToTopic([]byte{0x2a}) - - // create handler innards that increments every time a message hits it - var receives int - rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { - log.Trace("in allowraw handler") - receives++ - return nil - } - - // wrap this handler function with a handler without raw capability and register it - hndlrNoRaw := &handler{ - f: rawHandlerFunc, - } - ps.Register(&topic, hndlrNoRaw) - - // test it with a raw message, should be poo-poo - pssMsg := newPssMsg(&msgParams{ - raw: true, - }) - pssMsg.To = baseAddr.OAddr - pssMsg.Expire = uint32(time.Now().Unix() + 4200) - pssMsg.Payload = &whisper.Envelope{ - Topic: whisper.TopicType(topic), - } - ps.handlePssMsg(context.TODO(), pssMsg) - if receives > 0 { - t.Fatalf("Expected handler not to be executed with raw cap off") - } - - // now wrap the same handler function with raw capabilities and register it - hndlrRaw := &handler{ - f: rawHandlerFunc, - caps: &handlerCaps{ - raw: true, - }, - } - deregRawHandler := ps.Register(&topic, hndlrRaw) - - // should work now - pssMsg.Payload.Data = []byte("Raw Deal") - ps.handlePssMsg(context.TODO(), pssMsg) - if receives == 0 { - t.Fatalf("Expected handler to be executed with raw cap on") - } - - // now deregister the raw capable handler - prevReceives := receives - deregRawHandler() - - // check that raw messages fail again - pssMsg.Payload.Data = []byte("Raw Trump") - ps.handlePssMsg(context.TODO(), pssMsg) - if receives != prevReceives { - t.Fatalf("Expected handler not to be executed when raw handler is retracted") - } -} - -// BELOW HERE ARE TESTS USING THE SIMULATION FRAMEWORK - -// tests that the API layer can handle edge case values -func TestApi(t *testing.T) { - clients, err := setupNetwork(2, true) - if err != nil { - t.Fatal(err) - } - - topic := "0xdeadbeef" - - err = clients[0].Call(nil, "pss_sendRaw", "0x", topic, "0x666f6f") - if err != nil { - t.Fatal(err) - } - - err = clients[0].Call(nil, "pss_sendRaw", "0xabcdef", topic, "0x") - if err == nil { - t.Fatal("expected error on empty msg") - } - - overflowAddr := [33]byte{} - err = clients[0].Call(nil, "pss_sendRaw", hexutil.Encode(overflowAddr[:]), topic, "0x666f6f") - if err == nil { - t.Fatal("expected error on send too big address") - } -} - -// verifies that nodes can send and receive raw (verbatim) messages -func TestSendRaw(t *testing.T) { - t.Run("32", testSendRaw) - t.Run("8", testSendRaw) - t.Run("0", testSendRaw) -} - -func testSendRaw(t *testing.T) { - - var addrsize int64 - var err error - - paramstring := strings.Split(t.Name(), "/") - - addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) - log.Info("raw send test", "addrsize", addrsize) - - clients, err := setupNetwork(2, true) - if err != nil { - t.Fatal(err) - } - - topic := "0xdeadbeef" - - var loaddrhex string - err = clients[0].Call(&loaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 1 baseaddr fail: %v", err) - } - loaddrhex = loaddrhex[:2+(addrsize*2)] - var roaddrhex string - err = clients[1].Call(&roaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 2 baseaddr fail: %v", err) - } - roaddrhex = roaddrhex[:2+(addrsize*2)] - - time.Sleep(time.Millisecond * 500) - - // at this point we've verified that symkeys are saved and match on each peer - // now try sending symmetrically encrypted message, both directions - lmsgC := make(chan APIMsg) - lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) - defer lcancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, true, false) - log.Trace("lsub", "id", lsub) - defer lsub.Unsubscribe() - rmsgC := make(chan APIMsg) - rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) - defer rcancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, true, false) - log.Trace("rsub", "id", rsub) - defer rsub.Unsubscribe() - - // send and verify delivery - lmsg := []byte("plugh") - err = clients[1].Call(nil, "pss_sendRaw", loaddrhex, topic, hexutil.Encode(lmsg)) - if err != nil { - t.Fatal(err) - } - select { - case recvmsg := <-lmsgC: - if !bytes.Equal(recvmsg.Msg, lmsg) { - t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg) - } - case cerr := <-lctx.Done(): - t.Fatalf("test message (left) timed out: %v", cerr) - } - rmsg := []byte("xyzzy") - err = clients[0].Call(nil, "pss_sendRaw", roaddrhex, topic, hexutil.Encode(rmsg)) - if err != nil { - t.Fatal(err) - } - select { - case recvmsg := <-rmsgC: - if !bytes.Equal(recvmsg.Msg, rmsg) { - t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg) - } - case cerr := <-rctx.Done(): - t.Fatalf("test message (right) timed out: %v", cerr) - } -} - -// send symmetrically encrypted message between two directly connected peers -func TestSendSym(t *testing.T) { - t.Run("32", testSendSym) - t.Run("8", testSendSym) - t.Run("0", testSendSym) -} - -func testSendSym(t *testing.T) { - - // address hint size - var addrsize int64 - var err error - paramstring := strings.Split(t.Name(), "/") - addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) - log.Info("sym send test", "addrsize", addrsize) - - clients, err := setupNetwork(2, false) - if err != nil { - t.Fatal(err) - } - - var topic string - err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") - if err != nil { - t.Fatal(err) - } - - var loaddrhex string - err = clients[0].Call(&loaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 1 baseaddr fail: %v", err) - } - loaddrhex = loaddrhex[:2+(addrsize*2)] - var roaddrhex string - err = clients[1].Call(&roaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 2 baseaddr fail: %v", err) - } - roaddrhex = roaddrhex[:2+(addrsize*2)] - - // retrieve public key from pss instance - // set this public key reciprocally - var lpubkeyhex string - err = clients[0].Call(&lpubkeyhex, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 1 pubkey fail: %v", err) - } - var rpubkeyhex string - err = clients[1].Call(&rpubkeyhex, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 2 pubkey fail: %v", err) - } - - time.Sleep(time.Millisecond * 500) - - // at this point we've verified that symkeys are saved and match on each peer - // now try sending symmetrically encrypted message, both directions - lmsgC := make(chan APIMsg) - lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) - defer lcancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false) - log.Trace("lsub", "id", lsub) - defer lsub.Unsubscribe() - rmsgC := make(chan APIMsg) - rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) - defer rcancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) - log.Trace("rsub", "id", rsub) - defer rsub.Unsubscribe() - - lrecvkey := network.RandomAddr().Over() - rrecvkey := network.RandomAddr().Over() - - var lkeyids [2]string - var rkeyids [2]string - - // manually set reciprocal symkeys - err = clients[0].Call(&lkeyids, "psstest_setSymKeys", rpubkeyhex, lrecvkey, rrecvkey, defaultSymKeySendLimit, topic, roaddrhex) - if err != nil { - t.Fatal(err) - } - err = clients[1].Call(&rkeyids, "psstest_setSymKeys", lpubkeyhex, rrecvkey, lrecvkey, defaultSymKeySendLimit, topic, loaddrhex) - if err != nil { - t.Fatal(err) - } - - // send and verify delivery - lmsg := []byte("plugh") - err = clients[1].Call(nil, "pss_sendSym", rkeyids[1], topic, hexutil.Encode(lmsg)) - if err != nil { - t.Fatal(err) - } - select { - case recvmsg := <-lmsgC: - if !bytes.Equal(recvmsg.Msg, lmsg) { - t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg) - } - case cerr := <-lctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - } - rmsg := []byte("xyzzy") - err = clients[0].Call(nil, "pss_sendSym", lkeyids[1], topic, hexutil.Encode(rmsg)) - if err != nil { - t.Fatal(err) - } - select { - case recvmsg := <-rmsgC: - if !bytes.Equal(recvmsg.Msg, rmsg) { - t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg) - } - case cerr := <-rctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - } -} - -// send asymmetrically encrypted message between two directly connected peers -func TestSendAsym(t *testing.T) { - t.Run("32", testSendAsym) - t.Run("8", testSendAsym) - t.Run("0", testSendAsym) -} - -func testSendAsym(t *testing.T) { - - // address hint size - var addrsize int64 - var err error - paramstring := strings.Split(t.Name(), "/") - addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) - log.Info("asym send test", "addrsize", addrsize) - - clients, err := setupNetwork(2, false) - if err != nil { - t.Fatal(err) - } - - var topic string - err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") - if err != nil { - t.Fatal(err) - } - - time.Sleep(time.Millisecond * 250) - - var loaddrhex string - err = clients[0].Call(&loaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 1 baseaddr fail: %v", err) - } - loaddrhex = loaddrhex[:2+(addrsize*2)] - var roaddrhex string - err = clients[1].Call(&roaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 2 baseaddr fail: %v", err) - } - roaddrhex = roaddrhex[:2+(addrsize*2)] - - // retrieve public key from pss instance - // set this public key reciprocally - var lpubkey string - err = clients[0].Call(&lpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 1 pubkey fail: %v", err) - } - var rpubkey string - err = clients[1].Call(&rpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get node 2 pubkey fail: %v", err) - } - - time.Sleep(time.Millisecond * 500) // replace with hive healthy code - - lmsgC := make(chan APIMsg) - lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) - defer lcancel() - lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false) - log.Trace("lsub", "id", lsub) - defer lsub.Unsubscribe() - rmsgC := make(chan APIMsg) - rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) - defer rcancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) - log.Trace("rsub", "id", rsub) - defer rsub.Unsubscribe() - - // store reciprocal public keys - err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddrhex) - if err != nil { - t.Fatal(err) - } - err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddrhex) - if err != nil { - t.Fatal(err) - } - - // send and verify delivery - rmsg := []byte("xyzzy") - err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg)) - if err != nil { - t.Fatal(err) - } - select { - case recvmsg := <-rmsgC: - if !bytes.Equal(recvmsg.Msg, rmsg) { - t.Fatalf("node 2 received payload mismatch: expected %v, got %v", rmsg, recvmsg.Msg) - } - case cerr := <-rctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - } - lmsg := []byte("plugh") - err = clients[1].Call(nil, "pss_sendAsym", lpubkey, topic, hexutil.Encode(lmsg)) - if err != nil { - t.Fatal(err) - } - select { - case recvmsg := <-lmsgC: - if !bytes.Equal(recvmsg.Msg, lmsg) { - t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg.Msg) - } - case cerr := <-lctx.Done(): - t.Fatalf("test message timed out: %v", cerr) - } -} - -type Job struct { - Msg []byte - SendNode enode.ID - RecvNode enode.ID -} - -func worker(id int, jobs <-chan Job, rpcs map[enode.ID]*rpc.Client, pubkeys map[enode.ID]string, topic string) { - for j := range jobs { - rpcs[j.SendNode].Call(nil, "pss_sendAsym", pubkeys[j.RecvNode], topic, hexutil.Encode(j.Msg)) - } -} - -func TestNetwork(t *testing.T) { - t.Run("16/1000/4/sim", testNetwork) -} - -// params in run name: -// nodes/recipientAddresses/addrbytes/adaptertype -// if adaptertype is exec uses execadapter, simadapter otherwise -func TestNetwork2000(t *testing.T) { - if !*longrunning { - t.Skip("run with --longrunning flag to run extensive network tests") - } - t.Run("3/2000/4/sim", testNetwork) - t.Run("4/2000/4/sim", testNetwork) - t.Run("8/2000/4/sim", testNetwork) - t.Run("16/2000/4/sim", testNetwork) -} - -func TestNetwork5000(t *testing.T) { - if !*longrunning { - t.Skip("run with --longrunning flag to run extensive network tests") - } - t.Run("3/5000/4/sim", testNetwork) - t.Run("4/5000/4/sim", testNetwork) - t.Run("8/5000/4/sim", testNetwork) - t.Run("16/5000/4/sim", testNetwork) -} - -func TestNetwork10000(t *testing.T) { - if !*longrunning { - t.Skip("run with --longrunning flag to run extensive network tests") - } - t.Run("3/10000/4/sim", testNetwork) - t.Run("4/10000/4/sim", testNetwork) - t.Run("8/10000/4/sim", testNetwork) -} - -func testNetwork(t *testing.T) { - paramstring := strings.Split(t.Name(), "/") - nodecount, _ := strconv.ParseInt(paramstring[1], 10, 0) - msgcount, _ := strconv.ParseInt(paramstring[2], 10, 0) - addrsize, _ := strconv.ParseInt(paramstring[3], 10, 0) - adapter := paramstring[4] - - log.Info("network test", "nodecount", nodecount, "msgcount", msgcount, "addrhintsize", addrsize) - - nodes := make([]enode.ID, nodecount) - bzzaddrs := make(map[enode.ID]string, nodecount) - rpcs := make(map[enode.ID]*rpc.Client, nodecount) - pubkeys := make(map[enode.ID]string, nodecount) - - sentmsgs := make([][]byte, msgcount) - recvmsgs := make([]bool, msgcount) - nodemsgcount := make(map[enode.ID]int, nodecount) - - trigger := make(chan enode.ID) - - var a adapters.NodeAdapter - if adapter == "exec" { - dirname, err := ioutil.TempDir(".", "") - if err != nil { - t.Fatal(err) - } - a = adapters.NewExecAdapter(dirname) - } else if adapter == "tcp" { - a = adapters.NewTCPAdapter(newServices(false)) - } else if adapter == "sim" { - a = adapters.NewSimAdapter(newServices(false)) - } - net := simulations.NewNetwork(a, &simulations.NetworkConfig{ - ID: "0", - }) - defer net.Shutdown() - - f, err := os.Open(fmt.Sprintf("testdata/snapshot_%d.json", nodecount)) - if err != nil { - t.Fatal(err) - } - jsonbyte, err := ioutil.ReadAll(f) - if err != nil { - t.Fatal(err) - } - var snap simulations.Snapshot - err = json.Unmarshal(jsonbyte, &snap) - if err != nil { - t.Fatal(err) - } - err = net.Load(&snap) - if err != nil { - //TODO: Fix p2p simulation framework to not crash when loading 32-nodes - //t.Fatal(err) - } - - time.Sleep(1 * time.Second) - - triggerChecks := func(trigger chan enode.ID, id enode.ID, rpcclient *rpc.Client, topic string) error { - msgC := make(chan APIMsg) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", topic, false, false) - if err != nil { - t.Fatal(err) - } - go func() { - defer sub.Unsubscribe() - for { - select { - case recvmsg := <-msgC: - idx, _ := binary.Uvarint(recvmsg.Msg) - if !recvmsgs[idx] { - log.Debug("msg recv", "idx", idx, "id", id) - recvmsgs[idx] = true - trigger <- id - } - case <-sub.Err(): - return - } - } - }() - return nil - } - - var topic string - for i, nod := range net.GetNodes() { - nodes[i] = nod.ID() - rpcs[nodes[i]], err = nod.Client() - if err != nil { - t.Fatal(err) - } - if topic == "" { - err = rpcs[nodes[i]].Call(&topic, "pss_stringToTopic", "foo:42") - if err != nil { - t.Fatal(err) - } - } - var pubkey string - err = rpcs[nodes[i]].Call(&pubkey, "pss_getPublicKey") - if err != nil { - t.Fatal(err) - } - pubkeys[nod.ID()] = pubkey - var addrhex string - err = rpcs[nodes[i]].Call(&addrhex, "pss_baseAddr") - if err != nil { - t.Fatal(err) - } - bzzaddrs[nodes[i]] = addrhex - err = triggerChecks(trigger, nodes[i], rpcs[nodes[i]], topic) - if err != nil { - t.Fatal(err) - } - } - - time.Sleep(1 * time.Second) - - // setup workers - jobs := make(chan Job, 10) - for w := 1; w <= 10; w++ { - go worker(w, jobs, rpcs, pubkeys, topic) - } - - time.Sleep(1 * time.Second) - - for i := 0; i < int(msgcount); i++ { - sendnodeidx := rand.Intn(int(nodecount)) - recvnodeidx := rand.Intn(int(nodecount - 1)) - if recvnodeidx >= sendnodeidx { - recvnodeidx++ - } - nodemsgcount[nodes[recvnodeidx]]++ - sentmsgs[i] = make([]byte, 8) - c := binary.PutUvarint(sentmsgs[i], uint64(i)) - if c == 0 { - t.Fatal("0 byte message") - } - if err != nil { - t.Fatal(err) - } - err = rpcs[nodes[sendnodeidx]].Call(nil, "pss_setPeerPublicKey", pubkeys[nodes[recvnodeidx]], topic, bzzaddrs[nodes[recvnodeidx]]) - if err != nil { - t.Fatal(err) - } - - jobs <- Job{ - Msg: sentmsgs[i], - SendNode: nodes[sendnodeidx], - RecvNode: nodes[recvnodeidx], - } - } - - finalmsgcount := 0 - ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) - defer cancel() -outer: - for i := 0; i < int(msgcount); i++ { - select { - case id := <-trigger: - nodemsgcount[id]-- - finalmsgcount++ - case <-ctx.Done(): - log.Warn("timeout") - break outer - } - } - - for i, msg := range recvmsgs { - if !msg { - log.Debug("missing message", "idx", i) - } - } - t.Logf("%d of %d messages received", finalmsgcount, msgcount) - - if finalmsgcount != int(msgcount) { - t.Fatalf("%d messages were not received", int(msgcount)-finalmsgcount) - } - -} - -// check that in a network of a -> b -> c -> a -// a doesn't receive a sent message twice -func TestDeduplication(t *testing.T) { - var err error - - clients, err := setupNetwork(3, false) - if err != nil { - t.Fatal(err) - } - - var addrsize = 32 - var loaddrhex string - err = clients[0].Call(&loaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 1 baseaddr fail: %v", err) - } - loaddrhex = loaddrhex[:2+(addrsize*2)] - var roaddrhex string - err = clients[1].Call(&roaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 2 baseaddr fail: %v", err) - } - roaddrhex = roaddrhex[:2+(addrsize*2)] - var xoaddrhex string - err = clients[2].Call(&xoaddrhex, "pss_baseAddr") - if err != nil { - t.Fatalf("rpc get node 3 baseaddr fail: %v", err) - } - xoaddrhex = xoaddrhex[:2+(addrsize*2)] - - log.Info("peer", "l", loaddrhex, "r", roaddrhex, "x", xoaddrhex) - - var topic string - err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") - if err != nil { - t.Fatal(err) - } - - time.Sleep(time.Millisecond * 250) - - // retrieve public key from pss instance - // set this public key reciprocally - var rpubkey string - err = clients[1].Call(&rpubkey, "pss_getPublicKey") - if err != nil { - t.Fatalf("rpc get receivenode pubkey fail: %v", err) - } - - time.Sleep(time.Millisecond * 500) // replace with hive healthy code - - rmsgC := make(chan APIMsg) - rctx, cancel := context.WithTimeout(context.Background(), time.Second*1) - defer cancel() - rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false) - log.Trace("rsub", "id", rsub) - defer rsub.Unsubscribe() - - // store public key for recipient - // zero-length address means forward to all - // we have just two peers, they will be in proxbin, and will both receive - err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, "0x") - if err != nil { - t.Fatal(err) - } - - // send and verify delivery - rmsg := []byte("xyzzy") - err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg)) - if err != nil { - t.Fatal(err) - } - - var receivedok bool -OUTER: - for { - select { - case <-rmsgC: - if receivedok { - t.Fatalf("duplicate message received") - } - receivedok = true - case <-rctx.Done(): - break OUTER - } - } - if !receivedok { - t.Fatalf("message did not arrive") - } -} - -// symmetric send performance with varying message sizes -func BenchmarkSymkeySend(b *testing.B) { - b.Run(fmt.Sprintf("%d", 256), benchmarkSymKeySend) - b.Run(fmt.Sprintf("%d", 1024), benchmarkSymKeySend) - b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkSymKeySend) - b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkSymKeySend) - b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkSymKeySend) -} - -func benchmarkSymKeySend(b *testing.B) { - msgsizestring := strings.Split(b.Name(), "/") - if len(msgsizestring) != 2 { - b.Fatalf("benchmark called without msgsize param") - } - msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0) - if err != nil { - b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err) - } - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctx) - privkey, err := w.GetPrivateKey(keys) - ps := newTestPss(privkey, nil, nil) - defer ps.Stop() - msg := make([]byte, msgsize) - rand.Read(msg) - topic := BytesToTopic([]byte("foo")) - to := make(PssAddress, 32) - copy(to[:], network.RandomAddr().Over()) - symkeyid, err := ps.GenerateSymmetricKey(topic, to, true) - if err != nil { - b.Fatalf("could not generate symkey: %v", err) - } - symkey, err := ps.w.GetSymKey(symkeyid) - if err != nil { - b.Fatalf("could not retrieve symkey: %v", err) - } - ps.SetSymmetricKey(symkey, topic, to, false) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - ps.SendSym(symkeyid, topic, msg) - } -} - -// asymmetric send performance with varying message sizes -func BenchmarkAsymkeySend(b *testing.B) { - b.Run(fmt.Sprintf("%d", 256), benchmarkAsymKeySend) - b.Run(fmt.Sprintf("%d", 1024), benchmarkAsymKeySend) - b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkAsymKeySend) - b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkAsymKeySend) - b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkAsymKeySend) -} - -func benchmarkAsymKeySend(b *testing.B) { - msgsizestring := strings.Split(b.Name(), "/") - if len(msgsizestring) != 2 { - b.Fatalf("benchmark called without msgsize param") - } - msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0) - if err != nil { - b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err) - } - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctx) - privkey, err := w.GetPrivateKey(keys) - ps := newTestPss(privkey, nil, nil) - defer ps.Stop() - msg := make([]byte, msgsize) - rand.Read(msg) - topic := BytesToTopic([]byte("foo")) - to := make(PssAddress, 32) - copy(to[:], network.RandomAddr().Over()) - ps.SetPeerPublicKey(&privkey.PublicKey, topic, to) - b.ResetTimer() - for i := 0; i < b.N; i++ { - ps.SendAsym(common.ToHex(crypto.FromECDSAPub(&privkey.PublicKey)), topic, msg) - } -} -func BenchmarkSymkeyBruteforceChangeaddr(b *testing.B) { - for i := 100; i < 100000; i = i * 10 { - for j := 32; j < 10000; j = j * 8 { - b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceChangeaddr) - } - //b.Run(fmt.Sprintf("%d", i), benchmarkSymkeyBruteforceChangeaddr) - } -} - -// decrypt performance using symkey cache, worst case -// (decrypt key always last in cache) -func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) { - keycountstring := strings.Split(b.Name(), "/") - cachesize := int64(0) - var ps *Pss - if len(keycountstring) < 2 { - b.Fatalf("benchmark called without count param") - } - keycount, err := strconv.ParseInt(keycountstring[1], 10, 0) - if err != nil { - b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err) - } - if len(keycountstring) == 3 { - cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0) - if err != nil { - b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err) - } - } - pssmsgs := make([]*PssMsg, 0, keycount) - var keyid string - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctx) - privkey, err := w.GetPrivateKey(keys) - if cachesize > 0 { - ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)}) - } else { - ps = newTestPss(privkey, nil, nil) - } - defer ps.Stop() - topic := BytesToTopic([]byte("foo")) - for i := 0; i < int(keycount); i++ { - to := make(PssAddress, 32) - copy(to[:], network.RandomAddr().Over()) - keyid, err = ps.GenerateSymmetricKey(topic, to, true) - if err != nil { - b.Fatalf("cant generate symkey #%d: %v", i, err) - } - symkey, err := ps.w.GetSymKey(keyid) - if err != nil { - b.Fatalf("could not retrieve symkey %s: %v", keyid, err) - } - wparams := &whisper.MessageParams{ - TTL: defaultWhisperTTL, - KeySym: symkey, - Topic: whisper.TopicType(topic), - WorkTime: defaultWhisperWorkTime, - PoW: defaultWhisperPoW, - Payload: []byte("xyzzy"), - Padding: []byte("1234567890abcdef"), - } - woutmsg, err := whisper.NewSentMessage(wparams) - if err != nil { - b.Fatalf("could not create whisper message: %v", err) - } - env, err := woutmsg.Wrap(wparams) - if err != nil { - b.Fatalf("could not generate whisper envelope: %v", err) - } - ps.Register(&topic, &handler{ - f: noopHandlerFunc, - }) - pssmsgs = append(pssmsgs, &PssMsg{ - To: to, - Payload: env, - }) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := ps.process(pssmsgs[len(pssmsgs)-(i%len(pssmsgs))-1], false, false); err != nil { - b.Fatalf("pss processing failed: %v", err) - } - } -} - -func BenchmarkSymkeyBruteforceSameaddr(b *testing.B) { - for i := 100; i < 100000; i = i * 10 { - for j := 32; j < 10000; j = j * 8 { - b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceSameaddr) - } - } -} - -// decrypt performance using symkey cache, best case -// (decrypt key always first in cache) -func benchmarkSymkeyBruteforceSameaddr(b *testing.B) { - var keyid string - var ps *Pss - cachesize := int64(0) - keycountstring := strings.Split(b.Name(), "/") - if len(keycountstring) < 2 { - b.Fatalf("benchmark called without count param") - } - keycount, err := strconv.ParseInt(keycountstring[1], 10, 0) - if err != nil { - b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err) - } - if len(keycountstring) == 3 { - cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0) - if err != nil { - b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err) - } - } - addr := make([]PssAddress, keycount) - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctx) - privkey, err := w.GetPrivateKey(keys) - if cachesize > 0 { - ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)}) - } else { - ps = newTestPss(privkey, nil, nil) - } - defer ps.Stop() - topic := BytesToTopic([]byte("foo")) - for i := 0; i < int(keycount); i++ { - copy(addr[i], network.RandomAddr().Over()) - keyid, err = ps.GenerateSymmetricKey(topic, addr[i], true) - if err != nil { - b.Fatalf("cant generate symkey #%d: %v", i, err) - } - - } - symkey, err := ps.w.GetSymKey(keyid) - if err != nil { - b.Fatalf("could not retrieve symkey %s: %v", keyid, err) - } - wparams := &whisper.MessageParams{ - TTL: defaultWhisperTTL, - KeySym: symkey, - Topic: whisper.TopicType(topic), - WorkTime: defaultWhisperWorkTime, - PoW: defaultWhisperPoW, - Payload: []byte("xyzzy"), - Padding: []byte("1234567890abcdef"), - } - woutmsg, err := whisper.NewSentMessage(wparams) - if err != nil { - b.Fatalf("could not create whisper message: %v", err) - } - env, err := woutmsg.Wrap(wparams) - if err != nil { - b.Fatalf("could not generate whisper envelope: %v", err) - } - ps.Register(&topic, &handler{ - f: noopHandlerFunc, - }) - pssmsg := &PssMsg{ - To: addr[len(addr)-1][:], - Payload: env, - } - for i := 0; i < b.N; i++ { - if err := ps.process(pssmsg, false, false); err != nil { - b.Fatalf("pss processing failed: %v", err) - } - } -} - -// setup simulated network with bzz/discovery and pss services. -// connects nodes in a circle -// if allowRaw is set, omission of builtin pss encryption is enabled (see PssParams) -func setupNetwork(numnodes int, allowRaw bool) (clients []*rpc.Client, err error) { - nodes := make([]*simulations.Node, numnodes) - clients = make([]*rpc.Client, numnodes) - if numnodes < 2 { - return nil, fmt.Errorf("Minimum two nodes in network") - } - adapter := adapters.NewSimAdapter(newServices(allowRaw)) - net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - ID: "0", - DefaultService: "bzz", - }) - for i := 0; i < numnodes; i++ { - nodeconf := adapters.RandomNodeConfig() - nodeconf.Services = []string{"bzz", pssProtocolName} - nodes[i], err = net.NewNodeWithConfig(nodeconf) - if err != nil { - return nil, fmt.Errorf("error creating node 1: %v", err) - } - err = net.Start(nodes[i].ID()) - if err != nil { - return nil, fmt.Errorf("error starting node 1: %v", err) - } - if i > 0 { - err = net.Connect(nodes[i].ID(), nodes[i-1].ID()) - if err != nil { - return nil, fmt.Errorf("error connecting nodes: %v", err) - } - } - clients[i], err = nodes[i].Client() - if err != nil { - return nil, fmt.Errorf("create node 1 rpc client fail: %v", err) - } - } - if numnodes > 2 { - err = net.Connect(nodes[0].ID(), nodes[len(nodes)-1].ID()) - if err != nil { - return nil, fmt.Errorf("error connecting first and last nodes") - } - } - return clients, nil -} - -func newServices(allowRaw bool) adapters.Services { - stateStore := state.NewInmemoryStore() - kademlias := make(map[enode.ID]*network.Kademlia) - kademlia := func(id enode.ID) *network.Kademlia { - if k, ok := kademlias[id]; ok { - return k - } - params := network.NewKadParams() - params.NeighbourhoodSize = 2 - params.MaxBinSize = 3 - params.MinBinSize = 1 - params.MaxRetries = 1000 - params.RetryExponent = 2 - params.RetryInterval = 1000000 - kademlias[id] = network.NewKademlia(id[:], params) - return kademlias[id] - } - return adapters.Services{ - pssProtocolName: func(ctx *adapters.ServiceContext) (node.Service, error) { - // execadapter does not exec init() - initTest() - - ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - keys, err := wapi.NewKeyPair(ctxlocal) - privkey, err := w.GetPrivateKey(keys) - pssp := NewPssParams().WithPrivateKey(privkey) - pssp.AllowRaw = allowRaw - pskad := kademlia(ctx.Config.ID) - ps, err := NewPss(pskad, pssp) - if err != nil { - return nil, err - } - - ping := &Ping{ - OutC: make(chan bool), - Pong: true, - } - p2pp := NewPingProtocol(ping) - pp, err := RegisterProtocol(ps, &PingTopic, PingProtocol, p2pp, &ProtocolParams{Asymmetric: true}) - if err != nil { - return nil, err - } - if useHandshake { - SetHandshakeController(ps, NewHandshakeParams()) - } - ps.Register(&PingTopic, &handler{ - f: pp.Handle, - caps: &handlerCaps{ - raw: true, - }, - }) - ps.addAPI(rpc.API{ - Namespace: "psstest", - Version: "0.3", - Service: NewAPITest(ps), - Public: false, - }) - if err != nil { - log.Error("Couldnt register pss protocol", "err", err) - os.Exit(1) - } - pssprotocols[ctx.Config.ID.String()] = &protoCtrl{ - C: ping.OutC, - protocol: pp, - run: p2pp.Run, - } - return ps, nil - }, - "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { - addr := network.NewAddr(ctx.Config.Node()) - hp := network.NewHiveParams() - hp.Discovery = false - config := &network.BzzConfig{ - OverlayAddr: addr.Over(), - UnderlayAddr: addr.Under(), - HiveParams: hp, - } - return network.NewBzz(config, kademlia(ctx.Config.ID), stateStore, nil, nil), nil - }, - } -} - -func newTestPss(privkey *ecdsa.PrivateKey, kad *network.Kademlia, ppextra *PssParams) *Pss { - nid := enode.PubkeyToIDV4(&privkey.PublicKey) - // set up routing if kademlia is not passed to us - if kad == nil { - kp := network.NewKadParams() - kp.NeighbourhoodSize = 3 - kad = network.NewKademlia(nid[:], kp) - } - - // create pss - pp := NewPssParams().WithPrivateKey(privkey) - if ppextra != nil { - pp.SymKeyCacheCapacity = ppextra.SymKeyCacheCapacity - } - ps, err := NewPss(kad, pp) - if err != nil { - return nil - } - ps.Start(nil) - - return ps -} - -// API calls for test/development use -type APITest struct { - *Pss -} - -func NewAPITest(ps *Pss) *APITest { - return &APITest{Pss: ps} -} - -func (apitest *APITest) SetSymKeys(pubkeyid string, recvsymkey []byte, sendsymkey []byte, limit uint16, topic Topic, to hexutil.Bytes) ([2]string, error) { - - recvsymkeyid, err := apitest.SetSymmetricKey(recvsymkey, topic, PssAddress(to), true) - if err != nil { - return [2]string{}, err - } - sendsymkeyid, err := apitest.SetSymmetricKey(sendsymkey, topic, PssAddress(to), false) - if err != nil { - return [2]string{}, err - } - return [2]string{recvsymkeyid, sendsymkeyid}, nil -} - -func (apitest *APITest) Clean() (int, error) { - return apitest.Pss.cleanKeys(), nil -} diff --git a/swarm/pss/testdata/snapshot_128.json b/swarm/pss/testdata/snapshot_128.json deleted file mode 100644 index 8e1bc88b38..0000000000 --- a/swarm/pss/testdata/snapshot_128.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","name":"node_7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","enode":"enode://0c52fa76a36dd072dbe11c5e7ebc82ef6efdd0fa3da10a006f64a34abc8a9f4d721a5c4fc4ef5415438ff721ed76effac71cb456683d037aace2db5f49026522@127.0.0.1:0","enr":"0xf88fb84036d1f0bc1cc1963dccf82616505bc245b2af797a3ded53470756e0453fd7fde54210f291c7326eae82253d256d7367b7b8568b05250d5a2f08e6c83b1981d1cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c52fa76a36dd072dbe11c5e7ebc82ef6efdd0fa3da10a006f64a34abc8a9f4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fcXo2BgMG8frvuEaR/yW6P6LLXHDDLxKoc+Z6Otq/Kw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7dc5e8\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 cfbb c3a1 d6ff d0f3 | 63 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n001 2 0bcf 027f | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 3 539d 48b6 4b24 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 7 6742 667e 6982 6e5c | 11 6210 (0) 645b (0) 667e (0) 6742 (0)\n004 5 73b8 734e 7355 772e | 6 7639 (0) 772e (0) 757a (0) 73b8 (0)\n005 2 78cb 7b92 | 2 78cb (0) 7b92 (0)\n============ DEPTH: 6 ==========================================\n006 2 7f87 7fbc | 2 7f87 (0) 7fbc (0)\n007 1 7cf4 | 1 7cf4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","private_key":"c917cec67eeafea4150785766f590f1c97310aa195be916d29051a26b3171a53","name":"node_7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","services":["bzz","pss"],"enable_msg_events":true,"port":33259},"up":true}},{"node":{"info":{"id":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","name":"node_027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","enode":"enode://d49541d31306ef162578a3f30e389a71136992741d3611b524f2a1b37836ce7ee1dd57cc939af45575d8d483f71883fd82b19a52373b635a06117cf4a4ef067e@127.0.0.1:0","enr":"0xf88fb840ca9a8de2b1e9313144320c6cda217eccf7965c113dfd13a673882f078c78b4c16eaa6a88000df314c35dbc9734baea21b359cead3b4fc396d771f9ddb0347d1e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d49541d31306ef162578a3f30e389a71136992741d3611b524f2a1b37836ce7e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"An+0lkOHglg/ePt2mZM27tf7ZyqcnqUNBN9YDm6yE3c=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 027fb4\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 9d3c 9626 91eb aebd | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 8 4cd0 4b24 6c82 667e | 38 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n002 5 3cb1 3ee4 2459 26d1 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 4 1929 1be4 109e 13bc | 4 109e (0) 13bc (0) 1be4 (0) 1929 (0)\n004 3 0ff6 0ab9 0bcf | 3 0ff6 (0) 0ab9 (0) 0bcf (0)\n005 3 06b9 0427 0506 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n007 1 0390 | 1 0390 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 0218 | 1 0218 (0)\n010 0 | 0\n011 1 026d | 1 026d (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","private_key":"35e8d68fdca3b15bdf43c1cde2ec85199450a4588a06d9669dadc25c6921fa02","name":"node_027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","services":["bzz","pss"],"enable_msg_events":true,"port":41117},"up":true}},{"node":{"info":{"id":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","name":"node_03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","enode":"enode://fec12f13138cbdff7808d59f28b3b381ead6ce29e9e229304138d734fe76ca3c3a45e95962022868018fcf1f1fa0e1ac1d8882564c7e0cde1529db9b3232b19a@127.0.0.1:0","enr":"0xf88fb840dfe0f2eb384187472aca67b943618b6dbaf1909ced3442bcc018bee08cc8a00a216115d3306fae614384ddd4ecedd94e35505ba6c7a8f8a8fc9a2f17ea862a4b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fec12f13138cbdff7808d59f28b3b381ead6ce29e9e229304138d734fe76ca3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A5BzgK/NUiOPPYSo3uPfWZx/L5uQ+8EnHuiL21KsvVg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 039073\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 91eb 9d3c ed32 e16b | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 4 4b24 757a 667e 6ecb | 38 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n002 5 39db 3ee4 3cb1 26d1 | 12 286a (0) 2a22 (0) 213b (0) 2459 (0)\n003 4 13bc 109e 1be4 1929 | 4 109e (0) 13bc (0) 1be4 (0) 1929 (0)\n004 3 0ab9 0bcf 0ff6 | 3 0ff6 (0) 0ab9 (0) 0bcf (0)\n005 3 06b9 0427 0506 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n============ DEPTH: 7 ==========================================\n007 3 0218 026d 027f | 3 0218 (0) 026d (0) 027f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","private_key":"b4db734c8cd058c2d749fff4c60c20dc42442061273efc31e209e2410ea38934","name":"node_03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","services":["bzz","pss"],"enable_msg_events":true,"port":33597},"up":true}},{"node":{"info":{"id":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","name":"node_1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","enode":"enode://7b0a4f58064407b6a89a456dd7c991fa39ac01667f7731f4086a9e77cac79dbcaad821bf88ef0eae4cc2a07b14ea9bfea96ab342de836f2071b9a1a92bef83f4@127.0.0.1:0","enr":"0xf88fb840a4ea2bad27e691d6f015407aeb49fd6ef8e053ce798b351ed6925d81856bfe6736edaccb49c93ac2255f173fa0fda36fed07b165e6efe95bf93d54cd4bffabf30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027b0a4f58064407b6a89a456dd7c991fa39ac01667f7731f4086a9e77cac79dbc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GSmoS81kvwAtCvsWJJRmxbZgEjF0ofwb+IGRP4yH0f0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1929a8\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 a2ba 9d3c 895b e16b | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 3 4b24 757a 6ecb | 38 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n002 9 2459 26d1 2a22 3ee4 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 10 0ff6 0bcf 0ab9 0427 | 11 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n============ DEPTH: 4 ==========================================\n004 2 109e 13bc | 2 109e (0) 13bc (0)\n005 0 | 0\n006 1 1be4 | 1 1be4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","private_key":"db5a5448de2eddbf38d0c7d1521fef311345df8517384c0d6b57a7e674ddad53","name":"node_1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","services":["bzz","pss"],"enable_msg_events":true,"port":45321},"up":true}},{"node":{"info":{"id":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","name":"node_6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","enode":"enode://e21a50afba059b155fdd0211a966f7169bcbdb74404cb9ed08f192236eceea4c7b9ced1604b358e45c7153c5a7f75a6749f191d7021e0208d4df9aae45f23804@127.0.0.1:0","enr":"0xf88fb840997c2ef382cf15d5ad18e430d159fc5502d452c770bd172de18a323d9d5f59bc6432167188e9894a86efc4fa5721f7d28bafc11fee19e45a03f76624374b4fa30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e21a50afba059b155fdd0211a966f7169bcbdb74404cb9ed08f192236eceea4c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bssR/FrMFuzXA1FBD6GOxEoqg9nneM8luFp1NUk0Vrc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6ecb11\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 f410 f5c4 e16b e0b1 | 63 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n001 3 3ee4 0390 1929 | 27 286a (0) 2a22 (0) 213b (0) 2459 (0)\n002 9 5d60 5abc 539d 5776 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 7 7355 734e 73b8 772e | 12 78cb (0) 7b92 (0) 7fbc (0) 7f87 (0)\n004 2 667e 6728 | 5 6210 (0) 645b (0) 667e (0) 6742 (0)\n005 1 6982 | 1 6982 (0)\n============ DEPTH: 6 ==========================================\n006 3 6c82 6c02 6d60 | 3 6d60 (0) 6c82 (0) 6c02 (0)\n007 0 | 0\n008 1 6e5c | 1 6e5c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","private_key":"28fb42373087a7839e6469456ad91bd1d4c1ac2998d4255bdb18559e6594b6d8","name":"node_6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","services":["bzz","pss"],"enable_msg_events":true,"port":44113},"up":true}},{"node":{"info":{"id":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","name":"node_ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","enode":"enode://3d426d150fd9ee0de2b594986006891aed8ab3f74cde7ad6cc686e3a10992f727c3211fd7e1c70bd5d1a018adf0672f4c56fe30638e9c51da6156884ccb284e5@127.0.0.1:0","enr":"0xf88fb84061b157c270f717e96d2170c813f51c28cb513f10730481c1f0dd8325c02d72c512a23741c2968d0ca703d403e549c557be9ccba33b9817ab6cff09ec2630c41e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d426d150fd9ee0de2b594986006891aed8ab3f74cde7ad6cc686e3a10992f72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rQ0NxdQRTuRILWyb1ORmgzJ6vyuS3w0kLXkBmWOHZmg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ad0d0d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 109e 0bcf 6210 6ecb | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 2 cfbb d0f3 | 30 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n002 11 8cf9 895b 89c8 8be4 | 16 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n003 5 b70e b2b9 b381 b841 | 8 b8e1 (0) b841 (0) b92a (0) b486 (0)\n004 5 a7a6 a75a a085 a320 | 5 a320 (0) a2ba (0) a085 (0) a7a6 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 3 afa3 ae67 aebd | 3 ae67 (0) aebd (0) afa3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","private_key":"d01704345488dae1946ebc66f4903380ce4b938bed28d2aca5e644e493351f6d","name":"node_ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","services":["bzz","pss"],"enable_msg_events":true,"port":34797},"up":true}},{"node":{"info":{"id":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","name":"node_d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","enode":"enode://4237bb190c2cafcef9ac7ba0cbccf2e75e97a4e8c624e8adc279e935d9c7c0738ab94cb32406678bb61010467d21fc56071334a2860ca5d3e2fd5d414d293f73@127.0.0.1:0","enr":"0xf88fb8405ab3e3f555db63f58404371549be2cf78e94aa9475e7f4b9adc6aa73b5e878df2480291bc05f8cf0166ddea6c24f0fa246e9646d59fce792c15ea71c97be36010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034237bb190c2cafcef9ac7ba0cbccf2e75e97a4e8c624e8adc279e935d9c7c073","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0POYlpSA8981h/bUdUb/EmHK1NLpwm/zB341rhsmFT4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d0f398\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 38ab 26d1 2a22 4b24 | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 4 895b 92a1 a75a ad0d | 33 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n002 6 ebca e55d e0b1 e16b | 15 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n003 5 c3a1 c8e5 ca03 cbc5 | 9 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n004 3 db08 dfae dc97 | 3 db08 (0) dfae (0) dc97 (0)\n============ DEPTH: 5 ==========================================\n005 1 d6ff | 1 d6ff (0)\n006 1 d224 | 1 d224 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","private_key":"875e777570710eaf1d860d33b1d4e4afa6b44b0660cfe5be4aa6cc294c546e66","name":"node_d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","services":["bzz","pss"],"enable_msg_events":true,"port":33929},"up":true}},{"node":{"info":{"id":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","name":"node_cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","enode":"enode://8efcf09e90d2d51bd3c092605c42b4779dd2e58033f47e0334f6888cb53a11d9671659ea85a7b0c22913977f61e1a604b39360d562853873d8b3def8ab011126@127.0.0.1:0","enr":"0xf88fb840f2c79356478735337278a426353488d61e749b316e38e2d4f04fe88cd92f738a2546d62d6fe2bcce1af65b06b7d7345dc3f7c8571101680d66301f4a71c87b3a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028efcf09e90d2d51bd3c092605c42b4779dd2e58033f47e0334f6888cb53a11d9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"z7uepoK+yt6rELvQgLqOk1EAhah6xRnkNJZPqiIvwnU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cfbb9e\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 4b24 6d60 6c02 7fbc | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 4 92a1 9d3c b381 ad0d | 33 86ca (0) 83dc (0) 82f0 (0) 8b76 (0)\n002 5 e55d e0ea e0b1 e16b | 15 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n003 4 dc97 d6ff d224 d0f3 | 6 db08 (0) dfae (0) dc97 (0) d6ff (0)\n004 2 c181 c3a1 | 2 c181 (0) c3a1 (0)\n005 3 c8e5 ca03 cbc5 | 3 c8e5 (0) ca03 (0) cbc5 (0)\n006 1 cdcd | 1 cdcd (0)\n============ DEPTH: 7 ==========================================\n007 2 cec3 ce99 | 2 cec3 (0) ce99 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","private_key":"4269717f6ea28ec4c5441c5b5423a2e7c38b7d2b7d7ccc5172da8fad2d709f3b","name":"node_cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","services":["bzz","pss"],"enable_msg_events":true,"port":35713},"up":true}},{"node":{"info":{"id":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","name":"node_734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","enode":"enode://8bf678fe58741608b5ef92a443588c6eb7f2fe2cf9185e03f908d034e13b4c764e4ed1dc17c36b695812a5c110abb0c18ef88c32727ee10b3868acd09bba0cb4@127.0.0.1:0","enr":"0xf88fb84070de48a3c1c962367c4ff449d327203595b0e1c1ca9e490abd350b47ea74aa7e444e094ec367c1f4ebac57f0289314f2e165f40c16cd4631859c490adce7dc3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028bf678fe58741608b5ef92a443588c6eb7f2fe2cf9185e03f908d034e13b4c76","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c04CntJUhe3Um5PdnoW252V/hg5N7UvIpQlPUSrlg2s=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 734e02\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 e55d f5c4 d6ff d0f3 | 63 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n001 2 2a22 0bcf | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n002 7 5abc 539d 419a 4167 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 10 6c02 6d60 6ecb 6e5c | 11 6210 (0) 645b (0) 667e (0) 6742 (0)\n004 4 7b92 7f87 7dc5 7cf4 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 7639 772e 757a | 3 7639 (0) 772e (0) 757a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 73b8 | 1 73b8 (0)\n009 0 | 0\n010 0 | 0\n011 1 7355 | 1 7355 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","private_key":"0bb7de51881b72244a45a762173749b52aac74eb3a8c1d48f3a62ccd0302fc4a","name":"node_734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","services":["bzz","pss"],"enable_msg_events":true,"port":41955},"up":true}},{"node":{"info":{"id":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","name":"node_f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","enode":"enode://961a9e131513a2c5774c0dc13eb30f2ef01d760ff0d89e535cfda5a6f9295b8f3b0bd2e14350fd396460c2dfab8522f1257f4331f3ea483868e6079a1fb5da7a@127.0.0.1:0","enr":"0xf88fb8409230987fe11342ff370645f1e38d4fdf2d2d9d2c49f2cd3207b760f02c7c517c15952dc852b3d4d0c2dc88387b2c301f5f0ae7c0e668b9616d8ed680cad31ca10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102961a9e131513a2c5774c0dc13eb30f2ef01d760ff0d89e535cfda5a6f9295b8f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9cTSjfWXPsApIiGodehEYyPzOUCdk/D3OFmQEmkIo8M=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f5c4d2\npopulation: 39 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 3ee4 13bc 1929 027f | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 11 b70e b381 b2b9 a085 | 33 b486 (0) b70e (0) b16d (0) b2b9 (0)\n002 6 c3a1 ca03 cfbb d6ff | 15 db08 (0) dfae (0) dc97 (0) d6ff (0)\n003 6 ed32 ea0e ebca e16b | 10 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 f361 f360 | 2 f361 (0) f360 (0)\n006 1 f74e | 1 f74e (0)\n007 1 f410 | 1 f410 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","private_key":"46e5632ca34485b42e08ec702fe84421169074e80c41bc39e596de3815c6e021","name":"node_f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","services":["bzz","pss"],"enable_msg_events":true,"port":39029},"up":true}},{"node":{"info":{"id":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","name":"node_91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","enode":"enode://ae0bd86a797b580157ab4c21533c6f6c1780cb3c0cee9d7e2ff134e014f06b850f6d15e48654d074b11ee4d02fe3ea740579c66308e511746fd4105e2d21afff@127.0.0.1:0","enr":"0xf88fb84001756e4ad603612a22013c330b2cf03e87dc2141a015bede20c5765ed475cacb68aa1b9cec229906947a5e70ca06f66834998d2f887e2017ac427b638f9a09220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ae0bd86a797b580157ab4c21533c6f6c1780cb3c0cee9d7e2ff134e014f06b85","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"keup+cjykp049DoMfvqAnA0tWaMcvydgyQ5z0gJm1Sg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 91eba9\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7b92 39db 109e 0390 | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 3 c3a1 e16b f5c4 | 30 db08 (0) dfae (0) dc97 (0) d6ff (0)\n002 6 afa3 a320 b70e b2b9 | 17 b486 (0) b70e (0) b16d (0) b2b9 (0)\n003 2 89c8 895b | 8 86ca (0) 83dc (0) 82f0 (0) 8b76 (0)\n004 4 9d3c 9e02 9ee7 9a92 | 4 9a92 (0) 9ee7 (0) 9e02 (0) 9d3c (0)\n============ DEPTH: 5 ==========================================\n005 2 9626 957d | 2 957d (0) 9626 (0)\n006 1 92a1 | 1 92a1 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","private_key":"4836585cbd3b3547cff5060ac87f6987ada66424120a9b9538775f47d0f7df73","name":"node_91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","services":["bzz","pss"],"enable_msg_events":true,"port":44261},"up":true}},{"node":{"info":{"id":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","name":"node_e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","enode":"enode://13b2a9865ee51fe3d87fc17ec8cfe97872514aba0eff2dd9a2c4ad9fc1c23b95d14c057a24db7f653bd6a8beb80be7154482ae88ebd1c6a6cfbea08c7fc93951@127.0.0.1:0","enr":"0xf88fb84082f8084805a5a7bd16721d9d3440e711bcb186978b79670fdd73217dd65bbb844a407d171eebfa8bfacff33277985dddc10db2c12f6a3e2bdc0e776ca994dad80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10313b2a9865ee51fe3d87fc17ec8cfe97872514aba0eff2dd9a2c4ad9fc1c23b95","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4WsSxwi8XgVFAJ2u1EczxS10UMzHl9FY3UGjvJUHtr4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e16b12\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 6728 6ecb 6982 7dc5 | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 10 b381 afa3 a085 8cf9 | 33 b486 (0) b70e (0) b16d (0) b2b9 (0)\n002 5 c3a1 cfbb dfae d224 | 15 db08 (0) dfae (0) dc97 (0) d6ff (0)\n003 5 f360 f361 f410 f5c4 | 5 f361 (0) f360 (0) f74e (0) f410 (0)\n004 3 ed32 edc8 ea0e | 5 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n005 2 e77f e55d | 2 e77f (0) e55d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 e0ea e0b1 | 2 e0ea (0) e0b1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","private_key":"5ea17901397d5aaeb179c857d6c09266e923a0215431888d768e5539165ad4e8","name":"node_e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","services":["bzz","pss"],"enable_msg_events":true,"port":37359},"up":true}},{"node":{"info":{"id":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","name":"node_962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","enode":"enode://bfd89002d57335d3e459e80f6a6d01e10639d4fcc760c399b6ca84a4ac5af371aae339acaf6d3a3af784091aec154057c194534e146eec65c841ee33441bf00f@127.0.0.1:0","enr":"0xf88fb84052f31a4caf0d9b1de4fc6c97990f405550c3648b4538d159b61e3b3e25d7125368269c12bc6fbf114ab141f378f013d37094dee41bd8ca773529195ea998253e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bfd89002d57335d3e459e80f6a6d01e10639d4fcc760c399b6ca84a4ac5af371","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"liZ2gYwX+uH/xS/CkxjET5uMmAr9bT6YIXtAiNVoqAg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 962676\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 0ab9 0bcf 0506 018a | 65 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n001 3 c3a1 f361 e16b | 30 db08 (0) dfae (0) dc97 (0) d6ff (0)\n002 3 b92a a320 ad0d | 17 b486 (0) b70e (0) b16d (0) b2b9 (0)\n003 7 86ca 83dc 82f0 8cf9 | 8 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n004 3 9d3c 9e02 9a92 | 4 9d3c (0) 9ee7 (0) 9e02 (0) 9a92 (0)\n============ DEPTH: 5 ==========================================\n005 2 92a1 91eb | 2 92a1 (0) 91eb (0)\n006 1 957d | 1 957d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","private_key":"85a02e6c73fe7d4d4c93334d0c723acd5ff2e71b08e80169c82302596e77fc01","name":"node_962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","services":["bzz","pss"],"enable_msg_events":true,"port":45605},"up":true}},{"node":{"info":{"id":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","name":"node_6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","enode":"enode://e19d4c9793aa8f6a9a32bb81ca986936d9ea49e442c801424ae1b66b0494fc290b62403e22282d1d77439b36dfe907efe0b60126280ca75babc23becb470b1e7@127.0.0.1:0","enr":"0xf88fb84081ecd7a679832795b6c915559cf9bcd02e9b61f37e131f88935755d13d0ff6ab34c388d54a00d8d71d670052b1bac1301f7ff0527db702b60863ca194d14f1210183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e19d4c9793aa8f6a9a32bb81ca986936d9ea49e442c801424ae1b66b0494fc29","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bAKRFKn3PWmkLlkc8tExB+/wONPtqKuwJC2dbRafBcc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c0291\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 f410 cfbb c3a1 d0f3 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 2 3ee4 372d | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n002 7 539d 558e 5a01 5abc | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 6 7b92 7dc5 734e 7355 | 12 78cb (0) 7b92 (0) 7fbc (0) 7f87 (0)\n004 2 667e 6728 | 5 6210 (0) 645b (0) 6742 (0) 6728 (0)\n005 1 6982 | 1 6982 (0)\n006 2 6ecb 6e5c | 2 6e5c (0) 6ecb (0)\n============ DEPTH: 7 ==========================================\n007 1 6d60 | 1 6d60 (0)\n008 1 6c82 | 1 6c82 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","private_key":"40e5884353d6096401012e695c215b05187562c0e32a97ee4abcd43c25a0ad55","name":"node_6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","services":["bzz","pss"],"enable_msg_events":true,"port":37519},"up":true}},{"node":{"info":{"id":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","name":"node_372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","enode":"enode://7cd3bb16716b1076e17d80959f4ef0fc541fc21ed845356a47f3bda9b1b7cc3c69114f4f796a56b301fa411ec706f696106d9b052accfc958fcd51e391c51ffb@127.0.0.1:0","enr":"0xf88fb8406c50fb4ef43704e45da206358753811875825f0bb9f88f7e4510685d0045fdf252af80cdb5e4d427ca21741e0b0fda40d2b789a1cd793aef76efcceebf4250040183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037cd3bb16716b1076e17d80959f4ef0fc541fc21ed845356a47f3bda9b1b7cc3c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Ny1HN0pX0YzxNKH4/C0vwQ36z8C+ntiDGDo0nIlrN5M=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 372d47\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ea60 89c8 895b a085 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 8 4a18 48b6 539d 558e | 38 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n002 5 0506 0218 0bcf 1be4 | 15 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n003 5 2a22 213b 2459 2434 | 6 213b (0) 2459 (0) 2434 (0) 26d1 (0)\n============ DEPTH: 4 ==========================================\n004 5 38ab 39db 3e56 3ee4 | 5 39db (0) 38ab (0) 3e56 (0) 3ee4 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","private_key":"1be8d297f334edb94c9ea51d8debf701671d9b6417ac0686d6602848d866ee4e","name":"node_372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","services":["bzz","pss"],"enable_msg_events":true,"port":33327},"up":true}},{"node":{"info":{"id":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","name":"node_a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","enode":"enode://1018042bdefdc2e798c3ddd700486aba9fc20a89da51cae3496187cb9d6255d2b13be34e59108f3b3d1eab3f56f7a0988c0e866f58fcf360f6249fa89511f07d@127.0.0.1:0","enr":"0xf88fb84022e9bba09d0d2e41131e876b802569733bf1059ce20eb77f6b4b622ece181037505657543d3b05deec3ede00996d0c039955058490a884ad00126337c3b92eba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031018042bdefdc2e798c3ddd700486aba9fc20a89da51cae3496187cb9d6255d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p1q9Dc5aSIt+Bvkfq3qS7EKKshvek3LJ6PpIn0jns/4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a75abd\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 757a 109e 372d | 65 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n001 8 cdcd cbc5 c3a1 dc97 | 30 db08 (0) dfae (0) dc97 (0) d6ff (0)\n002 5 9a92 8b76 89c8 895b | 16 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n003 5 b8e1 b92a b381 b2b9 | 8 b16d (0) b2b9 (0) b381 (0) b486 (0)\n004 3 ad0d afa3 ae67 | 4 aebd (0) ae67 (0) afa3 (0) ad0d (0)\n============ DEPTH: 5 ==========================================\n005 3 a320 a2ba a085 | 3 a085 (0) a320 (0) a2ba (0)\n006 0 | 0\n007 0 | 0\n008 1 a7a6 | 1 a7a6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","private_key":"f0d55a442b4523bc34a50224cf58a48983f8e13bf68ed7aef1f210ec4181e4ba","name":"node_a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","services":["bzz","pss"],"enable_msg_events":true,"port":34721},"up":true}},{"node":{"info":{"id":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","name":"node_757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","enode":"enode://bcc2e6a83deced98cbb219f3952ee89113bb72388f8db9468b0ccedc5c9efd497340ca0dab2f4ad807e2a6f7c2083c9c6ff638d982c98e7742df1f7b926737ad@127.0.0.1:0","enr":"0xf88fb840292c38ff3ee7ca5696840d594c2568dfdb75ecbbeefd9b86d835dfc88808eb3b4bc9021d750154c42b701172f70e6763d08126f1989ed3bfbab925235bc983220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bcc2e6a83deced98cbb219f3952ee89113bb72388f8db9468b0ccedc5c9efd49","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dXpVdCTDOtie/YGF7BjXHAJYMOyyrtlR4zyMjZhtWTM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 757a55\npopulation: 46 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 e55d ed32 ea0e f410 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 11 2459 26d1 0bcf 0ab9 | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 0427 (0)\n002 8 517a 539d 558e 5d60 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 5 6ecb 6c02 645b 667e | 11 6982 (0) 6e5c (0) 6ecb (0) 6c82 (0)\n004 5 78cb 7b92 7f87 7cf4 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 7355 734e 73b8 | 3 73b8 (0) 7355 (0) 734e (0)\n============ DEPTH: 6 ==========================================\n006 2 7639 772e | 2 7639 (0) 772e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","private_key":"da2903aa985ff2bebcff008fe5e6086043ded662b94bf703bdd33aa8abbcad68","name":"node_757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","services":["bzz","pss"],"enable_msg_events":true,"port":33351},"up":true}},{"node":{"info":{"id":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","name":"node_4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","enode":"enode://54c96640ca98c787831ec404bd53cf02cf312f521c34f5484e8c9bc0b9b0d95be546ccb2dc35f2350b6b457a5f8d57ec62dfc95fd3f82be2cf6acabfad9383b7@127.0.0.1:0","enr":"0xf88fb840701b1435264d1443865d19c0d29add0cf76d12020726e2685d8e4da0a8eeab31323b97fafbbd0ca3d01635cd7f3b27615bc73d27b4fdbf67c108954bd567c8b00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10354c96640ca98c787831ec404bd53cf02cf312f521c34f5484e8c9bc0b9b0d95b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SyQ6Wuq+xtsOSoCpwlUwDNlFkab74OCqFw2k9s4U7f8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4b243a\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b2b9 d0f3 cfbb | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 10 26d1 2a22 1929 13bc | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 0427 (0)\n002 10 6ecb 6e5c 6d60 6c02 | 23 6982 (0) 6ecb (0) 6e5c (0) 6c82 (0)\n003 5 5abc 558e 5776 517a | 7 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n004 3 47c3 4167 41b9 | 4 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n005 1 4cd0 | 1 4cd0 (0)\n============ DEPTH: 6 ==========================================\n006 1 48b6 | 1 48b6 (0)\n007 1 4a18 | 1 4a18 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","private_key":"4f3791027f035431649d9fcd7cb9f8fd3c894da3f485f2c0e24c2a851fab97fb","name":"node_4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","services":["bzz","pss"],"enable_msg_events":true,"port":36491},"up":true}},{"node":{"info":{"id":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","name":"node_667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","enode":"enode://03bb27a5efeec49cef6564a99f3d8f48962be8be00db2ace069c57a131607c55bf856022b21bd4ec25e48b349b52b09fa2041ed165d3a8385ec34a5d7280d6d7@127.0.0.1:0","enr":"0xf88fb840307d719c21165c858e0413d4b18af8363443e8bba70afc6cc2b8dd5ff08a43a66e9ee7aec6b62b965901f872ab5832443df4fae667d7b3557eaea3c1e9052e020183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10303bb27a5efeec49cef6564a99f3d8f48962be8be00db2ace069c57a131607c55","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Zn7wQuna4YaUWB4EBMPYegmADotCFz0mVxw7+X4po3I=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 667ef0\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b2b9 957d dc97 dfae | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 4 0ab9 0bcf 027f 0390 | 27 0ff6 (0) 0ab9 (0) 0bcf (0) 06b9 (0)\n002 5 539d 5abc 5a01 48b6 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 7 7b92 7dc5 757a 772e | 12 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n004 5 6e5c 6ecb 6c82 6c02 | 6 6982 (0) 6ecb (0) 6e5c (0) 6c82 (0)\n005 1 6210 | 1 6210 (0)\n006 1 645b | 1 645b (0)\n============ DEPTH: 7 ==========================================\n007 2 6742 6728 | 2 6742 (0) 6728 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","private_key":"b61f7c457f7b07d448f38101f0b9a63485fa37f50da9a92362a48addc997a396","name":"node_667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","services":["bzz","pss"],"enable_msg_events":true,"port":46521},"up":true}},{"node":{"info":{"id":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","name":"node_6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","enode":"enode://5fd6f8ed3cd810ee8b1f94209e80e357d598434625f8644da0ebe3e07eb25a80c5ca8fef356aba34c04ca2acbed317344c504ffe32fd7635f0b94c3ce5f5eff2@127.0.0.1:0","enr":"0xf88fb840236d92a5eae6b161341b01c489cd53ae1380191a314d7106c6984b0eb94d216b3bf8b891301e7486d39136a85d0a085f7cd70f33df587aeb879ce0600b7663720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025fd6f8ed3cd810ee8b1f94209e80e357d598434625f8644da0ebe3e07eb25a80","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bWAZUnk1ibxrVzQMRRpqvwLqLBZjfpEO7QTN5u3f4Xo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6d6019\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 b2b9 957d d0f3 d224 | 63 db08 (0) dfae (0) dc97 (0) d6ff (0)\n001 2 3ee4 3cb1 | 27 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n002 5 48b6 4a18 4b24 5abc | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 7 78cb 7b92 7f87 7dc5 | 12 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n004 4 645b 6742 6728 667e | 5 6210 (0) 645b (0) 6742 (0) 6728 (0)\n005 1 6982 | 1 6982 (0)\n006 2 6e5c 6ecb | 2 6ecb (0) 6e5c (0)\n============ DEPTH: 7 ==========================================\n007 2 6c02 6c82 | 2 6c82 (0) 6c02 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","private_key":"18bc5eca469877f8bfa545da0ad2bd73daec62af973abe276fb20f1d04863e95","name":"node_6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","services":["bzz","pss"],"enable_msg_events":true,"port":33319},"up":true}},{"node":{"info":{"id":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","name":"node_3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","enode":"enode://5fd4ee4ef3698df17ace9e5c9df83f75a95f7e5f95f649cc8bdd52f61a7fac2171d1ee5f86535eee24bae2effb9f7ff69670824dbe6eb14a35b7665c2223da3d@127.0.0.1:0","enr":"0xf88fb840aff409e698e8f4f5cf56ca52947c18b6d9809b5f1e525fc10e843e36ee2ca5241e81898a9433b16d0a08764e529c7fb084f389f43419ee06e71bf301a946d2900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035fd4ee4ef3698df17ace9e5c9df83f75a95f7e5f95f649cc8bdd52f61a7fac21","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PLG0Bpcn3DI6aHyrTKJ2T2QVRQSIcG8bl8XLjKRjRv8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3cb1b4\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 89c8 8cf9 ae67 a085 | 63 db08 (0) dfae (0) dc97 (0) d224 (0)\n001 4 48b6 7355 6e5c 6d60 | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 9 1929 0427 0506 018a | 15 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n003 6 213b 2434 2459 26d1 | 6 213b (0) 2459 (0) 2434 (0) 26d1 (0)\n004 1 372d | 1 372d (0)\n005 2 39db 38ab | 2 39db (0) 38ab (0)\n============ DEPTH: 6 ==========================================\n006 2 3ee4 3e56 | 2 3e56 (0) 3ee4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","private_key":"f18fca734e8631f11eebe52259a8080c6109a0f5fe18f736743c0a34181f2eae","name":"node_3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","services":["bzz","pss"],"enable_msg_events":true,"port":43603},"up":true}},{"node":{"info":{"id":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","name":"node_b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","enode":"enode://c8fe782387da875269f14c7cd4bb3380d51b007537929342fbbdc7ea61b444f205d4e3bc17b6fd54daf1f730ce4aaca7e4af914aff70e0f3dbb2e8edabb226a1@127.0.0.1:0","enr":"0xf88fb840a624988c579ed3e88f99fb8ca769e17361f6331458d1424eff6108f9c6b1152a56461c35819897506a2c1c17c8d17c05b4e88113489bfa3ec2b477dc8e29997e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c8fe782387da875269f14c7cd4bb3380d51b007537929342fbbdc7ea61b444f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uSpxpPw3HgWWU4p/sqM+hTKcOcRAnJl5jZMYvCY6BKE=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b92a71\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0218 2a22 3cb1 | 65 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n001 4 e55d dc97 d6ff c3a1 | 30 db08 (0) dfae (0) dc97 (0) d224 (0)\n002 7 82f0 9a92 9d3c 9e02 | 16 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n003 5 a75a a085 a2ba afa3 | 9 aebd (0) ae67 (0) afa3 (0) ad0d (0)\n004 5 b486 b70e b16d b2b9 | 5 b16d (0) b2b9 (0) b381 (0) b486 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 2 b8e1 b841 | 2 b8e1 (0) b841 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","private_key":"6c47e1823351c4f8273293dc991f5d3e47a310824dc99d1d52beef8c89294f01","name":"node_b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","services":["bzz","pss"],"enable_msg_events":true,"port":42797},"up":true}},{"node":{"info":{"id":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","name":"node_2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","enode":"enode://a7c716f7518d16f027fc0d58cc55ab8ae2162f10c0cf5d81c251ca7871aa0987c94ba79fbe53061f70754735133653680cec4e97749c0ece47ae3d0087d943d4@127.0.0.1:0","enr":"0xf88fb84080004a46ab4e22a502d41f7bfe521c7b28973328433a5a30cba401e5f2fe9a1c100aecae60a1cc71aaac717ef8f08b2e07149090f6be981f06b7f4aa3a2bf7d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a7c716f7518d16f027fc0d58cc55ab8ae2162f10c0cf5d81c251ca7871aa0987","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KiLb7nGg7yfIQCIdtKWS1tyPFxr+2GX/gUo31jOj6qk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a22db\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 9d3c 89c8 a085 b92a | 63 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n001 6 7639 7355 734e 4b24 | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 12 1929 13bc 109e 0ab9 | 15 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n003 5 372d 38ab 39db 3e56 | 6 372d (0) 39db (0) 38ab (0) 3e56 (0)\n============ DEPTH: 4 ==========================================\n004 4 2459 2434 26d1 213b | 4 213b (0) 2459 (0) 2434 (0) 26d1 (0)\n005 0 | 0\n006 1 286a | 1 286a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","private_key":"983e054d5c73ca85071b2217c801a3085251fb1b921de91548a7a6a233b24777","name":"node_2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","services":["bzz","pss"],"enable_msg_events":true,"port":46129},"up":true}},{"node":{"info":{"id":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","name":"node_c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","enode":"enode://7defcbf17d10e9ee01953d449616f3699518c4d3585397ff9bc8593c072c9a6b812acfd3433a4089f86c780620500a11b9e3e2801b235000453c067ad2311f82@127.0.0.1:0","enr":"0xf88fb840de5af3f26f6196388d0546896aa7bf5ac6fc698d19f254306f9dc81a408a11586b063e732170349d2f8894e5ae2b69572727cb59a416373c82b651eca0cb6c580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027defcbf17d10e9ee01953d449616f3699518c4d3585397ff9bc8593c072c9a6b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"w6GzAb8Yf9gyaDEZfZOgJmrAzIKHuQCGMSQOK+yc8zc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c3a1b3\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7dc5 757a 667e 6982 | 65 41b9 (0) 419a (0) 4167 (0) 47c3 (0)\n001 7 a75a b381 b92a 82f0 | 33 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n002 7 f5c4 f74e ea0e ed32 | 15 f360 (0) f361 (0) f74e (0) f410 (0)\n003 5 dfae dc97 d6ff d224 | 6 db08 (0) dc97 (0) dfae (0) d224 (0)\n============ DEPTH: 4 ==========================================\n004 7 c8e5 ca03 cbc5 cdcd | 7 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n005 0 | 0\n006 1 c181 | 1 c181 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","private_key":"484569ae37b3c147f07f84fa525f767a19cb38f2839bdc5ea2c5e66a29a71514","name":"node_c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","services":["bzz","pss"],"enable_msg_events":true,"port":40743},"up":true}},{"node":{"info":{"id":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","name":"node_e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","enode":"enode://9bf89be750b3f7b410f5c7f487664a2e0984a1869ab3028316d121edb1de9c7d0044a57a07671607f39b16c19b4afd6bb65be16f70a2edda4a6c8cfef676f9e7@127.0.0.1:0","enr":"0xf88fb8407f93d5d7b618515bd5cba4bb810d1e7c011dcd28c79b7a11da77ca28ff0159924f52b0a9855f06e431c27bfc00244284259f11bcc2db35e6f81fa2d3e1901f6e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039bf89be750b3f7b410f5c7f487664a2e0984a1869ab3028316d121edb1de9c7d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5V2M2355QLEZKeflyUnva+t5mOUYCh8KPAv2Gu858bg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e55d8c\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 0390 13bc 1929 6ecb | 65 47c3 (0) 41b9 (0) 419a (0) 4167 (0)\n001 10 afa3 ae67 b92a b841 | 33 b16d (0) b2b9 (0) b381 (0) b486 (0)\n002 5 db08 dfae d0f3 cfbb | 15 db08 (0) dfae (0) dc97 (0) d224 (0)\n003 3 f361 f74e f5c4 | 5 f360 (0) f361 (0) f74e (0) f410 (0)\n004 4 ebca ea0e ed32 edc8 | 5 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n============ DEPTH: 5 ==========================================\n005 3 e16b e0b1 e0ea | 3 e0ea (0) e0b1 (0) e16b (0)\n006 1 e77f | 1 e77f (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","private_key":"70bfa2dd7936c527af87ad8ba7b3d514378ae9415b80790afbeb8c145ef60da3","name":"node_e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","services":["bzz","pss"],"enable_msg_events":true,"port":40869},"up":true}},{"node":{"info":{"id":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","name":"node_895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","enode":"enode://bdad63bb5585a3b586e639b7f3a5a588a466508ceda1e479e1a9b680bf7306e84cff0f49d32225c68a8e8c4ce351565f80823ea4eb59625cfa0f4e4a4c778940@127.0.0.1:0","enr":"0xf88fb840cf3575b7f89341293c93e42a94e09971765ed95f6b2e7b14e280dbe9f820d785440bcb6c7546cd319062f61ac1ccf8d316d6e62e604ccbdf856585b699e3d0b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bdad63bb5585a3b586e639b7f3a5a588a466508ceda1e479e1a9b680bf7306e8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iVvc0gDMTX7Fwk8XItCo6+3aeLeM3xzMjCKpgZgPV4Y=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 895bdc\npopulation: 37 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 0ab9 0bcf 018a 026d | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 8 d6ff d0f3 d224 dc97 | 30 db08 (0) dfae (0) dc97 (0) d224 (0)\n002 6 b8e1 ad0d afa3 a75a | 17 b16d (0) b2b9 (0) b381 (0) b486 (0)\n003 5 9a92 9e02 9d3c 9626 | 8 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n004 3 86ca 83dc 82f0 | 3 86ca (0) 83dc (0) 82f0 (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 8b76 8be4 | 2 8be4 (0) 8b76 (0)\n007 0 | 0\n008 1 89c8 | 1 89c8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","private_key":"dcb06c1695510d0ebdf81de665b6c30b1bc31fcffcdeb5a1d949119e3323d009","name":"node_895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","services":["bzz","pss"],"enable_msg_events":true,"port":36481},"up":true}},{"node":{"info":{"id":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","name":"node_a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","enode":"enode://200a1baeeb12eaff4957c04f960bc136c15c981b4ed91f50b6a3cd72f60ce1a9670bf2aada7c27159b884f728294220ddf2f7ab7c25bda08e51af6e0d2ac59cc@127.0.0.1:0","enr":"0xf88fb8409ac56bef876fd1aa5cf1e9dc9750872b7b31e85abe3b3bd7bcbe11b451f4a4a41eca4dab1ec561a4e4e38d69fcf6daf208f8b8a3ffae014bd67e43b9be5e10800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102200a1baeeb12eaff4957c04f960bc136c15c981b4ed91f50b6a3cd72f60ce1a9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"orq+SUEK4Ae8Qf8rfer3Ce2Eni9pZmzlqudqO3H0cIE=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a2babe\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0bcf 109e 13bc 1929 | 65 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n001 2 e0b1 d6ff | 30 f360 (0) f361 (0) f74e (0) f410 (0)\n002 5 83dc 82f0 8cf9 8b76 | 16 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n003 5 b70e b381 b2b9 b8e1 | 8 b16d (0) b2b9 (0) b381 (0) b486 (0)\n004 4 ad0d afa3 aebd ae67 | 4 aebd (0) ae67 (0) afa3 (0) ad0d (0)\n005 2 a7a6 a75a | 2 a7a6 (0) a75a (0)\n============ DEPTH: 6 ==========================================\n006 1 a085 | 1 a085 (0)\n007 1 a320 | 1 a320 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","private_key":"d2327e3f9e0f7d479fd3a5ab6629e91631a909dcea933881e6981e4d8f65f4b1","name":"node_a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","services":["bzz","pss"],"enable_msg_events":true,"port":42677},"up":true}},{"node":{"info":{"id":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","name":"node_8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","enode":"enode://81d1c6b434a911a8540ccca92dc7eb5f6af3c9f8e8661331630b961b9beebbc774961f8c9b6764495cd176cdc7a2234e00b1fe437cf0e0e62ffdebffe804300b@127.0.0.1:0","enr":"0xf88fb840282e7b8b2c9fe6bfd46ecfa1ef9c05c0ce8aa561d6727b69e6112e3458aa1bbd1e729fe940bc2ed0879a33afffe03e9bb6645ef7c6ed882f20af71d138c235810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10381d1c6b434a911a8540ccca92dc7eb5f6af3c9f8e8661331630b961b9beebbc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jPlXv5WmKcYMMdvP517MoUmoHHYfizSFiwT4MY5cdL0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8cf957\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 7b92 018a 026d 0ab9 | 65 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n001 11 cec3 f361 f5c4 e0ea | 30 f360 (0) f361 (0) f74e (0) f410 (0)\n002 6 b8e1 ad0d afa3 a75a | 17 b841 (0) b8e1 (0) b92a (0) b16d (0)\n003 4 9626 9a92 9d3c 9e02 | 8 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n004 3 86ca 83dc 82f0 | 3 86ca (0) 83dc (0) 82f0 (0)\n============ DEPTH: 5 ==========================================\n005 4 8be4 8b76 895b 89c8 | 4 8be4 (0) 8b76 (0) 89c8 (0) 895b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","private_key":"7cbecf45c8af825ad55165ca14a5390dc79b63f7d21abc54c8a3baadb93b0050","name":"node_8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","services":["bzz","pss"],"enable_msg_events":true,"port":38617},"up":true}},{"node":{"info":{"id":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","name":"node_9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","enode":"enode://1f9a4a0c1be2d3dc6cbe8fe451547748f181485a135d11125e490c4554edcb2a9c3915bce098a7a2d347392cbed94f9329000fa47ab5bd6611ae18f398feadf2@127.0.0.1:0","enr":"0xf88fb84073df5e59956667788fb2912ac8df533ca51baf49e3d0ab14bd339845667a29bd706b855764a6ae9a2143bd63225a6a73a0e252aaf849de6071447977ffc144f60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f9a4a0c1be2d3dc6cbe8fe451547748f181485a135d11125e490c4554edcb2a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ngLFOEYCpU6QDPpG1Zh7d/FudMunRayFD8raAcevkAQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9e02c5\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 39db 2434 018a 026d | 65 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n001 3 f361 c3a1 d6ff | 30 f360 (0) f361 (0) f74e (0) f410 (0)\n002 6 a320 ad0d afa3 b70e | 17 b841 (0) b8e1 (0) b92a (0) b16d (0)\n003 6 83dc 82f0 8b76 895b | 8 86ca (0) 83dc (0) 82f0 (0) 8be4 (0)\n004 4 91eb 92a1 957d 9626 | 4 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n005 1 9a92 | 1 9a92 (0)\n============ DEPTH: 6 ==========================================\n006 1 9d3c | 1 9d3c (0)\n007 0 | 0\n008 1 9ee7 | 1 9ee7 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","private_key":"a54d320f74dbd164c2e978d7a70edcb4a6c116debd0e98aeaafdf18a0caf5810","name":"node_9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","services":["bzz","pss"],"enable_msg_events":true,"port":45685},"up":true}},{"node":{"info":{"id":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","name":"node_539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","enode":"enode://79b76c3f04c3fe8a4d8e15ba7832fa0e0cb07d122736b0ddd187f783af4f63fd91451132a818a91e2aaee43e9e6b4aace8e002ee76166005b9a2fe9553283f1a@127.0.0.1:0","enr":"0xf88fb840267a7455083f7f198cb282b60318c8fc45fa5d66c3aa1d1b7cea64ea5940f4dd140ae387c995877ba388099faf98c6e647e66c692c3a237bcb78321b457f26ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10279b76c3f04c3fe8a4d8e15ba7832fa0e0cb07d122736b0ddd187f783af4f63fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"U535AtQtyZfGsOJNFq1otUxVfVa0HJcqMg1XYy2/vjw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 539df9\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 e55d b2b9 9e02 | 63 f360 (0) f361 (0) f74e (0) f410 (0)\n001 3 2a22 372d 38ab | 27 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n002 12 667e 6728 6742 6ecb | 23 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n003 8 47c3 4167 419a 41b9 | 8 4167 (0) 41b9 (0) 419a (0) 47c3 (0)\n004 3 5d60 5a01 5abc | 3 5d60 (0) 5a01 (0) 5abc (0)\n============ DEPTH: 5 ==========================================\n005 2 5776 558e | 2 5776 (0) 558e (0)\n006 1 517a | 1 517a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","private_key":"af360c6fe75b63f4d38464596d6a86faff221f4c287bfde6f06204cdadaaa7f8","name":"node_539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","services":["bzz","pss"],"enable_msg_events":true,"port":46373},"up":true}},{"node":{"info":{"id":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","name":"node_38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","enode":"enode://b59c9de0746cb3c3d75539274cc8216e4fe0ba577923dae16c2c38b2459f36f451764f8027ec684def5e6452ba84a2afc62f3729d3889e9c65307ecb10ae0496@127.0.0.1:0","enr":"0xf88fb840e51c952cba32bef6455c273e05c4252fc1e13ec6b7deee195982262b858831046faa9872c55686e7dc575653a070c1ec4d282cf32c09f2426240fa8250585f870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b59c9de0746cb3c3d75539274cc8216e4fe0ba577923dae16c2c38b2459f36f4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OKs9e9+yk7iBIkBMt8ULX7iQznZkwHXalVhVV6QwxAM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 38ab3d\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d0f3 a085 ae67 b70e | 63 f410 (0) f5c4 (0) f74e (0) f360 (0)\n001 4 7b92 7355 5abc 539d | 38 7f87 (0) 7fbc (0) 7dc5 (0) 7cf4 (0)\n002 6 0bcf 0ab9 0506 0218 | 15 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n003 4 2a22 2459 2434 213b | 6 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n004 1 372d | 1 372d (0)\n============ DEPTH: 5 ==========================================\n005 3 3ee4 3e56 3cb1 | 3 3e56 (0) 3ee4 (0) 3cb1 (0)\n006 0 | 0\n007 1 39db | 1 39db (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","private_key":"90080ed19445f25b61f6f51c31c7b5f0901bcc8b4d2af5754eb6200898460782","name":"node_38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","services":["bzz","pss"],"enable_msg_events":true,"port":44377},"up":true}},{"node":{"info":{"id":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","name":"node_b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","enode":"enode://8908b549b763c33a6d64dd794edf15467674ab7744abc8dadfe0a9ffe7edb0f232d68be0ce2cab3a1f1f4c1eb5bc265d2b5d241edb189daedf12f94294f83ece@127.0.0.1:0","enr":"0xf88fb840bd4af476eac6bae70a9bf4b3556d02f449fe1467ed3cb54cea8bcc7e51c1579a6949b225f34052028d4a72b4c7f804c49f2e12d4894046aedad89e4ffbf78d380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028908b549b763c33a6d64dd794edf15467674ab7744abc8dadfe0a9ffe7edb0f2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tw6W8BrIlH0t5jIEEq4zEDFsq6ZcJxCK0WsvIAQlW+Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b70e96\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6e5c 0218 109e 38ab | 65 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n001 5 db08 f5c4 f361 e55d | 30 f360 (0) f361 (0) f410 (0) f5c4 (0)\n002 7 91eb 9a92 9d3c 9e02 | 16 86ca (0) 82f0 (0) 83dc (0) 8be4 (0)\n003 8 a2ba a320 a085 a75a | 9 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n004 2 b8e1 b92a | 3 b841 (0) b8e1 (0) b92a (0)\n============ DEPTH: 5 ==========================================\n005 3 b2b9 b381 b16d | 3 b2b9 (0) b381 (0) b16d (0)\n006 1 b486 | 1 b486 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","private_key":"356f88370186e91459aaa1a01150f9a0a07c6ba89835476be5ee3177f2456a90","name":"node_b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","services":["bzz","pss"],"enable_msg_events":true,"port":36567},"up":true}},{"node":{"info":{"id":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","name":"node_6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","enode":"enode://aa49209c98c2acfa233719cd8ab7c559b1a4024986f005f61450405205031b502c13b39557ac3df31f081a1bcc3cf8de29357f78400a37d679e179bd1f15b597@127.0.0.1:0","enr":"0xf88fb840cfbea5c6873c85a8951ee4931c303f2eff6e82813d5e4d86c25d48a82b1a49e341d8b0c006a2036a8eb6cc687fdb9c38595d982c2da6d56ff80606137b1fb5090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103aa49209c98c2acfa233719cd8ab7c559b1a4024986f005f61450405205031b50","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"blwhOi21fq8uHhrMNBxy76uJsOQrbNGNtPmawa8VHWU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e5c21\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d6ff a320 b486 b70e | 63 f360 (0) f361 (0) f410 (0) f5c4 (0)\n001 3 3cb1 0218 109e | 27 2459 (0) 2434 (0) 26d1 (0) 213b (0)\n002 5 41b9 4b24 539d 5a01 | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 7 7f87 7dc5 7b92 78cb | 12 78cb (0) 7b92 (0) 7fbc (0) 7f87 (0)\n004 3 667e 6728 645b | 5 6210 (0) 645b (0) 6742 (0) 6728 (0)\n005 1 6982 | 1 6982 (0)\n============ DEPTH: 6 ==========================================\n006 3 6d60 6c82 6c02 | 3 6c82 (0) 6c02 (0) 6d60 (0)\n007 0 | 0\n008 1 6ecb | 1 6ecb (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","private_key":"5f2bdd7f08afe412e3fe6ff84df44e66752bb9b256a47fbc9581d982eadffdd4","name":"node_6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","services":["bzz","pss"],"enable_msg_events":true,"port":33895},"up":true}},{"node":{"info":{"id":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","name":"node_772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","enode":"enode://31b2a3729f35e5f4dd4e1ee95642c5672d2770f7624b097db81350287a180c1e49fff42d6c63128a806950d4128d494b8268a2b96fde995d89607b612ecec782@127.0.0.1:0","enr":"0xf88fb8404462b449bcf2410c7f21823b369db50987ba625ab6e4a803cdc4559caf61851a17783540a154b7d6f3a1d7ab7d08cd0851226dbccd517da51f555ad7c40bf5540183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10231b2a3729f35e5f4dd4e1ee95642c5672d2770f7624b097db81350287a180c1e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dy5MgNEo3rUq3wJKDrb+m76hyDNR7ZP1X0kM1eXGkmA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 772e4c\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b486 d6ff f74e ea0e | 63 f360 (0) f361 (0) f410 (0) f5c4 (0)\n001 2 109e 0ab9 | 27 286a (0) 2a22 (0) 2459 (0) 2434 (0)\n002 8 4a18 41b9 5d60 5abc | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 6 667e 645b 6d60 6c02 | 11 6210 (0) 645b (0) 6742 (0) 6728 (0)\n004 6 7f87 7fbc 7dc5 7cf4 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 73b8 734e 7355 | 3 73b8 (0) 7355 (0) 734e (0)\n============ DEPTH: 6 ==========================================\n006 1 757a | 1 757a (0)\n007 1 7639 | 1 7639 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","private_key":"8efd5800758dcfdbeb2cf4d84f54e399c106e2c731f6685f720a2eea4c481817","name":"node_772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","services":["bzz","pss"],"enable_msg_events":true,"port":37837},"up":true}},{"node":{"info":{"id":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","name":"node_0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","enode":"enode://76fd52545682d9fdd0ca8f38321e9b37b84ca6a997956e0069744d0cb0bccb1a617f66c8eafe8dd5ed392d7e9c2efa928347aefe1c976201f3abd3e7a54bfb88@127.0.0.1:0","enr":"0xf88fb84097a8f0f039558e79fbee580fbec1d41e14fbba47472a75f290402f4076cad6492048d5e3a00ebc8742f93aa523bf57f954a31dda07673ea76280d76e01e4c5190183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10276fd52545682d9fdd0ca8f38321e9b37b84ca6a997956e0069744d0cb0bccb1a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CrmEXCiQsKZKPlkyJBJF4AuBe3iAlPnuSPhvgLcmT+o=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ab984\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 ea60 e16b 91eb 9626 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 6 5776 4b24 667e 7b92 | 38 4167 (0) 41b9 (0) 419a (0) 47c3 (0)\n002 6 2a22 2434 3ee4 3cb1 | 12 26d1 (0) 2459 (0) 2434 (0) 213b (0)\n003 4 13bc 109e 1929 1be4 | 4 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n004 8 06b9 0506 0427 0390 | 8 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n============ DEPTH: 5 ==========================================\n005 1 0ff6 | 1 0ff6 (0)\n006 0 | 0\n007 1 0bcf | 1 0bcf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","private_key":"846db675d9c428c99df430ba38d3d3faf984abbe2f55df43af95bb096f86e896","name":"node_0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","services":["bzz","pss"],"enable_msg_events":true,"port":34333},"up":true}},{"node":{"info":{"id":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","name":"node_39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","enode":"enode://6ccc67d35840435af60a0430406169efc0037b4828edb5cd76e9bd5ac1e5aca65dd7a77219313f8a6c26f1ca7f5df41afd47dc389720d30b19e6979b52954c32@127.0.0.1:0","enr":"0xf88fb84055b20a8008a1872c0413f0ceea3a6a7121cc4e0dabef2b310f5bc43817bff888247a073d6946b7988936af22a7d1639fa5f109db9887292d255e6e771f8cda810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ccc67d35840435af60a0430406169efc0037b4828edb5cd76e9bd5ac1e5aca6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OdvVRiyQ2sdfSdmveZaEWUO76Sl1TvgSXu5/WnY+ne8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39dbd5\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 ae67 a085 8cf9 89c8 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 5 7355 48b6 41b9 558e | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 5 1929 0506 0390 0bcf | 15 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n003 4 2a22 213b 26d1 2434 | 6 26d1 (0) 2459 (0) 2434 (0) 213b (0)\n004 1 372d | 1 372d (0)\n============ DEPTH: 5 ==========================================\n005 3 3e56 3ee4 3cb1 | 3 3e56 (0) 3ee4 (0) 3cb1 (0)\n006 0 | 0\n007 1 38ab | 1 38ab (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","private_key":"791b9811412b1579e2e6d5f9fe6ddc88ce78a499b261b22e8817e02440f9e875","name":"node_39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","services":["bzz","pss"],"enable_msg_events":true,"port":36547},"up":true}},{"node":{"info":{"id":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","name":"node_d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","enode":"enode://72cbbeef82764d1b224a5af28e3e60dda17a49ccfe5b92cb84263bec1524623133bc14c9d0c60f36575f469f986b97d0bd09896ad8a7a068f1d52c4000c0d8d8@127.0.0.1:0","enr":"0xf88fb840ffaffd6544c636f742b7379273dcff32de002122a72f3ec80a94c93dd7f0347b5c5ab37d8762f17cce7877ddd4a925cb05ac0c19a51a71330445ff05ad5969450183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10272cbbeef82764d1b224a5af28e3e60dda17a49ccfe5b92cb84263bec15246231","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1v+3/SZo6bexM72RRBVvRzYZHvDW5ysHJ1l4LYOTHyI=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d6ffb7\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 6e5c 6d60 6c02 645b | 65 7b92 (0) 78cb (0) 7f87 (0) 7fbc (0)\n001 6 b16d b92a a75a a2ba | 33 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n002 5 f5c4 f74e ea0e ed32 | 15 f360 (0) f361 (0) f410 (0) f5c4 (0)\n003 4 c3a1 ca03 cdcd cfbb | 9 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n004 3 db08 dfae dc97 | 3 db08 (0) dfae (0) dc97 (0)\n============ DEPTH: 5 ==========================================\n005 2 d224 d0f3 | 2 d224 (0) d0f3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","private_key":"7d3834d39e62cf1e8548683eec363e19d020ce2f4971d98743bc58ffe1c91611","name":"node_d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","services":["bzz","pss"],"enable_msg_events":true,"port":42483},"up":true}},{"node":{"info":{"id":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","name":"node_e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","enode":"enode://c7e6fc03f7b10c7235bdd7ae9fd28ea2f96d514a90ddb54312b6f45c15873e47227b36c1c4f9d29e28b16527dc7bf154702a6ec4352a8d7eab15b325c2aba1b6@127.0.0.1:0","enr":"0xf88fb84024831e3097e6342c87a066a5ae145abdf8366f26e351a7a8d3f22d5e5802c8e963e13a456db9f0b08665eb9108b71d23537dd415c9dde62127fc947b89158b630183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c7e6fc03f7b10c7235bdd7ae9fd28ea2f96d514a90ddb54312b6f45c15873e47","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4LHE61tbTfwiNE7mXLlxbOyzjcyACZeT8gZBiE6uSFQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e0b1c4\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0390 13bc 1be4 1929 | 65 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n001 3 83dc a2ba a320 | 33 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n002 8 c3a1 c181 cdcd cfbb | 15 c8e5 (0) cbc5 (0) ca03 (0) cdcd (0)\n003 3 f361 f5c4 f74e | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 5 ed32 edc8 ebca ea60 | 5 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n005 2 e77f e55d | 2 e77f (0) e55d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 e16b | 1 e16b (0)\n008 0 | 0\n009 1 e0ea | 1 e0ea (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","private_key":"42fe12311467a8adbbfb209a06319e950148da4433177621af050a2a0b74e82c","name":"node_e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","services":["bzz","pss"],"enable_msg_events":true,"port":45685},"up":true}},{"node":{"info":{"id":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","name":"node_5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","enode":"enode://019ddc346857752f742b93cabbfc6b3c47c958ee5ad67be36c3c2f8e5acfa786f70344ce1d9b34c190ce414ca4af09b467ca8fdde6fcf4c8b09696c76c45b520@127.0.0.1:0","enr":"0xf88fb840153a0d6eeb5dc102fd9f75d0b8c51c7f01252e5cf45d6a4c5f3b65d4bd90a4d17affa644ffc8fca2d95c9ed93c70e093431ce452acb11d876cd55ca5dd802dba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102019ddc346857752f742b93cabbfc6b3c47c958ee5ad67be36c3c2f8e5acfa786","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WryW9Pp4gS22+3EP1CTdR0FF9+XQC0ztxTc7TFL0LPU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5abc96\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 e0ea e0b1 89c8 | 63 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n001 3 372d 39db 38ab | 27 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n002 12 78cb 734e 7355 772e | 23 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n003 4 4b24 4a18 48b6 41b9 | 8 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n004 4 558e 5776 517a 539d | 4 517a (0) 539d (0) 5776 (0) 558e (0)\n============ DEPTH: 5 ==========================================\n005 1 5d60 | 1 5d60 (0)\n006 0 | 0\n007 0 | 0\n008 1 5a01 | 1 5a01 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","private_key":"4e526a63f698dcdb8bb4a8c1a4a54fb1c3ba10476f285012af7137b504bdc215","name":"node_5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","services":["bzz","pss"],"enable_msg_events":true,"port":34327},"up":true}},{"node":{"info":{"id":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","name":"node_89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","enode":"enode://577ed924a2a73d22ee8998f00a82acbe7ce1e410878d5daa4d988ead6ad2cf4f385217ff0580f3dc311e0d8f79040dcb3e7f2b765f5e89fab86703f153374ace@127.0.0.1:0","enr":"0xf88fb8400137468cd822d505da53b9784f8a1606bb49e810dc372191a35921c562eb016d27a5cfcb4511315e38eefce0dfd07c703aa57dadbd6c14d29c0a504607c089900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102577ed924a2a73d22ee8998f00a82acbe7ce1e410878d5daa4d988ead6ad2cf4f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iciD1qhUcr2jKGZ+P9gFxwh2vFgspnY6uXrmNrF3K+Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 89c883\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 018a 026d 39db 3cb1 | 65 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n001 7 ea0e ea60 f74e f5c4 | 30 f360 (0) f361 (0) f410 (0) f5c4 (0)\n002 5 ad0d a320 a75a b8e1 | 17 b92a (0) b841 (0) b8e1 (0) b16d (0)\n003 3 91eb 9626 9e02 | 8 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n004 2 82f0 83dc | 3 86ca (0) 82f0 (0) 83dc (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 8be4 8b76 | 2 8be4 (0) 8b76 (0)\n007 0 | 0\n008 1 895b | 1 895b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","private_key":"17570e86447615758ea636804ecb65f791a12a421e904e723fbec9ab52e466f6","name":"node_89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","services":["bzz","pss"],"enable_msg_events":true,"port":42067},"up":true}},{"node":{"info":{"id":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","name":"node_dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","enode":"enode://0563ccfaae48ee129eb27f5c779f0c8349a22919de381a54c9a4f704070532a72d2f1926c6767afba2f9b4de908bf854498f5800374956e8c66ea2346df662c1@127.0.0.1:0","enr":"0xf88fb840fba3f24508ab6de5f8772b5dd896fc9b869cb17c48af0bc23b3c14145ef2aa0f76f8eb05025bcc10df608aa7979bda2203c12a4b429d308ce15aa4afabe8f1c50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030563ccfaae48ee129eb27f5c779f0c8349a22919de381a54c9a4f704070532a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3JfBoAGbSCoEi40VlB3+TDwaNEPZste0BGNwvISn5W8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dc97c1\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 6728 667e 6d60 6c02 | 65 5d60 (0) 5abc (0) 5a01 (0) 517a (0)\n001 4 a75a b92a 895b 89c8 | 33 b92a (0) b841 (0) b8e1 (0) b381 (0)\n002 3 f74e f361 e0ea | 15 f360 (0) f361 (0) f410 (0) f5c4 (0)\n003 4 c181 c3a1 cdcd cfbb | 9 c8e5 (0) ca03 (0) cbc5 (0) cdcd (0)\n004 3 d224 d0f3 d6ff | 3 d224 (0) d0f3 (0) d6ff (0)\n============ DEPTH: 5 ==========================================\n005 1 db08 | 1 db08 (0)\n006 1 dfae | 1 dfae (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","private_key":"9599415f62de56a6422afea8e7ebbc2b460cd56cc0f7b1fc73e96b6c8857e728","name":"node_dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","services":["bzz","pss"],"enable_msg_events":true,"port":41683},"up":true}},{"node":{"info":{"id":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","name":"node_e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","enode":"enode://bfb412d3f9e09403659416f8864d6a739bc396ae53bc9e2f6cb30239814538e65dbbf0339670dac268002695d39b8eb59b6c3a51420aa827ee75dce465a22669@127.0.0.1:0","enr":"0xf88fb8402b1a38e980290999c2f075d625bccda4a9614d6097ae9733957386a11a9be0804a2f004dc1383d9b4a35162a400684675d560cd72ec18d107d08e4d5cad01f490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bfb412d3f9e09403659416f8864d6a739bc396ae53bc9e2f6cb30239814538e6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4OpXXQ4u+ii8UfSdHiwkGWoZbaOzGW86Wial4xCAmvU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e0ea57\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 7dc5 6ecb 6728 517a | 65 5d60 (0) 5abc (0) 5a01 (0) 517a (0)\n001 5 957d 8cf9 83dc ae67 | 33 b92a (0) b841 (0) b8e1 (0) b381 (0)\n002 6 cdcd cfbb c181 db08 | 15 c8e5 (0) cbc5 (0) ca03 (0) cdcd (0)\n003 2 f361 f74e | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 4 ed32 edc8 ea60 ea0e | 5 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n005 2 e77f e55d | 2 e77f (0) e55d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 e16b | 1 e16b (0)\n008 0 | 0\n009 1 e0b1 | 1 e0b1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","private_key":"50f25d60500eb49b33f8855dbff5167ed90ae947f01800ca6e143886d4e2129e","name":"node_e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","services":["bzz","pss"],"enable_msg_events":true,"port":44889},"up":true}},{"node":{"info":{"id":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","name":"node_021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","enode":"enode://abd8116f367c9d2e1d15debf2ceadc5df783db3523482238cc8b10c5a61df20eee4a6ca29b99d2e09094fec869b212002aa3e56708b4d7c535f0edb00f6c6abf@127.0.0.1:0","enr":"0xf88fb840c3192e46a155becce8c64f9a7cce7f0bf743a33baf0b74dbde83751433990fe5215de0e3947206cfab59584d2e93f3075825686d26ddd6b4a7cca931dbec15f80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103abd8116f367c9d2e1d15debf2ceadc5df783db3523482238cc8b10c5a61df20e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AhgRpnV73N0voPtoQB3+AJ1ajhKZWM0wT7Qs9R3F0dM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 021811\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 9626 b70e b486 b16d | 63 b92a (0) b841 (0) b8e1 (0) b2b9 (0)\n001 4 4b24 558e 757a 6e5c | 38 7cf4 (0) 7dc5 (0) 7fbc (0) 7f87 (0)\n002 7 2a22 26d1 2434 213b | 12 213b (0) 26d1 (0) 2459 (0) 2434 (0)\n003 4 1be4 1929 13bc 109e | 4 1be4 (0) 1929 (0) 13bc (0) 109e (0)\n004 3 0ff6 0bcf 0ab9 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 3 06b9 0427 0506 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n007 1 0390 | 1 0390 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 027f 026d | 2 027f (0) 026d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","private_key":"f24fd4a4e7b3587f483542c46fe764f2846e84158cfc2282188fac740cb9939f","name":"node_021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","services":["bzz","pss"],"enable_msg_events":true,"port":38993},"up":true}},{"node":{"info":{"id":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","name":"node_109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","enode":"enode://f4df36e91a014ba253c93cc4a738dbeafed71095b9ad41b0e62616bad9b4f4301acd54ced99e80858045d79da80ac42f6d0d594ce127b880a5838fccc7f93da7@127.0.0.1:0","enr":"0xf88fb840a626a87192ca066e77595198c84a535d734661e1db5553a18cb8b62fbb77b6797af9aad58e1149921f53ec0a226a806dd29f5fa2c3f1f4c0309113f09ad4380c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f4df36e91a014ba253c93cc4a738dbeafed71095b9ad41b0e62616bad9b4f430","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EJ7xfIkBBL/FpIl9UmoK+qjJkcnSE2FgMvMFjQ/rfwA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 109ef1\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 91eb 895b a2ba a085 | 63 b92a (0) b841 (0) b8e1 (0) b2b9 (0)\n001 4 4b24 757a 772e 6e5c | 38 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n002 3 2a22 213b 38ab | 12 286a (0) 2a22 (0) 26d1 (0) 2459 (0)\n003 9 0bcf 0ab9 0506 0427 | 11 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n============ DEPTH: 4 ==========================================\n004 2 1929 1be4 | 2 1be4 (0) 1929 (0)\n005 0 | 0\n006 1 13bc | 1 13bc (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","private_key":"e9e24085b5783d5c7c9c652c4de2009dc89e215530c57e92cc3321481e56a5b4","name":"node_109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","services":["bzz","pss"],"enable_msg_events":true,"port":43049},"up":true}},{"node":{"info":{"id":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","name":"node_ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","enode":"enode://627fb4b3d57ec52bd28b0461d1ad5bd965015b0356be2d0727f9b548907a213a877ae14589528acf227113a87fff774a08eb7ca18e9860c62fc2f08a92941b8b@127.0.0.1:0","enr":"0xf88fb840626a2b83b4c2a20b607631df4b27b8945d07fd0ef4ccfce7f4ad41f83fd72d7931a5938937c2d2c8c99a377c59a782b69f9b5c99fd60f7e2d7d1727fb003eccc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103627fb4b3d57ec52bd28b0461d1ad5bd965015b0356be2d0727f9b548907a213a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7TLXTZvgZJ3h6ya5kVE3/kbsiQxlbJa+Uulmq24u0mA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed32d7\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6ecb 7dc5 757a 772e | 65 7fbc (0) 7f87 (0) 7cf4 (0) 7dc5 (0)\n001 3 957d 8cf9 8b76 | 33 b16d (0) b2b9 (0) b381 (0) b486 (0)\n002 4 c3a1 cdcd dfae d6ff | 15 c181 (0) c3a1 (0) c8e5 (0) cbc5 (0)\n003 3 f5c4 f74e f361 | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 5 e55d e77f e16b e0ea | 5 e77f (0) e55d (0) e16b (0) e0ea (0)\n============ DEPTH: 5 ==========================================\n005 3 ebca ea60 ea0e | 3 ebca (0) ea60 (0) ea0e (0)\n006 0 | 0\n007 0 | 0\n008 1 edc8 | 1 edc8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","private_key":"e60060a92fe8c46ac4f8a127abbd9c4d9e36cd927cfe0313a8fc445e8394b94b","name":"node_ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","services":["bzz","pss"],"enable_msg_events":true,"port":42957},"up":true}},{"node":{"info":{"id":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","name":"node_8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","enode":"enode://5552d93b800376a18cd819cd566ae575dedbe4b312bf6130b1c3c5f61d63b0b88680f68f25fb55b72c4fda4a23b178ee3c08e471cbe510bcf6c5c1de2f29cf24@127.0.0.1:0","enr":"0xf88fb840a9d59867b862012cf06f08dc04de0e6cac8ccec89f0305e926bf4a6cb8efcb3a74c771665a71443904b3e60d17b1ee22a23d29ba0a06925d1587f8bd8153e23d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025552d93b800376a18cd819cd566ae575dedbe4b312bf6130b1c3c5f61d63b0b8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"i3YZTxKTCDJMfQBmUw4CysJBDuC6lSgi8OyGbhJGHkQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8b7619\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 018a 39db 2434 213b | 65 7cf4 (0) 7dc5 (0) 7fbc (0) 7f87 (0)\n001 6 c181 cdcd dfae f361 | 30 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n002 10 b70e b486 b16d b8e1 | 17 b2b9 (0) b381 (0) b16d (0) b486 (0)\n003 2 9626 9e02 | 8 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n004 3 86ca 82f0 83dc | 3 86ca (0) 82f0 (0) 83dc (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 895b 89c8 | 2 895b (0) 89c8 (0)\n007 0 | 0\n008 1 8be4 | 1 8be4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","private_key":"e322c8c203344ce73e706dae3f4f6f7e500bb780f43fb03a222aacf8adaef519","name":"node_8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","services":["bzz","pss"],"enable_msg_events":true,"port":44125},"up":true}},{"node":{"info":{"id":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","name":"node_f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","enode":"enode://553cba5427fc16ce1f7fcf4b551e79c45f56c2fe6425442401a0d11eeb052ee63de2ce6c5458a79c564e3744bad912c50520c1369f52e0767e09ed40e9993ff8@127.0.0.1:0","enr":"0xf88fb8400139f5b8abcf514eef980efc398f34b1a0d66124a43a20c323ad1fc720ca5c40626fc02a811970e8641b50a20d6b4aca333b145cddf67c6614ee2cfb65b869fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102553cba5427fc16ce1f7fcf4b551e79c45f56c2fe6425442401a0d11eeb052ee6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"907N4Luqe2Uh+yBbWrnqY3kJJ39uHuHTSQ9c0B0PchY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f74ecd\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1be4 772e 5d60 558e | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 4 a320 83dc 89c8 8b76 | 33 b2b9 (0) b381 (0) b16d (0) b486 (0)\n002 8 db08 dfae dc97 d6ff | 15 c181 (0) c3a1 (0) c8e5 (0) cbc5 (0)\n003 10 edc8 ed32 ebca ea0e | 10 e77f (0) e55d (0) e16b (0) e0ea (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 f361 f360 | 2 f360 (0) f361 (0)\n006 2 f5c4 f410 | 2 f410 (0) f5c4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","private_key":"3e6b050dabdb0eb2468be45fc539a79410db1729eeba39afff4688885dc9b8ef","name":"node_f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","services":["bzz","pss"],"enable_msg_events":true,"port":42027},"up":true}},{"node":{"info":{"id":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","name":"node_a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","enode":"enode://4fd8fe083cbe1905328dfcdefb64a314acbfdec10223d8d960f4b9168ef65580fd762356abcbf5cf995c88f00464d41163bf422cd1d80a6e9f2c6dbea37e12dd@127.0.0.1:0","enr":"0xf88fb8406f2350c3165bd627d97c3623d2fb90d4ded4cd6dd1aa554d6c4c4e017a729e743f44b2ec69aaed61a87bdebb7e1c67143b222f796b4b902b3b820dca88419b690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034fd8fe083cbe1905328dfcdefb64a314acbfdec10223d8d960f4b9168ef65580","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oyBcHE+bcoFPDbaOiI48fviPJ8aB7Q1zHd5fCZn5LMw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a3205c\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6e5c 645b | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 4 e77f e0b1 ea0e f74e | 30 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n002 8 8b76 89c8 895b 8cf9 | 16 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n003 4 b8e1 b16d b70e b486 | 8 b381 (0) b2b9 (0) b16d (0) b486 (0)\n004 3 ad0d aebd ae67 | 4 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n005 2 a7a6 a75a | 2 a7a6 (0) a75a (0)\n============ DEPTH: 6 ==========================================\n006 1 a085 | 1 a085 (0)\n007 1 a2ba | 1 a2ba (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","private_key":"ab56cc2e159cf59b59a2b8abae5e8c927fd16d7844425b0c048bdf0c1c03f561","name":"node_a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","services":["bzz","pss"],"enable_msg_events":true,"port":38749},"up":true}},{"node":{"info":{"id":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","name":"node_ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","enode":"enode://27bd511098d142435c42d80c87870c55f35ecba4851735487a8148f63556be851405b124502231ff210e6674abc11534f6c8d43d28611d0564497cff8b0bbdb2@127.0.0.1:0","enr":"0xf88fb840d7c884944fcfd5f801f1a40862426a14631c18017bf1e8679ce01d826fb6b98e2a2a8e3e2ce8c35859ef1bdf9e6bb1ddc6717e5bd286dc5436a440b6066608200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10227bd511098d142435c42d80c87870c55f35ecba4851735487a8148f63556be85","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6g4d1B/gQrCfJzyY8CEolJz1Vh0g3ASz1COWHv7VIyc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ea0e1d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 5d60 6ecb 78cb 7f87 | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 4 957d 89c8 8cf9 a320 | 33 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n002 5 db08 dfae d6ff c3a1 | 15 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n003 3 f5c4 f74e f361 | 5 f360 (0) f361 (0) f410 (0) f5c4 (0)\n004 5 e55d e77f e16b e0b1 | 5 e55d (0) e77f (0) e16b (0) e0ea (0)\n005 2 ed32 edc8 | 2 edc8 (0) ed32 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ebca | 1 ebca (0)\n008 0 | 0\n009 1 ea60 | 1 ea60 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","private_key":"7a2a65840183134657aedc7f4311c4428e3b8341628df92550577eb8c5f61b1c","name":"node_ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","services":["bzz","pss"],"enable_msg_events":true,"port":43851},"up":true}},{"node":{"info":{"id":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","name":"node_2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","enode":"enode://634c327216fdc24e18f6724944cc2cdd81cd854a381e49a422c900ddb07bdbd3355b7de6240c4c3916088e39de937b6cc42f11fc8790d22d7721d0230a62273d@127.0.0.1:0","enr":"0xf88fb8403c29ef7a8afe4804b361f57edb95e1148ca1043464b23d9b238123129fcac29171eaf9a0a70e770cfe8185a3fb3fd61e5c5878f5b71c12487b79da7ab75e0e8d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103634c327216fdc24e18f6724944cc2cdd81cd854a381e49a422c900ddb07bdbd3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JDTGPn8ouD5/7t5/5o6pm5ifhTT2TWOwRnM+L0dFOPU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2434c6\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 a085 b8e1 9626 9e02 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 11 6c82 7639 7b92 78cb | 38 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n002 8 1be4 0ff6 0ab9 0218 | 15 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n003 4 372d 3cb1 38ab 39db | 6 372d (0) 3e56 (0) 3ee4 (0) 3cb1 (0)\n004 2 2a22 286a | 2 286a (0) 2a22 (0)\n005 1 213b | 1 213b (0)\n============ DEPTH: 6 ==========================================\n006 1 26d1 | 1 26d1 (0)\n007 0 | 0\n008 0 | 0\n009 1 2459 | 1 2459 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","private_key":"ea68ee64cd7bec8f6c5c0c14a4f6d55bc6c371c676c88a1657b73135e8183c29","name":"node_2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","services":["bzz","pss"],"enable_msg_events":true,"port":33513},"up":true}},{"node":{"info":{"id":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","name":"node_4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","enode":"enode://2e826c3eb8d5f9e300988ffa5fd5445a26ff486a0170c8b0d79fa439b3801c1851e45d69941f3bea632b20a7fcb3f1a53d0a504a3e886756ca25f61547eb71a3@127.0.0.1:0","enr":"0xf88fb8407eb028f17f3be43ac26f9c531d0ebeb3d8ed2e0920745e17760e6af36431612a5f81dc55334372f469f36342623f7ccd5b59f0b4e084f7aecbb474fe5ac68dc00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032e826c3eb8d5f9e300988ffa5fd5445a26ff486a0170c8b0d79fa439b3801c18","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ShgR3Z/r3hgBpgStgd6EotFTZtC1wzDzDzOY2g0QeCQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a1811\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8b76 dc97 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 4 018a 026d 372d 2434 | 27 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n002 7 772e 757a 7cf4 7f87 | 23 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n003 7 539d 517a 5776 558e | 7 5d60 (0) 5abc (0) 5a01 (0) 539d (0)\n004 4 4167 419a 41b9 47c3 | 4 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n005 1 4cd0 | 1 4cd0 (0)\n============ DEPTH: 6 ==========================================\n006 1 48b6 | 1 48b6 (0)\n007 1 4b24 | 1 4b24 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","private_key":"29e672b50332ffce13e3c1e62ab1c36c98284e8526e6c2010adc9fc40aa4e5a8","name":"node_4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","services":["bzz","pss"],"enable_msg_events":true,"port":45219},"up":true}},{"node":{"info":{"id":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","name":"node_026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","enode":"enode://1bdd224735ef8e9603bb3af3eb143963367ef184ba9c3a6266ffd8c7ea1c9825b0a565da1820ae283c905d35ad9c00c27d94edea8d308d28bb61b153a5c23831@127.0.0.1:0","enr":"0xf88fb840f1a2ef34af51d5a668030bf51780e698f351d5619a059fc5cf9c66b59b570ebc5e4bc9b8580fcb8e3f6196fc3a39e83a9220bf1726189b8e347b96e2818be9cf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031bdd224735ef8e9603bb3af3eb143963367ef184ba9c3a6266ffd8c7ea1c9825","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Am0uQbgtUG2mhaMMznzFdy9sHhZ7fVV+BTH7m3ndT/I=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 026d2e\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 83dc 8cf9 89c8 895b | 63 91eb (0) 92a1 (0) 957d (0) 9626 (0)\n001 8 757a 78cb 7cf4 7f87 | 38 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n002 4 3cb1 2a22 2434 213b | 12 372d (0) 3e56 (0) 3ee4 (0) 3cb1 (0)\n003 4 109e 13bc 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 3 0ff6 0bcf 0ab9 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 3 06b9 0506 0427 | 3 06b9 (0) 0427 (0) 0506 (0)\n006 1 018a | 1 018a (0)\n007 1 0390 | 1 0390 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 0218 | 1 0218 (0)\n010 0 | 0\n011 1 027f | 1 027f (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","private_key":"66e31ccc21cf370ceb1e2bceac1499aeab637ee09f233711ef38ba3a8ba0e258","name":"node_026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","services":["bzz","pss"],"enable_msg_events":true,"port":45529},"up":true}},{"node":{"info":{"id":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","name":"node_dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","enode":"enode://b854fc358c548e135da5fc791782f459cceb3528a48cd2ebb3c35942f92414b98eea4f354c64e8292a610ee59517399f6a9ec07a68e65dce31bb82f1df156b0d@127.0.0.1:0","enr":"0xf88fb840111fd0a9953783fdda698a6547ff1c8670f1b423fe5bcb157c98582d193a643c42c531c98d7b5114d96b1547a7ccc63a03fef119855f7697e1e124a3dbdc6ae90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b854fc358c548e135da5fc791782f459cceb3528a48cd2ebb3c35942f92414b9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"367ryOKcao+FGxK4DPQlZ80qQ+Ndl3MFo8EOUb9BFwo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dfaeeb\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6728 667e 6c02 6d60 | 65 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n001 5 a75a b16d b8e1 895b | 33 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n002 10 ed32 ea60 ea0e e16b | 15 e55d (0) e77f (0) e16b (0) e0b1 (0)\n003 5 c181 c3a1 ca03 cbc5 | 9 c3a1 (0) c181 (0) c8e5 (0) ca03 (0)\n004 3 d0f3 d224 d6ff | 3 d224 (0) d0f3 (0) d6ff (0)\n============ DEPTH: 5 ==========================================\n005 1 db08 | 1 db08 (0)\n006 1 dc97 | 1 dc97 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","private_key":"f2ca8fe02aa5e39a2995330d19104fe94adc0b9bb890ce50c15ac8987c368a64","name":"node_dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","services":["bzz","pss"],"enable_msg_events":true,"port":46381},"up":true}},{"node":{"info":{"id":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","name":"node_558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","enode":"enode://670a610cec9046cca8a6097ddf0772fcc8b207ce9c573c71356934060ecf3e756298aac965d239846a16ab795b8f20f2d33d1379d6b4da7b0785eac9cb0e706f@127.0.0.1:0","enr":"0xf88fb84039cbdcd9c4550e92047787028d8613d1d69e444a7a231d53694347cc8a8cf913329ac3d692c8320f28ceb7867eb72c22b4b490db3b9c28951b511d6b72692e410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103670a610cec9046cca8a6097ddf0772fcc8b207ce9c573c71356934060ecf3e75","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VY6wIXRL4ZODvprJG5934HR54OslV2vTKjr6qUwjEXg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 558eb0\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 8b76 ae67 f74e dc97 | 63 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n001 5 0218 39db 372d 2434 | 27 3cb1 (0) 3e56 (0) 3ee4 (0) 38ab (0)\n002 6 6c02 6ecb 645b 78cb | 23 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n003 5 41b9 47c3 48b6 4b24 | 8 4167 (0) 419a (0) 41b9 (0) 47c3 (0)\n004 3 5abc 5a01 5d60 | 3 5d60 (0) 5abc (0) 5a01 (0)\n============ DEPTH: 5 ==========================================\n005 2 517a 539d | 2 539d (0) 517a (0)\n006 1 5776 | 1 5776 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","private_key":"5de3f27f03f0565eb69405082120c753d823e962ee08c8e89dfca48ef957830c","name":"node_558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","services":["bzz","pss"],"enable_msg_events":true,"port":45963},"up":true}},{"node":{"info":{"id":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","name":"node_ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","enode":"enode://d5ac1961e227bd9f303a8273244adeaf02add8f9f4007c2f9d9c849ff3b9bbd9950d263905ac606d6dc5c4dd723e991ee27c80acf9584e36de09197b4db5ace5@127.0.0.1:0","enr":"0xf88fb8408715cddf6466f5cf540b8e6c8689a5881979f2696a0160c48f2274fb2ce56db820361055605b93b01a3f4324962a745010a973c17fab26ee763a8ada01abca260183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d5ac1961e227bd9f303a8273244adeaf02add8f9f4007c2f9d9c849ff3b9bbd9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rmf65JkNphyokiHFsWdcmSurtNcVtZk55HvRSRs78fQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ae67fa\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 39db 38ab 3cb1 3ee4 | 65 3e56 (0) 3ee4 (0) 3cb1 (0) 38ab (0)\n001 4 e55d e77f e0ea f361 | 30 c181 (0) c3a1 (0) c8e5 (0) cbc5 (0)\n002 3 9d3c 83dc 8b76 | 16 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n003 4 b8e1 b16d b486 b70e | 8 b2b9 (0) b381 (0) b16d (0) b486 (0)\n004 5 a7a6 a75a a085 a320 | 5 a7a6 (0) a75a (0) a085 (0) a2ba (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 ad0d | 1 ad0d (0)\n007 1 afa3 | 1 afa3 (0)\n008 1 aebd | 1 aebd (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","private_key":"20deaabb607e4c2f3c7df5c3c5e310bf29e1fdadae1b52f9d107d40cfb6b264c","name":"node_ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","services":["bzz","pss"],"enable_msg_events":true,"port":33595},"up":true}},{"node":{"info":{"id":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","name":"node_f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","enode":"enode://49397d0356ecc13c5bc27b3b5630f3bbab8e7c1ca7d2d4b5e074ca3c8b8dcfaf2fe2945ba899807de702c7eb3c40a572c9771d6e3211cc0b0d333e96c7990987@127.0.0.1:0","enr":"0xf88fb840a198329ff362f39bc5de95d22e342a70da5fadfb466b8eed4eb1b9f57dd6dc454815ce25795082edc3e776e68b01dc3a5d782775450daba93f28d4b4509f3dab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10349397d0356ecc13c5bc27b3b5630f3bbab8e7c1ca7d2d4b5e074ca3c8b8dcfaf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"82Eg/yULnnFk6WAhR5MyBU9n3mXNL+W240vFHQ/k0pw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f36120\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5d60 517a 1be4 0506 | 65 5776 (0) 558e (0) 539d (0) 517a (0)\n001 10 9e02 9626 8b76 89c8 | 33 9a92 (0) 9d3c (0) 9ee7 (0) 9e02 (0)\n002 5 ce99 c181 db08 dc97 | 15 d224 (0) d0f3 (0) d6ff (0) db08 (0)\n003 10 edc8 ed32 ebca ea0e | 10 e77f (0) e55d (0) e16b (0) e0b1 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 3 f74e f410 f5c4 | 3 f410 (0) f5c4 (0) f74e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 f360 | 1 f360 (0)\n========================================================================="}},"config":{"id":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","private_key":"71622f176e027738b9284c5ca316f6736d1af20a0c5b2874bc826a6493d3e403","name":"node_f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","services":["bzz","pss"],"enable_msg_events":true,"port":40147},"up":true}},{"node":{"info":{"id":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","name":"node_0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","enode":"enode://c7d55b42435ae9eebddd09b4960f97586b686903470dd4b908acfc157b42c2d6dfc9b4a54f29dfeb3fb84963511229a1b277bac428b07daf80036a03c9075180@127.0.0.1:0","enr":"0xf88fb84017229330778245921bef57e2428e7cec260ff8ddf2ca65fd32d601b6deb58561107253d30829606a2a6848f578bc6a7a38854ff60ef6c34af5b9b791d3c0e5e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c7d55b42435ae9eebddd09b4960f97586b686903470dd4b908acfc157b42c2d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BQbpSXSLYtodNrZj331qfnYCf3LO1dUvdGd/sx1+FQU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0506e9\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 9626 a7a6 db08 c181 | 63 91eb (0) 92a1 (0) 957d (0) 9626 (0)\n001 3 7b92 5d60 517a | 38 558e (0) 5776 (0) 539d (0) 517a (0)\n002 8 372d 39db 38ab 3cb1 | 12 3e56 (0) 3ee4 (0) 3cb1 (0) 38ab (0)\n003 4 13bc 109e 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 3 0ab9 0bcf 0ff6 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 5 018a 0390 026d 027f | 5 0390 (0) 0218 (0) 027f (0) 026d (0)\n============ DEPTH: 6 ==========================================\n006 1 06b9 | 1 06b9 (0)\n007 1 0427 | 1 0427 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","private_key":"d54090bceb0325e7d681953c0c9b885b52b9fde17c87981f51927d5458bdec1f","name":"node_0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","services":["bzz","pss"],"enable_msg_events":true,"port":42705},"up":true}},{"node":{"info":{"id":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","name":"node_cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","enode":"enode://15721bb131c5000be7e9d400500ccf12cd6a04edf750c1fc78e225c6728baa8fb5c18e2e68c16d05b26f9642d009b6ca670eb011fce286318a4281ec930da572@127.0.0.1:0","enr":"0xf88fb840c585ecd30f00f1f4839d519a833ff3434caa90c288ae094854454e6f9b846c84292aa12c66d3327f9e57934efb3cd562b9c14ba7c2c39303c39271dc148bab390183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10215721bb131c5000be7e9d400500ccf12cd6a04edf750c1fc78e225c6728baa8f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zc0WVyH2hR82H60LO6iMiHC+mtbWuMvOzHyJ4QaNl5o=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cdcd16\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6d60 645b 0506 | 65 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n001 4 a75a b16d 8b76 83dc | 33 9a92 (0) 9d3c (0) 9e02 (0) 9ee7 (0)\n002 6 f74e e0ea e0b1 edc8 | 15 e55d (0) e77f (0) e16b (0) e0b1 (0)\n003 5 d224 d6ff dc97 dfae | 6 d224 (0) d0f3 (0) d6ff (0) db08 (0)\n004 2 c181 c3a1 | 2 c3a1 (0) c181 (0)\n005 3 c8e5 ca03 cbc5 | 3 c8e5 (0) ca03 (0) cbc5 (0)\n============ DEPTH: 6 ==========================================\n006 3 cfbb ce99 cec3 | 3 cfbb (0) cec3 (0) ce99 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","private_key":"dc9c6faeb1b0ed2241977e5e119fb047b527baa72b57faf6a490bfa2463702b1","name":"node_cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","services":["bzz","pss"],"enable_msg_events":true,"port":44531},"up":true}},{"node":{"info":{"id":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","name":"node_645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","enode":"enode://c5df28a427ebcae9a135bf8f4e05d5507d48467c55937ae432e5453a53516d1d67d16f232b7ec71929f992ebb8d25fa8442c2e4ec12b9b9c2e90365d0ec58d62@127.0.0.1:0","enr":"0xf88fb8407d96a32e90f5234bc9b785b90e5ecbbc3c002e4307bfc19f4141f794943d59ac256d05f75f0afd515d598bdd6a82b8db9167d584b304303c4db1bc563447b0f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c5df28a427ebcae9a135bf8f4e05d5507d48467c55937ae432e5453a53516d1d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZFtOazb8GShyX2J67tJ49GxafWsP/3zP9VoEaNR7I+g=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 645b4e\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8b76 a320 d6ff cdcd | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 2 1be4 213b | 27 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n002 9 5d60 5abc 5a01 5776 | 15 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n003 6 734e 757a 772e 7cf4 | 12 7fbc (0) 7f87 (0) 7dc5 (0) 7cf4 (0)\n004 3 6c82 6d60 6e5c | 6 6982 (0) 6c82 (0) 6c02 (0) 6d60 (0)\n005 1 6210 | 1 6210 (0)\n============ DEPTH: 6 ==========================================\n006 3 667e 6742 6728 | 3 667e (0) 6742 (0) 6728 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","private_key":"04fc1c10d7b313a061609b0eed8efdc7b1d9fd9169d7d7d5381d5ef4a53086f9","name":"node_645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","services":["bzz","pss"],"enable_msg_events":true,"port":35261},"up":true}},{"node":{"info":{"id":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","name":"node_213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","enode":"enode://761923555d54e992f473a9407939c25446dcfdda08081916f298c2fb2c8380ed0cf602deba79e7ff4ebd2c17f9cece98ae0e15539870f66a634b733171e0ec27@127.0.0.1:0","enr":"0xf88fb84009b10445736e612ea99db7cb50e94305fdfee64d061a1bb4fb2cf291ff6ecffc7311805dc59471a2997aa537f1c1d964a2d26f94a8433a498003cd0ed5bace8b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103761923555d54e992f473a9407939c25446dcfdda08081916f298c2fb2c8380ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ITv2544CpXWFkIx1bwllKXFSw8QAoO1MQHpBHh7FlC0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 213bf6\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ea60 cec3 b16d 89c8 | 63 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n001 4 41b9 5776 558e 645b | 38 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n002 7 1be4 109e 0506 0427 | 15 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n003 4 372d 3cb1 38ab 39db | 6 3ee4 (0) 3e56 (0) 3cb1 (0) 38ab (0)\n004 2 286a 2a22 | 2 2a22 (0) 286a (0)\n============ DEPTH: 5 ==========================================\n005 3 26d1 2459 2434 | 3 26d1 (0) 2459 (0) 2434 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","private_key":"bb9e629d827643ea4b3d2c1f6c8a26cc16d191cec7709cdbdbf10fcfa47361b6","name":"node_213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","services":["bzz","pss"],"enable_msg_events":true,"port":33711},"up":true}},{"node":{"info":{"id":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","name":"node_018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","enode":"enode://e176b178b7c28353b25e6ae0584c3cd889c856b2bffd5c41cfb6b013ef2ebf3ee736f96dc0ebbb82bb3ebb2fefd70e8465cc77fe5bda8ab3068748044122bae4@127.0.0.1:0","enr":"0xf88fb8402a03da3911096a8fd7d223cc3dbf67101905e23b5b0c57af60f84593af3ac73e58f9d55a0d7ff7284740335e16e4305a45484856e16b8428743a7862d89b2f4d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e176b178b7c28353b25e6ae0584c3cd889c856b2bffd5c41cfb6b013ef2ebf3e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AYrcYT941uyHYnT4ISUf0EnrNlFkbNaeJ+/iEf6I2TY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 018adc\npopulation: 42 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 83dc 8cf9 89c8 895b | 63 957d (0) 9626 (0) 92a1 (0) 91eb (0)\n001 11 6c82 7639 7b92 7f87 | 38 734e (0) 7355 (0) 73b8 (0) 757a (0)\n002 3 3cb1 2a22 213b | 12 372d (0) 3e56 (0) 3ee4 (0) 3cb1 (0)\n003 4 109e 13bc 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 3 0ff6 0bcf 0ab9 | 3 0ff6 (0) 0bcf (0) 0ab9 (0)\n005 3 0506 0427 06b9 | 3 06b9 (0) 0427 (0) 0506 (0)\n============ DEPTH: 6 ==========================================\n006 4 0390 0218 027f 026d | 4 0390 (0) 0218 (0) 027f (0) 026d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","private_key":"b416fa1edc6a9481a2700407cc6b4cf1fe22447bcfced748269842bb79bd7be1","name":"node_018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","services":["bzz","pss"],"enable_msg_events":true,"port":38849},"up":true}},{"node":{"info":{"id":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","name":"node_edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","enode":"enode://bcb2c62558ac0c921253415556bb8521bb1f361278884453958a4ad1c6d2d761d9c4ea778253061cbb4a18a63c700bd5ec3b4e98d0ee89f4d68789a49a255c1a@127.0.0.1:0","enr":"0xf88fb840969cc1e8767d29e18d752912b07d4f68a5612caf1a3d7e4b924b03fb8f6f41da1725d64bd2cda2fabf6d5df9b87ac5e7873946a70a71fc605d58f5091e260e2c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bcb2c62558ac0c921253415556bb8521bb1f361278884453958a4ad1c6d2d761","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7ch5QVP7UXCF0nqDpLAOjDs38i0iQrhCyy+rZnZN6f4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: edc879\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 772e 5d60 5a01 1be4 | 65 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n001 3 a7a6 8cf9 83dc | 33 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n002 6 db08 ce99 cdcd ca03 | 15 c8e5 (0) ca03 (0) cbc5 (0) cfbb (0)\n003 3 f361 f360 f74e | 5 f5c4 (0) f410 (0) f74e (0) f360 (0)\n004 5 e16b e0b1 e0ea e55d | 5 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n============ DEPTH: 5 ==========================================\n005 3 ebca ea0e ea60 | 3 ebca (0) ea0e (0) ea60 (0)\n006 0 | 0\n007 0 | 0\n008 1 ed32 | 1 ed32 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","private_key":"cc8bb9100f25964f245e87e3f9bf408be100ad3a6d25298aaf5c1cec3309e03c","name":"node_edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","services":["bzz","pss"],"enable_msg_events":true,"port":46185},"up":true}},{"node":{"info":{"id":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","name":"node_5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","enode":"enode://be300889154a90ed33d9cf94b4ff711ba4b0fd2831f1c923f836379f54c554a322b2ffd67ad31b60921194ecbaf36fb2ae1fcaf4f83b5f8d09d04771a8bd6fde@127.0.0.1:0","enr":"0xf88fb84021eb12c9a4bca577771c8a61b0f665dda93925bca15665a86baca81ba20608c50975baba6dfbe9f8d7c81aed39d6fd56b12badc27b7e8cae94445a3bdf1cc94f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102be300889154a90ed33d9cf94b4ff711ba4b0fd2831f1c923f836379f54c554a3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WgGZP/e0vRL9slnpayagNtDPXUrpybUWvmS2Os7CRDo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a0199\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 dc97 e0ea edc8 b2b9 | 63 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n001 3 372d 2434 1be4 | 27 372d (0) 3cb1 (0) 3ee4 (0) 3e56 (0)\n002 6 757a 667e 645b 6c02 | 23 6210 (0) 6742 (0) 6728 (0) 667e (0)\n003 6 4167 41b9 419a 47c3 | 8 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n004 4 5776 558e 517a 539d | 4 558e (0) 5776 (0) 539d (0) 517a (0)\n============ DEPTH: 5 ==========================================\n005 1 5d60 | 1 5d60 (0)\n006 0 | 0\n007 0 | 0\n008 1 5abc | 1 5abc (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","private_key":"33fe2e9d121fb48e9e8ff1552b58a42c5f6d078b47223f83f9aecc781953dd8a","name":"node_5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","services":["bzz","pss"],"enable_msg_events":true,"port":39861},"up":true}},{"node":{"info":{"id":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","name":"node_b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","enode":"enode://3bd0292e58c0d4c952c3d2ff221410cb20c7ffac7848e2c5d351e32cbb578ddba8be42843dd17f2daa62079d6ce7886946d545db1845f9d31cf67dcd9e285c66@127.0.0.1:0","enr":"0xf88fb84069b7f53f8dde1ec32c5ac7119d271f0c63fdcfddf4ba67b3bd0f4a190049baee56b5a605f02fcefc86416f72d03d3a21fe91db5629d059a026b8a2ff9f3450ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023bd0292e58c0d4c952c3d2ff221410cb20c7ffac7848e2c5d351e32cbb578ddb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uOGoDZEhb9X4vD90E8r2it5/EkNU1E/nvRVaCJE0pwo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8e1a8\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2434 109e 0218 06b9 | 65 372d (0) 3cb1 (0) 3e56 (0) 3ee4 (0)\n001 5 e77f e55d db08 dfae | 30 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n002 7 83dc 89c8 895b 8b76 | 16 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n003 5 ae67 a320 a2ba a75a | 9 a085 (0) a2ba (0) a320 (0) a75a (0)\n004 5 b2b9 b381 b16d b70e | 5 b2b9 (0) b381 (0) b16d (0) b70e (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 b92a | 1 b92a (0)\n008 1 b841 | 1 b841 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","private_key":"dac5558d2b06b587645b8308b63c3c7a7d9d90ec36353760cb9c656ee41fe6d5","name":"node_b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","services":["bzz","pss"],"enable_msg_events":true,"port":33565},"up":true}},{"node":{"info":{"id":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","name":"node_b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","enode":"enode://f3da79d322438356e44f3b4036211300b07efa604f756ee0e60b1cfa5bd21fe2339ddf44138c970dd83db24f66b75d48e7b97492d75cae27dac3d1da16205d45@127.0.0.1:0","enr":"0xf88fb8403f9763127c7628679fe7fcaba9c97b58e29d4bab1758c67f241c249a66177230530b8da7ce97ec138bedc08717a7e96f184614db39decae489ad12dfe3d606090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f3da79d322438356e44f3b4036211300b07efa604f756ee0e60b1cfa5bd21fe2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tIbOMc6IDbOqoXoKwsLzVUtv5x+cBR7bVyl0NCr0rbk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b486ce\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 6c82 6c02 6e5c 7cf4 | 65 734e (0) 7355 (0) 73b8 (0) 757a (0)\n001 2 db08 c181 | 30 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n002 3 9ee7 8b76 83dc | 16 91eb (0) 92a1 (0) 957d (0) 9626 (0)\n003 4 a7a6 a320 afa3 ae67 | 9 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n004 3 b92a b841 b8e1 | 3 b92a (0) b841 (0) b8e1 (0)\n============ DEPTH: 5 ==========================================\n005 3 b2b9 b381 b16d | 3 b2b9 (0) b381 (0) b16d (0)\n006 1 b70e | 1 b70e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","private_key":"60109f1a20e5d694e88f021d4e588994aae7c2ecfca6a950149c53652f4a5b3a","name":"node_b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","services":["bzz","pss"],"enable_msg_events":true,"port":44351},"up":true}},{"node":{"info":{"id":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","name":"node_1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","enode":"enode://8375557348b05531d3d6a4b6f494f44e33c0a1862c0c63fce6ab3e8a389adb299f4fb14a74d2ef9160d2df04f362af2e9c7021f0cabc9bf4a116663b62dce076@127.0.0.1:0","enr":"0xf88fb8404ea89c730deaca09ae7f36423dd170ee83ef05e71559ce57692a4cb2a14e79a73f552356028fc016ecbee9961b2691884662145357a4c9db80d0d3156feda59c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028375557348b05531d3d6a4b6f494f44e33c0a1862c0c63fce6ab3e8a389adb29","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"G+Q0jsVnDNxPFk13sTVueRC20b5Km3IOVJ0C5Ugqnng=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1be434\npopulation: 41 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 14 cec3 cbc5 ea0e ea60 | 63 f5c4 (0) f410 (0) f74e (0) f360 (0)\n001 9 78cb 7f87 6c82 645b | 38 73b8 (0) 7355 (0) 734e (0) 757a (0)\n002 4 372d 286a 213b 2434 | 12 3e56 (0) 3ee4 (0) 3cb1 (0) 38ab (0)\n003 11 0ff6 0bcf 0ab9 018a | 11 0ff6 (0) 0bcf (0) 0ab9 (0) 06b9 (0)\n============ DEPTH: 4 ==========================================\n004 2 13bc 109e | 2 13bc (0) 109e (0)\n005 0 | 0\n006 1 1929 | 1 1929 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","private_key":"f4c9d012e654cc97f045dbff8811d75d2bc28f743389ed83138c83f208c0c4a3","name":"node_1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","services":["bzz","pss"],"enable_msg_events":true,"port":39499},"up":true}},{"node":{"info":{"id":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","name":"node_517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","enode":"enode://84e56a199123357e4baa395c602310fd7ee347f259e1a71c6f6fea49356dee106bdd2103681d15f896df139363b8caf91a70e2927012eb4ed3189abc8574c05f@127.0.0.1:0","enr":"0xf88fb84006dac2d9b267151a93241e398113497441d145d87211a3c352c7f87348ac8ce506d1e2d81d2e99f9e4320692bb2519b52e0ec44d5b98dd50de8964f0f869abef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10384e56a199123357e4baa395c602310fd7ee347f259e1a71c6f6fea49356dee10","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UXqpdwSCR9XRatUaKG/6xNj5EHM/BXiyIiATCMMtGV4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 517aa9\npopulation: 21 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 e0ea e77f f361 | 63 f410 (0) f5c4 (0) f74e (0) f360 (0)\n001 3 018a 0506 1be4 | 27 3cb1 (0) 3e56 (0) 3ee4 (0) 38ab (0)\n002 3 757a 772e 645b | 23 73b8 (0) 734e (0) 7355 (0) 757a (0)\n003 5 4a18 4b24 419a 41b9 | 8 47c3 (0) 4167 (0) 419a (0) 41b9 (0)\n004 3 5abc 5a01 5d60 | 3 5abc (0) 5a01 (0) 5d60 (0)\n============ DEPTH: 5 ==========================================\n005 2 558e 5776 | 2 558e (0) 5776 (0)\n006 1 539d | 1 539d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","private_key":"468bb419433b15b2933469b68aecf09e25fe8872c8128a2ee0198d626c5e16a9","name":"node_517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","services":["bzz","pss"],"enable_msg_events":true,"port":43881},"up":true}},{"node":{"info":{"id":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","name":"node_5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","enode":"enode://04a81661386177d0609fc1bd233738fbb96b9280ab323c85ceac159c0854dc725e4c84c8957ba802498745365c937a581e09c8a4a1580b0dce82e5dcaef08ee4@127.0.0.1:0","enr":"0xf88fb840dee34144fcdd9b6e5d1be0361509c91c011d627a6a3b69edbbcb3a90f7252f5b4aa02cec8d59613ac817a9336ddf3e1673f6509927af5c0b4bc44d01a9fb7f440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10204a81661386177d0609fc1bd233738fbb96b9280ab323c85ceac159c0854dc72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XWCOZqF0QgkREctHJyP+OuofK67KpUa1fUlQfGOmHNo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5d608e\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 f74e f361 edc8 ea0e | 63 f5c4 (0) f410 (0) f74e (0) f360 (0)\n001 2 018a 0506 | 27 38ab (0) 39db (0) 3e56 (0) 3ee4 (0)\n002 7 6ecb 645b 757a 772e | 23 73b8 (0) 734e (0) 7355 (0) 757a (0)\n003 3 47c3 41b9 4a18 | 8 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n004 4 5776 558e 539d 517a | 4 558e (0) 5776 (0) 539d (0) 517a (0)\n============ DEPTH: 5 ==========================================\n005 2 5abc 5a01 | 2 5abc (0) 5a01 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","private_key":"81c50622bdad71d45180a827fe4f2709ac6e73ab5b1d7f135ae6c563bdf67dfc","name":"node_5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","services":["bzz","pss"],"enable_msg_events":true,"port":46869},"up":true}},{"node":{"info":{"id":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","name":"node_83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","enode":"enode://9903840de4085e02bf4b40b91137ea82baf327272e40f2a68b0bacc22064465e695d1053d48ade3cc707fe05b2f395540b7e8aaed800b8a746085969ea98a8c1@127.0.0.1:0","enr":"0xf88fb840ef8ed31b921f8a77d4906bb0fa6b72a27e794b68d3615d8c5035c35186f636a554ccec2b28662884c8454b4134c077320be3b5e6472693c92cf8945deab453840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039903840de4085e02bf4b40b91137ea82baf327272e40f2a68b0bacc22064465e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g9xVbtNvN9BnZb4lVP6G6vHsIeKTH7IkAyOEU78CHfs=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 83dc55\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 018a 026d 2434 213b | 65 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n001 11 f361 f74e e77f e0b1 | 30 f410 (0) f5c4 (0) f74e (0) f360 (0)\n002 8 a7a6 a2ba a320 ae67 | 17 b70e (0) b486 (0) b2b9 (0) b381 (0)\n003 5 9626 9a92 9d3c 9e02 | 8 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n004 5 8cf9 895b 89c8 8be4 | 5 8cf9 (0) 8be4 (0) 8b76 (0) 895b (0)\n============ DEPTH: 5 ==========================================\n005 1 86ca | 1 86ca (0)\n006 0 | 0\n007 1 82f0 | 1 82f0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","private_key":"996588cd689e21ae98c63522cc84c5ca8c59901f1738bf888136a0d84745625a","name":"node_83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","services":["bzz","pss"],"enable_msg_events":true,"port":44859},"up":true}},{"node":{"info":{"id":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","name":"node_db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","enode":"enode://0620b99063bcbdca96543150c5bcaa6bbae76cfa9d6a5700cec06bcac3f80ddbb3e87099c7516c8bf7e1fc7bbe1a2c74decdb9beacdc44ed6b5ea859a7681da9@127.0.0.1:0","enr":"0xf88fb8409dedfae6e6fc520e43e7d06cb137d94f183daa858fb40bef2a6b1e677ec9e96c7ae3a0fdbc5513424aed12e0358fad4c8358f48c69e806c50c7d002c899356370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030620b99063bcbdca96543150c5bcaa6bbae76cfa9d6a5700cec06bcac3f80ddb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2wiBA/O28seE127Nmci0p3/Tm7Occt39kcmcGp3Tt1s=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: db0881\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7fbc 0427 0506 | 65 3cb1 (0) 3e56 (0) 3ee4 (0) 38ab (0)\n001 6 b16d b486 b70e b841 | 33 b92a (0) b841 (0) b8e1 (0) b70e (0)\n002 11 f74e f360 f361 e77f | 15 f410 (0) f5c4 (0) f74e (0) f360 (0)\n003 7 ca03 cbc5 c8e5 cdcd | 9 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n004 3 d0f3 d224 d6ff | 3 d224 (0) d0f3 (0) d6ff (0)\n============ DEPTH: 5 ==========================================\n005 2 dc97 dfae | 2 dc97 (0) dfae (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","private_key":"531ff73ac55db42d259eda258c322099463847f19f0e133a69fe506626d432c8","name":"node_db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","services":["bzz","pss"],"enable_msg_events":true,"port":33251},"up":true}},{"node":{"info":{"id":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","name":"node_c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","enode":"enode://c09ff8bce7f3f84fda572912d07e2fd5303e8a9bcd69f3794ebec6268fba90310761b6f73741b9701a1928f9af099bb8eda1d9d38e849a12fd21d9a8a6f43b37@127.0.0.1:0","enr":"0xf88fb8408bae0ad58fe6f74ee5e733985301353441b70d767126573c80639676f5d3c0d94ab77ee9239739d4a1b3ab7328206c2d561f9468e37e76fe16c2d02be7e0c5ab0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c09ff8bce7f3f84fda572912d07e2fd5303e8a9bcd69f3794ebec6268fba9031","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wYEFqjAqQ+NS2Zl0Wg+Aavn4y4u4M0k1faXIXol1rNE=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c18105\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 286a 0427 0506 | 65 3cb1 (0) 3ee4 (0) 3e56 (0) 38ab (0)\n001 5 8b76 b16d b486 b8e1 | 33 91eb (0) 92a1 (0) 9626 (0) 957d (0)\n002 5 e0b1 e0ea f74e f360 | 15 f5c4 (0) f410 (0) f74e (0) f360 (0)\n003 4 d224 dc97 dfae db08 | 6 d0f3 (0) d224 (0) d6ff (0) dc97 (0)\n============ DEPTH: 4 ==========================================\n004 7 c8e5 ca03 cbc5 cdcd | 7 ca03 (0) cbc5 (0) c8e5 (0) cdcd (0)\n005 0 | 0\n006 1 c3a1 | 1 c3a1 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","private_key":"7a2924b057c33f05e57a60b815f1c80855c3acc417bf37cd31d281f670cba443","name":"node_c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","services":["bzz","pss"],"enable_msg_events":true,"port":40633},"up":true}},{"node":{"info":{"id":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","name":"node_a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","enode":"enode://f06cb29c4ffab0c600cf7e7834032f1aab24cf48200d31c1c67b6ba2ee38195c9596df70c664d38cc53bdbcda0bb8c9bda598d0e0f3b377f5f6568b3725f7ba2@127.0.0.1:0","enr":"0xf88fb8404d99eb2b83e49511188c6105f0ef75fc98bd4e9871cb3b328d0fbec9f69153952df139a6d1d39c45e99b4baf70040b97087c9ccdf54aed111a2cf7435a6f574b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f06cb29c4ffab0c600cf7e7834032f1aab24cf48200d31c1c67b6ba2ee38195c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p6YYBNJw7WwnpLHopjTDDXzbr2RKHGfLxrCM2EmnEds=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a7a618\npopulation: 38 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 109e 0ff6 06b9 0506 | 65 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n001 8 f360 f361 f410 ebca | 30 f74e (0) f5c4 (0) f410 (0) f361 (0)\n002 6 92a1 9ee7 8b76 8be4 | 16 957d (0) 9626 (0) 91eb (0) 92a1 (0)\n003 6 b841 b8e1 b486 b70e | 8 b92a (0) b841 (0) b8e1 (0) b70e (0)\n004 4 ad0d afa3 aebd ae67 | 4 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n============ DEPTH: 5 ==========================================\n005 3 a085 a320 a2ba | 3 a085 (0) a2ba (0) a320 (0)\n006 0 | 0\n007 0 | 0\n008 1 a75a | 1 a75a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","private_key":"78a5f9f36119c4686d8fb667f830f052885e6485e92dd09b9fed7f9e01368f83","name":"node_a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","services":["bzz","pss"],"enable_msg_events":true,"port":35649},"up":true}},{"node":{"info":{"id":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","name":"node_b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","enode":"enode://3a9f619551e6b60c9edcac716ff28cd93af12dbc9b07a2c9ea541a8e3666f513d0b05e82cae81eb72534d3784d41a948cba2a1d9db8b3764feee40d52290427b@127.0.0.1:0","enr":"0xf88fb8403bcb9b72c0dd4b343993b4c02c8d3dfd1a66f01fd355938b0d91547730d0fdef30e0150cbf8f5999ecd82b2ba083bb019e0fc5d96ed35baf82b80b3645eb4c4f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033a9f619551e6b60c9edcac716ff28cd93af12dbc9b07a2c9ea541a8e3666f513","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sW3N8f8aVtSeN0Ux2YhdWcG8+7YoYEUg2bHYRmLtuco=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b16dcd\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7f87 78cb 41b9 47c3 | 65 38ab (0) 39db (0) 3cb1 (0) 3e56 (0)\n001 10 ce99 cdcd c8e5 cbc5 | 30 d224 (0) d0f3 (0) d6ff (0) dc97 (0)\n002 4 9d3c 9ee7 8b76 83dc | 16 9626 (0) 957d (0) 91eb (0) 92a1 (0)\n003 3 ae67 a320 a7a6 | 9 ad0d (0) afa3 (0) aebd (0) ae67 (0)\n004 3 b92a b841 b8e1 | 3 b92a (0) b841 (0) b8e1 (0)\n005 2 b70e b486 | 2 b70e (0) b486 (0)\n============ DEPTH: 6 ==========================================\n006 2 b2b9 b381 | 2 b2b9 (0) b381 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","private_key":"ede19b96340b0babe7021d81a8ec746406996af53908a387cd2e9f1551651869","name":"node_b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","services":["bzz","pss"],"enable_msg_events":true,"port":33287},"up":true}},{"node":{"info":{"id":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","name":"node_ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","enode":"enode://a3a82e04610c3851f4b6b80bdd5666f8c2eb2a5c4fe7a79dbfc5fa38de9bbd36ca8dd8a3d794ead924e43a0812bbbcaf1f394e4d77e9662238f80ccac0d8e52a@127.0.0.1:0","enr":"0xf88fb84090c476d24643383a66557141b62c940150453a05a838e91c6eaa1441befcedd441f7ac293638f5a01132227c8daf970bb3ec76d938fcd2257ef6282b758c36a30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a3a82e04610c3851f4b6b80bdd5666f8c2eb2a5c4fe7a79dbfc5fa38de9bbd36","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6mDvfLPyFmpcjihsiFmElDoupa/0cwAVvmoVAxBAzs8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ea60ef\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0ab9 1be4 372d 3e56 | 65 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n001 8 83dc 86ca 89c8 895b | 33 8cf9 (0) 8b76 (0) 8be4 (0) 895b (0)\n002 5 c8e5 ca03 d224 dfae | 15 d224 (0) d0f3 (0) d6ff (0) dc97 (0)\n003 4 f410 f74e f360 f361 | 5 f5c4 (0) f410 (0) f74e (0) f361 (0)\n004 3 e0b1 e0ea e77f | 5 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n005 2 ed32 edc8 | 2 ed32 (0) edc8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 ebca | 1 ebca (0)\n008 0 | 0\n009 1 ea0e | 1 ea0e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","private_key":"34572c71c9f4767ddfaee3aa21c52f966a73447695fe12dee7eb9ff693417140","name":"node_ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","services":["bzz","pss"],"enable_msg_events":true,"port":43863},"up":true}},{"node":{"info":{"id":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","name":"node_57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","enode":"enode://802bb2984957e4187577dba69e5a73714c65bc176e785c46c52c725e8cb118d05f0b0840a373188d1ccd56465c20ba7aedf21b7e5411c1c96ac32e6adad2e184@127.0.0.1:0","enr":"0xf88fb8401f7f3cc91efaede856461ce79b9ff9df6ced9d7358d2004d24fd403a006dd7604de40bc6b4f4e14b0292d0f15079e6c6aa69988b38698efb340481039bef5c300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102802bb2984957e4187577dba69e5a73714c65bc176e785c46c52c725e8cb118d0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V3ZFIhYmIMGtCxZqnEN3IlXQzAHknyEi7wnbBGgEpXA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 577645\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c8e5 dc97 e77f ea60 | 63 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n001 12 3ee4 286a 213b 2434 | 27 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n002 8 645b 6ecb 6c82 772e | 23 734e (0) 7355 (0) 73b8 (0) 757a (0)\n003 5 4a18 4b24 47c3 4167 | 8 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n004 3 5d60 5abc 5a01 | 3 5abc (0) 5a01 (0) 5d60 (0)\n============ DEPTH: 5 ==========================================\n005 2 539d 517a | 2 539d (0) 517a (0)\n006 1 558e | 1 558e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","private_key":"9de036860d3dc63ef40d3981f65da10bae27dd10ce542c76134e247073f512f4","name":"node_57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","services":["bzz","pss"],"enable_msg_events":true,"port":37591},"up":true}},{"node":{"info":{"id":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","name":"node_e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","enode":"enode://c80b19cf5a0bbf10af5ae60bf60765387031caab06906033df96362e07dd4e51e043bb824328834e600c0b6affc36df0d06ecd955103721482c11bedfe78e06e@127.0.0.1:0","enr":"0xf88fb84026a761e6c2aae397880443de1d6bb3b7770c8206f473451199148dcb9b74c03849739e4806e81c1ca8482e0712620998d9e4666d25b65e36e773f3c0f543a70f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c80b19cf5a0bbf10af5ae60bf60765387031caab06906033df96362e07dd4e51","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"539qqePfzOCi5dt5RwMiQkmrpgWVB1st+aWwswhVz0Y=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e77f6a\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1be4 5d60 517a 5776 | 65 38ab (0) 39db (0) 3cb1 (0) 3ee4 (0)\n001 13 92a1 957d 9ee7 83dc | 33 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n002 5 db08 dfae c8e5 ca03 | 15 d6ff (0) d224 (0) d0f3 (0) dc97 (0)\n003 4 f74e f410 f361 f360 | 5 f5c4 (0) f410 (0) f74e (0) f361 (0)\n004 5 ed32 edc8 ebca ea0e | 5 ed32 (0) edc8 (0) ebca (0) ea0e (0)\n============ DEPTH: 5 ==========================================\n005 3 e16b e0b1 e0ea | 3 e16b (0) e0b1 (0) e0ea (0)\n006 1 e55d | 1 e55d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","private_key":"c230ff1d7220134fe04e59de10522a8e372830d5b3eccbfbccf4b8e57536d4f9","name":"node_e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","services":["bzz","pss"],"enable_msg_events":true,"port":38009},"up":true}},{"node":{"info":{"id":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","name":"node_cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","enode":"enode://c9307563a6ac3d784c348187f2942d2aa64fb15afdb55d6fdfd6fa0bfc5e4a65281f9b0ef5dc5b155c0c97971411d8decd17c66ad96e3a0bca0f7bbfb6674ce8@127.0.0.1:0","enr":"0xf88fb8409fdaea6e03e3c24cf8967a46c99aaa146e74b7e455c4b7012f9c4b72fe74cbe831d49545d8fd8a8092b357b370922dfafe86853f004fb9f862395a41a00504000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c9307563a6ac3d784c348187f2942d2aa64fb15afdb55d6fdfd6fa0bfc5e4a65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zsPAHBR7NPJRBN3QslB2zvY6wiTq2p2fWgC4UTMxNU8=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cec3c0\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 0506 06b9 018a 0ff6 | 65 372d (0) 3cb1 (0) 3ee4 (0) 3e56 (0)\n001 9 b381 83dc 82f0 86ca | 33 86ca (0) 82f0 (0) 83dc (0) 8cf9 (0)\n002 2 f360 e77f | 15 f74e (0) f5c4 (0) f410 (0) f361 (0)\n003 2 d224 db08 | 6 d0f3 (0) d224 (0) d6ff (0) dc97 (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 3 c8e5 ca03 cbc5 | 3 cbc5 (0) ca03 (0) c8e5 (0)\n006 1 cdcd | 1 cdcd (0)\n============ DEPTH: 7 ==========================================\n007 1 cfbb | 1 cfbb (0)\n008 0 | 0\n009 1 ce99 | 1 ce99 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","private_key":"a43b0e0e48e2e4dbd79184eaade1af54404a0a89d0d250b881a1c131de5b2174","name":"node_cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","services":["bzz","pss"],"enable_msg_events":true,"port":44913},"up":true}},{"node":{"info":{"id":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","name":"node_6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","enode":"enode://e94d070b0cd5336bdebbdb63309d23c431e87c6bfa03474b5ffe002182e1fe617f0cb27a3e399ff36cc6eff93a64eae9ce3958400eba3b644a878ec673bc5a6a@127.0.0.1:0","enr":"0xf88fb840ac1282029a97bfacb7298ac94161d57a84cd6347e9fa18bd1e71f37ded792f352b8491cf02668d2daea43f1e02089f892431108a7e4a5708307096b4a57c4cd80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e94d070b0cd5336bdebbdb63309d23c431e87c6bfa03474b5ffe002182e1fe61","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bIL9q9CeDp0PxQdhOgWVHAKylT12OgYqXzKq9cxHfBk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c82fd\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b486 c8e5 cec3 | 63 86ca (0) 82f0 (0) 83dc (0) 8cf9 (0)\n001 9 286a 2459 2434 3e56 | 27 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n002 6 5a01 5776 47c3 41b9 | 15 5d60 (0) 5abc (0) 5a01 (0) 539d (0)\n003 5 78cb 7fbc 7f87 7cf4 | 12 7355 (0) 734e (0) 73b8 (0) 757a (0)\n004 4 6210 645b 667e 6742 | 5 645b (0) 667e (0) 6728 (0) 6742 (0)\n005 1 6982 | 1 6982 (0)\n006 2 6ecb 6e5c | 2 6ecb (0) 6e5c (0)\n============ DEPTH: 7 ==========================================\n007 1 6d60 | 1 6d60 (0)\n008 1 6c02 | 1 6c02 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","private_key":"fdb64dd6356458c4ea0b68ad6552a972f6b174e8db0fecb40fb8c03a61e39561","name":"node_6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","services":["bzz","pss"],"enable_msg_events":true,"port":36231},"up":true}},{"node":{"info":{"id":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","name":"node_c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","enode":"enode://bb7389fc8693197348309cc5f82cd99b2d73b478cefbdcf901844a69e35ea841449888e8cf056b1a4475970b6815a0a091c37e89df251953b7ba15fecb352b8b@127.0.0.1:0","enr":"0xf88fb840ceee340c58b4bfd938dbe46f60634de3127f2f253a2ba4925a2309b4e89c1c276391c132d230217a48dbfe44934f0a5204f62163714f90b0a7901404b5cc51c90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bb7389fc8693197348309cc5f82cd99b2d73b478cefbdcf901844a69e35ea841","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yOWhtFM90N4SrO5NMTafOXhReFaHGLk7vDIeyD4HFPA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8e5a1\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 0427 0506 06b9 018a | 65 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n001 6 b16d 8be4 83dc 82f0 | 33 86ca (0) 82f0 (0) 83dc (0) 8cf9 (0)\n002 5 e77f ea60 ebca edc8 | 15 f74e (0) f5c4 (0) f410 (0) f361 (0)\n003 3 d0f3 d224 db08 | 6 d6ff (0) d224 (0) d0f3 (0) dc97 (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 4 cdcd cfbb cec3 ce99 | 4 cdcd (0) cfbb (0) cec3 (0) ce99 (0)\n============ DEPTH: 6 ==========================================\n006 2 ca03 cbc5 | 2 cbc5 (0) ca03 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","private_key":"71b41bd09467c47283a158151bded935639f103d9452befe2459162ec74df521","name":"node_c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","services":["bzz","pss"],"enable_msg_events":true,"port":46751},"up":true}},{"node":{"info":{"id":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","name":"node_ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","enode":"enode://18280baf1cb264a91130e6abae9d7e90b21447733bc8929577cb926538b2b17dc0add3d3467b320fae85519f6415afb36e9e18ba27105b5d0d33b8636fb5a711@127.0.0.1:0","enr":"0xf88fb840de9d966e41db3e276b1d1d67ae48e915d7689ef8081e41029aea9165c3ac62ff7805be7f8862a63d07c38f176d370349ab59f6917ada9b5ae644e87897df08600183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10318280baf1cb264a91130e6abae9d7e90b21447733bc8929577cb926538b2b17d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zpnp03ERxS6Smxh/4gF5CxpVXfuLa23lTpTffMLUP9Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ce99e9\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7fbc 286a 0427 | 65 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n001 6 b381 b16d a7a6 86ca | 33 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n002 4 edc8 ebca f361 f360 | 15 f74e (0) f410 (0) f5c4 (0) f361 (0)\n003 2 db08 d224 | 6 d6ff (0) d0f3 (0) d224 (0) dc97 (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 3 cbc5 ca03 c8e5 | 3 cbc5 (0) ca03 (0) c8e5 (0)\n006 1 cdcd | 1 cdcd (0)\n============ DEPTH: 7 ==========================================\n007 1 cfbb | 1 cfbb (0)\n008 0 | 0\n009 1 cec3 | 1 cec3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","private_key":"f6a40f6cecf0cb1296f7e100e8ee72b402405531fc277f70a99355650e3d7248","name":"node_ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","services":["bzz","pss"],"enable_msg_events":true,"port":43447},"up":true}},{"node":{"info":{"id":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","name":"node_042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","enode":"enode://0220d1612c3a461835407833a67a205cdc87d1df9aabc985243ad449332e2d38b80f52f8973a28babecac8fc22daf2862497c79efdbeaf82cce5ffe402efde4a@127.0.0.1:0","enr":"0xf88fb84007dcb9c1db66f2f7829bea3542a0b3053a1cae6b9452c7619ecc9080f00be44a7842d6a03474709be30cb31e8a773adaafd033c60d684af4d63ae57f729b446d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020220d1612c3a461835407833a67a205cdc87d1df9aabc985243ad449332e2d38","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BCeI1bcsuEo3VWXRINI5orFP3ziz9fmSKE14U1B3FIo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 042788\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 aebd a7a6 b16d f410 | 63 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n001 4 7639 5776 4cd0 41b9 | 38 6ecb (0) 6e5c (0) 6d60 (0) 6c02 (0)\n002 8 3ee4 3e56 3cb1 2459 | 12 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n003 4 13bc 109e 1929 1be4 | 4 13bc (0) 109e (0) 1929 (0) 1be4 (0)\n004 2 0ab9 0ff6 | 3 0bcf (0) 0ab9 (0) 0ff6 (0)\n005 5 0390 0218 027f 026d | 5 0390 (0) 0218 (0) 027f (0) 026d (0)\n============ DEPTH: 6 ==========================================\n006 1 06b9 | 1 06b9 (0)\n007 1 0506 | 1 0506 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","private_key":"ef2c90067d97cab14a4cf2eff2fa9332bc6149d7c6ddc78f3dfddf9fa938b9ba","name":"node_042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","services":["bzz","pss"],"enable_msg_events":true,"port":46141},"up":true}},{"node":{"info":{"id":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","name":"node_41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","enode":"enode://2a29ba5bbf7e82989e16f954d13795448cfffbc9f0d87a5e01c809de44cee798cba2568c3318ad4e7ac48915e5e99c46b3973d7ca9da44d169ced570e274088c@127.0.0.1:0","enr":"0xf88fb8407a50ecfb4ac26fa2aa0595d78a631d0be7ee8d3588ddd05dda07c3dedcfe07d83f0e6e095a3fe0d3382f43949ae3f633f5a780c1ee3921341dbe3c17cf9eec0a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022a29ba5bbf7e82989e16f954d13795448cfffbc9f0d87a5e01c809de44cee798","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QbnuetGWmOl1ibBZrTMzy2TwLBYAbZT7PQutfO2P8jg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 41b9ee\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b16d a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 11 39db 286a 2434 2459 | 27 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n002 9 645b 6c02 6c82 6ecb | 23 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n003 7 5a01 5abc 5d60 539d | 7 5a01 (0) 5abc (0) 5d60 (0) 539d (0)\n004 3 4cd0 4b24 4a18 | 4 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n005 1 47c3 | 1 47c3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 4167 | 1 4167 (0)\n009 0 | 0\n010 1 419a | 1 419a (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","private_key":"beb43b0ce6c2e3a4e7f2ec5be3324f334a3bed25b9becf17d1738a61f2613c93","name":"node_41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","services":["bzz","pss"],"enable_msg_events":true,"port":40537},"up":true}},{"node":{"info":{"id":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","name":"node_78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","enode":"enode://8fe37769462119a45a588a0a6abcb43165093a0ad74a8e18016277a214169950e9f5c7d10bc217d0b80998c4cee74c344027362a9b3ca485d8c98f12dc287640@127.0.0.1:0","enr":"0xf88fb840a0f01bac92cac5d6526e266529aebd70a42a5e443d9e68bb1da73f022bb2fe79551dbcdcaa994812c375e725c8126e32ef46d373f744fcecd8f7bc0ef3f26d1b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028fe37769462119a45a588a0a6abcb43165093a0ad74a8e18016277a214169950","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eMvBmiTQlat4WISQWMZcBhxSKJuR3dks7jS+2YruSlk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 78cbc1\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ea0e b486 b16d a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 6 026d 0ff6 1be4 286a | 27 372d (0) 38ab (0) 39db (0) 3e56 (0)\n002 9 5abc 5d60 558e 5776 | 15 5a01 (0) 5abc (0) 5d60 (0) 539d (0)\n003 6 6982 6e5c 6d60 6c82 | 11 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n004 4 73b8 757a 772e 7639 | 6 734e (0) 7355 (0) 73b8 (0) 757a (0)\n============ DEPTH: 5 ==========================================\n005 4 7dc5 7cf4 7fbc 7f87 | 4 7dc5 (0) 7cf4 (0) 7fbc (0) 7f87 (0)\n006 1 7b92 | 1 7b92 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","private_key":"7de1fbbba1cd14694bd6b63bb00d807182ac42a8ffabee58c1eb352d696871cc","name":"node_78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","services":["bzz","pss"],"enable_msg_events":true,"port":45671},"up":true}},{"node":{"info":{"id":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","name":"node_7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","enode":"enode://a63ffc43cec6078c4261ca9a8bc556c4694f55f153d5ec2065743f7151a3b8e16a1f329f2db489e9646c33005a30ccd6947c2be1189038b9497b1634608cf116@127.0.0.1:0","enr":"0xf88fb84074c9fcda11cf86d8033a7ec003b37f4192bc99d18862396df30d040e21b6ed611ad763446b7690ea37ef1d4237ca2dcec449f1cb3a2df4176f2099ce8b39a9960183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a63ffc43cec6078c4261ca9a8bc556c4694f55f153d5ec2065743f7151a3b8e1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f4fafuVbTIyPnVVBH/iNOgtjv+5qUWkX1J+mJz+1uGo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7f87da\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ea0e b486 b16d a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 6 026d 018a 0ff6 1be4 | 27 372d (0) 3cb1 (0) 3e56 (0) 3ee4 (0)\n002 6 5d60 5776 4a18 419a | 15 5abc (0) 5a01 (0) 5d60 (0) 539d (0)\n003 7 6e5c 6d60 6c82 6982 | 11 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n004 5 734e 73b8 757a 772e | 6 7355 (0) 734e (0) 73b8 (0) 757a (0)\n005 2 7b92 78cb | 2 7b92 (0) 78cb (0)\n============ DEPTH: 6 ==========================================\n006 2 7dc5 7cf4 | 2 7dc5 (0) 7cf4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 7fbc | 1 7fbc (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","private_key":"a7e3fdde74aed0e2ae459190f839adf63156aa7982bde3d6ab0f33a8e8526b9d","name":"node_7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","services":["bzz","pss"],"enable_msg_events":true,"port":39359},"up":true}},{"node":{"info":{"id":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","name":"node_47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","enode":"enode://9b43113635c9212f3a25073df459dd4340386c80a79823d1931a15f6efe8cfa8bc4887bfa1237da6956b72e5c06e1c9a79a8daad206a3e91916b29e0a2027bc5@127.0.0.1:0","enr":"0xf88fb840a37ee48405baa3c5ff376e49a1443eb509afff243b04f89c05b8f4e6eb8c9c7a5756c4c8a97256b7c92d95133662d4d5fb77bc09cf085f06283d82d85c5a62630183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039b43113635c9212f3a25073df459dd4340386c80a79823d1931a15f6efe8cfa8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"R8Pg37v86+7OeIZcjJiVdzYM2cxGo7Q/S3sB7RTcMOY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 47c3e0\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 dc97 b16d aebd a7a6 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 9 3ee4 286a 2434 2459 | 27 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n002 5 645b 6c82 7639 78cb | 23 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n003 6 5a01 5d60 539d 517a | 7 5abc (0) 5a01 (0) 5d60 (0) 539d (0)\n004 4 4cd0 48b6 4b24 4a18 | 4 4cd0 (0) 48b6 (0) 4b24 (0) 4a18 (0)\n============ DEPTH: 5 ==========================================\n005 3 4167 419a 41b9 | 3 4167 (0) 41b9 (0) 419a (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","private_key":"760e9a634e4459a6137e0a4164c2ff06b954c6bb74a19084566e563f864b8de4","name":"node_47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","services":["bzz","pss"],"enable_msg_events":true,"port":34401},"up":true}},{"node":{"info":{"id":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","name":"node_06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","enode":"enode://5e63692a1ce43cab6bc865e299006fcb429319aa159f11fa0e2d5cde573fce9a20be804b3baa55b8f64ceec46e9e671021661f6724946f19d2ab392d2f6772c7@127.0.0.1:0","enr":"0xf88fb8405aa541c395a887f464be5f1f9cf2706523e11b6aed11376895a795f591303d765ad2220baf9fc3dd3ccf472503e282fb7698969f2cc2a6d9df6ad10f2c7dd32a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035e63692a1ce43cab6bc865e299006fcb429319aa159f11fa0e2d5cde573fce9a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BrlfG6x2ykkl1QmwYhbyETrF3PBR71qgoyCuZAaeC20=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 06b95f\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 cec3 c8e5 cbc5 f410 | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 11 6c82 7639 7b92 7cf4 | 38 6982 (0) 6e5c (0) 6ecb (0) 6d60 (0)\n002 5 3ee4 26d1 2434 2459 | 12 372d (0) 38ab (0) 39db (0) 3cb1 (0)\n003 2 13bc 1be4 | 4 109e (0) 13bc (0) 1929 (0) 1be4 (0)\n004 2 0ab9 0ff6 | 3 0bcf (0) 0ab9 (0) 0ff6 (0)\n005 5 0390 026d 027f 0218 | 5 0390 (0) 0218 (0) 026d (0) 027f (0)\n============ DEPTH: 6 ==========================================\n006 2 0427 0506 | 2 0506 (0) 0427 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","private_key":"f46e1e932cac23f40da5e48808b19557c22164c16823eea2720fa52ea9286449","name":"node_06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","services":["bzz","pss"],"enable_msg_events":true,"port":35629},"up":true}},{"node":{"info":{"id":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","name":"node_0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","enode":"enode://f907d19b4970dee3081d1119e31908cb0ebcc915b2aa05c1dde8014b35d9aa0d3d2786013bad40ee4a9b54b615ed3a7236e9f526787cd201f18ab4a210e87ed2@127.0.0.1:0","enr":"0xf88fb840c0b7ab20a60ff949e9036939be157446dee043fa8688afcf67585ec1ce0377cd5af23af126525f9bd3f6170033dc2bd748394bc9398c95fa363d5c317c84bc480183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f907d19b4970dee3081d1119e31908cb0ebcc915b2aa05c1dde8014b35d9aa0d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D/Z7Dp7GUJx3hklbez3bF2tPgiH/MA9AnwCj04noh0w=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ff67b\npopulation: 40 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 b381 b2b9 b486 aebd | 63 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n001 13 5776 4cd0 47c3 4167 | 38 6982 (0) 6ecb (0) 6e5c (0) 6d60 (0)\n002 4 3e56 2434 2459 286a | 12 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n003 3 13bc 1929 1be4 | 4 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n004 8 0390 026d 027f 0218 | 8 0390 (0) 0218 (0) 026d (0) 027f (0)\n============ DEPTH: 5 ==========================================\n005 2 0ab9 0bcf | 2 0ab9 (0) 0bcf (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","private_key":"b19b4a43edf29d1bbb5774dd2c0f184ba873cf22764297c41af632f4d4521b57","name":"node_0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","services":["bzz","pss"],"enable_msg_events":true,"port":41299},"up":true}},{"node":{"info":{"id":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","name":"node_ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","enode":"enode://f32d87347fa320045d0437419b4f64bc07721d44cdc75a314bce969b021b92855772ec300a5cffcbd948b59461a4880ae1a8c59dc3e802876989a9edfc7c1efd@127.0.0.1:0","enr":"0xf88fb84014d558cfdcb467455447b89e2c52d929511fbde130fe2234fc3b57ca137a2f4a479c493406c6012eab1fd459e6315d30b354b20cfaca4f8bdbdecd4949c911af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f32d87347fa320045d0437419b4f64bc07721d44cdc75a314bce969b021b9285","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ygNtHvnmzjZU8tdp8WkmqhSVcZNYZCZInhVTnfqPd2M=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ca036d\npopulation: 30 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 6982 7fbc 7639 0ff6 | 65 5a01 (0) 5abc (0) 5d60 (0) 517a (0)\n001 5 b381 b16d 86ca 92a1 | 33 ad0d (0) afa3 (0) ae67 (0) aebd (0)\n002 8 edc8 ebca ea60 e77f | 15 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n003 5 dfae db08 d6ff d224 | 6 dc97 (0) dfae (0) db08 (0) d6ff (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 4 cdcd cfbb ce99 cec3 | 4 cdcd (0) cfbb (0) ce99 (0) cec3 (0)\n============ DEPTH: 6 ==========================================\n006 1 c8e5 | 1 c8e5 (0)\n007 1 cbc5 | 1 cbc5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","private_key":"b23dda65c58838a9d2ba74acdddbfc1935094baca5b3b23176f48999f0ebc423","name":"node_ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","services":["bzz","pss"],"enable_msg_events":true,"port":41163},"up":true}},{"node":{"info":{"id":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","name":"node_7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","enode":"enode://c7b74655869120b2c4706d8c143ddf837a6d4ff7ba2cb1a30bdd8096b461cbd9af42aa144a134bdf16b6ad9b6b03829d1987131098736c2fe041122be46acd7d@127.0.0.1:0","enr":"0xf88fb840ac1c45c3987cfa0bec095840df22a0a404d1b8972dbd3231eb99168cfdad644a4c5f06f117723a23bc327ac428b9d187a2a9f1e96f0f9924e76b7e7b5415ef250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c7b74655869120b2c4706d8c143ddf837a6d4ff7ba2cb1a30bdd8096b461cbd9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"djn5pm6P9w9VTDRvqiX3gUCVfClbdI/EKhLfeXL0/MY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7639f9\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b486 92a1 f360 ca03 | 63 a320 (0) a2ba (0) a085 (0) a75a (0)\n001 12 018a 027f 06b9 0427 | 27 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n002 5 5776 4cd0 47c3 419a | 15 5d60 (0) 5abc (0) 5a01 (0) 539d (0)\n003 4 6742 6210 6982 6c82 | 11 6ecb (0) 6e5c (0) 6d60 (0) 6c02 (0)\n004 5 7f87 7fbc 7cf4 78cb | 6 7b92 (0) 78cb (0) 7dc5 (0) 7cf4 (0)\n005 3 734e 7355 73b8 | 3 734e (0) 7355 (0) 73b8 (0)\n============ DEPTH: 6 ==========================================\n006 1 757a | 1 757a (0)\n007 1 772e | 1 772e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","private_key":"1f28b72e347e6a5c993f2226d06196d963341d6dffe3204efca5eb82a9707088","name":"node_7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","services":["bzz","pss"],"enable_msg_events":true,"port":34577},"up":true}},{"node":{"info":{"id":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","name":"node_f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","enode":"enode://a3b1ef5f74c19769b24261107a80bcb5c7314e85dadcf17d941563517510613feeba9bc1b3b3f57abccfc02fb83d4cb78cd9c7da05a955ce6fe67f03479ad64a@127.0.0.1:0","enr":"0xf88fb840fce892c7ce07a80ebaf87930e850fbe62526831641a569b7c882e674fe6429995831d7b67c7a099dfc693d60591b92835664b864ff2db071138b0c37efa03dc70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a3b1ef5f74c19769b24261107a80bcb5c7314e85dadcf17d941563517510613f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"82CEBIvw/5had/UYN5b3s3twhe5u6ou8X8YlWIVMzmc=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f36084\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1be4 419a 6982 7639 | 65 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n001 7 957d 82f0 8be4 a7a6 | 33 a320 (0) a2ba (0) a085 (0) a75a (0)\n002 8 db08 d0f3 c181 cec3 | 15 dfae (0) dc97 (0) db08 (0) d6ff (0)\n003 5 edc8 ea60 ebca e16b | 10 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 3 f74e f410 f5c4 | 3 f74e (0) f5c4 (0) f410 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 1 f361 | 1 f361 (0)\n========================================================================="}},"config":{"id":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","private_key":"5b7394337e91a274738c8e16b112b9c1d7682e033938b183e88d96322c81f6ee","name":"node_f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","services":["bzz","pss"],"enable_msg_events":true,"port":43813},"up":true}},{"node":{"info":{"id":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","name":"node_419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","enode":"enode://06f9ae5d93bede98bb8d04bad5677a64f79b8f1c3c17543de53e89dce96c87db7c8015e798b254f5490956cbd58a052bd3309ea1ec4b41cdeb763a59e1df2ea0@127.0.0.1:0","enr":"0xf88fb840f48fdca05279f70013ea36233f54604e2e5652203d6586c7f5ac11e49ab9b1c14d6ee24716fd542ede56f18e8d74f6b13de4985d774042f464d3dde6a87e07dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10206f9ae5d93bede98bb8d04bad5677a64f79b8f1c3c17543de53e89dce96c87db","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QZpmJt0CbAQ4RhWSEhmSxr4YaDdQEWVbbUBRZs2O338=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 419a66\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 b841 8be4 92a1 9ee7 | 63 a2ba (0) a320 (0) a085 (0) a75a (0)\n001 2 0ff6 06b9 | 27 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n002 10 78cb 7cf4 7f87 7fbc | 23 6ecb (0) 6e5c (0) 6d60 (0) 6c02 (0)\n003 3 539d 517a 5a01 | 7 5d60 (0) 5abc (0) 5a01 (0) 558e (0)\n004 3 4a18 48b6 4cd0 | 4 4cd0 (0) 4b24 (0) 4a18 (0) 48b6 (0)\n005 1 47c3 | 1 47c3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 4167 | 1 4167 (0)\n009 0 | 0\n010 1 41b9 | 1 41b9 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","private_key":"1784affdde58532fc95837b5bd7b50ad427deccd1487d4abe583699bf0056194","name":"node_419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","services":["bzz","pss"],"enable_msg_events":true,"port":45225},"up":true}},{"node":{"info":{"id":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","name":"node_9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","enode":"enode://4fb204c7f877f39de63aaf107893f86e4a577583c7b352b55b873761870d61feeef14c9ae88c1ccf3f5901056645987349fbae583c5290bfaa425cedff42bbae@127.0.0.1:0","enr":"0xf88fb840db1e4e5331aa8fa6e8b15b7dddbce0bf805b41932f86eeb643714780ae1df8f27e4cc31ec2f7a6a984c1c623dfeb0ab29c35155b5294e015213643b1ad9986d40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024fb204c7f877f39de63aaf107893f86e4a577583c7b352b55b873761870d61fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nuez4GtFNhXL2HN8t0UVsVD1GPGi6qLbkOVHCN0WG30=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ee7b3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 06b9 286a 7b92 419a | 65 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n001 6 e77f d224 ca03 c8e5 | 30 dc97 (0) dfae (0) db08 (0) d6ff (0)\n002 8 b841 b8e1 b486 b2b9 | 17 a320 (0) a2ba (0) a085 (0) a75a (0)\n003 4 86ca 82f0 83dc 8be4 | 8 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n004 3 91eb 92a1 957d | 4 9626 (0) 957d (0) 91eb (0) 92a1 (0)\n005 1 9a92 | 1 9a92 (0)\n============ DEPTH: 6 ==========================================\n006 1 9d3c | 1 9d3c (0)\n007 0 | 0\n008 1 9e02 | 1 9e02 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","private_key":"14f6f6dc12c8535f9c0ecd71836c9bf9f02b9aad5a2e86ed0c61e30246f7451a","name":"node_9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","services":["bzz","pss"],"enable_msg_events":true,"port":43061},"up":true}},{"node":{"info":{"id":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","name":"node_286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","enode":"enode://68d1075d86a39ad083dd215a50f24b3428c9189dadaa43b155a9130844d25cd85ea26a1760fefd9019e5a59c2d57b2d76fc6f2f5484471c72f53ebfdd52fdb75@127.0.0.1:0","enr":"0xf88fb84027739fe9f8470c3be7639f03c5d1339a233678f728db90a68fcee15810f3b0d22702adf6eae7e82f5738fa558e2caa4f523ddc3607fff8bf0f865a8183e225870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10368d1075d86a39ad083dd215a50f24b3428c9189dadaa43b155a9130844d25cd8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KGrrpka7pKiqHDcr7p8sn/Cis6u08YvjISJVVcbc5OU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 286aeb\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 ea60 d224 c181 c8e5 | 63 dfae (0) dc97 (0) db08 (0) d6ff (0)\n001 9 5776 47c3 41b9 7f87 | 38 5abc (0) 5a01 (0) 5d60 (0) 539d (0)\n002 5 1be4 0ff6 06b9 0506 | 15 109e (0) 13bc (0) 1929 (0) 1be4 (0)\n003 3 3cb1 3ee4 3e56 | 6 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n============ DEPTH: 4 ==========================================\n004 4 213b 26d1 2434 2459 | 4 213b (0) 26d1 (0) 2434 (0) 2459 (0)\n005 0 | 0\n006 1 2a22 | 1 2a22 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","private_key":"976efa040e6f45cc8e22838f1bbfc9b811fa7841ca2c8092a7cc8e335815e92a","name":"node_286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","services":["bzz","pss"],"enable_msg_events":true,"port":33919},"up":true}},{"node":{"info":{"id":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","name":"node_621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","enode":"enode://dc01b24ab4982764516ace14b88809eb185560373dfbf6fcded5a81bd3fada53e0be683e0c468b1e836de13076e0ccac4e368e8c0946bf24d4390af626af29f1@127.0.0.1:0","enr":"0xf88fb84098e9b3ff2b11a0cacb15bf38a25b7cfe5b534459b7abf909c02314e31e17fd35658770c3cbabde925fb6d0d702842012518483cf082bfa9acb5cd08308a88da60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dc01b24ab4982764516ace14b88809eb185560373dfbf6fcded5a81bd3fada53","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YhB2zmuC5wyQpK3yNapvcbEW4wLdaxXcrgf0qBYBJFU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 621076\npopulation: 23 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ad0d a7a6 a085 957d | 63 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n001 2 0ff6 286a | 27 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n002 2 419a 4167 | 15 5abc (0) 5a01 (0) 5d60 (0) 517a (0)\n003 8 7cf4 7fbc 7f87 7b92 | 12 7355 (0) 734e (0) 73b8 (0) 757a (0)\n004 2 6982 6c82 | 6 6e5c (0) 6ecb (0) 6d60 (0) 6c02 (0)\n============ DEPTH: 5 ==========================================\n005 4 645b 667e 6728 6742 | 4 645b (0) 667e (0) 6728 (0) 6742 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","private_key":"7c196a80ce1002ecd7f34c4db3cc6862875ca81e18dff1b002bc566b0275f318","name":"node_621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","services":["bzz","pss"],"enable_msg_events":true,"port":45645},"up":true}},{"node":{"info":{"id":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","name":"node_ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","enode":"enode://d5dfcc59c4faaf151e2776e409ecb40fa62ba49cf62037b1857207692f6458d99e28f78a29bb3453d075d55c0a7b1574c3bae19e941395eabbb9934073eef2de@127.0.0.1:0","enr":"0xf88fb840314fdfeda295b7bdfcfa72520885849888dae3f5054cf13b02569d9d15272ec149953ca0fdab37be304e3c314f453a3aff78855724625541e7dbae0ac5a5aea10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d5dfcc59c4faaf151e2776e409ecb40fa62ba49cf62037b1857207692f6458d9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"68pRjlFG9JrHW8qordLvTR0ixc/S4jJsa0GCbUXOVa4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ebca51\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 13bc 7cf4 6982 6210 | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 6 957d 82f0 b381 b841 | 33 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n002 7 db08 d224 d0f3 ce99 | 15 dc97 (0) dfae (0) db08 (0) d6ff (0)\n003 5 f361 f360 f74e f5c4 | 5 f74e (0) f5c4 (0) f410 (0) f361 (0)\n004 3 e0b1 e55d e77f | 5 e16b (0) e0ea (0) e0b1 (0) e55d (0)\n005 2 ed32 edc8 | 2 ed32 (0) edc8 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 ea0e ea60 | 2 ea0e (0) ea60 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","private_key":"3d5e22365b5c9d1fdeb13d45cd12ef39ca2553f7d838ed915e74c428827504e0","name":"node_ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","services":["bzz","pss"],"enable_msg_events":true,"port":46379},"up":true}},{"node":{"info":{"id":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","name":"node_cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","enode":"enode://dc20237eda8fa674c764f707dd28b4c1e19ad46cbb7206be66d38eac7d630e4047f8dde066f6946ccef3c6b197e5b3b3a3dc60e0590ed7af75c63287f70a0a75@127.0.0.1:0","enr":"0xf88fb840af3cea3226ce0700aa6c6adfefb1f86b66df4dcfe207c13f42675d0f2375ea654d37d12e6bdfa169779ee5783787cc49c83bd4b25575dfe986252e7aff23216f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dc20237eda8fa674c764f707dd28b4c1e19ad46cbb7206be66d38eac7d630e40","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"y8XUKVG8bhhylrX4zk0E5HLiZnCmKFHznWXzHFCGX2o=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cbc5d4\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 0ff6 06b9 0427 027f | 65 109e (0) 13bc (1) 1929 (0) 1be4 (0)\n001 6 92a1 b381 b16d b841 | 33 a75a (0) a7a6 (0) a2ba (0) a320 (0)\n002 3 f360 edc8 ebca | 15 f361 (0) f360 (0) f74e (0) f5c4 (0)\n003 4 dfae db08 d224 d0f3 | 6 dc97 (0) dfae (0) db08 (0) d6ff (0)\n004 2 c3a1 c181 | 2 c3a1 (0) c181 (0)\n005 4 cdcd cfbb ce99 cec3 | 4 cdcd (0) cfbb (0) ce99 (0) cec3 (0)\n============ DEPTH: 6 ==========================================\n006 1 c8e5 | 1 c8e5 (0)\n007 1 ca03 | 1 ca03 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","private_key":"b4f4e78aa0688362953df7a69f8c6cdf22151679efa7d71ae0d29d64348105e8","name":"node_cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","services":["bzz","pss"],"enable_msg_events":true,"port":38181},"up":true}},{"node":{"info":{"id":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","name":"node_7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","enode":"enode://1f9e2e5916cccc7c7134cfa950fd528992f3fe0cbfa44ca1ea2a878752c3e5841e41803494191b3e9009d2cfa0dc612e127490a75d21164eb4adca2514b011b6@127.0.0.1:0","enr":"0xf88fb84035545a7728c7f874e5cb8ed3369cfdc416e36f6462741040c8c5c6693860e0c6084d4da3f1318070c10b0958611e7fe3f63780cb689743695cbaf7f8bffbc4ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f9e2e5916cccc7c7134cfa950fd528992f3fe0cbfa44ca1ea2a878752c3e584","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fPSDinyDpzbOWc+huXRnSgGF2+F6jzzSl5Sju+gUre4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7cf483\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b486 ebca cbc5 | 63 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n001 4 3e56 0ff6 026d 06b9 | 27 109e (0) 13bc (0) 1929 (0) 1be4 (0)\n002 7 5d60 5776 4167 419a | 15 5a01 (0) 5abc (0) 5d60 (0) 539d (0)\n003 5 6210 645b 6742 6c82 | 11 6e5c (0) 6ecb (0) 6d60 (0) 6c02 (0)\n004 5 757a 772e 7639 73b8 | 6 7355 (0) 734e (0) 73b8 (0) 757a (0)\n005 2 78cb 7b92 | 2 7b92 (0) 78cb (0)\n============ DEPTH: 6 ==========================================\n006 2 7f87 7fbc | 2 7f87 (0) 7fbc (0)\n007 1 7dc5 | 1 7dc5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","private_key":"f8097f48d51332321d9d6d051a647bcc23dc5f6d3d90af68302348ec6554eb2c","name":"node_7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","services":["bzz","pss"],"enable_msg_events":true,"port":35111},"up":true}},{"node":{"info":{"id":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","name":"node_7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","enode":"enode://e828a02c476bfb4f9e77624db84d48a68fbe905c50586631faff90022af54eadba081aafe50144c86cb2d8c87f5da11a72f2824fd6e5fee8a4788b73232c0b06@127.0.0.1:0","enr":"0xf88fb840d7e722a5a02da1ba8ba198af44bd707ae67cb31ac9ba6bb979e42378114d7c467b0ae58de3699cd853cab121b1714bbeaa20692c31bf959346c9a2558080616a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e828a02c476bfb4f9e77624db84d48a68fbe905c50586631faff90022af54ead","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f7wYQ+IiLjyONaMhXRu7TVRX2LntM3SeB+IvJbqe5XY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7fbc18\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 ca03 c8e5 cfbb ce99 | 63 dc97 (0) dfae (0) db08 (0) d6ff (0)\n001 3 3e56 0ff6 06b9 | 27 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n002 3 4167 419a 41b9 | 15 5d60 (0) 5a01 (0) 5abc (0) 517a (0)\n003 4 6c82 6982 6210 6742 | 11 645b (0) 667e (0) 6728 (0) 6742 (0)\n004 4 772e 7639 7355 73b8 | 6 734e (0) 7355 (0) 73b8 (0) 757a (0)\n005 2 78cb 7b92 | 2 78cb (0) 7b92 (0)\n============ DEPTH: 6 ==========================================\n006 2 7dc5 7cf4 | 2 7dc5 (0) 7cf4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 7f87 | 1 7f87 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","private_key":"2a6bc25e58ea6c30639feb4e97a394af64178e6a42aaab9b082079c20f02434e","name":"node_7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","services":["bzz","pss"],"enable_msg_events":true,"port":40281},"up":true}},{"node":{"info":{"id":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","name":"node_86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","enode":"enode://160b7b02fe623f5d12e809600a6b47beeb4b30b2951dd67841739f40d54b98b2549eba0adfd40193ef0171a252a403d74752d6b9b7f68c89f18dda26437b2c59@127.0.0.1:0","enr":"0xf88fb8407c73d98812b302dac9f29fe48726b92a0dfa7517895f046594c3773f02a3e4e420da6443c739e51a2ccb79bfa2681764763bf1e4d8dcf515239dd132259941530183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103160b7b02fe623f5d12e809600a6b47beeb4b30b2951dd67841739f40d54b98b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hsoQeNrkDyOuGzrEc5dGDZ7AvyQ6DeNytAU4HWci/LI=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 86ca10\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4167 7fbc | 65 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n001 7 ea60 e77f d224 cec3 | 30 dc97 (0) dfae (0) db08 (0) d6ff (0)\n002 4 a085 a7a6 ad0d aebd | 17 a2ba (0) a320 (0) a085 (0) a75a (0)\n003 5 9ee7 9a92 9626 957d | 8 9a92 (0) 9d3c (0) 9e02 (0) 9ee7 (0)\n004 4 8cf9 895b 8b76 8be4 | 5 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n============ DEPTH: 5 ==========================================\n005 2 83dc 82f0 | 2 83dc (0) 82f0 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","private_key":"f6fd1d1772c650e60c41e06f59fc6bba67d5cc264f8fe14e6908e77e9c43f9e2","name":"node_86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","services":["bzz","pss"],"enable_msg_events":true,"port":46147},"up":true}},{"node":{"info":{"id":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","name":"node_4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","enode":"enode://a7bb630e0a99ad26a47f5bcf331536335c3e04dd4ffdbd27f229ec42dcc5eb7016e0e5f2cb8b3cf3489a317e161fdbc729703ba936b737ee2295a4b87f070e41@127.0.0.1:0","enr":"0xf88fb8402c97a2dc8b64057107147453b6c09e3c44ef973679e5658b0b6d0b2b187c4853555cb891d58dbfd328bb8cb83e55bad3c63f3fb185644e4684308ee0bc87b7550183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a7bb630e0a99ad26a47f5bcf331536335c3e04dd4ffdbd27f229ec42dcc5eb70","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QWeUbeJQsBPhvhbuhL/izKroPmmeYYs48xAWxOQx5ro=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 416794\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f410 86ca | 63 dfae (0) dc97 (0) db08 (0) d6ff (0)\n001 4 13bc 0ff6 018a 06b9 | 27 1929 (0) 1be4 (0) 109e (0) 13bc (0)\n002 13 7b92 78cb 7cf4 7f87 | 23 645b (0) 667e (0) 6728 (0) 6742 (0)\n003 3 5a01 539d 5776 | 7 5d60 (0) 5abc (0) 5a01 (0) 517a (0)\n004 4 4b24 4a18 48b6 4cd0 | 4 4b24 (0) 4a18 (0) 48b6 (0) 4cd0 (0)\n005 1 47c3 | 1 47c3 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 2 41b9 419a | 2 41b9 (0) 419a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","private_key":"2e633e4e9e522151a2b2bd98030f66cd31b2e81feb8ab86004b194a703e3fb86","name":"node_4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","services":["bzz","pss"],"enable_msg_events":true,"port":42087},"up":true}},{"node":{"info":{"id":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","name":"node_f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","enode":"enode://df462c25ee8bcaf3bcfd05af911c6466c62d31175cf9c44288595b39729d64e7a2e81626fe01bc61b0036fbf2dadb271171e7e9c6812214526b2f1c83e6c5881@127.0.0.1:0","enr":"0xf88fb8404a32ca40db377ce80d0e646c9643936683374ce6e8ec14963aae37672d13490f2f06bf8861a4b5f426b9f70eb96e75389076f3d92ce641abc9191a362c185bb00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df462c25ee8bcaf3bcfd05af911c6466c62d31175cf9c44288595b39729d64e7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9BDUrJt0jCT6DUjDBTuxzqimfQvMTl/L2yYcDHUizDQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f410d4\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 3ee4 0ff6 06b9 0427 | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 5 b381 a7a6 82f0 957d | 33 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n002 2 ca03 d224 | 15 dc97 (0) dfae (0) db08 (0) d6ff (0)\n003 4 e16b e77f ea60 ebca | 10 e16b (0) e0b1 (0) e0ea (0) e55d (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 2 f361 f360 | 2 f361 (0) f360 (0)\n006 1 f74e | 1 f74e (0)\n007 1 f5c4 | 1 f5c4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","private_key":"a9a777290064b28ab9e2bd8edfcf9cf14e40ba8fb169ba18ec322bebd1e9796c","name":"node_f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","services":["bzz","pss"],"enable_msg_events":true,"port":46863},"up":true}},{"node":{"info":{"id":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","name":"node_92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","enode":"enode://d4f739677902ad2701144cab8f87489253d25aeda47e8ed5817e4562ddaae678ffe9c52f8716f132ce74f96161ed770ccc5627a11dca2ea4024b49b8a6054f11@127.0.0.1:0","enr":"0xf88fb8400fb72975a9f5e05d571cc9bc2a2acf555ccd87f5b870d76b312c9964b17f7bc45382dd2fc4e0c93ff5987f761bc2e9faa304c2be53ed8588128a89d0b881c5750183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d4f739677902ad2701144cab8f87489253d25aeda47e8ed5817e4562ddaae678","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"kqFQHtQeKbt92OtLSs7K6YP0x8g/OYlc1o94ELZF8d0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 92a150\npopulation: 24 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7b92 7639 419a | 65 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n001 8 d224 d0f3 ca03 cbc5 | 30 c181 (0) c3a1 (0) cdcd (0) cfbb (0)\n002 3 afa3 a7a6 b841 | 17 a320 (0) a2ba (0) a085 (0) a75a (0)\n003 3 8be4 86ca 82f0 | 8 83dc (0) 82f0 (0) 86ca (0) 8cf9 (0)\n004 4 9a92 9d3c 9e02 9ee7 | 4 9d3c (0) 9e02 (0) 9ee7 (0) 9a92 (0)\n============ DEPTH: 5 ==========================================\n005 2 9626 957d | 2 9626 (0) 957d (0)\n006 1 91eb | 1 91eb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","private_key":"d99269d5a3d87afd088aa258ab85c5ee8f988fdd019689f5f639b1e488b7abae","name":"node_92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","services":["bzz","pss"],"enable_msg_events":true,"port":43101},"up":true}},{"node":{"info":{"id":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","name":"node_b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","enode":"enode://8df6b1e4435d4b72ae0f6dcda1002d86349ac28a9b9a182692a0fd2cb5f10255b8f960fddb898e957a04daa3a6b3f6aa6ef97bed544b4b99ad81edff6707d20f@127.0.0.1:0","enr":"0xf88fb840b8517e545b313545c0b7003080e9c0b7e74c291b272d1e018dc8684a4ca24bcc4f7af3c9997eb09cf50e46161d175a929d29372f4a73ec5cb21e06b0c6d0146e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038df6b1e4435d4b72ae0f6dcda1002d86349ac28a9b9a182692a0fd2cb5f10255","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uEEfGY/WWMWiAog1wK8zQhRYOcBsik84LZ+d5IXUbAg=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8411f\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 06b9 419a 73b8 | 65 5a01 (0) 5abc (0) 5d60 (0) 5776 (0)\n001 6 db08 cbc5 e77f e55d | 30 f74e (0) f410 (0) f5c4 (0) f361 (0)\n002 6 82f0 8be4 9d3c 9ee7 | 16 83dc (0) 82f0 (0) 86ca (0) 8cf9 (0)\n003 5 a7a6 a085 ad0d afa3 | 9 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n004 4 b486 b16d b381 b2b9 | 5 b70e (0) b486 (0) b16d (0) b381 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 0 | 0\n007 1 b92a | 1 b92a (0)\n008 1 b8e1 | 1 b8e1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","private_key":"949877f6e6d76788923054b7bd6526b9001f04a77df87bc9161352dc5453e5bc","name":"node_b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","services":["bzz","pss"],"enable_msg_events":true,"port":33251},"up":true}},{"node":{"info":{"id":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","name":"node_8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","enode":"enode://fc32bff950e71029ffb87f1cd11cd8b80e17e8a1bb87da502f53a1ce59ae43cfe17583075dd14d54a9e2e5f0a45ea7a7e66a3ef496ff5fbe5170bb5cf2c94b21@127.0.0.1:0","enr":"0xf88fb840c686f651105296aa062d5461136529224697c9783747504a33939d92f192c56e1b9b95e2c2493d32ede538f135f81cc3e3ec89f91ba1d068c056c407c775d30c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fc32bff950e71029ffb87f1cd11cd8b80e17e8a1bb87da502f53a1ce59ae43cf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"i+RhID9eu1chNI9TezfXaPe9NZrz4Y0ffpry+QHEmEU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8be461\npopulation: 26 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 419a 7b92 73b8 | 65 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n001 6 ea60 e77f f360 c8e5 | 30 f74e (0) f5c4 (0) f410 (0) f361 (0)\n002 5 a7a6 ad0d afa3 aebd | 17 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n003 5 9d3c 9ee7 9a92 92a1 | 8 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n004 3 86ca 83dc 82f0 | 3 86ca (0) 83dc (0) 82f0 (0)\n005 1 8cf9 | 1 8cf9 (0)\n============ DEPTH: 6 ==========================================\n006 2 89c8 895b | 2 89c8 (0) 895b (0)\n007 0 | 0\n008 1 8b76 | 1 8b76 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","private_key":"0f6530f636582633a6311f48aa9d253eab18b87cbebe43f367a159aa3c241c46","name":"node_8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","services":["bzz","pss"],"enable_msg_events":true,"port":45015},"up":true}},{"node":{"info":{"id":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","name":"node_aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","enode":"enode://f282cd19ae6a9df87585322507e574bc32df4841972dd882a9a05870050a1b598c8fc33af74f96a6420a9880385812d048ace508f80750a8de0cb24c56212d78@127.0.0.1:0","enr":"0xf88fb84031ffcecf6c8f21aa2106e8d9bbdaa2414c925860a95299b3ade0ebacc68255dc2f7eb3419664abbd0c8819f34be4a3452dfb3fdd59dd7c81c6133f3c7b98d96b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f282cd19ae6a9df87585322507e574bc32df4841972dd882a9a05870050a1b59","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rr1hNdECUrB/iRs6czCQP68T1AnE9xCGMHFfoHVPk44=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aebd61\npopulation: 29 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 3e56 3ee4 13bc 0ff6 | 65 018a (0) 0390 (0) 0218 (0) 026d (0)\n001 5 f360 e77f ebca d224 | 30 f74e (0) f5c4 (0) f410 (0) f361 (0)\n002 5 9d3c 9ee7 82f0 86ca | 16 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n003 3 b841 b2b9 b381 | 8 b70e (0) b486 (0) b16d (0) b381 (0)\n004 4 a7a6 a320 a2ba a085 | 5 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 ad0d | 1 ad0d (0)\n007 1 afa3 | 1 afa3 (0)\n008 1 ae67 | 1 ae67 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","private_key":"1052de44bfe98977c2f57b1304d18f99ad509385a540c598539f43a9fd01a076","name":"node_aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","services":["bzz","pss"],"enable_msg_events":true,"port":32913},"up":true}},{"node":{"info":{"id":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","name":"node_4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","enode":"enode://26c256c0419d8280c23d163c3dada761578f80e066c614882b6efe25eb4b5d9e06e50aa77e5306508227275d3ad527fc67dca7f4c3066a7e89e5b7d0b48cf106@127.0.0.1:0","enr":"0xf88fb840d136e30739a296b8258bac9b8c021058e3b129b00b86eefcae768e963d71000d436fb91ca2511d958b15dbd33372cf80dd57a8b2d6439fd1a7a261f5d8d66feb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10226c256c0419d8280c23d163c3dada761578f80e066c614882b6efe25eb4b5d9e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TNDzjlKlCPgc+V4TcMmUrqLXpJoqCOPgVPU2KaZhlBA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4cd0f3\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b2b9 b381 aebd | 63 f74e (0) f5c4 (0) f410 (0) f361 (0)\n001 7 13bc 0ff6 0bcf 027f | 27 018a (0) 0390 (0) 0218 (0) 026d (0)\n002 9 6728 6742 6ecb 6982 | 23 757a (0) 772e (0) 7639 (0) 734e (0)\n003 2 5a01 539d | 7 558e (0) 5776 (0) 517a (0) 539d (0)\n004 4 47c3 4167 41b9 419a | 4 47c3 (0) 4167 (0) 41b9 (0) 419a (0)\n============ DEPTH: 5 ==========================================\n005 3 4a18 4b24 48b6 | 3 4a18 (0) 4b24 (0) 48b6 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","private_key":"bc76c03a436db84839741888c68b1cdddedd194bc0c48dd035a5b8fce7fa6f2b","name":"node_4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","services":["bzz","pss"],"enable_msg_events":true,"port":38223},"up":true}},{"node":{"info":{"id":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","name":"node_2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","enode":"enode://d7f147b4838d04a590e69acd66b2f879e2de85f8607e998c3e8c35841145bbe75feb3b9a00e5c33fe2185506151da35ab450699981b512c4dcf86ec22e5538e6@127.0.0.1:0","enr":"0xf88fb8400f37b8427aa3076dbc1caa48263b9df3bc54fe10fadece63d56c92ecd89cbe31074c7a98aa40bbd3a1d5adf1c59ce9dbf534f2d891b802986e99ee22585328ec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d7f147b4838d04a590e69acd66b2f879e2de85f8607e998c3e8c35841145bbe7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JFn+klCzMRyGUw0At6m4ulextRUcEmJi5wxV0ejTeSQ=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2459fe\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 a085 afa3 ea60 cec3 | 63 e0b1 (0) e0ea (0) e16b (0) e77f (0)\n001 11 757a 7639 7355 7b92 | 38 757a (0) 772e (0) 7639 (0) 734e (0)\n002 7 0bcf 0ff6 0427 06b9 | 15 0506 (0) 0427 (0) 06b9 (0) 018a (0)\n003 5 372d 38ab 3cb1 3ee4 | 6 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n004 2 2a22 286a | 2 2a22 (0) 286a (0)\n005 1 213b | 1 213b (0)\n============ DEPTH: 6 ==========================================\n006 1 26d1 | 1 26d1 (0)\n007 0 | 0\n008 0 | 0\n009 1 2434 | 1 2434 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","private_key":"4c8204f3f41c8735aa70c249cbaa8f57ea41b39b651490de8de8c12fd2691eaa","name":"node_2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","services":["bzz","pss"],"enable_msg_events":true,"port":37643},"up":true}},{"node":{"info":{"id":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","name":"node_698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","enode":"enode://d6a014202d01536e4928ed4efbe17f6d6a7fa8fc624bafce75e43cd1f25f6aeb2a474087e08c4e0b49a38a5e4486fa8c08092f00164df92082dec0fbd9834433@127.0.0.1:0","enr":"0xf88fb840151b4bf6e849b0ac2ec218151f8dfa803c5b5d34733bf46e1c711e9d2ba90c6c6a9084cf38dcd6cc4ccc77d3aa6b062ad0ccd53666db1de1d30ace82ce35afb10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d6a014202d01536e4928ed4efbe17f6d6a7fa8fc624bafce75e43cd1f25f6aeb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aYJH0QOokl2LtMVqMFbknF78WV/O0cidSZQ7uboB85Q=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 698247\npopulation: 35 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 cbc5 ca03 c8e5 c3a1 | 63 e0ea (0) e0b1 (0) e16b (0) e77f (0)\n001 2 3ee4 2459 | 27 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n002 4 4167 419a 4cd0 48b6 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 10 7639 7355 734e 73b8 | 12 757a (0) 772e (0) 7639 (0) 734e (0)\n004 3 6210 6728 6742 | 5 6210 (0) 645b (0) 667e (0) 6728 (0)\n============ DEPTH: 5 ==========================================\n005 5 6e5c 6ecb 6d60 6c82 | 5 6e5c (0) 6ecb (0) 6c82 (0) 6c02 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","private_key":"20311624a5a56cae7a90aedb142273ff36c5f5d52598fa621d5e388c078ca94f","name":"node_698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","services":["bzz","pss"],"enable_msg_events":true,"port":40773},"up":true}},{"node":{"info":{"id":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","name":"node_6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","enode":"enode://84717a6835e106aad3b6c055224217d5d064ac8909100b55eaabc37dc20949be1f33a3b838405bcd5e71cbfbb69170d21ff07952aab37534f965efccaf979d50@127.0.0.1:0","enr":"0xf88fb840d2f711c921f221581b2944e9166c506e85656605df5d204f343f836509260aa24240127b85cb3cf9945ddb9030e85db8e5e6f393b31b1b7cda2cd36a8eeda4110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10284717a6835e106aad3b6c055224217d5d064ac8909100b55eaabc37dc20949be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z0LMobd4P8vtjQs0BQj5PMTfrKj/PxP9WTVEhsTWKZM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6742cc\npopulation: 27 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 b2b9 b381 957d 82f0 | 63 ed32 (0) edc8 (0) ea60 (0) ea0e (0)\n001 2 26d1 13bc | 27 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n002 5 539d 4167 4cd0 4b24 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 9 7639 734e 7355 73b8 | 12 757a (0) 772e (0) 7639 (0) 734e (0)\n004 3 6d60 6c82 6982 | 6 6e5c (0) 6ecb (0) 6c02 (0) 6c82 (0)\n005 1 6210 | 1 6210 (0)\n006 1 645b | 1 645b (0)\n============ DEPTH: 7 ==========================================\n007 1 667e | 1 667e (0)\n008 0 | 0\n009 1 6728 | 1 6728 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","private_key":"0cb73f4cde658fd3ac83b434133145d5fbd0bf4f9ab6e3923171d443eba90568","name":"node_6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","services":["bzz","pss"],"enable_msg_events":true,"port":40229},"up":true}},{"node":{"info":{"id":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","name":"node_82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","enode":"enode://e8117dddd5f5e8f212dbd7147bd8bf02068ddb0e94123d323731d22a7f0103610057f6ae1a76d6442bef79f3ae52f0faf62c535b759ee126461f402b83ba45bd@127.0.0.1:0","enr":"0xf88fb840d046f5dff4971dc895e66458c436e6e3a27c96b8d53df7b3b9ad0e77f4345ed32a7b206c7a3d662fd18b0f7a404a7dc243abbdc9a8a677f9973dd2b99af279ff0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e8117dddd5f5e8f212dbd7147bd8bf02068ddb0e94123d323731d22a7f010361","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gvA024j9JrR8JrlcP4eh9FT/5FJq6GvrK7HY8sIYwlw=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 82f034\npopulation: 34 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6982 6742 | 65 06b9 (0) 0506 (0) 0427 (0) 018a (0)\n001 9 f360 f410 f5c4 ebca | 30 e77f (0) e55d (0) e0ea (0) e0b1 (0)\n002 9 a085 a2ba ad0d aebd | 17 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n003 7 9a92 9ee7 9e02 9d3c | 8 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n004 5 8cf9 89c8 895b 8b76 | 5 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n============ DEPTH: 5 ==========================================\n005 1 86ca | 1 86ca (0)\n006 0 | 0\n007 1 83dc | 1 83dc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","private_key":"c43af8c1c17ec355ac7f8bef6f05ba9db12db47c9e201a266d0d65065798ba3c","name":"node_82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","services":["bzz","pss"],"enable_msg_events":true,"port":33523},"up":true}},{"node":{"info":{"id":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","name":"node_b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","enode":"enode://a22d89dcb4290953d158b22c35c5c68eeb5e11220f22b58314ba70f7fc2b7603b7c6e1ff81f0dd1b53230d0a89eab8629e5629a51e8933fa5561cf04542b202a@127.0.0.1:0","enr":"0xf88fb8400a3de612482002f22886dbd86e19870d74873631d82f29687df78027690518e16dc049dcbcfbe0ea0984b62dd97074247757a9c4675a87c49da61843ca343e2d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a22d89dcb4290953d158b22c35c5c68eeb5e11220f22b58314ba70f7fc2b7603","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"srmsD021iIZZevexnWFQSYrIrXyARnFiiqNDhLj+UF4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2b9ac\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 6d60 6742 6728 667e | 65 5d60 (0) 5abc (0) 5a01 (0) 558e (0)\n001 2 f5c4 d224 | 30 ed32 (0) edc8 (0) ea60 (0) ea0e (0)\n002 5 91eb 9d3c 9ee7 9a92 | 16 9ee7 (0) 9e02 (0) 9d3c (0) 9a92 (0)\n003 6 a75a a085 a2ba ad0d | 9 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n004 3 b92a b8e1 b841 | 3 b92a (0) b8e1 (0) b841 (0)\n005 2 b486 b70e | 2 b486 (0) b70e (0)\n============ DEPTH: 6 ==========================================\n006 1 b16d | 1 b16d (0)\n007 1 b381 | 1 b381 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","private_key":"468f3a0090d15106e770801e7f4f0fc26bf78d3698be131eb3585ca410116084","name":"node_b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","services":["bzz","pss"],"enable_msg_events":true,"port":42099},"up":true}},{"node":{"info":{"id":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","name":"node_3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","enode":"enode://4b65a104001fb3c5edd9eb6477d5e7daca674195a347fa8deb71a83931f3475569a6ee580c248b2243c09b8787be153f817ee6b282fb0572424fa91c9243ffb6@127.0.0.1:0","enr":"0xf88fb8409d8ea451f2658de612662bd9b07a86cb819f781fa9d8f8e1350199a2666dae1d498b271416d9b6f88a3f0468d2f2971a017e78e789d14596d7ca1b56365597d10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024b65a104001fb3c5edd9eb6477d5e7daca674195a347fa8deb71a83931f34755","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PlbUUz7BT2ZW4esl+zXa1HydtHn2Z6a2/po6qMEumC4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3e56d4\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 ea60 d224 a085 aebd | 63 ed32 (0) edc8 (0) ea0e (0) ea60 (0)\n001 6 48b6 6c82 7639 7fbc | 38 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n002 5 0427 0ff6 0bcf 1929 | 15 06b9 (0) 0506 (0) 0427 (0) 018a (0)\n003 4 2a22 286a 26d1 2459 | 6 2a22 (0) 286a (0) 213b (0) 2434 (0)\n004 1 372d | 1 372d (0)\n005 2 39db 38ab | 2 39db (0) 38ab (0)\n============ DEPTH: 6 ==========================================\n006 1 3cb1 | 1 3cb1 (0)\n007 0 | 0\n008 1 3ee4 | 1 3ee4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","private_key":"3934a1eb89e5d3bd316aca133dcf3e380fe237373fdc981c7d7c138612ca06c2","name":"node_3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","services":["bzz","pss"],"enable_msg_events":true,"port":44945},"up":true}},{"node":{"info":{"id":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","name":"node_7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","enode":"enode://f8572034b7fc585c1903d4bb5879cf1ffbac94cbc1897edfe98d9b9f84d93d26b67f2abeb88ce77608ed262152ac3840f448f26a5a61afa46eea388e2f4b7a42@127.0.0.1:0","enr":"0xf88fb8400e94e52c2270cce5bdd17883b40ecc21d4ec6157af03e3c97775e38e6fc0370d63efe0aae8270863a14fb499442bdd706b616fb6843938b664eb2f43ba9fce8f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f8572034b7fc585c1903d4bb5879cf1ffbac94cbc1897edfe98d9b9f84d93d26","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"e5JCE3+Mwr7Hs+AAP9kwJpIc6xDfrbvVtqpk1hp0814=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7b9242\npopulation: 48 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 8be4 8cf9 957d 9626 | 63 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n001 14 13bc 0ab9 0bcf 0ff6 | 27 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n002 3 4167 48b6 4cd0 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 9 6982 6d60 6c02 6e5c | 11 6210 (0) 645b (0) 667e (0) 6728 (0)\n004 6 7639 772e 757a 734e | 6 757a (0) 772e (0) 7639 (0) 734e (0)\n============ DEPTH: 5 ==========================================\n005 4 7cf4 7dc5 7f87 7fbc | 4 7f87 (0) 7fbc (0) 7cf4 (0) 7dc5 (0)\n006 1 78cb | 1 78cb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","private_key":"5a6b556ff9b73fe0850c45f469fbfd6e6f0d2d5af3f3831f4376a08b8ca8a549","name":"node_7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","services":["bzz","pss"],"enable_msg_events":true,"port":39179},"up":true}},{"node":{"info":{"id":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","name":"node_73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","enode":"enode://14b035995d987becf991740865f7caa23bad70978a889984199627036686ab81a14519d760274790b6bacf5268d2e469987a4470aae895019e00d2d43d366278@127.0.0.1:0","enr":"0xf88fb84057f0098ffc99b981a4c2b43591db40bfbc63ac9be4c3abecc42ba157711a2e2a7c925f830e8fa6b04074eea3c2c534df67e40efc15f1bb75348fbed8d0d468870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10214b035995d987becf991740865f7caa23bad70978a889984199627036686ab81","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c7jRhA0Kj/5pdS7Jb4/d7LDiJybIeYLVcsqazByc2/w=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 73b8d1\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 8be4 b841 d6ff d224 | 63 9ee7 (0) 9e02 (0) 9d3c (0) 9a92 (0)\n001 3 3ee4 0bcf 13bc | 27 06b9 (0) 0427 (0) 0506 (0) 0390 (0)\n002 4 419a 4167 48b6 4cd0 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 6 6ecb 6982 667e 6728 | 11 6210 (0) 645b (0) 667e (0) 6728 (0)\n004 6 7dc5 7cf4 7f87 7fbc | 6 7f87 (0) 7fbc (0) 7cf4 (0) 7dc5 (0)\n005 3 772e 7639 757a | 3 772e (0) 7639 (0) 757a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 2 734e 7355 | 2 734e (0) 7355 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","private_key":"29694c9dcdcbd8510814aabcc1c9a32e23b92f4596464ba205244a4954cc0595","name":"node_73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","services":["bzz","pss"],"enable_msg_events":true,"port":36127},"up":true}},{"node":{"info":{"id":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","name":"node_d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","enode":"enode://235360aff6df4553e2efa53a861609209743e1ea81cd07f7bcbe80ae9fbf012a2caca09eb6dbac7be69d14d3805a552d18a626a6e5356659180c8d804f7f7ee3@127.0.0.1:0","enr":"0xf88fb840f7e66d84700fe9e82cd1cdeca1acbb2242b09a69b0e50173bac5c41180f1f8d14138152b7755e0228ce2d6b526c3c01bdddaabf90a2a856f715944f373533aef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103235360aff6df4553e2efa53a861609209743e1ea81cd07f7bcbe80ae9fbf012a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0iRfBnm0NvqrwBZOC4XgLi7/utMG6CKbVVUkpebRpfk=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d2245f\npopulation: 43 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 286a 2459 3ee4 3e56 | 65 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n001 12 895b 8be4 86ca 82f0 | 33 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n002 5 ebca ea60 e16b f5c4 | 15 e55d (0) e77f (0) e0ea (0) e0b1 (0)\n003 9 c181 c3a1 c8e5 ca03 | 9 c181 (0) c3a1 (0) c8e5 (0) ca03 (0)\n004 3 db08 dfae dc97 | 3 dfae (0) dc97 (0) db08 (0)\n============ DEPTH: 5 ==========================================\n005 1 d6ff | 1 d6ff (0)\n006 1 d0f3 | 1 d0f3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","private_key":"658311d7ee69a3bf84aa43c15ac573ea72807a5e080c322310e7bc701ab52fab","name":"node_d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","services":["bzz","pss"],"enable_msg_events":true,"port":38759},"up":true}},{"node":{"info":{"id":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","name":"node_b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","enode":"enode://b72f0a95514b0161e67d4b36b1dc91cb319117d3f1c34731bb2c685769f11741575d3c41f4c1c8188b85f47c62b149e4f3e5f72394ebc5780c85c06528570c33@127.0.0.1:0","enr":"0xf88fb84012121d864e031d97c287200a10956bbe49c61b0fcb145897fa0a4a0da21a317d48aff38a1901706b29ce01ec8bc17ee9be0c1764a516acafc5cd40048dfe61690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b72f0a95514b0161e67d4b36b1dc91cb319117d3f1c34731bb2c685769f11741","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s4HnXlLkzdFoBWJF+C06F0e2f0AOtA6xIDa3Puf+IeU=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b381e7\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0ff6 6742 48b6 4cd0 | 65 558e (0) 5776 (0) 517a (0) 539d (0)\n001 13 f5c4 f410 f360 ebca | 30 e77f (0) e55d (0) e0ea (0) e0b1 (0)\n002 5 82f0 9d3c 9ee7 91eb | 16 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n003 7 a7a6 a75a a2ba a085 | 9 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n004 3 b8e1 b841 b92a | 3 b92a (0) b8e1 (0) b841 (0)\n005 2 b486 b70e | 2 b486 (0) b70e (0)\n============ DEPTH: 6 ==========================================\n006 1 b16d | 1 b16d (0)\n007 1 b2b9 | 1 b2b9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","private_key":"78a74e69c0e211af6e3f2806e5cf0475ccdb1b5ccfba14e1968b82747e20be0a","name":"node_b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","services":["bzz","pss"],"enable_msg_events":true,"port":44485},"up":true}},{"node":{"info":{"id":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","name":"node_957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","enode":"enode://61d644b51f9244f36e197d9d614070a5487f071bc7c7753d43edb80f72e5a2c43cda36d5b2f9f070228bb54c8810c5789af96b66be77a6df61aabfffe5da4c8f@127.0.0.1:0","enr":"0xf88fb840d573110433511ff59f78b0fe666d311957c43ee0f9ef6c673d1f53736e1d4b9f6c77c5620e6c97f670e61f3e1d83f77ce36c004b9587fb9ddd3bcc8486e455320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10361d644b51f9244f36e197d9d614070a5487f071bc7c7753d43edb80f72e5a2c4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lX2Km0Erb0zRUcvAe4102UmICuZlxUXeuxgYE4nJnuY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 957d8a\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 7b92 6ecb 6d60 6742 | 65 6210 (0) 645b (0) 667e (0) 6742 (0)\n001 13 f5c4 f410 f360 e0ea | 30 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n002 2 b92a b381 | 17 a75a (0) a7a6 (0) a320 (0) a2ba (0)\n003 3 8be4 86ca 82f0 | 8 8cf9 (0) 895b (0) 89c8 (0) 8b76 (0)\n004 4 9a92 9e02 9ee7 9d3c | 4 9e02 (0) 9ee7 (0) 9d3c (0) 9a92 (0)\n============ DEPTH: 5 ==========================================\n005 2 92a1 91eb | 2 91eb (0) 92a1 (0)\n006 1 9626 | 1 9626 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","private_key":"9cbb036a358368a04ab266b8fd487e4bcfead509da1f1d57b0e7fa3db574c99c","name":"node_957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","services":["bzz","pss"],"enable_msg_events":true,"port":46189},"up":true}},{"node":{"info":{"id":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","name":"node_26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","enode":"enode://1999562f9de6c42f0577c494aec14691db3aec49ed40e75ea9eedb72e5295d9d0d659f4991946f9fbacc74feaeb5e5181dc23ba10299dd01ec1dec9c00d84ad1@127.0.0.1:0","enr":"0xf88fb84017d136a2bd2b8c6b071ea759278494f6636844e06c788ffe4eff0e1226cd0b0864d646c596173bbf67bc7403a5623bcd2d044273ed7d5c0efbeee8916cc39cc70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031999562f9de6c42f0577c494aec14691db3aec49ed40e75ea9eedb72e5295d9d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JtGvH77mVBo2PqdweCXjfaAoFC8Ad5EWVgrSDx3hjns=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26d1af\npopulation: 31 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 e16b d0f3 a085 89c8 | 63 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n001 8 4b24 48b6 6742 6728 | 38 6210 (0) 645b (0) 667e (0) 6742 (0)\n002 7 13bc 1929 06b9 0390 | 15 0427 (0) 0506 (0) 06b9 (0) 018a (0)\n003 5 372d 39db 3cb1 3e56 | 6 372d (0) 39db (0) 38ab (0) 3cb1 (0)\n004 2 286a 2a22 | 2 286a (0) 2a22 (0)\n005 1 213b | 1 213b (0)\n============ DEPTH: 6 ==========================================\n006 2 2434 2459 | 2 2434 (0) 2459 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","private_key":"7e2c84991a191ba4057e485ef2cfc2020c5ccac17ccaace8db0733f7bea4b410","name":"node_26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","services":["bzz","pss"],"enable_msg_events":true,"port":44455},"up":true}},{"node":{"info":{"id":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","name":"node_3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","enode":"enode://5c685dacbd760c9d05b018f58ac52239966ab2c181ec106125ebad06ab336c7cc4087f4f32a38e9b17edcabd74afe7fd36bbd33e12542ca0646b98bd7e11d489@127.0.0.1:0","enr":"0xf88fb84065e447a80639420887319bbbd8ff453a67c8f00fa8ddcbbbf04b02d24240226a600ae407deabfe11ae74c2b0dc46e86f08d9f08d4d77a1df3e3f3f41dacd5ac10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035c685dacbd760c9d05b018f58ac52239966ab2c181ec106125ebad06ab336c7c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PuSyDAR+cBtYwG/MgWA2S9KVc/YfTZ8ZNdd6wp9qHoY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3ee4b2\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 89c8 a085 aebd ae67 | 63 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n001 8 5776 47c3 7639 73b8 | 38 6d60 (0) 6c82 (0) 6c02 (0) 6e5c (0)\n002 9 0ab9 0bcf 0427 06b9 | 15 0506 (0) 0427 (0) 06b9 (0) 018a (0)\n003 3 286a 2459 26d1 | 6 286a (0) 2a22 (0) 213b (0) 2434 (0)\n004 1 372d | 1 372d (0)\n005 2 39db 38ab | 2 39db (0) 38ab (0)\n============ DEPTH: 6 ==========================================\n006 1 3cb1 | 1 3cb1 (0)\n007 0 | 0\n008 1 3e56 | 1 3e56 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","private_key":"452609d27fac9e357776f968c4726676474f4f5fdc9da0bf89f6362b3ba19ff2","name":"node_3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","services":["bzz","pss"],"enable_msg_events":true,"port":41679},"up":true}},{"node":{"info":{"id":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","name":"node_13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","enode":"enode://6016e452462a437136ffaab5816dde72ff1910f4a456f38c172033a88cc4e204cd4c199e769f890c78f4db86f19416a9522fdeb434384eedc3c2f1ef28b88acc@127.0.0.1:0","enr":"0xf88fb840149fc3c3a63d0f1305a848030d0a2b93385095eec084ca87fb44428c87d118f37da0a3ca28e3f65c085d3befbc01cbe7cf22d90d1d9ed4df2d4ae92c6c4245dc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026016e452462a437136ffaab5816dde72ff1910f4a456f38c172033a88cc4e204","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E7xkU1065JUJjkrGswqR0YBNqwq3mUTyxqxTybzN9i0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 13bc64\npopulation: 40 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 cec3 c3a1 f5c4 f410 | 63 ed32 (0) edc8 (0) ea0e (0) ea60 (0)\n001 8 4cd0 4b24 4167 7b92 | 38 7639 (0) 772e (0) 757a (0) 73b8 (0)\n002 5 2a22 26d1 2459 3e56 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 11 0ff6 0ab9 0bcf 0427 | 11 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n============ DEPTH: 4 ==========================================\n004 2 1be4 1929 | 2 1be4 (0) 1929 (0)\n005 0 | 0\n006 1 109e | 1 109e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","private_key":"8434ae4dfa2723b5719768bc711f7425c5bd0924b3b0ec5d8cc2c9b399b5766a","name":"node_13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","services":["bzz","pss"],"enable_msg_events":true,"port":40705},"up":true}},{"node":{"info":{"id":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","name":"node_9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","enode":"enode://b7082416512639ee57846e95b5e2dbc63995f361401c3b313732cf2d3d033441790dce7c2460efd7937015b4638e6247ed82c823aa0802925c366c91ae09e68b@127.0.0.1:0","enr":"0xf88fb84099372399c4d3fd5cadf0c624920ed74d76194f722b61996a6a6c99fbce6110170e82d7b4d993a5850e772df12e975549b3191f0cf7f6abae21e9a136f6bff1cc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b7082416512639ee57846e95b5e2dbc63995f361401c3b313732cf2d3d033441","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mpIws/fzhlIIId7njr6S6MZKT2pQ8mOTJ8YuRcq0BWM=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9a9230\npopulation: 25 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7b92 7355 39db 13bc | 65 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n001 2 e16b f5c4 | 30 edc8 (0) ed32 (0) ea60 (0) ea0e (0)\n002 6 ad0d a75a b70e b2b9 | 17 b92a (0) b8e1 (0) b841 (0) b486 (0)\n003 6 83dc 82f0 86ca 8cf9 | 8 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n004 4 92a1 91eb 957d 9626 | 4 92a1 (0) 91eb (0) 957d (0) 9626 (0)\n============ DEPTH: 5 ==========================================\n005 3 9ee7 9e02 9d3c | 3 9ee7 (0) 9e02 (0) 9d3c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","private_key":"e878354e1d0c9956e28fa14cdc5a61945f6f2b2fbea9a8367dbe5f064b174592","name":"node_9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","services":["bzz","pss"],"enable_msg_events":true,"port":35207},"up":true}},{"node":{"info":{"id":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","name":"node_9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","enode":"enode://4faf10bd09731418ac192c8a57f170f322ffe575d3a2ee2efafec45fb7da6fd3712457dd5a78fd5e1a2efa1003715aea87cca4d49b10fd1d3845b72435b8ee4c@127.0.0.1:0","enr":"0xf88fb84082c3796decac811025287334946817180d001c3d8d7721d3971aa9cb879fed0c0acd50bf82c7fa565e2540bef5f1b5731accc7b6a4c70ebe972111d0deda6a8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024faf10bd09731418ac192c8a57f170f322ffe575d3a2ee2efafec45fb7da6fd3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nTx55KCsTluVqjJUXzuNhvdFlPqiN9XCVmzwL71gsRo=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9d3c79\npopulation: 36 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 7b92 0bcf 0ab9 018a | 65 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n001 2 e16b cfbb | 30 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n002 11 b16d b381 b2b9 b70e | 17 b92a (0) b8e1 (0) b841 (0) b486 (0)\n003 5 8cf9 8be4 895b 83dc | 8 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n004 4 91eb 92a1 9626 957d | 4 92a1 (0) 91eb (0) 9626 (0) 957d (0)\n005 1 9a92 | 1 9a92 (0)\n============ DEPTH: 6 ==========================================\n006 2 9e02 9ee7 | 2 9ee7 (0) 9e02 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","private_key":"907b7ec9e8b65f1de5310f5964f2c97a21a13adf1c0b9e8a4cb0ba38c73dc24c","name":"node_9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","services":["bzz","pss"],"enable_msg_events":true,"port":37201},"up":true}},{"node":{"info":{"id":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","name":"node_a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","enode":"enode://3699407c49116a8a7ddb656a1e7e586838f3e72cfdf9cd942b81adc4fa745f01cf3dd9f2682d44deb8172544a05e86055f3cae6822aa14e3b98a5870a259ad33@127.0.0.1:0","enr":"0xf88fb840de466b2eda8d1345b19b33da7313d03db5548f84b7f7d728a6a1346a44e29bfe6b37764e639f35270f9df761fdeffb3207f2c4716c87d65a25d30afdff134a5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033699407c49116a8a7ddb656a1e7e586838f3e72cfdf9cd942b81adc4fa745f01","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oIUEXDNc4uR9vf6xrbYs5sO+02qTzzRIxFdXoaiOKV0=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a08504\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 109e 3ee4 3e56 3cb1 | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 3 d224 e16b f5c4 | 30 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n002 3 82f0 86ca 9d3c | 16 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n003 5 b92a b841 b70e b2b9 | 8 b8e1 (0) b841 (0) b92a (0) b486 (0)\n004 4 ad0d ae67 aebd afa3 | 4 ad0d (0) ae67 (0) aebd (0) afa3 (0)\n005 2 a7a6 a75a | 2 a7a6 (0) a75a (0)\n============ DEPTH: 6 ==========================================\n006 2 a320 a2ba | 2 a320 (0) a2ba (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","private_key":"40d0f667c75292876d80bf036c58b652ae8eaf08e6543afce8efe01b5ba38af5","name":"node_a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","services":["bzz","pss"],"enable_msg_events":true,"port":33037},"up":true}},{"node":{"info":{"id":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","name":"node_7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","enode":"enode://8f6eaa7d371d5a4d8c1f71c52540914abe2f27afe0a753b8b7ce09e09ceeea61785f53dea26d90c6455d9a37657c52155faf04192b6b8ecef078b8b27ecc7572@127.0.0.1:0","enr":"0xf88fb840ef3018c62f6e420fbce8abac717ede992b1c276bfe0ce90b7b1d8ed88c0a2060783837e6f1f927d5f126a1c274bb6fa274db17107672ef312532d457aeea68200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028f6eaa7d371d5a4d8c1f71c52540914abe2f27afe0a753b8b7ce09e09ceeea61","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"c1X6sQWE5DEvXLXDyCbn+cFNp01i0H0KgAfOnG6ZW+k=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7355fa\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d6ff 9a92 a085 | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 7 3cb1 38ab 39db 372d | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 3 5abc 539d 48b6 | 15 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n003 7 6742 667e 6982 6ecb | 11 6982 (0) 6d60 (0) 6c82 (0) 6c02 (0)\n004 3 7fbc 7dc5 7b92 | 6 78cb (0) 7b92 (0) 7f87 (0) 7fbc (0)\n005 3 7639 772e 757a | 3 7639 (0) 772e (0) 757a (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 0 | 0\n008 1 73b8 | 1 73b8 (0)\n009 0 | 0\n010 0 | 0\n011 1 734e | 1 734e (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","private_key":"65b0005e792636557ba85af62557e19b18b9174bbbef4d0d1a9df6ed86564cd2","name":"node_7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","services":["bzz","pss"],"enable_msg_events":true,"port":35631},"up":true}},{"node":{"info":{"id":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","name":"node_48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","enode":"enode://0cbf237e6aeb863aeb824af9ceface5a8f94eb2330907633723afa315ad810ca5fa9de4f687c6a6035eab2339a4cb9803b61f752c39ec949930c3699850fa0bb@127.0.0.1:0","enr":"0xf88fb8408c25a5258f12cb8ddea2eb309508a3b3bb615e0af2611013a4caa40a060e503d076f528b777885fa04eccb0ab89a0d909844f92a68099ed5b0cb0d3b417c2cda0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030cbf237e6aeb863aeb824af9ceface5a8f94eb2330907633723afa315ad810ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SLYUlYqGkngO9b1cleDbT/Z9603g3LuHjKRHm/uGlX4=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48b614\npopulation: 32 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f5c4 b2b9 b381 afa3 | 63 ed32 (0) edc8 (0) ea0e (0) ea60 (0)\n001 7 39db 3e56 3cb1 372d | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 12 6982 6c02 6d60 6ecb | 23 6982 (0) 6d60 (0) 6c82 (0) 6c02 (0)\n003 3 539d 558e 5abc | 7 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n004 3 47c3 4167 419a | 4 47c3 (0) 4167 (0) 41b9 (0) 419a (0)\n005 1 4cd0 | 1 4cd0 (0)\n============ DEPTH: 6 ==========================================\n006 2 4a18 4b24 | 2 4a18 (0) 4b24 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","private_key":"270a9d9bfe65cba3f7905cabdc33f12696f57f495f5b1f4f717c4f686cb9fb22","name":"node_48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","services":["bzz","pss"],"enable_msg_events":true,"port":33663},"up":true}},{"node":{"info":{"id":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","name":"node_afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","enode":"enode://318bacfd1e44885c89d878b681a769550aa404ad1b963f802ec5bcc8ad70cecde25b68156ac8fce5ab0574e0518f7a5931f1e66b578bc395678f5541d523a0a4@127.0.0.1:0","enr":"0xf88fb840f8a54e090fb7de27c570ae1607b52faecfb241df7ca595859ef729b0b22447b7052a90ae67d12246ec2040000f85a4697bb924b273657efe3faf78db0f755c920183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102318bacfd1e44885c89d878b681a769550aa404ad1b963f802ec5bcc8ad70cecd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"r6PeXOvJ+WzyCjUFj0hW/kO0isWc+ORlZfGU9DhiKlI=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: afa3de\npopulation: 28 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2459 0bcf 6728 48b6 | 65 286a (0) 2a22 (0) 213b (0) 2434 (0)\n001 3 e55d e16b f5c4 | 30 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n002 8 91eb 92a1 9d3c 9e02 | 16 8cf9 (0) 89c8 (0) 895b (0) 8b76 (0)\n003 6 b92a b841 b486 b70e | 8 b8e1 (0) b841 (0) b92a (0) b486 (0)\n004 4 a7a6 a75a a2ba a085 | 5 a7a6 (0) a75a (0) a320 (0) a2ba (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 ad0d | 1 ad0d (0)\n007 2 ae67 aebd | 2 ae67 (0) aebd (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","private_key":"e19117f65a5dd05127cf7d2d994fdf61d54c6d9c1113d8cbbd46927df4e3c23a","name":"node_afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","services":["bzz","pss"],"enable_msg_events":true,"port":36875},"up":true}},{"node":{"info":{"id":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","name":"node_67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","enode":"enode://81035bfc5935b3ecdf8f5134d14f109559ce2602e1ef2ae36ff475c43b469a32b2d71d843c6e1a1d45509706538e0956e768594aac04aaf5a712a9a3405251ac@127.0.0.1:0","enr":"0xf88fb840eae38a1667d14d43e83b2c0d0a1c2fb4ccbc358bf1134594c33b2b58d710260809ad16b7f243040e51a0eb368e12ea4ed50a0b438fdbd2f23231d37b12e093010183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10281035bfc5935b3ecdf8f5134d14f109559ce2602e1ef2ae36ff475c43b469a32","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZyiPhK2nd4hYE5x0kXsirmmO1D30mmUwpWZkjwdO3kY=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67288f\npopulation: 33 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 12 d6ff dfae dc97 f5c4 | 63 ebca (0) ea60 (0) ea0e (0) edc8 (0)\n001 2 26d1 0bcf | 27 286a (0) 2a22 (0) 213b (0) 2434 (0)\n002 6 539d 5abc 4167 4cd0 | 15 5d60 (0) 5a01 (0) 5abc (0) 558e (0)\n003 4 7b92 734e 73b8 757a | 12 7639 (0) 772e (0) 757a (0) 73b8 (0)\n004 5 6d60 6c02 6e5c 6ecb | 6 6982 (0) 6e5c (0) 6ecb (0) 6d60 (0)\n005 1 6210 | 1 6210 (0)\n006 1 645b | 1 645b (0)\n============ DEPTH: 7 ==========================================\n007 1 667e | 1 667e (0)\n008 0 | 0\n009 1 6742 | 1 6742 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","private_key":"8b748538936665f38549ca75239d192493fd5ff24f126d318b4335bae35d9d6b","name":"node_67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","services":["bzz","pss"],"enable_msg_events":true,"port":43817},"up":true}},{"node":{"info":{"id":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","name":"node_0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","enode":"enode://0379db849a652e76893c5565c230efe72c4d44c416b9bb323529807baef9a4843b1ba9d548fe30e116edbd1e0e376d0a9a983b35542e9d414e227b915231d22e@127.0.0.1:0","enr":"0xf88fb8403c83a4015938e95101f3db5859df1555fc2fb05d2c47650e84388bb516e27426523605a2d76c9118658082f4fb8ef3cecffb3add5ea8986a4b53a1daa0c4e4660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020379db849a652e76893c5565c230efe72c4d44c416b9bb323529807baef9a484","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"C8+KirAGXKjIW4tmQfTG4LDeYOee8y6/b/jxCaxOHXA=","hive":"\n=========================================================================\nThu Feb 28 17:45:49 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0bcf8a\npopulation: 39 (127), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 e16b 895b 9d3c 9626 | 63 edc8 (0) ed32 (0) ebca (0) ea60 (0)\n001 10 4cd0 4b24 48b6 757a | 38 5d60 (0) 5a01 (0) 5abc (0) 5776 (0)\n002 9 372d 38ab 39db 3cb1 | 12 286a (0) 2a22 (0) 213b (0) 2434 (0)\n003 4 1be4 1929 109e 13bc | 4 1be4 (0) 1929 (0) 109e (0) 13bc (0)\n004 6 0506 018a 0390 0218 | 8 06b9 (0) 0427 (0) 0506 (0) 018a (0)\n============ DEPTH: 5 ==========================================\n005 1 0ff6 | 1 0ff6 (0)\n006 0 | 0\n007 1 0ab9 | 1 0ab9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","private_key":"a66755f09e07ea306f890663b424f0162339cc7ac848e7ed878743e6e0d7cd71","name":"node_0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","services":["bzz","pss"],"enable_msg_events":true,"port":39147},"up":true}}],"conns":[{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","other":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","other":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","up":true},{"one":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b8411f198fd658c5a2028835c0af3342145839c06c8a4f382d9f9de485d46c08","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","up":true},{"one":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"372d47374a57d18cf134a1f8fc2d2fc10dfacfc0be9ed883183a349c896b3793","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","up":true},{"one":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"edc8794153fb517085d27a83a4b00e8c3b37f22d2242b842cb2fab66764de9fe","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"b70e96f01ac8947d2de6320412ae3310316caba65c27108ad16b2f2004255be4","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"3cb1b4069727dc323a687cab4ca2764f6415450488706f1b97c5cb8ca46346ff","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7cf4838a7c83a736ce59cfa1b974674a0185dbe17a8f3cd29794a3bbe814adee","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"e0b1c4eb5b5b4dfc22344ee65cb9716cecb38dcc80099793f20641884eae4854","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"f74ecde0bbaa7b6521fb205b5ab9ea637909277f6e1ee1d3490f5cd01d0f7216","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"7355fab10584e4312f5cb5c3c826e7f9c14da74d62d07d0a8007ce9c6e995be9","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"dc97c1a0019b482a048b8d15941dfe4c3c1a3443d9b2d7b4046370bc84a7e56f","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","other":"3ee4b20c047e701b58c06fcc8160364bd29573f61f4d9f1935d77ac29f6a1e86","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"dfaeebc8e29c6a8f851b12b80cf42567cd2a43e35d977305a3c10e51bf41170a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"5abc96f4fa78812db6fb710fd424dd474145f7e5d00b4cedc5373b4c52f42cf5","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"698247d103a8925d8bb4c56a3056e49c5efc595fced1c89d49943bb9ba01f394","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","up":true},{"one":"a75abd0dce5a488b7e06f91fab7a92ec428ab21bde9372c9e8fa489f48e7b3fe","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"d0f398969480f3df3587f6d47546ff1261cad4d2e9c26ff3077e35ae1b26153e","other":"db088103f3b6f2c784d76ecd99c8b4a77fd39bb39c72ddfd91c99c1a9dd3b75b","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","up":true},{"one":"67288f84ada7778858139c74917b22ae698ed43df49a6530a566648f074ede46","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","up":true},{"one":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"c18105aa302a43e352d999745a0f806af9f8cb8bb83349357da5c85e8975acd1","up":true},{"one":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","other":"d6ffb7fd2668e9b7b133bd9144156f4736191ef0d6e72b072759782d83931f22","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"419a6626dd026c0438461592121992c6be1868375011655b6d405166cd8edf7f","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","other":"ea60ef7cb3f2166a5c8e286c885984943a2ea5aff4730015be6a15031040cecf","up":true},{"one":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"2a22dbee71a0ef27c840221db4a592d6dc8f171afed865ff814a37d633a3eaa9","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","up":true},{"one":"cdcd165721f6851f361fad0b3ba88c8870be9ad6d6b8cbcecc7c89e1068d979a","other":"d2245f0679b436faabc0164e0b85e02e2effbad306e8229b555524a5e6d1a5f9","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","other":"e0ea575d0e2efa28bc51f49d1e2c24196a196da3b3196f3a5a26a5e310809af5","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","other":"a3205c1c4f9b72814f0db68e888e3c7ef88f27c681ed0d731dde5f0999f92ccc","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"621076ce6b82e70c90a4adf235aa6f71b116e302dd6b15dcae07f4a816012455","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","up":true},{"one":"021811a6757bdcdd2fa0fb68401dfe009d5a8e129958cd304fb42cf51dc5d1d3","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"a2babe49410ae007bc41ff2b7deaf709ed849e2f69666ce5aae76a3b71f47081","other":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"92a1501ed41e29bb7dd8eb4b4acecae983f4c7c83f39895cd68f7810b645f1dd","other":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"ae67fae4990da61ca89221c5b1675c992babb4d715b59939e47bd1491b3bf1f4","other":"aebd6135d10252b07f891b3a7330903faf13d409c4f7108630715fa0754f938e","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6742cca1b7783fcbed8d0b340508f93cc4dfaca8ff3f13fd59354486c4d62993","up":true},{"one":"027fb496438782583f78fb76999336eed7fb672a9c9ea50d04df580e6eb21377","other":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"645b4e6b36fc1928725f627aeed278f46c5a7d6b0fff7ccff55a0468d47b23e8","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","up":true},{"one":"962676818c17fae1ffc52fc29318c44f9b8c980afd6d3e98217b4088d568a808","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"b8e1a80d91216fd5f8bc3f7413caf68ade7f124354d44fe7bd155a089134a70a","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"5d608e66a17442091111cb472723fe3aea1f2baecaa546b57d49507c63a61cda","other":"539df902d42dc997c6b0e24d16ad68b54c557d56b41c972a320d57632dbfbe3c","up":true},{"one":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","other":"cec3c01c147b34f25104ddd0b25076cef63ac224eada9d9f5a00b8513331354f","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"286aeba646bba4a8aa1c372bee9f2c9ff0a2b3abb4f18be321225555c6dce4e5","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"667ef042e9dae18694581e0404c3d87a09800e8b42173d26571c3bf97e29a372","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"47c3e0dfbbfcebeece78865c8c989577360cd9cc46a3b43f4b7b01ed14dc30e6","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"109ef17c890104bfc5a4897d526a0afaa8c991c9d213616032f3058d0feb7f00","up":true},{"one":"f5c4d28df5973ec0292221a875e8446323f339409d93f0f7385990126908a3c3","other":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","up":true},{"one":"cbc5d42951bc6e187296b5f8ce4d04e472e26670a62851f39d65f31c50865f6a","other":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","up":true},{"one":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","other":"b486ce31ce880db3aaa17a0ac2c2f3554b6fe71f9c051edb572974342af4adb9","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","other":"57764522162620c1ad0b166a9c43772255d0cc01e49f2122ef09db046804a570","up":true},{"one":"6e5c213a2db57eaf2e1e1acc341c72efab89b0e42b6cd18db4f99ac1af151d65","other":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"5a01993ff7b4bd12fdb259e96b26a036d0cf5d4ae9c9b516be64b63acec2443a","up":true},{"one":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","other":"41b9ee7ad19698e97589b059ad3333cb64f02c16006d94fb3d0bad7ced8ff238","up":true},{"one":"3e56d4533ec14f6656e1eb25fb35dad47c9db479f667a6b6fe9a3aa8c12e982e","other":"39dbd5462c90dac75f49d9af7996845943bbe929754ef8125eee7f5a763e9def","up":true},{"one":"213bf6e78e02a57585908c756f0965297152c3c400a0ed4c407a411e1ec5942d","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"b381e75e52e4cdd168056245f82d3a1747b67f400eb40eb12036b73ee7fe21e5","other":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"a085045c335ce2e47dbdfeb1adb62ce6c3bed36a93cf3448c45757a1a88e295d","up":true},{"one":"0506e949748b62da1d36b663df7d6a7e76027f72ced5d52f74677fb31d7e1505","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","other":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"ed32d74d9be0649de1eb26b9915137fe46ec890c656c96be52e966ab6e2ed260","up":true},{"one":"38ab3d7bdfb293b88122404cb7c50b5fb890ce7664c075da95585557a430c403","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"9e02c5384602a54e900cfa46d5987b77f16e74cba745ac850fcada01c7af9004","other":"957d8a9b412b6f4cd151cbc07b8d74d949880ae665c545debb18181389c99ee6","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b92a71a4fc371e0596538a7fb2a33e85329c39c4409c99798d9318bc263a04a1","up":true},{"one":"26d1af1fbee6541a363ea7707825e37da028142f00779116560ad20f1de18e7b","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"9a9230b3f7f386520821dee78ebe92e8c64a4f6a50f2639327c62e45cab40563","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"ebca518e5146f49ac75bcaa8add2ef4d1d22c5cfd2e2326c6b41826d45ce55ae","other":"ea0e1dd41fe042b09f273c98f02128949cf5561d20dc04b3d423961efed52327","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"8cf957bf95a629c60c31dbcfe75ecca149a81c761f8b34858b04f8318e5c74bd","up":true},{"one":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","other":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","up":true},{"one":"86ca1078dae40f23ae1b3ac47397460d9ec0bf243a0de372b405381d6722fcb2","other":"895bdcd200cc4d7ec5c24f1722d0a8ebedda78b78cdf1ccc8c22a981980f5786","up":true},{"one":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","other":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","up":true},{"one":"48b614958a8692780ef5bd5c95e0db4ff67deb4de0dcbb878ca4479bfb86957e","other":"558eb021744be19383be9ac91b9f77e07479e0eb25576bd32a3afaa94c231178","up":true},{"one":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"734e029ed25485edd49b93dd9e85b6e7657f860e4ded4bc8a5094f512ae5836b","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"2459fe9250b3311c86530d00b7a9b8ba57b1b5151c126262e70c55d1e8d37924","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7fbc1843e2222e3c8e35a3215d1bbb4d5457d8b9ed33749e07e22f25ba9ee576","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ca036d1ef9e6ce3654f2d769f16926aa14957193586426489e15539dfa8f7763","up":true},{"one":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","other":"018adc613f78d6ec876274f821251fd049eb3651646cd69e27efe211fe88d936","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"ce99e9d37111c52e929b187fe201790b1a555dfb8b6b6de54e94df7cc2d43fd4","up":true},{"one":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","other":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","up":true},{"one":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","other":"517aa977048247d5d16ad51a286ffac4d8f910733f0578b222201308c32d195e","up":true},{"one":"9d3c79e4a0ac4e5b95aa32545f3b8d86f74594faa237d5c2566cf02fbd60b11a","other":"83dc556ed36f37d06765be2554fe86eaf1ec21e2931fb22403238453bf021dfb","up":true},{"one":"2434c63e7f28b83e7feede7fe68ea99b989f8534f64d63b046733e2f474538f5","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"73b8d1840d0a8ffe69752ec96f8fddecb0e22726c87982d572ca9acc1c9cdbfc","up":true},{"one":"4cd0f38e52a508f81cf95e1370c994aea2d7a49a2a08e3e054f53629a6619410","other":"4a1811dd9febde1801a604ad81de84a2d15366d0b5c330f30f3398da0d107824","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"026d2e41b82d506da685a30cce7cc5772f6c1e167b7d557e0531fb9b79dd4ff2","up":true},{"one":"03907380afcd52238f3d84a8dee3df599c7f2f9b90fbc1271ee88bdb52acbd58","other":"06b95f1bac76ca4925d509b06216f2113ac5dcf051ef5aa0a320ae64069e0b6d","up":true},{"one":"042788d5b72cb84a375565d120d239a2b14fdf38b3f5f992284d78535077148a","other":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","up":true},{"one":"c3a1b301bf187fd8326831197d93a0266ac0cc8287b9008631240e2bec9cf337","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"8b76194f129308324c7d0066530e02cac2410ee0ba952822f0ec866e12461e44","other":"82f034db88fd26b47c26b95c3f87a1f454ffe4526ae86beb2bb1d8f2c218c25c","up":true},{"one":"7639f9a66e8ff70f554c346faa25f78140957c295b748fc42a12df7972f4fcc6","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"4167946de250b013e1be16ee84bfe2ccaae83e699e618b38f31016c4e431e6ba","other":"4b243a5aeabec6db0e4a80a9c255300cd94591a6fbe0e0aa170da4f6ce14edff","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","up":true},{"one":"f36120ff250b9e7164e96021479332054f67de65cd2fe5b6e34bc51d0fe4d29c","other":"f410d4ac9b748c24fa0d48c3053bb1cea8a67d0bcc4e5fcbdb261c0c7522cc34","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"afa3de5cebc9f96cf20a35058f4856fe43b48ac59cf8e46565f194f438622a52","up":true},{"one":"91eba9f9c8f2929d38f43a0c7efa809c0d2d59a31cbf2760c90e73d20266d528","other":"9ee7b3e06b453615cbd8737cb74515b150f518f1a2eaa2db90e54708dd161b7d","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"7b9242137f8cc2bec7b3e0003fd93026921ceb10dfadbbd5b6aa64d61a74f35e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"cfbb9ea682becadeab10bbd080ba8e93510085a87ac519e434964faa222fc275","other":"c8e5a1b4533dd0de12acee4d31369f39785178568718b93bbc321ec83e0714f0","up":true},{"one":"772e4c80d128deb52adf024a0eb6fe9bbea1c83351ed93f55f490cd5e5c69260","other":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","up":true},{"one":"89c883d6a85472bda328667e3fd805c70876bc582ca6763ab97ae636b1772be4","other":"8be461203f5ebb5721348f537b37d768f7bd359af3e18d1f7e9af2f901c49845","up":true},{"one":"e77f6aa9e3dfcce0a2e5db794703224249aba60595075b2df9a5b0b30855cf46","other":"e55d8cdb7e7940b11929e7e5c949ef6beb7998e5180a1f0a3c0bf61aef39f1b8","up":true},{"one":"a7a61804d270ed6c27a4b1e8a634c30d7cdbaf644a1c67cbc6b08cd849a711db","other":"ad0d0dc5d4114ee4482d6c9bd4e46683327abf2b92df0d242d79019963876668","up":true},{"one":"7f87da7ee55b4c8c8f9d55411ff88d3a0b63bfee6a516917d49fa6273fb5b86a","other":"757a557424c33ad89efd8185ec18d71c025830ecb2aed951e33c8c8d986d5933","up":true},{"one":"1929a84bcd64bf002d0afb16249466c5b660123174a1fc1bf881913f8c87d1fd","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"0bcf8a8ab0065ca8c85b8b6641f4c6e0b0de60e79ef32ebf6ff8f109ac4e1d70","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6d601952793589bc6b57340c451a6abf02ea2c16637e910eed04cde6eddfe17a","up":true},{"one":"e16b12c708bc5e0545009daed44733c52d7450ccc797d158dd41a3bc9507b6be","other":"f36084048bf0ff985a77f5183796f7b37b7085ee6eea8bbc5fc62558854cce67","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6c029114a9f73d69a42e591cf2d13107eff038d3eda8abb0242d9d6d169f05c7","up":true},{"one":"b16dcdf1ff1a56d49e374531d9885d59c1bcfbb628604520d9b1d84662edb9ca","other":"b2b9ac0f4db58886597af7b19d6150498ac8ad7c804671628aa34384b8fe505e","up":true},{"one":"78cbc19a24d095ab7858849058c65c061c52289b91ddd92cee34bed98aee4a59","other":"7dc5e8d8180c1bc7ebbee11a47fc96e8fe8b2d71c30cbc4aa1cf99e8eb6afcac","up":true},{"one":"6c82fdabd09e0e9d0fc507613a05951c02b2953d763a062a5f32aaf5cc477c19","other":"6ecb11fc5acc16ecd70351410fa18ec44a2a83d9e778cf25b85a7535493456b7","up":true},{"one":"0ff67b0e9ec6509c7786495b7b3ddb176b4f8221ff300f409f00a3d389e8874c","other":"0ab9845c2890b0a64a3e5932241245e00b817b788094f9ee48f86f80b7264fea","up":true},{"one":"13bc64535d3ae495098e4ac6b30a91d1804dab0ab79944f2c6ac53c9bccdf62d","other":"1be4348ec5670cdc4f164d77b1356e7910b6d1be4a9b720e549d02e5482a9e78","up":true}]} \ No newline at end of file diff --git a/swarm/pss/testdata/snapshot_16.json b/swarm/pss/testdata/snapshot_16.json deleted file mode 100644 index b6a7bf8115..0000000000 --- a/swarm/pss/testdata/snapshot_16.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","name":"node_26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","enode":"enode://e6b0213542756a047ab018ae745faab8a1c821082dc7bc64d13bee50591b554c10508dc284a7c3e686504bda30edf0ee9d3d5588e926725705014eb57ec321a7@127.0.0.1:0","enr":"0xf88fb840ef67bfea09687245f9a21fbeae2c963d6a827f70953457a32df964dc3fc96f3f1630e241de2d2ba4da049d18c459d2fd798c5be2d6dfbd9290457f678f7628af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e6b0213542756a047ab018ae745faab8a1c821082dc7bc64d13bee50591b554c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JlBMs9mhIiev3EMGVJbMr/cXLk2mKqdNN/JxraPwDcc=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26504c\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 b2f3 | 5 d465 (0) c7c0 (0) ece3 (0) 9ed4 (0)\n001 2 6a51 55bc | 5 689c (0) 6a51 (0) 72d3 (0) 769c (0)\n002 2 0160 0ffa | 2 0ffa (0) 0160 (0)\n============ DEPTH: 3 ==========================================\n003 3 348e 304c 3a9a | 3 3a9a (0) 348e (0) 304c (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","private_key":"1882828490f180d94a676998d372c267a462d3992a1499fdc9535ce176a5a7c0","name":"node_26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","services":["bzz","pss"],"enable_msg_events":true,"port":44851},"up":true}},{"node":{"info":{"id":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","name":"node_b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","enode":"enode://f69f214e3a7a9acc20ceac92869db21701e0dfab27365dbf13271def097914735fa4c6e47ff354aa9b04c0c5b1d42f903a55fa8de2490e66627fe1ae1e1f5ff1@127.0.0.1:0","enr":"0xf88fb840aec067e5c9519ed112d73b546bf81054e0afcadfaf54794b42cc67e8ff3f64ae5aba1b9fa38e9916af5117d49d34acbbc6a9fddf6eb4463fc85e8340738bdb490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f69f214e3a7a9acc20ceac92869db21701e0dfab27365dbf13271def09791473","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"svOmnVL5gDfPvcQKUpYSyJDNSwYb+odBFJPfXG4etdk=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b2f3a6\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 55bc 6a51 769c 0160 | 11 689c (0) 6a51 (0) 72d3 (0) 769c (0)\n============ DEPTH: 1 ==========================================\n001 3 d465 c7c0 ece3 | 3 d465 (0) c7c0 (0) ece3 (0)\n002 1 9ed4 | 1 9ed4 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","private_key":"2bc350f43a600469515791e72c828ea18e25dae28a8eba34ad9123f2b2d0e7b4","name":"node_b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","services":["bzz","pss"],"enable_msg_events":true,"port":46035},"up":true}},{"node":{"info":{"id":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","name":"node_ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","enode":"enode://3f0c7d44d331f144a130eff41ad30fa260c30f29f27b2c6a9ce94dc86ade5a4f1457ff241b4e48f42dab7e3f4d4ed626b22ada5032bb29645c0ab5a6c7ddca61@127.0.0.1:0","enr":"0xf88fb8406aa846ed3e1e91c35a8db13e47424870d976fba32a38ecbbd87fef3f04b0bd5c04ab395313a732a3e5121e0c32768abedb704b835b81713c24e136bdc970d1560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033f0c7d44d331f144a130eff41ad30fa260c30f29f27b2c6a9ce94dc86ade5a4f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7OMMXOQMJ2mXPpVL/Ye5c6dTiH9Ks58rY4o8sonspSE=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ece30c\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 689c 72d3 348e 304c | 11 689c (0) 6a51 (0) 72d3 (0) 769c (0)\n001 2 9ed4 b2f3 | 2 9ed4 (0) b2f3 (0)\n============ DEPTH: 2 ==========================================\n002 2 c7c0 d465 | 2 d465 (0) c7c0 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","private_key":"1f5005e874a37bbc0f9f920f3089faf5b0189f3ab1796fa370cb89e58b9517d3","name":"node_ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","services":["bzz","pss"],"enable_msg_events":true,"port":41799},"up":true}},{"node":{"info":{"id":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","name":"node_304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","enode":"enode://25b34252e979970bc75da4174ee863e64564c2a62367a9f03f9a4806a84cbbfd7154163bc5c765cd9993870ed9f39a862e80e9020638355cedb3f5deb6a5f80f@127.0.0.1:0","enr":"0xf88fb840cfc8be3771521eb84480fed1ead36e67bbdb0acf5db42a3d1ad0f6aba80130bf6bc03592b7ab85cafe0d19266c3b004b2057b042ba69ee8e00c4d569d0193d5c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10325b34252e979970bc75da4174ee863e64564c2a62367a9f03f9a4806a84cbbfd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MEwYqasfC8Ql4cDV6C+qQ7yzkSpolu4hJgVvgKpZnHI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 304c18\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c7c0 ece3 | 5 9ed4 (0) b2f3 (0) d465 (0) c7c0 (0)\n001 2 72d3 769c | 5 769c (0) 72d3 (0) 689c (0) 6a51 (0)\n002 2 0ffa 0160 | 2 0160 (0) 0ffa (0)\n003 1 2650 | 1 2650 (0)\n============ DEPTH: 4 ==========================================\n004 1 3a9a | 1 3a9a (0)\n005 1 348e | 1 348e (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","private_key":"411d5a05b2233c28b2366e3ffc2e67effdd61216f64124ab18ef047fd2d2b6ed","name":"node_304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","services":["bzz","pss"],"enable_msg_events":true,"port":40347},"up":true}},{"node":{"info":{"id":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","name":"node_c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","enode":"enode://f4bb3d33407ed52c3ed7a46a9394efb0907b2ec97d79e08a4cebde9206d7b9f1d7dbfef2c01efc191b2342e7dcfc725015f6d6c639ce8af7ce3f2240c41a3d24@127.0.0.1:0","enr":"0xf88fb840bfa01ff6980a93944637109a5b15621a9bf50a678e6b21a6cb08b903a5db94e770fa89cdb38ab4a7540b4262ad9f2036ee6a3868b6de7a437d5c3c71402f097f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f4bb3d33407ed52c3ed7a46a9394efb0907b2ec97d79e08a4cebde9206d7b9f1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"x8CAzgtexu3l4A87QIeZUZcE+2KOgXfB7sLnrtfzsbA=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c7c080\npopulation: 6 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0ffa 304c | 11 55bc (0) 769c (0) 72d3 (0) 689c (0)\n001 2 9ed4 b2f3 | 2 b2f3 (0) 9ed4 (0)\n============ DEPTH: 2 ==========================================\n002 1 ece3 | 1 ece3 (0)\n003 1 d465 | 1 d465 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","private_key":"8bd7e85f0ac64efbc80d7952b31f33602531d2e9ce2f589ebfbdc66fceadde81","name":"node_c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","services":["bzz","pss"],"enable_msg_events":true,"port":46599},"up":true}},{"node":{"info":{"id":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","name":"node_0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","enode":"enode://99de6da9abebfa76fefdac94de902456d8450886946933b5e9da18e4b0709d7c27109b17d024419e205fa3b2cc50268f330217b105a0a92126e1c1697b593dfd@127.0.0.1:0","enr":"0xf88fb840e1d27e54275610c9979cc6255e9363b42c5e2c746301dc788af52d58e895775e37d99e021fc6f9746aba2070d0e48855e7a4c8f04bee0d96ef8c49c8234f97840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10399de6da9abebfa76fefdac94de902456d8450886946933b5e9da18e4b0709d7c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"D/r+COmRGbJA86Hzbd07vd0fPD8T6IOdRVHkP3llgWo=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0ffafe\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 c7c0 | 5 b2f3 (0) 9ed4 (0) ece3 (0) d465 (0)\n001 2 689c 55bc | 5 55bc (0) 769c (0) 72d3 (0) 689c (0)\n============ DEPTH: 2 ==========================================\n002 4 3a9a 304c 348e 2650 | 4 2650 (0) 3a9a (0) 348e (0) 304c (0)\n003 0 | 0\n004 1 0160 | 1 0160 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","private_key":"a19af618fec44371482faf5f2f6366acf984bdaf717c382869e46dc18edea77e","name":"node_0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","services":["bzz","pss"],"enable_msg_events":true,"port":43693},"up":true}},{"node":{"info":{"id":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","name":"node_9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","enode":"enode://ae0f2a151e99e9e9e54938545cf4f19f56a6a10bbad2f1966661dee90753d398c6771c23d7ee70db1715897e3364a561e38ae3fff21349d579e9abf44dcf8d5f@127.0.0.1:0","enr":"0xf88fb840ff4b95dcfbd61ccc46ca0a798ba8dcaa6cb23ae891ee35cfbdfbfb7811614a8a08192ebcced83a5c6afbf3d95c08b6d5fd18af8d5df806d341ed361398e3554f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ae0f2a151e99e9e9e54938545cf4f19f56a6a10bbad2f1966661dee90753d398","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ntQLcOTHKZemyYD2hi0K6PNmsb5Ix3/Pp5ZTYvsd18Y=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ed40b\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 769c 55bc 3a9a 0160 | 11 55bc (0) 769c (0) 72d3 (0) 689c (0)\n============ DEPTH: 1 ==========================================\n001 3 ece3 c7c0 d465 | 3 ece3 (0) c7c0 (0) d465 (0)\n002 1 b2f3 | 1 b2f3 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","private_key":"d19f0df4bba07418a557ec945ed8c8851ed01e20e7760c72954352862bf77ba6","name":"node_9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","services":["bzz","pss"],"enable_msg_events":true,"port":35629},"up":true}},{"node":{"info":{"id":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","name":"node_d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","enode":"enode://338975eb003552bbb837272c2b48a049b7fab8958571e0eb9bc1d1cdc967cbbe42ee93adeed75700391016cf7d311e7d06f48cef371f2b80ff80bfd6a27bd16d@127.0.0.1:0","enr":"0xf88fb840f009eadfddb5e69c6ca89a5d2ba64ee2ec31ebe85623adea4e036e4136f1f4d74d0933a43c9a0bdb66eec46cdbed18bfde269fa892da42d47d2b8bd1b6db3be30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103338975eb003552bbb837272c2b48a049b7fab8958571e0eb9bc1d1cdc967cbbe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1GWYv89EN/iGN8p1VXMBB1NfOLQZycs1M83FNuGWJp8=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d46598\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 348e 2650 72d3 689c | 11 2650 (0) 3a9a (0) 304c (0) 348e (0)\n001 2 b2f3 9ed4 | 2 b2f3 (0) 9ed4 (0)\n============ DEPTH: 2 ==========================================\n002 1 ece3 | 1 ece3 (0)\n003 1 c7c0 | 1 c7c0 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","private_key":"adccac5625a153c4cca90a971fbe0b7b2f9f62af166fd1fcad0a6559e042e2a5","name":"node_d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","services":["bzz","pss"],"enable_msg_events":true,"port":39805},"up":true}},{"node":{"info":{"id":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","name":"node_6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","enode":"enode://0fe608947dab328f476e8dd8d94ea391e604adcf4a15901224e32c9a3bc6e198d13751af168e9b31f140ee82d39e29d0f347cd733cd44797abf34ce629c57a75@127.0.0.1:0","enr":"0xf88fb840bf749d25f9054ed9f97df2a3d695fe170ece0e2d67d097756696bf90d2d5c5dd7f67527f9f8368d18843438f769883c32cc76fab8eeb57768a9d66fedd125e800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030fe608947dab328f476e8dd8d94ea391e604adcf4a15901224e32c9a3bc6e198","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"alFzAxcq/rAXX/M/YjLaqcLPmjdTuc2XPS4aG7ss0cg=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6a5173\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b2f3 d465 | 5 b2f3 (0) 9ed4 (0) ece3 (0) c7c0 (0)\n001 2 3a9a 2650 | 6 2650 (0) 3a9a (0) 304c (0) 348e (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 769c 72d3 | 2 769c (0) 72d3 (0)\n004 0 | 0\n005 0 | 0\n006 1 689c | 1 689c (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","private_key":"0ab9fec01ec19b2a335b0ada3a02e30702d90efb1f3c1a0bf2b9cd36a9f87fc9","name":"node_6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","services":["bzz","pss"],"enable_msg_events":true,"port":41555},"up":true}},{"node":{"info":{"id":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","name":"node_689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","enode":"enode://9e1aac08a4928876280c211e71ffd510eeb78fbebff4ac254af5a302f8913cf798a0f55a79b99735f8a01dc4adc39428659649437d1bb0b88d3383e6b7ad7104@127.0.0.1:0","enr":"0xf88fb8402129c2f1dadb690035ffe0776862b987152c612355ed44a6927c7402b5801fe05b2d540e5e19afb63be6e975809af1bcc385286bad2dd92baacec2f7931386680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029e1aac08a4928876280c211e71ffd510eeb78fbebff4ac254af5a302f8913cf7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aJyaD1eoOEaCWf4u4IJEatFcWW7zYboWwrkrU922ykE=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 689c9a\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 ece3 | 5 ece3 (0) d465 (0) c7c0 (0) b2f3 (0)\n001 2 0160 0ffa | 6 0ffa (0) 0160 (0) 2650 (0) 3a9a (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 769c 72d3 | 2 769c (0) 72d3 (0)\n004 0 | 0\n005 0 | 0\n006 1 6a51 | 1 6a51 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","private_key":"31c956ed431b0b0f061c15e1263dbf111de4a9f4dd5335680fa9f64c0821fa0b","name":"node_689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","services":["bzz","pss"],"enable_msg_events":true,"port":36247},"up":true}},{"node":{"info":{"id":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","name":"node_72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","enode":"enode://d21eb565193ce78749091397af418bba7c9b152f3ccf4199e17df26bd700459fbb87ada766a3cdea29a1fdf9656b6b1372948fcc2eb030dc879b029bdd6b04e5@127.0.0.1:0","enr":"0xf88fb840f89a9aa64661b1f4d6ac8e6aab664af27a58b08bcc3c43066d458d99dcf75bc6536c7326631a031ff2b89404eedfbe566a8beea5d3eb0e0865b206d8ea25bc070183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d21eb565193ce78749091397af418bba7c9b152f3ccf4199e17df26bd700459f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ctPRRIhY45MQPRvSlAk94Ovz7IqLTTtH+mmGrbVcUrI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 72d3d1\npopulation: 8 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 ece3 | 5 ece3 (0) d465 (0) c7c0 (0) b2f3 (0)\n001 2 304c 348e | 6 0ffa (0) 0160 (0) 2650 (0) 3a9a (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 6a51 689c | 2 6a51 (0) 689c (0)\n004 0 | 0\n005 1 769c | 1 769c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","private_key":"278c5f54c5e9f2d2688383f0a5f98b72a01d76b532799a74162c2f169d8a4819","name":"node_72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","services":["bzz","pss"],"enable_msg_events":true,"port":36181},"up":true}},{"node":{"info":{"id":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","name":"node_348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","enode":"enode://5b1fa3f55ee9c0fd34bf203045faf80d0a8fcded75c21a9a319fe6d628698f8aa78c60d5d78df5b3c54c29fd27f10be4a63c66895cc743e1a0cbe795e87114ca@127.0.0.1:0","enr":"0xf88fb84017bd33bdfe5b6e2c263ef3e95f0acaf1a4e902e79b4cfbe40e6ad57b4f9b21e019473a61a57e1b999ce432c288a6c8fa685df4afd8872c98757be969446b1ff60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025b1fa3f55ee9c0fd34bf203045faf80d0a8fcded75c21a9a319fe6d628698f8a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NI6TUbEGJaai/gROZ2l81UzlfIbaJXBFnst51Ky4bzI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 348e93\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d465 ece3 | 5 ece3 (0) d465 (0) c7c0 (0) b2f3 (0)\n001 2 55bc 72d3 | 5 55bc (0) 6a51 (0) 689c (0) 769c (0)\n002 2 0160 0ffa | 2 0ffa (0) 0160 (0)\n003 1 2650 | 1 2650 (0)\n============ DEPTH: 4 ==========================================\n004 1 3a9a | 1 3a9a (0)\n005 1 304c | 1 304c (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","private_key":"fdb4b30d8d9482f9581193c6f6b57e5213922001901c46407528810f0e598058","name":"node_348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","services":["bzz","pss"],"enable_msg_events":true,"port":37669},"up":true}},{"node":{"info":{"id":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","name":"node_3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","enode":"enode://90143f4ad7bfd6cc2ba948ab8de4587aa7a2948de5b096c65ef276f04ff7c4aa4e043e0add0734c668c1f8c59e7d4294d2bb2bde96490ce04ce95eaaadb4bab3@127.0.0.1:0","enr":"0xf88fb84090f225e54c8dff490b8cdfbcf4d956adc2125d2bd2b2c98c090d6d6775ad78ed3cc047b26c655c81bedff72ccfdeecca053020666d23c3342a27b7ffc339dff30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10390143f4ad7bfd6cc2ba948ab8de4587aa7a2948de5b096c65ef276f04ff7c4aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Opo7ONDc1IRfidcJG4L19nX8NVfQmXnED/wSp7u/5BQ=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3a9a3b\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 3 55bc 6a51 769c | 5 55bc (0) 6a51 (0) 689c (0) 769c (0)\n002 2 0ffa 0160 | 2 0ffa (0) 0160 (0)\n003 1 2650 | 1 2650 (0)\n============ DEPTH: 4 ==========================================\n004 2 304c 348e | 2 304c (0) 348e (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","private_key":"8affc7f653083f993524996d8a2de34d88ba748c3485d4cd721ce02207edacae","name":"node_3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","services":["bzz","pss"],"enable_msg_events":true,"port":46571},"up":true}},{"node":{"info":{"id":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","name":"node_769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","enode":"enode://c1b9d33acbb2c9146cad2b1ff6786740ae264aad8c633fdeead6fc07a584de39e78116f9790d1b88e80590ba6a40b0dba329474f371d2001205f9b5cfcd7e1e3@127.0.0.1:0","enr":"0xf88fb840678a2b8e8007983d072232c0a39be22bad2ab19c2a8010bc814b74e7c1d40edd0169d827cb6191c5b4ed4d7079a6cad6163b76a826017bf524f74655b92d26320183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c1b9d33acbb2c9146cad2b1ff6786740ae264aad8c633fdeead6fc07a584de39","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dpyUjXldExlfM2Gvava9t2/dZu09t5bM7BBPfcIf76A=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 769c94\npopulation: 9 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 3 0160 304c 3a9a | 6 0ffa (0) 0160 (0) 2650 (0) 304c (0)\n002 1 55bc | 1 55bc (0)\n============ DEPTH: 3 ==========================================\n003 2 6a51 689c | 2 6a51 (0) 689c (0)\n004 0 | 0\n005 1 72d3 | 1 72d3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","private_key":"dbc7392e8eb09f40ef0971a14aa3db440d1a125b32876942e60f8582ad70c046","name":"node_769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","services":["bzz","pss"],"enable_msg_events":true,"port":35637},"up":true}},{"node":{"info":{"id":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","name":"node_0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","enode":"enode://e7237f8772dd77b211f061e619e63fac712395256ff49128a7152f1bfc4ba15fe7b9339c51e2f98e0824faec48ae462e6a340f94c11ff1d32e692aac18a63c07@127.0.0.1:0","enr":"0xf88fb84013c8bd0c52cc1d01e9d8a1394b7be84bc47f042841d0073347d93646bf6a3d266c3fd3dc41ac81c04d6b2027a7aa4d2688270827ab197f79a29e426130530c7a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e7237f8772dd77b211f061e619e63fac712395256ff49128a7152f1bfc4ba15f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AWBDakeR13v37ZyYIoin9ex6Gg0o9h9n6ujcZWxicsQ=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 016043\npopulation: 10 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 3 689c 769c 55bc | 5 6a51 (0) 689c (0) 72d3 (0) 769c (0)\n============ DEPTH: 2 ==========================================\n002 4 2650 3a9a 348e 304c | 4 3a9a (0) 348e (0) 304c (0) 2650 (0)\n003 0 | 0\n004 1 0ffa | 1 0ffa (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","private_key":"bec59ef09d2194c27ec1b844af85605ac08c87830784fab76b080d3420c06898","name":"node_0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","services":["bzz","pss"],"enable_msg_events":true,"port":45829},"up":true}},{"node":{"info":{"id":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","name":"node_55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","enode":"enode://2de6037913178726275c8ef050e0dae981406aa551fea37112bdb34d1a403bb5f86fe8cbb04732fbde1f0f362bba71bc6499c16b59fab0f7f0d6f1c0c1d103d6@127.0.0.1:0","enr":"0xf88fb84002914870f5ffed74456e9316ad731fc2686c9a0189c095584882392fe59512a56195aeeabfbb7fd0f7615cfa429568a033dc0447bc5d1a34ba2a05ad8bb762c30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022de6037913178726275c8ef050e0dae981406aa551fea37112bdb34d1a403bb5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Vby/E5LQzXeChqIcl6LSKn5KJJTBlxR8OfXC8k1PuhI=","hive":"\n=========================================================================\nThu Feb 28 17:16:22 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 55bcbf\npopulation: 11 (15), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ed4 b2f3 | 5 b2f3 (0) 9ed4 (0) d465 (0) c7c0 (0)\n001 5 348e 3a9a 2650 0ffa | 6 3a9a (0) 348e (0) 304c (0) 2650 (0)\n============ DEPTH: 2 ==========================================\n002 4 769c 72d3 689c 6a51 | 4 6a51 (0) 689c (0) 72d3 (0) 769c (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","private_key":"ba62b88bff913813741dd50c907c918e974132dcde3c6f57ea49a0bb1ce5cd26","name":"node_55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","services":["bzz","pss"],"enable_msg_events":true,"port":39363},"up":true}}],"conns":[{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","other":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","other":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"ece30c5ce40c2769973e954bfd87b973a753887f4ab39f2b638a3cb289eca521","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","other":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"c7c080ce0b5ec6ede5e00f3b408799519704fb628e8177c1eec2e7aed7f3b1b0","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","other":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"0ffafe08e99119b240f3a1f36ddd3bbddd1f3c3f13e8839d4551e43f7965816a","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"26504cb3d9a12227afdc43065496ccaff7172e4da62aa74d37f271ada3f00dc7","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","up":true},{"one":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","up":true},{"one":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","other":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","up":true},{"one":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true},{"one":"304c18a9ab1f0bc425e1c0d5e82faa43bcb3912a6896ee2126056f80aa599c72","other":"72d3d1448858e393103d1bd294093de0ebf3ec8a8b4d3b47fa6986adb55c52b2","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"b2f3a69d52f98037cfbdc40a529612c890cd4b061bfa87411493df5c6e1eb5d9","up":true},{"one":"689c9a0f57a838468259fe2ee082446ad15c596ef361ba16c2b92b53ddb6ca41","other":"0160436a4791d77bf7ed9c982288a7f5ec7a1a0d28f61f67eae8dc656c6272c4","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"d46598bfcf4437f88637ca7555730107535f38b419c9cb3533cdc536e196269f","up":true},{"one":"769c948d795d13195f3361af6af6bdb76fdd66ed3db796ccec104f7dc21fefa0","other":"9ed40b70e4c72997a6c980f6862d0ae8f366b1be48c77fcfa7965362fb1dd7c6","up":true},{"one":"6a517303172afeb0175ff33f6232daa9c2cf9a3753b9cd973d2e1a1bbb2cd1c8","other":"3a9a3b38d0dcd4845f89d7091b82f5f675fc3557d09979c40ffc12a7bbbfe414","up":true},{"one":"348e9351b10625a6a2fe044e67697cd54ce57c86da2570459ecb79d4acb86f32","other":"55bcbf1392d0cd778286a21c97a2d22a7e4a2494c197147c39f5c2f24d4fba12","up":true}]} \ No newline at end of file diff --git a/swarm/pss/testdata/snapshot_2.json b/swarm/pss/testdata/snapshot_2.json deleted file mode 100644 index 8be6e0dc2b..0000000000 --- a/swarm/pss/testdata/snapshot_2.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","enode":"enode://6a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f9757875b6b8d02f88fafe3fd7f20f0349a0060ace7c0be1d65470e736a3319431b5c14@127.0.0.1:0","enr":"0xf88fb84096f5dd9030fc74da3701ef7b06dfe4d44068118f8041a728876904d70fa8c88c20df197c343522c76d75d3a12507c567213c13b46a94ed4800f47474643f4ee70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f975787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/TfkUhDds2+LXs75ydnT+CAbqVI7/WpwKRMzzzuSB+E=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fd37e4\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 1 3594 | 1 3594 (0)\n001 0 | 0\n002 1 cb08 | 1 cb08 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","private_key":"6a02f87b1d13a15ce24bfa58456af8aaabdcf8cb58b9f86c19ab14c721c80f91","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","services":["bzz","pss"],"enable_msg_events":true,"port":39341},"up":true}},{"node":{"info":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","enode":"enode://0972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03397efbad98888f8d740b7cf55c357d1d6d74b5e8cb935f71b19e0e16ceef03f9@127.0.0.1:0","enr":"0xf88fb840d5f39b1ebcd5b616ef67b1c0239ed4501ef45c6a00e5bd8cd3f2ac88870d4c4b6ce4a4af820afab9a714d99a5fef53ec3c042fc3243f403819bcfb3504c2150d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NZRDinSApcPcBkQOKKFgRMDH0okhnaAvnkHaGBCCeAU=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 359443\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 fd37 cb08 | 2 fd37 (0) cb08 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","private_key":"26266470b7f4e9341cbbbb304b1aed116626cb1bea55d639cdbef1a069c18123","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","services":["bzz","pss"],"enable_msg_events":true,"port":33055},"up":true}}],"conns":[{"one":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","other":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","up":true}]} diff --git a/swarm/pss/testdata/snapshot_256.json b/swarm/pss/testdata/snapshot_256.json deleted file mode 100644 index 936956bec4..0000000000 --- a/swarm/pss/testdata/snapshot_256.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","name":"node_e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","enode":"enode://665ca8f57d847b22e62b829c7ca8327fc4a01497fbf18ce0214f19a4b405f2fd118bdc8d27a509942be90c4afff8774dc02810508099969cc215322120c6722b@127.0.0.1:0","enr":"0xf88fb840b69f6ddfa1a4af418eeffe8589e24339f2fdbd6bf67d70b7cae0a2096864dfc82dccb22867e1d5a9145d71caadcefde60e887c16a42164c3db6b4770bcff210b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103665ca8f57d847b22e62b829c7ca8327fc4a01497fbf18ce0214f19a4b405f2fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5oEkSHKLS9pZYq3OsXB7KfZh09GmsszV+Bg8mh9NAbY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e68124\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 48b8 741a 26ab 08bd | 126 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n001 7 81a5 8402 9464 9257 | 75 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n002 5 da36 d3e9 cc33 c603 | 27 d408 (0) d700 (0) d209 (0) d302 (0)\n003 4 f6c0 f1ed f215 ff75 | 14 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n004 4 eff2 ef99 e867 eb68 | 7 ed42 (0) ec90 (0) eebd (0) ef99 (0)\n005 4 e0a0 e09f e2d3 e277 | 4 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n============ DEPTH: 6 ==========================================\n006 1 e471 | 1 e471 (0)\n007 0 | 0\n008 1 e64d | 1 e64d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","private_key":"c62579f0a0c6aaaaa7a8aa18a22d928d27a2d496e9588ec36573b5f174136358","name":"node_e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","services":["bzz","pss"],"enable_msg_events":true,"port":33261},"up":true}},{"node":{"info":{"id":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","name":"node_14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","enode":"enode://1c9940e663ec6a7e9bf3e8add2faed3ad8f989ef1529cafb7f37c82a208f43d00f4ba05c1ea62caf472acb15c91b3587c96849c286efd4f173f438ea2b45d32a@127.0.0.1:0","enr":"0xf88fb840410f25aaf4a49487580fbd3c098fb137c2cbccf0c65806bf66715f0af1be0a5f5f5b20d60466ba1fb85cb219d6f9f1a7b216cfe6486aa9c00152e38dc2d1e66b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021c9940e663ec6a7e9bf3e8add2faed3ad8f989ef1529cafb7f37c82a208f43d0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FISfgRryDOGfspQX0gwV/BbaHkWuvfeVosbMtnHkvaw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 14849f\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9257 eb68 e681 | 130 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n001 3 44ad 4005 741a | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 4 2c85 3a62 3728 36b9 | 28 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n003 7 0e3b 08bd 08e5 08f8 | 21 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n004 6 194e 18e0 1add 1dec | 9 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n005 3 1049 1070 138d | 3 1049 (0) 1070 (0) 138d (0)\n============ DEPTH: 6 ==========================================\n006 2 1686 1784 | 2 1686 (0) 1784 (0)\n007 0 | 0\n008 1 140d | 1 140d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","private_key":"0ce521739058eb06cff2ff0e748a604866b37fa96e7a559c5bf7cabf4161382e","name":"node_14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","services":["bzz","pss"],"enable_msg_events":true,"port":34017},"up":true}},{"node":{"info":{"id":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","name":"node_eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","enode":"enode://0057d96aee5b09baeb627555fe6299fdc637bd55f9be2ddfc59faa67cb940257578d1df147fa29d0539d8eec0fc0d2786aa7530aa346ceae8ee6f8e72d1fb052@127.0.0.1:0","enr":"0xf88fb8405bf3c589a9657ead2e83ff8f2cc355982f3f594e94903e9e6ac19daf8a03e1b84a3d1c607e264646ac31a086ef73bfee66a4f95df458b208a93f2a5441a7607d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020057d96aee5b09baeb627555fe6299fdc637bd55f9be2ddfc59faa67cb940257","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"62hqaG/XDkFlnMaewNtT0VEt/sI4kYr9ClFdjOF31Nk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb686a\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 48b8 741a 26ab 012b | 126 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n001 7 a616 a970 8402 8074 | 75 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n002 5 cc33 c603 c2d0 da36 | 27 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n003 3 ff75 f1ed f215 | 14 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n004 5 e09f e2d3 e277 e471 | 7 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n============ DEPTH: 5 ==========================================\n005 5 ec90 ed42 eebd ef99 | 5 ec90 (0) ed42 (0) eebd (0) ef99 (0)\n006 1 e867 | 1 e867 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","private_key":"37e0f62adb81157cd9de3310d81d70da17cb3a0502320958b7c6d9ca1038d8f6","name":"node_eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","services":["bzz","pss"],"enable_msg_events":true,"port":36177},"up":true}},{"node":{"info":{"id":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","name":"node_9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","enode":"enode://5684177873a4d0e494fceca55b1a36e1a8a19025e03e483ae89cee9173b38082137fbfceb506946ae900a3cbc47697c7ba3c5bd553225e0e76ff5ce7657a7bdb@127.0.0.1:0","enr":"0xf88fb840e67f1444113ce4de2d80f4652cda49192b5c1dee37c8fb129cc60b1e655af7c60190c9a804b2498da20b36cf8aa01e2c492357464bf092615a60192953e13c6f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035684177873a4d0e494fceca55b1a36e1a8a19025e03e483ae89cee9173b38082","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lGStjaGl7/3ANRdC3/+ulB/9n6tGljeySRyuzlPFfcg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9464ad\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 741a 4a95 4b79 012b | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 7 c603 d959 da36 d3e9 | 55 d408 (0) d700 (0) d209 (0) d302 (0)\n002 5 bdc5 bcf8 ba91 a8b5 | 37 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n003 6 8ea2 8b43 8358 80d7 | 21 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n004 3 9c8e 9f7d 9ec8 | 9 9b8e (0) 9959 (0) 9948 (0) 9f0e (0)\n005 2 93c0 9257 | 3 93ea (0) 93c0 (0) 9257 (0)\n006 1 97da | 1 97da (0)\n============ DEPTH: 7 ==========================================\n007 3 95c0 955d 9518 | 3 95c0 (0) 955d (0) 9518 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","private_key":"a5dc0083f0aaf88eee5eaf79c81465d05f0ba64c386da9145ba4a4a3f5c8d143","name":"node_9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","services":["bzz","pss"],"enable_msg_events":true,"port":40977},"up":true}},{"node":{"info":{"id":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","name":"node_9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","enode":"enode://0376a4d936b21276f20e6c33483aeaefb1d89d83a01af38405c081fd675c7c8b1d93cd7eb661bee8fb060ef4f98f6b75eeffe191df26a19f18c2f08c94471f6e@127.0.0.1:0","enr":"0xf88fb840a3a1a51f7bff86552a58bbd5dda6348d6aa82a599d96adbfbf9f19e93e0eace7305ea1d01a495196a928bb866ae512f0244f06e2abaa0dfc679bee3fadec82e10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020376a4d936b21276f20e6c33483aeaefb1d89d83a01af38405c081fd675c7c8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"klfck0378XRztwy4UzPG+rZ+6bYiimRldsT1clPxAE4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9257dc\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1784 1484 08bd | 126 5987 (0) 5814 (0) 5bd8 (0) 5a8b (0)\n001 2 e681 eb68 | 55 d408 (0) d700 (0) d209 (0) d302 (0)\n002 5 b3f9 bdc5 a0c8 a616 | 37 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n003 8 8ea2 8862 8b43 8358 | 21 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n004 2 9c8e 9c21 | 9 9959 (0) 9948 (0) 9b8e (0) 9f0e (0)\n005 5 97da 95c0 955d 9518 | 5 97da (0) 95c0 (0) 955d (0) 9518 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 93ea 93c0 | 2 93ea (0) 93c0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","private_key":"c15e326cf8ee6333e5811786737f8322f412341ae09e5ae9917860bd26ca1947","name":"node_9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","services":["bzz","pss"],"enable_msg_events":true,"port":37221},"up":true}},{"node":{"info":{"id":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","name":"node_08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","enode":"enode://ee9d7c5a65b07eb7d05d2621c99bd374c33ea4438206d3f07d2a6dcfe9adfafeebc06b85d8dfa9ab05c74b2c0295ffb280931ca84b185dbb6ed924fd6be61f9a@127.0.0.1:0","enr":"0xf88fb84032fc3b696637e089700dfa3a41ddefe8e8a6a55db4660a332527484de910804419abdb982ab9fb545f5ee12c11f033e48e66220126f229aedcbb54c3a789b6d60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ee9d7c5a65b07eb7d05d2621c99bd374c33ea4438206d3f07d2a6dcfe9adfafe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CL0eBJhZtKfIB4ypdB/j2qZouf5HjaBtGkNc1VZrPhE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08bd1e\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e681 9464 9257 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 2 4b79 741a | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 6 26ab 2c85 2a50 30fe | 28 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n003 4 1fd0 138d 1784 1484 | 16 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n004 4 0314 035f 0111 012b | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 3 0d1c 0cfc 0e3b | 5 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 0942 096a 09b3 | 3 0942 (0) 096a (0) 09b3 (0)\n008 0 | 0\n009 2 08e5 08f8 | 2 08e5 (0) 08f8 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","private_key":"eeb1d4b4ded34ed420c6f517fa508883a73d457008f055da9edb7156e78474c2","name":"node_08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","services":["bzz","pss"],"enable_msg_events":true,"port":38971},"up":true}},{"node":{"info":{"id":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","name":"node_012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","enode":"enode://54002fd97799e33da3d495d928026863bbec17ed7e7d6ea78725e5259435c2740cb37de72cb4c58f07e09869598312f477b7eccb62b46fb181ba49cffd1bc315@127.0.0.1:0","enr":"0xf88fb840c5a8e2adab6eef8cfcdbd07f1a0fa37ae261091b64e83e95a4e7436cd1c39015121dc7fe55ccbd229c0de2f7ceab2ab9b1c6f500bac9380f6d792dcbf80c555d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10354002fd97799e33da3d495d928026863bbec17ed7e7d6ea78725e5259435c274","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ASuieNWCaRJBh1xMFOrZH/85g+GQ332bQ63jhOhMEfs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 012ba2\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 eb68 9464 8402 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 4 44ad 4b79 741a 7660 | 61 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n002 5 2c85 26ab 30fe 3728 | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 4 1fd0 1dc0 1784 1484 | 16 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n004 5 0e3b 09b3 08e5 08f8 | 11 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n005 4 07f5 046c 0594 0561 | 4 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n006 3 035f 0314 025d | 3 0314 (0) 035f (0) 025d (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0191 | 1 0191 (0)\n009 0 | 0\n010 1 0111 | 1 0111 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","private_key":"8c41148ea8aab694bf31dcfd89a8271ecfb228b4917b2e2d119d11e64ffe2eed","name":"node_012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","services":["bzz","pss"],"enable_msg_events":true,"port":33063},"up":true}},{"node":{"info":{"id":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","name":"node_025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","enode":"enode://789950b2dbebd332a0eef5b3bd998c4a7cb7b2b5bfd38dac2836a078eb6322d32967e68fcc10ab9841df4de5e02ffa4dae77e7ec75235fdfb542285073464c68@127.0.0.1:0","enr":"0xf88fb840bde2b58110c1cdfcae19192e9dc65d42bad215e4fa6ede43f8c3bfc2fc4fcf0e356406d032ece99c466696adf702d2436aa2abf92b0f598d3282aa2974487cb60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102789950b2dbebd332a0eef5b3bd998c4a7cb7b2b5bfd38dac2836a078eb6322d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Al3h0uxSnTp9owLu8PjFSZZhbUDJQMCVbUcP/CoAfzM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 025de1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 eb68 8402 | 130 d408 (0) d700 (0) d209 (0) d302 (0)\n001 3 741a 48f1 4a95 | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 6 30fe 3728 36b9 26ab | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 4 1fd0 1dc0 1784 1484 | 16 194e (0) 19ea (0) 18e0 (0) 1b1d (0)\n004 4 0d1c 0e3b 0942 08f8 | 11 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n005 4 07f5 046c 0561 0594 | 4 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n006 3 0191 0111 012b | 3 0191 (0) 0111 (0) 012b (0)\n============ DEPTH: 7 ==========================================\n007 2 0314 035f | 2 0314 (0) 035f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","private_key":"89eff5a9452d1e0c16a61c6b956e8ba73cc6af297693643037294f04f933c9b4","name":"node_025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","services":["bzz","pss"],"enable_msg_events":true,"port":40297},"up":true}},{"node":{"info":{"id":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","name":"node_8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","enode":"enode://5adb68b61a7c2016141b6a2c5f6f62fb6bbaf0055b55208fe1d40c13de6c0f33882fe2c62b81ac1be1dfa20077589c4a2035252280a7fc51de6b283f2402cfbf@127.0.0.1:0","enr":"0xf88fb840c0f93ae82bca086787974a9909d7cb74ab3af63f5282df001769504d385c646d1a08448f09cd3b12b8434eacfb1d951d6d50470fa0c545eac3abc11690ef8bd80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035adb68b61a7c2016141b6a2c5f6f62fb6bbaf0055b55208fe1d40c13de6c0f33","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hAK9YigoEe0jay+h8NQa1LvlTkIO40rcYWTP1Lr4ZY0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8402bd\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4b79 741a 012b 025d | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 5 c603 da36 ff75 eb68 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 2 aaf0 a970 | 37 b8e1 (0) bbaf (0) ba91 (0) bea1 (0)\n003 4 9c8e 9518 9464 9257 | 17 9b8e (0) 9948 (0) 9959 (0) 9f0e (0)\n004 5 8cc3 8ea2 8e7b 8b43 | 9 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n005 7 837f 834f 8358 80d7 | 8 837f (0) 834f (0) 8358 (0) 81a5 (0)\n============ DEPTH: 6 ==========================================\n006 2 87a3 86d6 | 2 87a3 (0) 86d6 (0)\n007 0 | 0\n008 1 84a9 | 1 84a9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","private_key":"0a9e0691c50298a2bc085029a26783b783f3b1d81068d25096da660201582e65","name":"node_8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","services":["bzz","pss"],"enable_msg_events":true,"port":41495},"up":true}},{"node":{"info":{"id":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","name":"node_741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","enode":"enode://b7159c8574bad546d319bf27fe0b85a491ad9e0df9b3974553552f5dcae8ac16db1bdb41f7115872a65027698b5ba532c39b6955a5e8091d9a2158e594a75f69@127.0.0.1:0","enr":"0xf88fb8409311b5e1b31fdf6f1ec55524169f3ce36a87b92068a58be80cba7c7f8bb4e0ee07c122fc032f110c6cf8c75a2855a020d34a069f2acd2066f7b5e4da4ef8b6c80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b7159c8574bad546d319bf27fe0b85a491ad9e0df9b3974553552f5dcae8ac16","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dBqFSuKZ30mnOHJbxYq+YU5eQwL/7NgyC77ehBLRYMA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 741a85\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e681 eb68 9464 8402 | 130 d700 (0) d408 (0) d302 (0) d3e9 (0)\n001 9 2c85 26ab 1fd0 1784 | 65 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n002 7 5a26 5c7c 46bf 4005 | 35 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n003 6 6c01 6d5e 648a 67f3 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 6 7850 7933 7e47 7c46 | 9 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 7049 70f6 | 2 7049 (0) 70f6 (0)\n006 1 7660 | 1 7660 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","private_key":"d86ec48bb09bc70772b1ac1e6c492b9675a44a28adc64095a3be584ce92f8fdc","name":"node_741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","services":["bzz","pss"],"enable_msg_events":true,"port":36283},"up":true}},{"node":{"info":{"id":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","name":"node_4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","enode":"enode://94db8d2b348f151986140b50ea45c8f5983f78caf7ba871b2aeb20a7aefb5e6566c5628c702e8979281130632ade26f0222060bc53728c0c0ddf7137947c5229@127.0.0.1:0","enr":"0xf88fb840558b22c25fa4ad6f7b89ee4a1a18c379bfc0bc76aac0da6365611dff788030f334f0feae2e90705123442b2419a399ad4d6f5f57c8f5f6e781272904113539c60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10394db8d2b348f151986140b50ea45c8f5983f78caf7ba871b2aeb20a7aefb5e65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SpXUn1gFewObVaNPZ6NIwFL2F3AGXkEkP/BV78VwqTU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4a95d4\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 da36 ba91 9464 | 130 d408 (0) d700 (0) d209 (0) d302 (0)\n001 5 26ab 2c85 2a50 298a | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 4 6c01 6790 648a 741a | 26 68cb (0) 6b4e (0) 6e7f (0) 6d3c (0)\n003 8 5144 50c1 5538 5c37 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 6 435d 4005 402c 46bf | 9 46bf (0) 447c (0) 447a (0) 44ad (0)\n005 2 4d91 4cec | 3 4d38 (0) 4d91 (0) 4cec (0)\n============ DEPTH: 6 ==========================================\n006 5 482e 48b8 48de 48d7 | 5 482e (0) 48b8 (0) 48de (0) 48d7 (0)\n007 1 4b79 | 1 4b79 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","private_key":"aa7a512548b186d6f17490300bba5369b634d9649b74c421af1d43d3f8cafec6","name":"node_4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","services":["bzz","pss"],"enable_msg_events":true,"port":43231},"up":true}},{"node":{"info":{"id":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","name":"node_4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","enode":"enode://7e2ea6ad36e886e7ef31de1d7d85a0a3d85618dea99621ee2bceacb048b10e9b26862e9fe9a918204e39cb7ed0b1c849b19345b1064cf890de27151a144ecdc0@127.0.0.1:0","enr":"0xf88fb8409159ad0c33b90bbed5e06a27c0189aecee7e3eeaf36cc509cf20318bfee1d84d525df4a5b228a2e4fccf906ba509a8318400ec3cfeaf76d800fade5a071b9f560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027e2ea6ad36e886e7ef31de1d7d85a0a3d85618dea99621ee2bceacb048b10e9b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"S3noMYbyqwWTLqqZmCouUzc7g3gOMtIk0VyyyFRiRR8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4b79e8\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ba91 8402 9464 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 3 012b 08bd 08f8 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 3 648a 741a 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 5 5a26 5bd8 5c37 5c7c | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 435d 4005 46bf 447a | 9 46bf (0) 447c (0) 447a (0) 44ad (0)\n005 2 4cec 4d91 | 3 4cec (0) 4d38 (0) 4d91 (0)\n============ DEPTH: 6 ==========================================\n006 5 482e 48b8 48f1 48de | 5 482e (0) 48b8 (0) 48de (0) 48d7 (0)\n007 1 4a95 | 1 4a95 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","private_key":"e6dad134228b16f662707d719d2a5b4104da298ca8bdb6085d4d86557ff74820","name":"node_4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","services":["bzz","pss"],"enable_msg_events":true,"port":42249},"up":true}},{"node":{"info":{"id":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","name":"node_08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","enode":"enode://266b673803b457c94430107ebcaad9bbe27ca7b2d7f2f4a2795330eb1370ef17684e5f79a2b76a8e8b68388a0135357d0643a71451e4475030776a4662c17dd5@127.0.0.1:0","enr":"0xf88fb840f107f7f7c79de397fcaa167703a506621bf1b28b3a12767f3f3b156c7d64d64a4a4bd7e9ec8535b076496f0d44b8077b7597f9b75a20a611dba6ecc55ffe6f900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103266b673803b457c94430107ebcaad9bbe27ca7b2d7f2f4a2795330eb1370ef17","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CPhIeORP7SrbSyaFufKT3Dxz1fm8HEdIcNlD7CrnPb4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08f848\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c42e c2d0 c8ea cdb1 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 5 7660 741a 4005 48f1 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 5 26ab 2c85 3c5b 3728 | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 5 1fd0 1dec 1dc0 1784 | 16 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n004 3 0111 012b 025d | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 4 0d1c 0cfc 0e80 0e3b | 5 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 096a 0942 09b3 | 3 0942 (0) 096a (0) 09b3 (0)\n008 0 | 0\n009 1 08bd | 1 08bd (0)\n010 0 | 0\n011 1 08e5 | 1 08e5 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","private_key":"c9ea240d0ca10a37109b638b6ff80df72e80f58b0bdaab9117ece2449c7ded0f","name":"node_08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","services":["bzz","pss"],"enable_msg_events":true,"port":33617},"up":true}},{"node":{"info":{"id":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","name":"node_81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","enode":"enode://9c7ee34c91cca6a255a1d8adf1770f230ddc3b14a4fd7052094be159092b67122725fa2cbea906cf1014c841ef9be502872b8e7205e080a0861036ac05c947bc@127.0.0.1:0","enr":"0xf88fb84016f0ddeab6ab02fec27c0d81fe6b7c75926f73593cc76cfe70a797016f5de68257234757637d614c0e3afe0b4a62d76a0ea9e61189d9b6cc35df8210941da9800183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029c7ee34c91cca6a255a1d8adf1770f230ddc3b14a4fd7052094be159092b6712","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gaWgf5L4E+hbUBsAKOHKpuamx++lGV7LaTzS2R1RMqA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 81a5a0\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5a26 48f1 7660 08f8 | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 3 da36 e681 ff75 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 3 aaf0 a0c8 b3f9 | 37 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n003 2 9c8e 9518 | 17 9b8e (0) 9959 (0) 9948 (0) 9f0e (0)\n004 5 8cc3 8e28 8e7b 8b43 | 9 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n005 4 87a3 86d6 84a9 8402 | 4 87a3 (0) 86d6 (0) 84a9 (0) 8402 (0)\n006 3 837f 834f 8358 | 3 837f (0) 834f (0) 8358 (0)\n============ DEPTH: 7 ==========================================\n007 4 80d7 8073 8074 8006 | 4 80d7 (0) 8006 (0) 8073 (0) 8074 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","private_key":"f268036ece7b4c34b20e291a59e9e6eb8c169846ed02ae120104c2a9db928aa8","name":"node_81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","services":["bzz","pss"],"enable_msg_events":true,"port":41021},"up":true}},{"node":{"info":{"id":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","name":"node_7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","enode":"enode://57d4fa9adc668bc6252f2871ae51f3507be8299126d91348d691d765826efd907e3086acd9c139e0d4f2ad542648e855aed9dd718e7b160ccff5e2d3eda8d109@127.0.0.1:0","enr":"0xf88fb840728d16ca2bed2ed57accf482d7d01246e23016bfb73bffb10c3b7b47db93f7b6528ae999d54cf0807af525b9c502e27200c19a8faaf1f69330d98b8488863ef10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10357d4fa9adc668bc6252f2871ae51f3507be8299126d91348d691d765826efd90","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dmCCj7DI+JIB005vTWHMa6mjDOrW5OuCU/bMkuGEXyM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 766082\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c603 da36 81a5 | 130 c8c8 (0) c8ea (0) c9c3 (0) c961 (0)\n001 5 2c85 3728 36b9 012b | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 10 5a26 5bd8 5663 5144 | 35 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n003 5 6c01 6d5e 6795 6790 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 6 7850 7e47 7d16 7c46 | 9 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 70f6 7049 | 2 70f6 (0) 7049 (0)\n006 1 741a | 1 741a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","private_key":"a661a84382c924fa6b8c1d349120fa836ebbeb7f53552df109787f65a9ea40b1","name":"node_7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","services":["bzz","pss"],"enable_msg_events":true,"port":33705},"up":true}},{"node":{"info":{"id":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","name":"node_48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","enode":"enode://bdc3539551669afb2e5251b20cd32b76991a299ed144c7cdf2df6a562307c9ccb061dc13c4a0428c279b481d48bdc454f8cf3c2d334d023820636940194a536a@127.0.0.1:0","enr":"0xf88fb840166e7488211c50622095d0c7a0a9b5798b716da7a2f18087617760eab6cbd432533b34999879c21ac95d597a2e7afdc751503e82f98018f4988dcfc2255bb7de0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bdc3539551669afb2e5251b20cd32b76991a299ed144c7cdf2df6a562307c9cc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SPHKbUMwGfky+krgPg3svL6j/mNe3/RFimabg/gWK5o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48f1ca\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 da36 81a5 ba91 b3f9 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 2 025d 08f8 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 6c01 6795 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 7 5538 52a8 5144 5c37 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 402c 4005 447a 44ad | 9 46bf (0) 447c (0) 447a (0) 44ad (0)\n005 2 4cec 4d91 | 3 4cec (0) 4d38 (0) 4d91 (0)\n006 2 4b79 4a95 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 1 48b8 | 1 48b8 (0)\n010 2 48d7 48de | 2 48de (0) 48d7 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","private_key":"93ccc60464556d17f764da4d4f9627036f03862e51eedf2272ff4ab6de460bca","name":"node_48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","services":["bzz","pss"],"enable_msg_events":true,"port":44895},"up":true}},{"node":{"info":{"id":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","name":"node_b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","enode":"enode://0fff61eaf24fc39fce31fcc08d7f4530cf34ea9b316c8552a2665bb588bc2b715ac681a15fec8f10bd07b5e7efba1b60dbceb2bda52c437fe7e10bef54e9385b@127.0.0.1:0","enr":"0xf88fb8408e0903553e420a153b07746b27efee96df98e493517320da509b578ea9a335ad7d7f75c1be85cc91b87448690b53259d60f1f1d962827db10e0c45302d5991460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030fff61eaf24fc39fce31fcc08d7f4530cf34ea9b316c8552a2665bb588bc2b71","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s/lfIl4ra3bmx+98hsr4PjUhP2oi2kHmU8ocGQviPJw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b3f95f\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 44ad 4005 48f1 | 126 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n001 5 ff75 e277 c2d0 c603 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 7 9c8e 9257 9518 8cc3 | 38 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n003 10 a330 a0c8 a5ac a505 | 23 a4ee (0) a5ac (0) a505 (0) a7a8 (0)\n004 8 bdc5 bcf8 bea1 be68 | 8 bcf8 (0) bdc5 (0) bea1 (0) be68 (0)\n============ DEPTH: 5 ==========================================\n005 5 b5ea b4a1 b6df b659 | 5 b4a1 (0) b5ea (0) b659 (0) b6df (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","private_key":"b88ec7f2f180fa33cf884de2d17cd8bb2fd54c0091c86a3485fa2253753391f4","name":"node_b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","services":["bzz","pss"],"enable_msg_events":true,"port":38851},"up":true}},{"node":{"info":{"id":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","name":"node_4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","enode":"enode://d59ebe745d21b2e3762354724988cc2e1922981561a7a1b59c692b63aab87866680e05dbd639fbc0e1edeea41158e6f0fc89f9858965ddfb88c4f7a837044694@127.0.0.1:0","enr":"0xf88fb8408bd7fa4d67c32ec7cede14876f0a7782e437190163434552f623d2b45f923ba14d0f771d61ec044c8ba306a6f70b9985dbb9ee95912d035959e20b757ce8a4e80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d59ebe745d21b2e3762354724988cc2e1922981561a7a1b59c692b63aab87866","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QAX9H6j7sxiymmLDaK2leeUSLKBXjmp1xQlVK+S2O3Y=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4005fd\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 da36 ff75 9518 ba91 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 4 2c85 1484 08f8 0e3b | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 4 6790 648a 741a 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 5a26 5bd8 5c7c 5c37 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 4a95 4b79 48b8 48d7 | 10 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n005 4 46bf 447a 447c 44ad | 4 46bf (0) 447c (0) 447a (0) 44ad (0)\n============ DEPTH: 6 ==========================================\n006 3 43d4 43c9 435d | 3 43d4 (0) 43c9 (0) 435d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 402c | 1 402c (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","private_key":"a8676ecb5e3d5d9afec421fe21a57c5fc1d107a450dc67d5f5882520afa62a7c","name":"node_4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","services":["bzz","pss"],"enable_msg_events":true,"port":37241},"up":true}},{"node":{"info":{"id":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","name":"node_ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","enode":"enode://3d2e2c472696bba49a923f035e188a58a75779bfaf0028b65c790cc6a72fcb0522fd663a55e2e7d8e2983cb895d6808cb75263b2e36ab3e6da0795ca222c1eb7@127.0.0.1:0","enr":"0xf88fb840a320a767aa7097e0c7a488fcc471bd6d30e05b616b05a63af5bcc89118d574f21c903d1427e4802c1331a3a2dc43b52ecbed21f4b1bbc488d64a8f640550ba990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d2e2c472696bba49a923f035e188a58a75779bfaf0028b65c790cc6a72fcb05","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/3WxkBfIQSjzjexPY+HyR6VpHcD64YbmZ6/ttf6dLIA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ff75b1\npopulation: 44 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2a50 26ab 0e3b 44ad | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 11 b3f9 a616 a0c8 ab71 | 75 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n002 12 c42e c6a8 c603 c74d | 27 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n003 7 e867 eb68 eff2 e277 | 14 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n004 4 f756 f1ed f305 f215 | 7 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n005 2 f9de f8ff | 3 fa24 (0) f9de (0) f8ff (0)\n============ DEPTH: 6 ==========================================\n006 2 fc51 fc39 | 2 fc51 (0) fc39 (0)\n007 1 feb3 | 1 feb3 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","private_key":"a98bd329cd3c7942c9f230208e49b4c880749a41fcd4ccf7561fab55c6c08641","name":"node_ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","services":["bzz","pss"],"enable_msg_events":true,"port":33251},"up":true}},{"node":{"info":{"id":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","name":"node_44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","enode":"enode://888d38ff57ed4518cedab3e8dd7e3c2974e8a18eb4105f019d5da60aeea595855f40a76650488189d7de83a61938b4546ae8f1bb85109783ec72c771e5689819@127.0.0.1:0","enr":"0xf88fb840e02be04b2b82d311eb77cd1c1af28fba50cdcceb3a24f4bdb29b0f6450344a6d5d8cb185e0ef49a9d8b194f7819fc6ad342d52f9cb50cfc49c284a7c78d351590183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103888d38ff57ed4518cedab3e8dd7e3c2974e8a18eb4105f019d5da60aeea59585","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RK2qv5xGYIo3TtgW08QMY7ZkX09uAzp2QxvI+IcT60E=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 44adaa\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ba91 b3f9 ff75 | 130 a4ee (0) a5ac (0) a505 (0) a7a8 (0)\n001 3 1484 012b 0e3b | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 6790 648a 7660 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 5a26 5bd8 5c37 5538 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 48b8 48d7 48f1 4a95 | 10 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n005 4 43d4 435d 402c 4005 | 5 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n006 1 46bf | 1 46bf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 447c 447a | 2 447c (0) 447a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","private_key":"97d76c34244a41e0f1ac5de3b564727ac2f324b9ad5cfca455fe8b70c05abb39","name":"node_44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","services":["bzz","pss"],"enable_msg_events":true,"port":38577},"up":true}},{"node":{"info":{"id":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","name":"node_0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","enode":"enode://cdf4c78c9aa3593dd7a6467f48660ca11115fbe248d9cf9e1d57c19c890c1fc71aca0582ad7017bdc5053ce094c5905b7f77e2be5402f313786253842933cd16@127.0.0.1:0","enr":"0xf88fb840ee3d9598b270079ccc13e4add3d88bee1c6abf8d5e8431c4681a6ae45369d4b0668f324e4de0c56328849c15238ea899fc1710b328f6172fbf89dff1306ab2bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cdf4c78c9aa3593dd7a6467f48660ca11115fbe248d9cf9e1d57c19c890c1fc7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Djt3IvP4TYOz10S+pOiTcVoB1N889KHGpoI6H1ya1rg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e3b77\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9518 ff75 da36 | 130 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n001 2 4005 44ad | 61 7895 (0) 7850 (0) 79e5 (0) 7933 (0)\n002 3 26ab 3728 36b9 | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 7 1fd0 1dec 1add 18e0 | 16 194e (0) 19ea (0) 18e0 (0) 1b1d (0)\n004 5 0111 012b 0314 035f | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 6 09b3 0942 096a 08bd | 6 0942 (0) 096a (0) 09b3 (0) 08bd (0)\n006 2 0cfc 0d1c | 2 0cfc (0) 0d1c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0e80 | 1 0e80 (0)\n009 0 | 0\n010 0 | 0\n011 1 0e2b | 1 0e2b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","private_key":"4f28295b9dd454af1f4de9ea11d0d1a2952fc64eb6835cbc1c6c1a564d826654","name":"node_0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","services":["bzz","pss"],"enable_msg_events":true,"port":41795},"up":true}},{"node":{"info":{"id":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","name":"node_da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","enode":"enode://61c96923ec6ffd96df32f0db9954bf468bd5c4c24271a86b243cd934bc8da77f1177964c7a53fc07b86f5ef32a9e1c85af77bb56fd699a99f15caae4fbb38a68@127.0.0.1:0","enr":"0xf88fb8405a4f50ee12c7e45a28c023ae4e6c05ca7407d66aea05f2837e8718b934145bb30f026867c53e3fd3eb1c9ca2829a6fe691a3b5edacee2cdd0fcd600c5614255b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261c96923ec6ffd96df32f0db9954bf468bd5c4c24271a86b243cd934bc8da77f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2jbR35WhWLDT+edAfWY6a2Ed3gp38ApYS5epOatqAN4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: da36d1\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7660 48f1 4a95 4005 | 126 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n001 8 a0c8 acee aaf0 b3f9 | 75 b8e1 (0) bbaf (0) ba91 (0) bea1 (0)\n002 6 e681 e277 eb68 e867 | 28 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n003 9 c8ea cdb1 cc33 c2d0 | 16 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n004 3 d209 d302 d3e9 | 5 d700 (0) d408 (0) d3e9 (0) d302 (0)\n005 1 ddb8 | 1 ddb8 (0)\n006 2 d9cf d959 | 2 d9cf (0) d959 (0)\n============ DEPTH: 7 ==========================================\n007 1 dbd4 | 1 dbd4 (0)\n008 1 dad0 | 1 dad0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","private_key":"2022f7c1008e4670055ca434f78ed6debd0e7564d06d9d22625bafe9c2184bc8","name":"node_da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","services":["bzz","pss"],"enable_msg_events":true,"port":39225},"up":true}},{"node":{"info":{"id":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","name":"node_951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","enode":"enode://e61d35f746dd8b1d91286e1abb0448cbb68371b867574358604ed002233ecaebfcd5a07cbabc0bdca25a58c76fa53abd80a1bf7d62c410f2841611b676334041@127.0.0.1:0","enr":"0xf88fb840f8c031b80bf4308c84323e167eeca84179f0feebb5aad18f694024f8fde4f3424adbec09f917bc90d2d319b9debb6c903064655c754915614dc59b490178d75b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e61d35f746dd8b1d91286e1abb0448cbb68371b867574358604ed002233ecaeb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lRh3s07hU1tQWcSb6wPolg/5wStpTvZHCMd8MP8dxwY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 951877\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4005 0e3b 36b9 2c85 | 126 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n001 3 e867 ff75 da36 | 55 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n002 2 b3f9 ab71 | 37 be68 (0) bea1 (0) bfc7 (0) bcf8 (0)\n003 9 8862 8b43 8cc3 8e7b | 21 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n004 3 9ec8 9f7d 9c8e | 9 9948 (0) 9959 (0) 9b8e (0) 9f0e (0)\n005 3 93c0 93ea 9257 | 3 93ea (0) 93c0 (0) 9257 (0)\n006 1 97da | 1 97da (0)\n007 1 9464 | 1 9464 (0)\n============ DEPTH: 8 ==========================================\n008 1 95c0 | 1 95c0 (0)\n009 1 955d | 1 955d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","private_key":"bc5b57ce450e26704097f3e90b7256f3d38b4a75973b2384deec064351eee3f7","name":"node_951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","services":["bzz","pss"],"enable_msg_events":true,"port":39271},"up":true}},{"node":{"info":{"id":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","name":"node_ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","enode":"enode://ac1fef7e9d3c51f02d8ade00cb8763bb163c214f15f52ba8025bfb6355dca1d1a9779350f5c60d02763b12902f5b176366dec0e51eb4879d0031a407cb80ba6d@127.0.0.1:0","enr":"0xf88fb84047e8f17977626db088d3ce02b567c210e5ded10efc65966d542ffd2e829e25822186597f28307a91d4fde8fc4019ff71797412eb3a69a20aa8deb95f096b3c370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ac1fef7e9d3c51f02d8ade00cb8763bb163c214f15f52ba8025bfb6355dca1d1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"q3GeYKd7pSU/FpDJIN+d2fOmIHHpzOnWLgABpSKzQJ4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ab719e\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 36b9 2c85 | 126 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n001 5 c603 e277 e681 e867 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 3 84a9 9c8e 9518 | 38 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n003 3 ba91 bdc5 b3f9 | 14 bea1 (0) be68 (0) bfc7 (0) bcf8 (0)\n004 3 a616 a330 a0c8 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 2 aeb4 acee | 3 acee (0) af02 (0) aeb4 (0)\n006 4 a970 a8f4 a8ff a8b5 | 4 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n============ DEPTH: 7 ==========================================\n007 1 aaf0 | 1 aaf0 (0)\n008 0 | 0\n009 1 ab3f | 1 ab3f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","private_key":"a4ae96d7ecb3971ea097b37390920857ffaf67fc5bae59c8cabde67de15feeb1","name":"node_ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","services":["bzz","pss"],"enable_msg_events":true,"port":34781},"up":true}},{"node":{"info":{"id":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","name":"node_2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","enode":"enode://b1fe3894a67c4139a898d93a93cacc87e3e6a0072f2e75faa1d692fcdae02da9056ee9d0ef8bd7de2d4cb801bea1a4c92867b686648ccdf4acc15d10ea9e92ab@127.0.0.1:0","enr":"0xf88fb840acad001cebe20e5d67e33bade1ef67f0c02b361f95b012af873d06038de2c89e7a9bcb738bbf325462227e88eefa257d8d3e3fe6567496e9bd6bcf7a4315e7b70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b1fe3894a67c4139a898d93a93cacc87e3e6a0072f2e75faa1d692fcdae02da9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LIX1NhstWrz3md5Q/lix7SAG6hj3WCN0jDPrfpWxzDk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c85f5\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c534 8e7b 9c8e 9518 | 130 e471 (0) e64d (0) e681 (0) e0a0 (0)\n001 7 741a 7660 6795 648a | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 9 1484 1add 1fd0 1dec | 37 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n003 7 3c5b 3cab 3a62 3b02 | 17 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n004 4 244c 24f8 26ac 26ab | 4 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n005 2 298a 2a50 | 2 298a (0) 2a50 (0)\n006 2 2fd2 2e65 | 2 2fd2 (0) 2e65 (0)\n============ DEPTH: 7 ==========================================\n007 1 2ddf | 1 2ddf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 2c80 | 1 2c80 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","private_key":"2a8ffc679012d1aa50e2f65a8e57b2ec4320e84272a5e905cb90098bace2bddb","name":"node_2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","services":["bzz","pss"],"enable_msg_events":true,"port":36571},"up":true}},{"node":{"info":{"id":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","name":"node_36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","enode":"enode://e4d9f33c795e51155d700cb64f1a8d4ead769a1d93d77825a6c680750ad444ef939dbfcecf0020bb04e1bb818d28af91aaa6809d9abb42ebd3088ff3c351ec3f@127.0.0.1:0","enr":"0xf88fb84053bd3c1b1a365ed2377b3066ad1f581f1d671a75bebdf3c21d41c6e15045a85771fe183fc7f77629dcf4d2be91de26315edfc83ccc82cb68b3e900fb1fd3a6330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e4d9f33c795e51155d700cb64f1a8d4ead769a1d93d77825a6c680750ad444ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Nrk2VsqwIhP6dhJK9iURCTVqvF4K5d0eIDxqAT4BRUg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 36b936\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9518 ab71 aaf0 | 130 f305 (0) f215 (0) f2b4 (0) f1ed (0)\n001 5 648a 7660 46bf 5a26 | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 10 1fd0 138d 1784 1484 | 37 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n003 4 26ab 2a50 298a 2c85 | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 7 3c5b 3cab 3f31 3938 | 8 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n005 5 32ff 3051 30fe 31e1 | 6 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n============ DEPTH: 6 ==========================================\n006 1 3411 | 1 3411 (0)\n007 1 3728 | 1 3728 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","private_key":"fc142c5cdb7737fcd9e994ef0aab4a60ef1b23c59685a99f70384ecdcab96da9","name":"node_36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","services":["bzz","pss"],"enable_msg_events":true,"port":34195},"up":true}},{"node":{"info":{"id":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","name":"node_aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","enode":"enode://7108119c77ee1ca51a8cfa49207c81c9236c48de66d0ec4441d03b409214e6cb3e6aeda9074eefc6cab261e2da67787c1e6dc5c56d9face762f3c6d228ddb3bf@127.0.0.1:0","enr":"0xf88fb840e1516801e5e9795f89e9742eb3c020e4aeab9eaa0544e8eaf742e91b186387817613a49d6e2bc5ca531ae9afe63aed360830056c25d161bee0ccf74ec289a82c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037108119c77ee1ca51a8cfa49207c81c9236c48de66d0ec4441d03b409214e6cb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qvBRoIepL4dKP2x5IwFeTP+0uz7zgcl3/ZAvIehB0PQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aaf051\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3728 36b9 | 126 7895 (0) 7850 (0) 79e5 (0) 7933 (0)\n001 5 ff75 e277 e867 da36 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 7 9c8e 8cc3 81a5 8006 | 38 87a3 (0) 86d6 (0) 84a9 (0) 8402 (0)\n003 3 bdc5 ba91 b3f9 | 14 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n004 3 a616 a330 a0c8 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 2 aeb4 acee | 3 acee (0) af02 (0) aeb4 (0)\n006 3 a8f4 a8b5 a970 | 4 a8ff (0) a8f4 (0) a8b5 (0) a970 (0)\n============ DEPTH: 7 ==========================================\n007 2 ab3f ab71 | 2 ab3f (0) ab71 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","private_key":"4faa6df719db312ce7196c8b218ffe31a118192b63af6a064b63993d06809021","name":"node_aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","services":["bzz","pss"],"enable_msg_events":true,"port":43443},"up":true}},{"node":{"info":{"id":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","name":"node_3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","enode":"enode://c114f0b7917ddfc94778644a8fcb80d6219c100706ef4f7685c3a1b20836923b2f8b668cb508c542e5140d0de8dbf3eb6d39dd3fa988cc89e5a35475d33c5ff5@127.0.0.1:0","enr":"0xf88fb8409f56eb9c402420e1ba9d1221c060d99fadee62aa892110c184c542ddc788cb872ee790ce149a666c38cbe359cba9f433a75a62641e1d1f785c7bf1f7e9c0ac220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c114f0b7917ddfc94778644a8fcb80d6219c100706ef4f7685c3a1b20836923b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NygVLIjx5eYfZSOwno87sQI7cA3szcpfzB5kiBNrDlc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 372815\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9c8e aaf0 | 130 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n001 5 7660 648a 5bd8 5144 | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 11 138d 1484 1784 1dc0 | 37 1049 (0) 1070 (0) 138d (0) 1686 (0)\n003 2 26ab 2c85 | 11 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n004 4 3c5b 3cab 3b02 3a62 | 8 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n005 5 30fe 3051 3188 31e6 | 6 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n============ DEPTH: 6 ==========================================\n006 1 3411 | 1 3411 (0)\n007 1 36b9 | 1 36b9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","private_key":"3557d9f64ffafd68249ae21654f5c1fd8576ede29a7e184fa2c80dcfcf01ca7d","name":"node_3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","services":["bzz","pss"],"enable_msg_events":true,"port":41719},"up":true}},{"node":{"info":{"id":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","name":"node_9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","enode":"enode://4c2931c91d607781aedf9552788ec9df705def28333007e9246811be0a3ebfa8eb44baad1ddf0620a99257cb0cf9afaf7f714cae4f241510bffdf3c4b6682350@127.0.0.1:0","enr":"0xf88fb840d76ae62f54de16a707c5789592f92afaa9c1ad444f8e7fa013c8f39c20a34d4f2c0d88f8931465fc033eb4be4b1c1f4fe8150dd91ba8297ce363ffa61f1d4d440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c2931c91d607781aedf9552788ec9df705def28333007e9246811be0a3ebfa8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nI4fI/JgxaRrAAFXJnWxnlKTymXn/fwTHAdhLpxAcvo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9c8e1f\npopulation: 44 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 46bf 08e5 2c85 3728 | 126 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n001 3 ff75 e867 c603 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 9 b3f9 a616 a0c8 a330 | 37 b8e1 (0) bbaf (0) ba91 (0) bea1 (0)\n003 14 87a3 86d6 84a9 8402 | 21 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n004 7 9257 93c0 97da 9464 | 8 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n005 3 9b8e 9948 9959 | 3 9b8e (0) 9959 (0) 9948 (0)\n006 2 9f7d 9ec8 | 3 9f0e (0) 9f7d (0) 9ec8 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 9c21 | 1 9c21 (0)\n009 0 | 0\n010 1 9ca1 | 1 9ca1 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","private_key":"f14ad2c3fc9ee9c4bf7c847d746dbc352159a0f470e5f9c054c623e85b32dd58","name":"node_9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","services":["bzz","pss"],"enable_msg_events":true,"port":41867},"up":true}},{"node":{"info":{"id":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","name":"node_46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","enode":"enode://4d4243ce1bbd72776f1cd9a14309b16117af879a4d6670c2c684a772062c9ca6ce7591b97f0b28a854431891b0d2b0d4517991326bbaf7aba8056bb1eae0fd6b@127.0.0.1:0","enr":"0xf88fb84047ede3289ec2767e1b71b8a461306f27846efb00e6bd82d79a5712ec11cf570a5dd5b750d5ee3254949142a30b40d0a43174a43a895303db9fe7e2794325736e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034d4243ce1bbd72776f1cd9a14309b16117af879a4d6670c2c684a772062c9ca6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Rr+ovqVrC+Gr+lrTVhu2v0ntZpXYPuKywZLFoECDR88=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 46bfa8\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9c8e ba91 a0c8 | 130 f6c0 (0) f645 (0) f756 (0) f305 (0)\n001 3 08e5 36b9 3728 | 65 1070 (0) 1049 (0) 138d (0) 1686 (0)\n002 5 6c01 648a 6795 741a | 26 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n003 4 52a8 50c1 5144 5a26 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 5 4a95 4b79 48b8 48d7 | 10 4d38 (0) 4d91 (0) 4cec (0) 4a95 (0)\n005 4 4005 402c 43d4 435d | 5 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n============ DEPTH: 6 ==========================================\n006 3 447c 447a 44ad | 3 447c (0) 447a (0) 44ad (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","private_key":"b70820e75826e847f92eaf68756a7853fdb2b9405385a07431acd85be07346c3","name":"node_46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","services":["bzz","pss"],"enable_msg_events":true,"port":46727},"up":true}},{"node":{"info":{"id":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","name":"node_a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","enode":"enode://c4dfc6549432092140b323c294e153ed2fce4e66d90c5342dd739a17b6f8e941241ae157f54b265c8c20b6fdbea7d31097672735a366fd0a39cd6b8e3b7a8b9e@127.0.0.1:0","enr":"0xf88fb84096f40381fc8d8894e700731acada297f8d3f467ebe034ffb0fb3ba1aed4804fc2b00a87923ceb549a89ef5c5cf4d2fe663bb50e216cd249ef9a408b6c57ffe2b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c4dfc6549432092140b323c294e153ed2fce4e66d90c5342dd739a17b6f8e941","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oMiLpwWZsOcsGPpq7dFNYHzKPppJpdUBZdCE5wMowt0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a0c88b\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 648a 5144 46bf | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 da36 c603 c6a8 ff75 | 55 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n002 8 9257 9c8e 8e7b 84a9 | 38 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n003 5 b3f9 bdc5 be68 bfc7 | 14 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n004 5 aaf0 ab71 a970 aeb4 | 10 acee (0) af02 (0) aeb4 (0) a8f4 (0)\n005 4 a505 a7a8 a606 a616 | 7 a4ee (0) a5ac (0) a505 (0) a742 (0)\n============ DEPTH: 6 ==========================================\n006 4 a2a1 a2e6 a327 a330 | 4 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n007 1 a1c8 | 1 a1c8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","private_key":"1d99f9d95bb5133e67b3abc4fa875f292bb3ef13fc4c32d522507cb6251a737b","name":"node_a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","services":["bzz","pss"],"enable_msg_events":true,"port":38619},"up":true}},{"node":{"info":{"id":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","name":"node_648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","enode":"enode://d8d46c12cb0b4cecaf8ab1b972365c7b0568897ccea94352a7b702da0ca1bc6bf559f91c6612d9f452d2af2a32d9b56233b6176241e824db5d784bd0f8015b9b@127.0.0.1:0","enr":"0xf88fb84012854e946d3ccd03e5b967f46ecf70aa3b0b1ccebf7bb7d40f2f80c30110a99b478aa38170b4c3aea017b04fbafa023de9fc42342d0643729f55ce9d2b7119760183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d8d46c12cb0b4cecaf8ab1b972365c7b0568897ccea94352a7b702da0ca1bc6b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ZIqW1hiY6y0zb/fVoinP63ufWHKC5A+f5kDhga4mvdM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 648a96\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c603 aeb4 a0c8 | 130 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n001 4 2c85 36b9 3728 08e5 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 9 4b79 4a95 402c 4005 | 35 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n003 6 7ce7 7c7c 7e47 7049 | 13 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n004 4 6b4e 6e7f 6d5e 6c01 | 7 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n005 1 60c5 | 1 60c5 (0)\n============ DEPTH: 6 ==========================================\n006 4 6758 67f3 6790 6795 | 4 6758 (0) 67f3 (0) 6790 (0) 6795 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","private_key":"919debfc547283a6f83386441c4f7b3eaec238931b8e97ea9cf7b8f5516ff110","name":"node_648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","services":["bzz","pss"],"enable_msg_events":true,"port":34693},"up":true}},{"node":{"info":{"id":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","name":"node_51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","enode":"enode://61414ffd81e2e685b199ba6089abc6cf7c18cf4bd3654114e8c2a99dfdc4413b8e36b194557bf9b65dc44deaa9478cd4f1c712bbd946ec4ae3e057c878f05610@127.0.0.1:0","enr":"0xf88fb840bb0506fc37a0cd2ae940ab2b93d4b26476b65fbfb40eefe43af7b43776d9a275164cb946279137a07b6bc6cca0ab5bacc802d203049766cf1abf3081b6d7c1ca0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261414ffd81e2e685b199ba6089abc6cf7c18cf4bd3654114e8c2a99dfdc4413b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UUQKtH/FB2wAytFqVCuEbCazKB7OpNvKeVrpuAGD7JA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 51440a\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 aeb4 a0c8 e277 c603 | 130 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n001 3 3728 36b9 08e5 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 7660 6795 648a | 26 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n003 9 48f1 4a95 4b79 435d | 19 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n004 4 5c7c 5c37 5bd8 5a26 | 10 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n005 3 5663 56ca 5538 | 3 5663 (0) 56ca (0) 5538 (0)\n============ DEPTH: 6 ==========================================\n006 1 52a8 | 1 52a8 (0)\n007 1 50c1 | 1 50c1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","private_key":"1e8a712b0dd95600c1e67872aa3bcc3e875f05bfe3dacb2f0d546ccd810825bc","name":"node_51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","services":["bzz","pss"],"enable_msg_events":true,"port":36863},"up":true}},{"node":{"info":{"id":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","name":"node_c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","enode":"enode://bed7f6e2cf97600f47210eb1b764eabd6a4725c42d3a7333ed8c4b102442528805dbb8bbcc925fcb62432d06c6418410818d9acbc7bccc0c5979e978bc71a414@127.0.0.1:0","enr":"0xf88fb84044f3f935b08146d7ec9f7864874f4641340f171f272858a0f0889877add866cb5795ad8f80508454ba568f7a3f082d552beb4897dd6eb51d7f8675869573fcaf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bed7f6e2cf97600f47210eb1b764eabd6a4725c42d3a7333ed8c4b1024425288","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xgMTjkD+L4XMY0AXlWraY5n8qZlp478MHuhCg3TnefE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c60313\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 08e5 7660 648a 5144 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 b3f9 a0c8 aaf0 ab71 | 75 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n002 6 ff75 e681 e277 eff2 | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 5 d3e9 d302 d209 d959 | 11 d408 (0) d700 (0) d3e9 (0) d302 (0)\n004 5 c8c8 c961 cf52 cd6c | 8 c8ea (0) c8c8 (0) c9c3 (0) c961 (0)\n005 3 c190 c272 c2d0 | 3 c190 (0) c272 (0) c2d0 (0)\n006 2 c42e c534 | 2 c42e (0) c534 (0)\n============ DEPTH: 7 ==========================================\n007 1 c74d | 1 c74d (0)\n008 1 c6a8 | 1 c6a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","private_key":"f8c72bb1240635df9cef74f22b6fe80b40ab667b1917f49f50bbdff097c07eb4","name":"node_c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","services":["bzz","pss"],"enable_msg_events":true,"port":35079},"up":true}},{"node":{"info":{"id":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","name":"node_08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","enode":"enode://ea5b166448c3dd527b2c18555655ee6f90b2bbf3b1d4a447c551801ecab3dba7e5dca4dd2877fc63533ca94dbb39d0583cd6551a0e81bc418ac506a0b2fcdf27@127.0.0.1:0","enr":"0xf88fb840c953b80c5d75dd35fac2c5a49c4dc5308f80a1a9482547b48755d37fb417193c0dc806cf8ce00ec289850183f6837f5c684a68add6e9420bdb6fb937684d72b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ea5b166448c3dd527b2c18555655ee6f90b2bbf3b1d4a447c551801ecab3dba7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"COWiaPOXOFxpp/7IVa5NiJz6mK/vW3wJ/EhB4/iJStg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 08e5a2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9c8e aeb4 e277 e867 | 130 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n001 4 648a 46bf 5144 5a26 | 61 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n002 3 2c85 36b9 3728 | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 6 138d 1784 140d 1484 | 16 1049 (0) 1070 (0) 138d (0) 1686 (0)\n004 4 0594 0314 012b 0111 | 10 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n005 4 0d1c 0cfc 0e2b 0e3b | 5 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 09b3 0942 096a | 3 0942 (0) 096a (0) 09b3 (0)\n008 0 | 0\n009 1 08bd | 1 08bd (0)\n010 0 | 0\n011 1 08f8 | 1 08f8 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","private_key":"23182ea48dee85a9137e3024980f59b9d2ab3ff4d922fcd1b30583fdf83baaca","name":"node_08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","services":["bzz","pss"],"enable_msg_events":true,"port":45333},"up":true}},{"node":{"info":{"id":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","name":"node_5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","enode":"enode://2ef3561ee8a3827e57f043fc9f0ab7cffb1bcd3ae7cdbbcf67699cd748e6b8da52fcbf6de1738f3da9b1101b0accddafdd133fbd61899b1a5c45a148344055d0@127.0.0.1:0","enr":"0xf88fb84086144704d9432e5493c584d85cf6d3997698361f501788b244566421cbd614c02beeeba7a937b9b0f2616fef916d5978e3079068bedcc45fcf6f749fa354a41d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022ef3561ee8a3827e57f043fc9f0ab7cffb1bcd3ae7cdbbcf67699cd748e6b8da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Wiauc+6/J/bb7CQU8Sd6JJ6BSnoGeQ1wYWEOUiewhvY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a26ae\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 84a9 81a5 8006 80d7 | 130 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n001 3 2c85 36b9 08e5 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 6 7c46 7e47 741a 7660 | 26 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n003 9 4b79 4a95 48f1 435d | 19 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n004 2 52a8 5144 | 6 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n005 3 5d82 5c37 5c7c | 4 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n006 2 5814 5987 | 2 5814 (0) 5987 (0)\n007 1 5bd8 | 1 5bd8 (0)\n============ DEPTH: 8 ==========================================\n008 2 5ac0 5a8b | 2 5ac0 (0) 5a8b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","private_key":"be696e717d5a91103bc542c6cd7e0b0be4b48502beeb1853da20425d07766a9f","name":"node_5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","services":["bzz","pss"],"enable_msg_events":true,"port":33893},"up":true}},{"node":{"info":{"id":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","name":"node_e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","enode":"enode://72e1ea4365070797e7b04d70c2fcad2502d98a96da55ad4a160b42dabf961951e630354d7ca7c321cbf1f5626574b2619a9fdc940ba34d9d1a7a4040f7dd292d@127.0.0.1:0","enr":"0xf88fb840825ecb133fee1dc489fa785a34e83053c110b2233e3c247614a64b09fa55a9770f3b85c38cea0f103bbbe6a97b8cac4ee63240e58e4675694db27f5402ff50660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10372e1ea4365070797e7b04d70c2fcad2502d98a96da55ad4a160b42dabf961951","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6GdtF5ZmJcT9rGvZQ3mBoM+GnIsAEIEu3wx5gF4OH/E=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e8676d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2a50 1dec 08e5 5a26 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 8862 93c0 9518 9c8e | 75 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n002 4 d209 da36 d959 c603 | 27 d700 (0) d408 (0) d3e9 (0) d302 (0)\n003 6 f756 f215 ff75 fc51 | 14 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n004 6 e471 e64d e681 e09f | 7 e471 (0) e64d (0) e681 (0) e0a0 (0)\n============ DEPTH: 5 ==========================================\n005 5 eff2 ef99 eebd ec90 | 5 ec90 (0) ed42 (0) eebd (0) ef99 (0)\n006 1 eb68 | 1 eb68 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","private_key":"08fe456242f38e34929ed0b545e558015d4a0759d6306e8a146d36cf893d4b5b","name":"node_e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","services":["bzz","pss"],"enable_msg_events":true,"port":45195},"up":true}},{"node":{"info":{"id":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","name":"node_aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","enode":"enode://95bfeea5c376843748c0b4579a13d01255d69aeb09a34f505ba5f0f0a66f5af8c58878ee35613db89c943fddbee64ed3a135d8518501eac5a9adb497b2779202@127.0.0.1:0","enr":"0xf88fb840ba5b589b63f888f95db7ac61bda2976a43eed9b35eac3e78cff7033f9fad31052b057c291e9b5977783d568855bf8ed309fbdaa39fec7b2b08484bfc149e16fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10295bfeea5c376843748c0b4579a13d01255d69aeb09a34f505ba5f0f0a66f5af8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rrRf4QsNvQ9yq2p3+/lxqPRtvN2WwI8jJ50UNLTzix0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aeb45f\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 648a 5144 09b3 08e5 | 126 7895 (0) 7850 (0) 79e5 (0) 7933 (0)\n001 6 c6a8 d302 e64d e277 | 55 d408 (0) d700 (0) d3e9 (0) d302 (0)\n002 6 9c8e 8006 80d7 8862 | 38 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n003 3 b3f9 bfc7 be68 | 14 b8e1 (0) bbaf (0) ba91 (0) bdc5 (0)\n004 4 a505 a616 a0c8 a330 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 7 aaf0 ab3f ab71 a8f4 | 7 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n============ DEPTH: 6 ==========================================\n006 1 acee | 1 acee (0)\n007 1 af02 | 1 af02 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","private_key":"fd2d10c67a8ec4e327748697560a38d057a694d0f889a4a046bfa41de466686e","name":"node_aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","services":["bzz","pss"],"enable_msg_events":true,"port":39549},"up":true}},{"node":{"info":{"id":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","name":"node_e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","enode":"enode://892384debfb7b9e896252f96c210dbb3def7e24f74947e7737c5c68c7d0a4e43a9859926ef56ea490f905c0fc71a8703571b636948be1f5fe6b5f1ade6d4a5f6@127.0.0.1:0","enr":"0xf88fb840f52490d9e0dee88fedf1f1da621cec20d765e3eff7b5e213d5bb3fbda356b49520319ae12d1f41a30d4b20d4b7b0052635b3ab1532ffe66f9935b55c4b7e56b70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102892384debfb7b9e896252f96c210dbb3def7e24f74947e7737c5c68c7d0a4e43","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4ncM73wa0xK3DZTKVXDkXzJMeYoxqTID9QUWeuqxIrY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e2770c\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1add 1dec 08e5 5144 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 8 b3f9 a0c8 ab71 aaf0 | 75 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n002 5 d209 da36 d959 c74d | 27 d408 (0) d700 (0) d3e9 (0) d302 (0)\n003 6 f215 f756 ff75 fc51 | 14 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n004 6 ed42 eebd ef99 eff2 | 7 ec90 (0) ed42 (0) eebd (0) ef99 (0)\n005 3 e471 e64d e681 | 3 e471 (0) e681 (0) e64d (0)\n============ DEPTH: 6 ==========================================\n006 2 e0a0 e09f | 2 e0a0 (0) e09f (0)\n007 0 | 0\n008 1 e2d3 | 1 e2d3 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","private_key":"2c978daf46f400bc226fdece07412297280001b2715e8c93de73a32f023d5431","name":"node_e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","services":["bzz","pss"],"enable_msg_events":true,"port":38147},"up":true}},{"node":{"info":{"id":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","name":"node_8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","enode":"enode://eaaca956b740a54195744f6fbd39e020a7ed769cde7f3df89d0ad741ab11159109304ecbba955b7a09dc92014980a987cb17974458d5bf95cdb518ebd41ad4c9@127.0.0.1:0","enr":"0xf88fb84076f9d40288370d9a357f38d036465939c57156da3ee6f9beff1bfae263870b645bb1081bff97858367926e3e377114d326935c349eb355349a781b34a81f12c30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103eaaca956b740a54195744f6fbd39e020a7ed769cde7f3df89d0ad741ab111591","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jnuW0o7a5xHhpM7g2JTgvZLN9BC6b2FxP32bC+52HUw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8e7b96\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 26ab 298a 2c85 6795 | 126 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n001 3 f8ff eff2 e277 | 55 cf52 (0) cc33 (0) cd6c (0) cdb1 (0)\n002 3 a0c8 aeb4 acee | 37 b8e1 (0) ba91 (0) bbaf (0) bdc5 (0)\n003 2 9518 9c8e | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 9 8402 84a9 837f 8358 | 12 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n005 3 8b43 8862 8854 | 3 8b43 (0) 8854 (0) 8862 (0)\n006 2 8d19 8cc3 | 2 8d19 (0) 8cc3 (0)\n007 1 8f9a | 1 8f9a (0)\n============ DEPTH: 8 ==========================================\n008 1 8ea2 | 1 8ea2 (0)\n009 1 8e28 | 1 8e28 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","private_key":"ad33c8a077ba94e011226ec6b81f81a198f556dce8d1eb447d60309f2ec96157","name":"node_8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","services":["bzz","pss"],"enable_msg_events":true,"port":45223},"up":true}},{"node":{"info":{"id":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","name":"node_679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","enode":"enode://ed0a39e471509e34dba42412c9de5254e84965cf0532fb62288d0ec74098a7bcbc079ad9c063d1c5be83f76623f266d20dedf46ff8a631ebef5304d8062d47c9@127.0.0.1:0","enr":"0xf88fb840f2fb222edf9f0115e6c84901f82209242c979a9850fdb20841b740c82795ec9516c9f9b248ce6f15b12d488ecc61618fb48e78f2cbfc28a11242c72af5571b140183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ed0a39e471509e34dba42412c9de5254e84965cf0532fb62288d0ec74098a7bc","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z5VUtBDkFc/N8bFO+HdZJpsryvB/RUESKXfbOkAJHaI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 679554\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eff2 e277 8862 8e7b | 130 c961 (0) c9c3 (0) c8ea (0) c8c8 (0)\n001 4 2c85 3c5b 0111 1dec | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 6 48f1 447a 46bf 402c | 35 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n003 6 7660 741a 7049 7ce7 | 13 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n004 5 6b4e 6e7f 6d3c 6d5e | 7 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 6758 | 1 6758 (0)\n009 1 67f3 | 1 67f3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 6790 | 1 6790 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","private_key":"295ee49e1d8a7a3fe5af430314a49ea88e405bb74583239a90f3a140bd4d5d7d","name":"node_679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","services":["bzz","pss"],"enable_msg_events":true,"port":37471},"up":true}},{"node":{"info":{"id":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","name":"node_8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","enode":"enode://cde94747f8a20e0bb2560ee9a2af2f6b6537e357a16d3405053a591946807074639abe205cc94e3d89e61445686731991d30a685a5e21a23d43f604cd3164970@127.0.0.1:0","enr":"0xf88fb840c4e3c83eec1c9b3873f6d92f1f6c212da5808e380a2298bd31f54eec9e76abc17d44dc112b0c2d2633b2fdf34f53afcc250b2bb0b5b596df651a3eda03d154cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cde94747f8a20e0bb2560ee9a2af2f6b6537e357a16d3405053a591946807074","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iGLNhdcDkRm5hPdSpFisBJXd6pjGn8HRJB23hzpxLBE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8862cd\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5a26 6795 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 3 d959 e867 e277 | 55 cf52 (0) cdb1 (0) cd6c (0) cc33 (0)\n002 3 b3f9 aeb4 acee | 37 b8e1 (0) bbaf (0) ba91 (0) bdc5 (0)\n003 3 9518 9257 9c8e | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 9 86d6 84a9 8402 834f | 12 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n005 5 8cc3 8d19 8e7b 8e28 | 6 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n============ DEPTH: 6 ==========================================\n006 1 8b43 | 1 8b43 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 8854 | 1 8854 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","private_key":"5b139026f24d426829e4000c0729b6cf94f244c94dc6f40c4408a50c7bbc7e2c","name":"node_8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","services":["bzz","pss"],"enable_msg_events":true,"port":33033},"up":true}},{"node":{"info":{"id":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","name":"node_aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","enode":"enode://41590aa46824b94b64e61a0ba359d8b90fd986c1b1ff0556d51bfa03064616d68e5db68d74e7c89ce7a21c7baca305a808a409df46280f96ae5110560aba272d@127.0.0.1:0","enr":"0xf88fb8407a50df7269c86adec9f03aec5a49050ce842bd9f615b6a0c7f718e6bd95d59c153e0b12a99f1e8583eba20470c4bf7315e9376df0e719fb29eb5845d5eee653f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10341590aa46824b94b64e61a0ba359d8b90fd986c1b1ff0556d51bfa03064616d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rO7nWiYNRSUgYP6XHqvUveJfkS20o8bkf0oJVy/gFpc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aceee7\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 09b3 3c5b 6c01 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 5 da36 d959 e64d e277 | 55 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n002 7 9c8e 80d7 8006 8cc3 | 38 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n003 5 ba91 bdc5 bfc7 be68 | 14 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n004 3 a616 a0c8 a330 | 13 a4ee (0) a5ac (0) a505 (0) a742 (0)\n005 6 a970 a8ff a8b5 aaf0 | 7 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n============ DEPTH: 6 ==========================================\n006 2 af02 aeb4 | 2 af02 (0) aeb4 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","private_key":"0aacb09a0fb2947e95aacfb35aee79d77b33577dc33960a8eda97847f015ef58","name":"node_aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","services":["bzz","pss"],"enable_msg_events":true,"port":41855},"up":true}},{"node":{"info":{"id":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","name":"node_6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","enode":"enode://b9df58044341d94dfdfbd7423f9f8e44cbd1988eb021f9af28aff240c9a82a2cd80e372bdf01aff5ea2cfc8f237351d75a33d6b5cedbbaf11e3fc7e01299ac0d@127.0.0.1:0","enr":"0xf88fb84038e531185ddede85a603500b82295e3edf51326825e4ce34730604ab4d3522bd103c828112617841c50911bd782b291d031c80b1847b70b2466f8a594e8228ad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b9df58044341d94dfdfbd7423f9f8e44cbd1988eb021f9af28aff240c9a82a2c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bAFCmE1imuaZWJTenn5euNP+ReFkHX69Y5WdLmFUi6M=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6c0142\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 eff2 8cc3 84a9 acee | 130 c961 (0) c9c3 (0) c8ea (0) c8c8 (0)\n001 4 3c5b 0111 1add 1dec | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 8 48d7 48f1 4a95 447a | 35 4d38 (0) 4d91 (0) 4cec (0) 4a95 (0)\n003 6 741a 7660 7049 7c7c | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 5 60c5 648a 6758 67f3 | 6 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n005 2 68cb 6b4e | 2 68cb (0) 6b4e (0)\n006 1 6e7f | 1 6e7f (0)\n============ DEPTH: 7 ==========================================\n007 3 6d5e 6d3c 6dd3 | 3 6dd3 (0) 6d3c (0) 6d5e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","private_key":"9ca2399351f822028b5da22e6bc0154901d8ea738bbdf6bdcd4bcc21c3ed0d5b","name":"node_6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","services":["bzz","pss"],"enable_msg_events":true,"port":36003},"up":true}},{"node":{"info":{"id":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","name":"node_eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","enode":"enode://e8b833b40e8298b358b18b45e4339fb6608150de9aac211997746cd94c54f9aaf222cffa82031877b46c104bcf3925b66ec72c0249c56469a6e91915a5e55264@127.0.0.1:0","enr":"0xf88fb84052bdfa57cdb21c78128b249f7474f67fc7914496c70263b47c9c07b65968118861855f3f3557bbe4d668f5f65ac095b39e2e02b29c76aec618aa9680f4dda5570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8b833b40e8298b358b18b45e4339fb6608150de9aac211997746cd94c54f9aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7/JFC+p5f/Ztk+fBwbCXfN3zq7pkv6UbzFCdcoVp4vo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eff245\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1dec 6795 6c01 52a8 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 7 8e7b 8006 80d7 a330 | 75 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n002 4 c603 c74d d209 d959 | 27 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n003 4 fc51 ff75 f9de f8ff | 14 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n004 3 e681 e64d e277 | 7 e471 (0) e681 (0) e64d (0) e09f (0)\n005 2 e867 eb68 | 2 eb68 (0) e867 (0)\n006 2 ec90 ed42 | 2 ec90 (0) ed42 (0)\n============ DEPTH: 7 ==========================================\n007 1 eebd | 1 eebd (0)\n008 0 | 0\n009 1 ef99 | 1 ef99 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","private_key":"5dfe6750469b59c78af3ed5c6d49cda36cf5da33a2b02380cadc1833ffacec3e","name":"node_eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","services":["bzz","pss"],"enable_msg_events":true,"port":44215},"up":true}},{"node":{"info":{"id":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","name":"node_52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","enode":"enode://6d8774da40def7a5b17bb5815e018bc2cefba4129897e17f1a8fe1c9b86218c3d980322811c74b84881232dfa2370d502be9bf56cf705dc2fa1442fab44e1a9f@127.0.0.1:0","enr":"0xf88fb8404567e884ed9478156080ac3b497bacbba7c91cebeb40e60ff39f2fc98237d0bb13fdcab19d93a55bc38c89b23f382274493972d896ce4cb24af71a9f169ab2cd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036d8774da40def7a5b17bb5815e018bc2cefba4129897e17f1a8fe1c9b86218c3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Uqh0fk6jX29Qxy18SBYW9opeQ5YkgzK4/2nTp3LeSaw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 52a874\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d959 eff2 | 130 b8e1 (0) ba91 (0) bbaf (0) bfc7 (0)\n001 4 3c5b 0111 1add 1dec | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 7e47 6795 6c01 | 26 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n003 8 4cec 48f1 435d 402c | 19 4d38 (0) 4d91 (0) 4cec (0) 4b79 (0)\n004 6 5d82 5c7c 5c37 5987 | 10 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n005 2 56ca 5538 | 3 5663 (0) 56ca (0) 5538 (0)\n============ DEPTH: 6 ==========================================\n006 2 50c1 5144 | 2 50c1 (0) 5144 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","private_key":"7184fbc50435ce3da686084be1e05ae373d949ebfd17f019adc5f3d36e027659","name":"node_52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","services":["bzz","pss"],"enable_msg_events":true,"port":38653},"up":true}},{"node":{"info":{"id":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","name":"node_d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","enode":"enode://5f6d3c7b333f15437a8e10851a5e5b69df52d2a88441bf1b087a510149da211b403d95794b7be4b00888e746c0db90dd087f785db90c5ce96e76e977a0c3658d@127.0.0.1:0","enr":"0xf88fb840b90e0d1da9269f37eba660dc778bd68fc19e66ec3e2f8286c01ee9b08b44ac4704329c54f9f909700083ee04d27d04a671277fc4dab0023848748a1f385c96c10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035f6d3c7b333f15437a8e10851a5e5b69df52d2a88441bf1b087a510149da211b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2Vll5EndQGmHY4TPSzT5hnMeJVp5SPCoYtIpsd3bxQI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d95965\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0111 3c5b 52a8 | 126 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n001 5 acee 9464 8862 80d7 | 75 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n002 4 f8ff e277 e867 eff2 | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 4 c8c8 c603 c6a8 c74d | 16 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n004 3 d3e9 d302 d209 | 5 d700 (0) d408 (0) d3e9 (0) d302 (0)\n005 1 ddb8 | 1 ddb8 (0)\n============ DEPTH: 6 ==========================================\n006 3 dbd4 dad0 da36 | 3 dbd4 (0) dad0 (0) da36 (0)\n007 0 | 0\n008 1 d9cf | 1 d9cf (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","private_key":"3e7c884510e8b3aa30441168b9f41d34a41cc93dd314587ff58a092474081075","name":"node_d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","services":["bzz","pss"],"enable_msg_events":true,"port":42317},"up":true}},{"node":{"info":{"id":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","name":"node_8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","enode":"enode://00b96eb6a76e41ed136cbe16d1d887b7bbac5a0bd72bb337756b733add37c60d759a8e32a3de23839c55ca9896ae7de7f3d7e955f907935c60f6837c76407032@127.0.0.1:0","enr":"0xf88fb8404180b1565d27eada9a91fcc9783f8bb81c62344bcfe8f579644b225ff80f24972b11fbbd09b6e8e56b49515a95647d596e31f4aab16005512cc2a95035324c810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10200b96eb6a76e41ed136cbe16d1d887b7bbac5a0bd72bb337756b733add37c60d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gAawgMeKCrVPob51qTm+4jNDIv3tbDVj3hWWsXw2Fyw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8006b0\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5a26 1dec | 126 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n001 3 eff2 d302 d959 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 5 a0c8 a330 aaf0 aeb4 | 37 b8e1 (0) ba91 (0) bbaf (0) bcf8 (0)\n003 2 9518 9c8e | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 3 8862 8cc3 8e7b | 9 8b43 (0) 8854 (0) 8862 (0) 8f9a (0)\n005 4 87a3 86d6 8402 84a9 | 4 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n006 3 837f 8358 834f | 3 837f (0) 8358 (0) 834f (0)\n007 1 81a5 | 1 81a5 (0)\n008 1 80d7 | 1 80d7 (0)\n============ DEPTH: 9 ==========================================\n009 2 8073 8074 | 2 8073 (0) 8074 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","private_key":"fcb5be43acaccb42dc1ccc165ea1cfd8c513cf177216d2c30891da51422d3c28","name":"node_8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","services":["bzz","pss"],"enable_msg_events":true,"port":34767},"up":true}},{"node":{"info":{"id":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","name":"node_1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","enode":"enode://0f9ec77321a98a1f538e0d5d9ef25b2b88fb31c678c3eb96345ec11e120bf502f24062c58885fab4104bcde1c4d556514688684c9f451a52d5296e1e904b553f@127.0.0.1:0","enr":"0xf88fb840a7d34c4c4c304a57c17de44dce8fa8a85dd33c61c06dd8848a767401a5f335044a5ea299bd475fb2a27fc686f0d4f124f75520dc1dde65822225e7467289bafb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030f9ec77321a98a1f538e0d5d9ef25b2b88fb31c678c3eb96345ec11e120bf502","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Hex3wvTK8FPC0FJK40otlwv0dDoNAJ2PxUMHfd/f49A=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1dec77\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 e277 e867 eff2 a330 | 130 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n001 3 6795 6c01 52a8 | 61 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n002 3 2c85 2a50 3c5b | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 5 0e3b 0cfc 08f8 09b3 | 21 0d1c (0) 0cfc (0) 0e80 (0) 0e2b (0)\n004 6 1049 138d 1784 1686 | 7 1070 (0) 1049 (0) 138d (0) 1686 (0)\n005 6 19ea 194e 18e0 1b1d | 6 19ea (0) 194e (0) 18e0 (0) 1b1d (0)\n============ DEPTH: 6 ==========================================\n006 1 1fd0 | 1 1fd0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1dc0 | 1 1dc0 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","private_key":"26da41b73f097099d65984b38ff4a2abed7a066916fc7defac16025a9b048f64","name":"node_1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","services":["bzz","pss"],"enable_msg_events":true,"port":44061},"up":true}},{"node":{"info":{"id":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","name":"node_1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","enode":"enode://9548a286c10115387facaf19d1e4f0a89e912d85029c1c487158207abe9e881aa61089ccb01238b15c8cd3cea9a71d520c4253dd1b487a963865c8947790bc2a@127.0.0.1:0","enr":"0xf88fb840ec288c0946306b1c5322ec315d33d13022eaef5463fd9d585df1000c7f70914713feb9d24a31c080bfca34d7f32d2f2f4a7cc8472108a6e5b3a68a74f3777ff80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029548a286c10115387facaf19d1e4f0a89e912d85029c1c487158207abe9e881a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Gt3UqfAUhiEuE+Q6llC395NhfRy1n7jZQScNeuVfV18=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1addd4\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 e277 a330 80d7 | 130 f1ed (0) f215 (0) f2b4 (0) f305 (0)\n001 3 52a8 447a 6c01 | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 4 2c85 298a 26ab 3c5b | 28 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n003 3 0e3b 08e5 0111 | 21 0d1c (0) 0cfc (0) 0e80 (0) 0e2b (0)\n004 3 1784 1484 140d | 7 1049 (0) 1070 (0) 138d (0) 1686 (0)\n005 3 1fd0 1dc0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 19ea 194e 18e0 | 3 19ea (0) 194e (0) 18e0 (0)\n============ DEPTH: 7 ==========================================\n007 2 1b1d 1bd5 | 2 1b1d (0) 1bd5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","private_key":"0913c134c0b143e925b0c88a1fdf7b3b79761d599db43e77f87db4896c1677ea","name":"node_1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","services":["bzz","pss"],"enable_msg_events":true,"port":39027},"up":true}},{"node":{"info":{"id":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","name":"node_80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","enode":"enode://9e5ae61e978f364f62889e17b22a8f9248f40ec009d4b43b3b05f92eda9394c87e382e2459b92a93e6b62e2103ab0f7a3c37c5251ef272e7c4ce8b47145ba2b1@127.0.0.1:0","enr":"0xf88fb840e9a52f21b9b8b379be4383a4cff9a6331d63db696a7236c2b700b217ca1e7bb97104740ffffdf09ddfb44f932fa5534cbd2541e7a4dd75920c0dc26241fa43290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039e5ae61e978f364f62889e17b22a8f9248f40ec009d4b43b3b05f92eda9394c8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gNfokruyaAirsdFTAHf+xrCHaMFRqfIgiB2jyGK64K8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 80d7e8\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5a26 3b02 3c5b 0111 | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 4 eff2 d302 d209 d959 | 55 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n002 5 aaf0 acee aeb4 a0c8 | 37 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n003 6 9c8e 9257 97da 9464 | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 6 8b43 8854 8862 8e7b | 9 8b43 (0) 8854 (0) 8862 (0) 8f9a (0)\n005 4 86d6 87a3 8402 84a9 | 4 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n006 3 837f 8358 834f | 3 837f (0) 8358 (0) 834f (0)\n007 1 81a5 | 1 81a5 (0)\n============ DEPTH: 8 ==========================================\n008 3 8073 8074 8006 | 3 8073 (0) 8074 (0) 8006 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","private_key":"ba50fc539edd826fed0a669af162891458571b2d3feed69df70bd146d17ce4ed","name":"node_80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","services":["bzz","pss"],"enable_msg_events":true,"port":39407},"up":true}},{"node":{"info":{"id":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","name":"node_0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","enode":"enode://5ee976bcaa543b5d2ea1a0bce5b0ff16849ede88771b4d0539bcf66b2a275089315547a16297807f96f1634144fba1112ca22817182c90947739c6db02226d55@127.0.0.1:0","enr":"0xf88fb840b273fc1fa015b0a0b045a26f170ca39c7ded0d15989a8d2f9a15df15c5c1471a3943fd8ce033b73dd6cc8f6d988a1e6f4b6ad088a8148478fe0728cdc8a5b4aa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035ee976bcaa543b5d2ea1a0bce5b0ff16849ede88771b4d0539bcf66b2a275089","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ARHnIKhLMQ+GPCUw++FJ5qIhrLrQEGXF0FLSs+Fxb1Q=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0111e7\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d209 d959 80d7 | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 4 6795 6c01 52a8 447a | 61 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n002 2 2a50 3c5b | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 3 18e0 1add 1dec | 16 1070 (0) 1049 (0) 138d (0) 1686 (0)\n004 6 0cfc 0e3b 09b3 08bd | 11 0d1c (0) 0cfc (0) 0e80 (0) 0e2b (0)\n005 4 046c 0594 0561 07f5 | 4 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n006 3 025d 035f 0314 | 3 025d (0) 035f (0) 0314 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0191 | 1 0191 (0)\n009 0 | 0\n010 1 012b | 1 012b (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","private_key":"91fae292525cee25df7bf4db07a65551f7691e6d2bc6a6919a32b5862b97dc00","name":"node_0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","services":["bzz","pss"],"enable_msg_events":true,"port":44549},"up":true}},{"node":{"info":{"id":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","name":"node_3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","enode":"enode://d5a336637f6123924c25472b63ed0ce1759aaa0df7f6d4a18ab36dd8976db21757be5de42d1a3edef967c5d508a894b841f272453643d4c7827490b2286d7177@127.0.0.1:0","enr":"0xf88fb8404f46f3f9d69855c1359b03501474fc383b4578f1b7b40877d2c279c467756cf54804a11759187a452f18bc0291d786321ce06bae18d6cd130e358172c6c4ee5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d5a336637f6123924c25472b63ed0ce1759aaa0df7f6d4a18ab36dd8976db217","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PFsuElAgyA42dN+crDTeTY86lO4CVW+1V5IbbVSYuTM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3c5b2e\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 d959 c74d acee 80d7 | 130 f1ed (0) f215 (0) f2b4 (0) f305 (0)\n001 6 6c01 6795 402c 447a | 61 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n002 6 1784 1dc0 1dec 1add | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 4 26ab 2c85 298a 2a50 | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 6 3728 36b9 30fe 3051 | 9 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n005 5 3980 3938 397a 3b02 | 5 3980 (0) 3938 (0) 397a (0) 3b02 (0)\n============ DEPTH: 6 ==========================================\n006 1 3f31 | 1 3f31 (0)\n007 0 | 0\n008 1 3cab | 1 3cab (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","private_key":"10f73f4d9bbb99564f267bf19aee5d5029238f913a01009124c433e72e461c43","name":"node_3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","services":["bzz","pss"],"enable_msg_events":true,"port":35855},"up":true}},{"node":{"info":{"id":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","name":"node_84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","enode":"enode://7c5c0013e73e1e336ff20c1718a135e5725dc06c6f0c9f9090220223d8e9ae14776b3d3d2073ec0f9ac79ad91739644142a122c2ac9e79f6fedbeb3d24fbe15a@127.0.0.1:0","enr":"0xf88fb840ffe7dbb7a2a573810eb50ef23e54deecd328d7b7e0502170861ff9dd20f39c683db509751dd87bfb7a1b6e1671d2f50655924fa021c7601cd337daed4a4b0f910183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027c5c0013e73e1e336ff20c1718a135e5725dc06c6f0c9f9090220223d8e9ae14","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hKnbdkXHktw4wfIROo8FkNBOHJTZqMRkqw7IIZMD2WY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 84a9db\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5a26 402c 7e47 67f3 | 126 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n001 4 e64d f8ff c603 c74d | 55 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n002 8 bfc7 be68 b3f9 aaf0 | 37 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n003 3 9c8e 97da 9518 | 17 93ea (0) 93c0 (0) 9257 (0) 97da (0)\n004 5 8862 8854 8ea2 8e7b | 9 8b43 (0) 8854 (0) 8862 (0) 8f9a (0)\n005 7 837f 8358 834f 81a5 | 8 837f (0) 8358 (0) 834f (0) 81a5 (0)\n============ DEPTH: 6 ==========================================\n006 2 87a3 86d6 | 2 87a3 (0) 86d6 (0)\n007 0 | 0\n008 1 8402 | 1 8402 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","private_key":"942aadc68bdea22f3ce52da3ae7b6f7c03ec9e47e5d2b153161be660d1a0ae91","name":"node_84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","services":["bzz","pss"],"enable_msg_events":true,"port":33215},"up":true}},{"node":{"info":{"id":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","name":"node_c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","enode":"enode://97af56cb76aa2eaec4aeef2c8cec152cbe5b98224f219b0fc82f0c0a3648951cf0b429a35548829391d1a4d9a663cde74dd333c0c012e6a1f8d6e677a006dc00@127.0.0.1:0","enr":"0xf88fb840c23585d8a52b92c0cd98c86cc18d8ea7593dd6740927c3fa9aab25a49c02996a1091206cf56d09a3ac4f253656b976411b2307fdd0c77cbf1607b6df7e163f760183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10297af56cb76aa2eaec4aeef2c8cec152cbe5b98224f219b0fc82f0c0a3648951c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"x02AHoWsD9iVFIDRB7Qe3cXJJ3VhTEiGs/cy+j0aeR0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c74d80\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 447a 3a62 3c5b | 126 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n001 2 8cc3 84a9 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 5 ff75 f8ff e277 e64d | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 6 d209 d302 dbd4 dad0 | 11 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n004 2 cd6c c8c8 | 8 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n005 2 c2d0 c272 | 3 c190 (0) c272 (0) c2d0 (0)\n006 2 c534 c42e | 2 c534 (0) c42e (0)\n============ DEPTH: 7 ==========================================\n007 2 c603 c6a8 | 2 c603 (0) c6a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","private_key":"459826aca20135c53b872b1b2eee49b09c127ff95d3a98d517dc55c101f6562a","name":"node_c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","services":["bzz","pss"],"enable_msg_events":true,"port":46857},"up":true}},{"node":{"info":{"id":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","name":"node_8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","enode":"enode://f5bd9f767508bd665cf322b697829a1c303223f3e1953dac7fb2aa3ecb12f562a82f48929f997d96979eda587e53151f11fb6b0c1a477bcaea877333608f8938@127.0.0.1:0","enr":"0xf88fb84049abb7ae67d8f18e608e10433911a04e12e66842debe93fddfd1b92dd4b5249e2e0d73655939db3ec05377a8ea47300d98f115a6d484239b195f4757342458470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f5bd9f767508bd665cf322b697829a1c303223f3e1953dac7fb2aa3ecb12f562","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jMP7OQCdCtwm/KHi7paCLRaNTevDef1RbBXUtKFiQjE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8cc3fb\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1dec 6c01 7e47 402c | 126 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n001 2 d209 c74d | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 6 be68 b3f9 aaf0 acee | 37 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n003 4 9c8e 93c0 95c0 9518 | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 8 834f 837f 81a5 80d7 | 12 8358 (0) 834f (0) 837f (0) 81a5 (0)\n005 3 8854 8862 8b43 | 3 8b43 (0) 8854 (0) 8862 (0)\n============ DEPTH: 6 ==========================================\n006 4 8f9a 8ea2 8e28 8e7b | 4 8f9a (0) 8ea2 (0) 8e28 (0) 8e7b (0)\n007 1 8d19 | 1 8d19 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","private_key":"ab529b2f870b41497c801949c1e6f8803428c7a8a5401009fb5aecf2146a8021","name":"node_8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","services":["bzz","pss"],"enable_msg_events":true,"port":32793},"up":true}},{"node":{"info":{"id":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","name":"node_a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","enode":"enode://2e41f2b550586042c5f6fc98479cf8647f043156b413c46a8a44e5e748b12ad67219bf8846538c69bd1512ba2b2372b455d2db5bb6833d24f26e6c9a1f59d5c8@127.0.0.1:0","enr":"0xf88fb840ae31abaa7b69ba78463e2aabc17bdba4aab8ffa918141bc3c9628311a50f0e8f60fc4d7edd0a2d6d9d31bdc7358e66ea37b3726c4daa85d3112b655b7bea23220183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022e41f2b550586042c5f6fc98479cf8647f043156b413c46a8a44e5e748b12ad6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ozCfi4u6TY+9fGGT12ccuQe5TnEVXvYTjgJIaC/wDlg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a3309f\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 447a 402c 09b3 1dec | 126 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n001 5 f8ff e64d eff2 d302 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 5 9c8e 8006 80d7 84a9 | 38 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n003 3 b3f9 bfc7 be68 | 14 b8e1 (0) bbaf (0) ba91 (0) bcf8 (0)\n004 4 aaf0 ab71 aeb4 acee | 10 a8f4 (0) a8ff (0) a8b5 (0) a970 (0)\n005 4 a5ac a505 a606 a616 | 7 a4ee (0) a5ac (0) a505 (0) a742 (0)\n006 2 a1c8 a0c8 | 2 a1c8 (0) a0c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a2e6 a2a1 | 2 a2e6 (0) a2a1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a327 | 1 a327 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","private_key":"f5a3649f592d0f7c3eced972c572abd68fb996716ce6c51e2f9c236db5ee5f7f","name":"node_a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","services":["bzz","pss"],"enable_msg_events":true,"port":46725},"up":true}},{"node":{"info":{"id":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","name":"node_2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","enode":"enode://c001df527a6a418a2bb70ac07ea54973e446f8037817071d1099e394bf3cf208a58bf9796e8e5c5f9fe0ab71cde46b1e3b320c911fa86e6af286e603ce8a9d04@127.0.0.1:0","enr":"0xf88fb840543888f27b45d292760976edb014e7c72679a5831e78c7496fd2bc5d78af0c377e0981dcbe633f5465ca9546ada0184be5e5a640dd77b8f6ea51c936515ab1d20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c001df527a6a418a2bb70ac07ea54973e446f8037817071d1099e394bf3cf208","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KlB/XLkhE3pyJcnEmIqFFK8PfjxELLi/K7YS3FIqfa8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2a507f\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f9de f8ff ff75 e867 | 130 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n001 3 7e47 4a95 447a | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 6 1dec 08bd 09b3 07f5 | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 11 36b9 3051 3188 31e6 | 17 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n004 4 24f8 244c 26ac 26ab | 4 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n============ DEPTH: 5 ==========================================\n005 5 2fd2 2e65 2ddf 2c80 | 5 2fd2 (0) 2e65 (0) 2ddf (0) 2c80 (0)\n006 1 298a | 1 298a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","private_key":"ba89f2c3d704a1b02be39f28124317f79d2630278219ab9397e5250cbaab1347","name":"node_2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","services":["bzz","pss"],"enable_msg_events":true,"port":40127},"up":true}},{"node":{"info":{"id":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","name":"node_447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","enode":"enode://93cb54d9649a77b0cdde7ac6f47e4b97f7601de7e8881dd99e904b4c0f29e973261a2ca33856145834ad9fa4b35e8100f57851652ae17382da483d915520cef9@127.0.0.1:0","enr":"0xf88fb840f9ca3c35e33f2fe6bfb3114da2e3c50397d620dc275d5fdf0fca027de00c6ba20aceee4ab1ac417c80e3c10d7ab9f21e3b07da298b81aac6a8f6b7b38a4936d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10393cb54d9649a77b0cdde7ac6f47e4b97f7601de7e8881dd99e904b4c0f29e973","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RHpBHID71CK/oMNY0/Kh/mJWwF41rMY1CVjfvmLNW5s=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 447a41\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a330 8cc3 c74d d209 | 130 b78f (0) b659 (0) b6df (0) b5ea (0)\n001 8 140d 1add 0314 0111 | 65 1049 (0) 1070 (0) 138d (0) 1686 (0)\n002 6 6c01 648a 6758 6795 | 26 60c5 (0) 648a (0) 6758 (0) 6790 (0)\n003 8 5bd8 5a8b 5a26 5d82 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 6 48f1 48b8 4b79 4a95 | 10 4a95 (0) 4b79 (0) 482e (0) 48b8 (0)\n005 5 43d4 43c9 435d 4005 | 5 43d4 (0) 43c9 (0) 435d (0) 4005 (0)\n006 1 46bf | 1 46bf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 44ad | 1 44ad (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 447c | 1 447c (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","private_key":"333ffec493a411ee5a1cf2f27903e2738e2967073c019fcbf70844d2c5e221fb","name":"node_447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","services":["bzz","pss"],"enable_msg_events":true,"port":46191},"up":true}},{"node":{"info":{"id":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","name":"node_d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","enode":"enode://fa46b1409f74c7047256751457bb4839d22d4c44e870020c92b9a8094d40fffd0bbe32e0d0e17a80c1a5cda6744641633435612ef66e4d1efe652f2190e9898c@127.0.0.1:0","enr":"0xf88fb840ec8f9457cb967b5716665ff449c2d75e0cba1fb09465164ee48b4a314d3bbb0d2cffff4ac93409d690a86ae7b8031ec765f327ec503895ea2d4ae58be0ea6d490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fa46b1409f74c7047256751457bb4839d22d4c44e870020c92b9a8094d40fffd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0gkxzj2pcv0j6jBuXGBKH72UF7oCZUxc2+J4/iWfddU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d20931\npopulation: 23 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0111 3a62 447a | 126 1070 (0) 1049 (0) 138d (0) 1686 (0)\n001 3 80d7 8cc3 a330 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 5 f8ff e867 eff2 e277 | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 4 c8c8 c74d c6a8 c603 | 16 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n004 4 dbd4 dad0 da36 d959 | 6 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n005 2 d700 d408 | 2 d700 (0) d408 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 d3e9 d302 | 2 d3e9 (0) d302 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","private_key":"1efdf65d1076ab6055d3624a77725affdd2e31a88571efc3f60d3ccaff92f6bb","name":"node_d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","services":["bzz","pss"],"enable_msg_events":true,"port":39387},"up":true}},{"node":{"info":{"id":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","name":"node_3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","enode":"enode://699f62b0ede6090f23dc2599d33c7358ae7b40e7968fafc5a628f37665146f48126c277ba115635c40a4b4b0c21129c569efe2b0088a0e1a2a7c2e79793fd6ad@127.0.0.1:0","enr":"0xf88fb8408c0574ebe34e80bece2feb6738856fa36e55e93c1692ea7e973fb6f5948061ba1afefff01aa4e3ffe13b7ab2318e4d5201b0083ee6a4067fe0a7436c371f93c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103699f62b0ede6090f23dc2599d33c7358ae7b40e7968fafc5a628f37665146f48","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OmKO8XHB8m+glm64khC+ChQwWq6L/tEPTtkBdpj0D0s=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3a628e\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c6a8 c74d d209 | 130 b659 (0) b6df (0) b78f (0) b4a1 (0)\n001 4 7e47 5c37 402c 447a | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 7 1484 140d 1dc0 18e0 | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 4 26ab 2c85 2a50 298a | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 7 36b9 3728 3051 30fe | 9 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n005 3 3f31 3cab 3c5b | 3 3f31 (0) 3cab (0) 3c5b (0)\n============ DEPTH: 6 ==========================================\n006 3 3980 3938 397a | 3 3980 (0) 3938 (0) 397a (0)\n007 1 3b02 | 1 3b02 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","private_key":"dcc4c59e4839e1a65f299219ca7016fdaa5f40089be97dd01f6e44b309e517e1","name":"node_3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","services":["bzz","pss"],"enable_msg_events":true,"port":45801},"up":true}},{"node":{"info":{"id":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","name":"node_031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","enode":"enode://f6a817139fae4583a57556cc9a0a457c0473f3420d9c159dde94147684cef58dee5800eba9eed6ce4bca94ed4f0b5990cf1300abc416d3abe67117ff987e3893@127.0.0.1:0","enr":"0xf88fb840ac7d354eab1b00a4d18d770c7a56c8bd41a723c51be5b45f95ac7541b76ffd8a6b2abb20615da04d0e0b07abf9c9d1a2c014424bc3c8d645913be94303912ddd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f6a817139fae4583a57556cc9a0a457c0473f3420d9c159dde94147684cef58d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AxRQ7CDzU0NbQptfpk9hbQfJ1Yavq8eidy4FrVyIv1A=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 031450\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e64d d302 | 130 b4a1 (0) b5ea (0) b78f (0) b659 (0)\n001 2 447a 402c | 61 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n002 5 2a50 31e1 31e6 3b02 | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 2 18e0 140d | 16 1fd0 (0) 1dc0 (0) 1dec (0) 1b1d (0)\n004 6 0e2b 0e3b 0cfc 08bd | 11 0e80 (0) 0e2b (0) 0e3b (0) 0d1c (0)\n005 3 07f5 0561 0594 | 4 07f5 (0) 046c (0) 0561 (0) 0594 (0)\n006 3 0191 012b 0111 | 3 0191 (0) 012b (0) 0111 (0)\n============ DEPTH: 7 ==========================================\n007 1 025d | 1 025d (0)\n008 0 | 0\n009 1 035f | 1 035f (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","private_key":"71841c7c5c5d9ea8a678e5f6274467f74b6f88c13bbf848178459758f86d8039","name":"node_031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","services":["bzz","pss"],"enable_msg_events":true,"port":43487},"up":true}},{"node":{"info":{"id":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","name":"node_402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","enode":"enode://5bc25029b77714e83add4d5587be2adb2f795f9c9a708fa117f943c07da69023a978354c7584edf8e72592dd799def444d777216cbff5e09d84ed2a3e6cfc802@127.0.0.1:0","enr":"0xf88fb8405ae20f58d8ca24088b13d83e73fa85b6edd318d7a36af6bae3b1561d4e35defe0bc84c46bd137181da067946faf218082b19c9f7508adabe054d430ca14ba09b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025bc25029b77714e83add4d5587be2adb2f795f9c9a708fa117f943c07da69023","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"QCz50L/6AX6+o07eESB/M2az6kUMBCgCkSmo6AJqu+c=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 402cf9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 84a9 8cc3 a330 e64d | 130 b4a1 (0) b5ea (0) b659 (0) b6df (0)\n001 5 298a 3c5b 3a62 3b02 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 5 6d5e 6c01 648a 6795 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 3 5a26 5144 52a8 | 16 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n004 6 48d7 48f1 4a95 4cec | 10 482e (0) 48b8 (0) 48f1 (0) 48de (0)\n005 4 46bf 44ad 447c 447a | 4 46bf (0) 44ad (0) 447c (0) 447a (0)\n============ DEPTH: 6 ==========================================\n006 3 43d4 43c9 435d | 3 43d4 (0) 43c9 (0) 435d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 4005 | 1 4005 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","private_key":"94e11eac44f6245218d5abd3d9478e311e64c9803c0c5ea086b6de56d4679633","name":"node_402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","services":["bzz","pss"],"enable_msg_events":true,"port":32811},"up":true}},{"node":{"info":{"id":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","name":"node_3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","enode":"enode://713a1cedffa4515ada02fdd05d03e281b216f290f667a579b6122990b58832fda74606019246522aa1ea21612c64c9b061a99f77ecf52541607f91c645c9b911@127.0.0.1:0","enr":"0xf88fb84078578015605b97496872b339f38876ed514660f63b799e2055976f1d31a7256c29c36362b416362b1c38dcd9dbaf0d98160a481b84e0944a33d9103c1cf2c9890183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103713a1cedffa4515ada02fdd05d03e281b216f290f667a579b6122990b58832fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OwIMhPtg9Zd5Mk1FHZdw1oPggTO7qi1XYvYbj9S42f0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b020c\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a330 9f0e 80d7 d302 | 130 b4a1 (0) b5ea (0) b659 (0) b6df (0)\n001 4 6e7f 6b4e 5c37 402c | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 2 138d 0314 | 37 1070 (0) 1049 (0) 138d (0) 1686 (0)\n003 4 26ab 2c85 2a50 298a | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 7 3188 31e6 31e1 30fe | 9 32ff (0) 30fe (0) 3051 (0) 3188 (0)\n005 3 3f31 3c5b 3cab | 3 3f31 (0) 3cab (0) 3c5b (0)\n============ DEPTH: 6 ==========================================\n006 3 3980 3938 397a | 3 3980 (0) 3938 (0) 397a (0)\n007 1 3a62 | 1 3a62 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","private_key":"f0c6bf4c9b4e4f3d3db2b470e1adab35d6500594faf84c40d4e589d3b516a6e9","name":"node_3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","services":["bzz","pss"],"enable_msg_events":true,"port":45529},"up":true}},{"node":{"info":{"id":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","name":"node_d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","enode":"enode://1d5fd1a24eda6285258a0e82b28b81dc86c0d970745ed58fd4ee8cf25414dfd16855e91f57f27d49ff28688f9e48d9df98094d7afcb28de571ad2db259f803dd@127.0.0.1:0","enr":"0xf88fb840142c7e76eea3d74e38e90903bb658e1359757cafd5441e5414d06d489b74a4f567b2017ecbbcb487cf547fd852e100846966134719b652071d9580fa25f868360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031d5fd1a24eda6285258a0e82b28b81dc86c0d970745ed58fd4ee8cf25414dfd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0wIqRpVudbyoW6idl7aUo6ZPA8zC2IHtDNaH1D1IaSU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3022a\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 67f3 402c 140d 0cfc | 126 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n001 6 bfc7 aeb4 a330 8854 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 6 e64d ed42 eebd ff75 | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 6 c6a8 c603 c74d cd6c | 16 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n004 5 ddb8 da36 dad0 dbd4 | 6 ddb8 (0) dad0 (0) da36 (0) dbd4 (0)\n005 2 d700 d408 | 2 d700 (0) d408 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 d209 | 1 d209 (0)\n008 1 d3e9 | 1 d3e9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","private_key":"d6122cfb13c379e5e6975a57ca7446d6faa10cf87da8ddde9793a570ba433a96","name":"node_d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","services":["bzz","pss"],"enable_msg_events":true,"port":46297},"up":true}},{"node":{"info":{"id":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","name":"node_298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","enode":"enode://e2572a35a51863ebd4d0e48420c58ffb5088cadae300e5779152fe7e009a73f879306e12e40543ab0f2ea87351f9114b427df2e411379eeaeb2f2dd4f6734383@127.0.0.1:0","enr":"0xf88fb840a94663c556b354f4695fad007ac31ab668951708699de5cfaf696a677d15555c6120984becc7bc3b1c3724a42f37b9e009cb7b6c5f37f23758c3a9d2941638d00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e2572a35a51863ebd4d0e48420c58ffb5088cadae300e5779152fe7e009a73f8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"KYrl0XPFNgvJrVtJLtNd47bgyuhoo0v+YxGoul6ph34=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 298ae5\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9f0e 8e7b e64d d302 | 130 b3f9 (0) b78f (0) b659 (0) b6df (0)\n001 5 4a95 402c 447a 7e47 | 61 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n002 8 1add 194e 18e0 140d | 37 138d (0) 1070 (0) 1049 (0) 1784 (0)\n003 11 36b9 3051 3188 31e6 | 17 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n004 3 24f8 26ac 26ab | 4 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n============ DEPTH: 5 ==========================================\n005 5 2fd2 2e65 2ddf 2c80 | 5 2fd2 (0) 2e65 (0) 2ddf (0) 2c80 (0)\n006 1 2a50 | 1 2a50 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","private_key":"b0b337287594e581c25600a9c7123555efd6242dd53a8bc83caa7c7890443ac5","name":"node_298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","services":["bzz","pss"],"enable_msg_events":true,"port":33555},"up":true}},{"node":{"info":{"id":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","name":"node_e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","enode":"enode://1c9f6fc264902a736faaf67f7c0de6faee097992d30a5ed225cb334c2a3525ec83d7a038643357fc6c0f7ed5c86e8d272bb475054048f26964e53a4c23b85c6b@127.0.0.1:0","enr":"0xf88fb84037d31d5c2464b59a7a8c3d22f66575e1d23a2d4ea24038f76b84d3446bcd41e51fd1f5dc7189f516c23bbefa0b11f2e7185ef3277b7aa33a4c84594247c8d7bb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031c9f6fc264902a736faaf67f7c0de6faee097992d30a5ed225cb334c2a3525ec","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5k2QdgzYHk8RK78UMudsgvpBc/1HS5iPQJbOGHNj/YE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e64d90\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 09b3 0594 0314 18e0 | 126 0191 (0) 012b (0) 0111 (0) 025d (0)\n001 6 84a9 be68 a0c8 a330 | 75 b4a1 (0) b5ea (0) b6df (0) b659 (0)\n002 4 d302 d209 c6a8 c74d | 27 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n003 3 ff75 f8ff f9de | 14 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n004 4 e867 ed42 eff2 eebd | 7 eb68 (0) e867 (0) ef99 (0) eff2 (0)\n005 3 e09f e2d3 e277 | 4 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n============ DEPTH: 6 ==========================================\n006 1 e471 | 1 e471 (0)\n007 0 | 0\n008 1 e681 | 1 e681 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","private_key":"7d27024b921b4fc8acb154f5988128977df743101939d754b1b2b55b69bf2b2e","name":"node_e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","services":["bzz","pss"],"enable_msg_events":true,"port":44039},"up":true}},{"node":{"info":{"id":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","name":"node_7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","enode":"enode://12b03573c2a76013619215fba5146b7c44aa72aa214d577e70f611196a80f33b6d2332c3736388f5fdb74a5924f3ee97a4f435093835efe46cfa7b049237fe74@127.0.0.1:0","enr":"0xf88fb840c9ef22c878c1759a06aee668ff6358beb1cf4dd0e15021dce3fd0e637754d3cf1bbebf8a3aa0d6e9bc391e27ad7c93101089f6d54bd0257fb3536766cb4258bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212b03573c2a76013619215fba5146b7c44aa72aa214d577e70f611196a80f33b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fkei+CmEpgDIWDYFqR1cuPLZoYlhhF6cQi7deOIKw6M=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7e47a2\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 84a9 8cc3 c6a8 e64d | 130 ab71 (0) ab3f (0) aaf0 (0) a8b5 (0)\n001 6 298a 2a50 397a 3a62 | 65 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n002 8 5a26 52a8 4d91 4cec | 35 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n003 8 6b4e 6e7f 6d5e 6c01 | 13 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n004 2 7660 741a | 4 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n005 3 7850 79e5 7933 | 4 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n============ DEPTH: 6 ==========================================\n006 4 7d16 7ce7 7c7c 7c46 | 4 7d16 (0) 7ce7 (0) 7c7c (0) 7c46 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","private_key":"aa9445dea3d9ca188039006df2529b909dbd39486296eeeb022fb2dd285c4536","name":"node_7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","services":["bzz","pss"],"enable_msg_events":true,"port":42041},"up":true}},{"node":{"info":{"id":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","name":"node_c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","enode":"enode://454955797f0067874592850e49998fdc19a2c7bd33a4ff25e33927c6558364eaaf7a788b4ec32bb46722acea4d1a61b9755b0779fbdb323a0f1807ccf6337571@127.0.0.1:0","enr":"0xf88fb84055d87acf3986e47cda898bdd603f343a724a7fc35b5f908e71195bea21f0cfae27ff3cda3965530d8614a9170b9f1aed47abe0d78c21209022d88b407fa338f40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103454955797f0067874592850e49998fdc19a2c7bd33a4ff25e33927c6558364ea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xqgiByYkPM6qbyzr2shXoF7+chMj8KBkx/hag0DT2pY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c6a822\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3a62 18e0 7e47 | 126 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n001 5 a0c8 aeb4 95c0 97da | 75 a742 (0) a7a8 (0) a616 (0) a606 (0)\n002 4 e64d eebd ff75 f8ff | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 5 d302 d209 dbd4 da36 | 11 ddb8 (0) dad0 (0) da36 (0) dbd4 (0)\n004 3 cd6c c961 c8c8 | 8 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n005 3 c190 c272 c2d0 | 3 c190 (0) c272 (0) c2d0 (0)\n006 2 c42e c534 | 2 c42e (0) c534 (0)\n============ DEPTH: 7 ==========================================\n007 1 c74d | 1 c74d (0)\n008 1 c603 | 1 c603 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","private_key":"8f0f60c08655c540026e8566ec695b938ce61b2b96646b0264adf44d9e42610e","name":"node_c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","services":["bzz","pss"],"enable_msg_events":true,"port":44073},"up":true}},{"node":{"info":{"id":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","name":"node_18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","enode":"enode://339676ff1a748c6537d18f6876bb9f1909665415872fa5d5c3a62ee4142ccd6fceb523240a14dc3df222a387212b8f68be3b473f1299016b0b9d342152f0d610@127.0.0.1:0","enr":"0xf88fb840a9c71d615a4992252278bfec4f901f2a5c0bcd153ec613f025be3ea3b9ec116e7fc2d46f878030a2375d5d8467b882559e854ec34a52e0633388ca26268d39dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102339676ff1a748c6537d18f6876bb9f1909665415872fa5d5c3a62ee4142ccd6f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GOAKfg+Cahq6P4wPUz7ZBfLu5ge2l//wVu54dNN0rc0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 18e00a\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e64d c6a8 | 130 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n001 3 435d 6d5e 67f3 | 61 5ff0 (0) 5c7c (0) 5c37 (0) 5d82 (0)\n002 5 298a 3051 31e6 31e1 | 28 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n003 8 096a 0cfc 0e3b 07f5 | 21 012b (0) 0111 (0) 0191 (0) 025d (0)\n004 5 1049 138d 1686 1484 | 7 1049 (0) 1070 (0) 138d (0) 1784 (0)\n005 3 1fd0 1dc0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 1b1d 1bd5 1add | 3 1b1d (0) 1bd5 (0) 1add (0)\n============ DEPTH: 7 ==========================================\n007 2 194e 19ea | 2 19ea (0) 194e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","private_key":"69b0a121df38253f732ead7d4d9eeb8e3c8f00aef1fb652004da58fd2ebf948f","name":"node_18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","services":["bzz","pss"],"enable_msg_events":true,"port":34725},"up":true}},{"node":{"info":{"id":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","name":"node_140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","enode":"enode://83dc6dc1925eb88e36d37f5c7526d73f05174a1253f00d127ad745dd1c054fa3b925abc6cb084f944a9e2d9ca49f821e98bec10d624c3deaab9c7e2954f80e4e@127.0.0.1:0","enr":"0xf88fb8404586a446db7c94f54415cdc0dc16014a70c60a090734bcdd910014501ce446962d9ec042f168a1cdec3b66fed17422d985d8e4114b5fe512b80e9cd3bead80a00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10283dc6dc1925eb88e36d37f5c7526d73f05174a1253f00d127ad745dd1c054fa3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FA3SEvKxk+5qnX/BT32jIcfvb9Nn+08ZSST9CtXRNcw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 140dd2\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 97da d302 c8c8 f8ff | 130 a742 (0) a7a8 (0) a616 (0) a606 (0)\n001 5 447c 447a 435d 4d91 | 61 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n002 3 31e6 3a62 298a | 28 3411 (0) 3728 (0) 36b9 (0) 32ff (0)\n003 8 07f5 0594 0561 0314 | 21 012b (0) 0111 (0) 0191 (0) 025d (0)\n004 7 1fd0 1dc0 1dec 1bd5 | 9 1fd0 (0) 1dc0 (0) 1dec (0) 1b1d (0)\n005 3 1049 1070 138d | 3 1049 (0) 1070 (0) 138d (0)\n============ DEPTH: 6 ==========================================\n006 2 1784 1686 | 2 1686 (0) 1784 (0)\n007 0 | 0\n008 1 1484 | 1 1484 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","private_key":"a027baaf8dce7a0533664447524ef6ad27032751f5eb84a289de80342d0fe705","name":"node_140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","services":["bzz","pss"],"enable_msg_events":true,"port":44825},"up":true}},{"node":{"info":{"id":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","name":"node_09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","enode":"enode://9d74be605030a4907946d4c396dbc3848b07c4d4d5b66b9171d8ba6d5e60a2558a4bfb0bb3a6b54e540d6dc7628eefcd573ba70bdb77f1f5f121cc0799e85e60@127.0.0.1:0","enr":"0xf88fb840b3dec516c58c4b1c9e69344e8b6c2d6dd826b010cbb4c7b61bd88a6ea6693da73750485c7a1a3bdc77bf30c5076e8a5b2b144deaecf8527f717b018f22c4adc80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029d74be605030a4907946d4c396dbc3848b07c4d4d5b66b9171d8ba6d5e60a255","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CbP6MHgJMeGLksddHN6vo2VgnFZeTowlPTk4NcuC2Y4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 09b3fa\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 aeb4 acee a330 a505 | 130 a970 (0) a8f4 (0) a8ff (0) a8b5 (0)\n001 3 435d 7e47 6d5e | 61 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n002 6 31e1 3a62 397a 3cab | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 2 1dec 140d | 16 1fd0 (0) 1dc0 (0) 1dec (0) 1bd5 (0)\n004 7 0594 0561 07f5 0111 | 10 012b (0) 0111 (0) 0191 (0) 025d (0)\n005 4 0e80 0e3b 0e2b 0cfc | 5 0e80 (0) 0e2b (0) 0e3b (0) 0d1c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 08bd 08e5 08f8 | 3 08bd (0) 08f8 (0) 08e5 (0)\n008 2 0942 096a | 2 0942 (0) 096a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","private_key":"30b0537c3a07c424ed947f31703b416041d6e1ccd1b086cb191d59b53dc632d8","name":"node_09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","services":["bzz","pss"],"enable_msg_events":true,"port":43439},"up":true}},{"node":{"info":{"id":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","name":"node_f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","enode":"enode://51f9bf866b226268237ad44341962115f0595ddc49c87a900c927b7c2c162dae6a3f123b9555e8c0f82927450546ddf8317d461eafe4931b368e709e84b8f060@127.0.0.1:0","enr":"0xf88fb840286a47e012b67dd7b25cc0b9cb9a212019f9b305881989ae09c749fed48a57e16d518566943216dbd238b448ee51fcae686fbc6b12e927e5ab9cfc2d499505000183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10251f9bf866b226268237ad44341962115f0595ddc49c87a900c927b7c2c162dae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+P90QNb0q7HIlJYzaEN0HtU6VEzt7u1x2OvgsIaYQ40=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f8ff74\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6d5e 67f3 2a50 140d | 126 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n001 7 a330 be68 84a9 8e7b | 75 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n002 8 da36 d959 d209 d302 | 27 ddb8 (0) d9cf (0) d959 (0) da36 (0)\n003 6 e867 ed42 eff2 eebd | 14 eb68 (0) e867 (0) ef99 (0) eff2 (0)\n004 3 f2b4 f305 f756 | 7 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n005 2 fc51 ff75 | 4 feb3 (0) ff75 (0) fc39 (0) fc51 (0)\n============ DEPTH: 6 ==========================================\n006 1 fa24 | 1 fa24 (0)\n007 1 f9de | 1 f9de (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","private_key":"d5ad379d43fa81ba9467d7945d0122c5695d2f7ebdf9d7e1c3384191bd5c4d12","name":"node_f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","services":["bzz","pss"],"enable_msg_events":true,"port":41309},"up":true}},{"node":{"info":{"id":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","name":"node_67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","enode":"enode://e379d322e7ad17953d786c9d00289bcf6921926341c7ecf7c128f043b29b702a5b01c6d92c3a39261f59fe8a2ebe5b26edd01d4971f910d0d6e18250e613e301@127.0.0.1:0","enr":"0xf88fb8400be4b9b202ed1e87dd987244284a9c5a5ad6c866e575c7ec5a929b2e91efad41349b08437a98a0f2909c85c3eedc1f2ba650f16d0a0fcb33ec7276e6cc22801e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e379d322e7ad17953d786c9d00289bcf6921926341c7ecf7c128f043b29b702a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z/OD5TNOm2cB0duyCHbUupp+V4rwR2yu1KfhtwHyvts=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67f383\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 84a9 8854 97da d302 | 130 a8b5 (0) a8ff (0) a8f4 (0) a970 (0)\n001 3 298a 18e0 0594 | 65 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n002 3 4d91 447a 435d | 35 5ff0 (0) 5c7c (0) 5c37 (0) 5d82 (0)\n003 3 741a 7933 7e47 | 13 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n004 6 6b4e 68cb 6e7f 6c01 | 7 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 6758 | 1 6758 (0)\n009 2 6790 6795 | 2 6790 (0) 6795 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","private_key":"b8e7f7fd21a946d988fa718b9babed932cf73070403fbd1c56456f04b8243262","name":"node_67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","services":["bzz","pss"],"enable_msg_events":true,"port":34903},"up":true}},{"node":{"info":{"id":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","name":"node_05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","enode":"enode://b3698b249bc2ecf1f856c3e3f12be6868853b3aa64fe9685b03162dd2a7afd9c491d8328e465d64d17fa49aa429a13c10f1db958b6ab89988370d6465cc0fc01@127.0.0.1:0","enr":"0xf88fb8408c0c34055a93806f387d7f730226b400b33e051c8aabfdda7c998e756544709f2476a88d4935a5c9776c54d5b8a5100260193615759717d3a016f9791a671cc40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b3698b249bc2ecf1f856c3e3f12be6868853b3aa64fe9685b03162dd2a7afd9c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BZSewaWC+nDKuVxZ58DTFVg7+fwyDGDDUmiTHyHpCFM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 05949e\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 97da 8854 ed42 e64d | 130 a970 (0) a8f4 (0) a8ff (0) a8b5 (0)\n001 4 4cec 7e47 6d5e 67f3 | 61 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n002 6 298a 3cab 397a 3a62 | 28 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n003 3 140d 18e0 194e | 16 1fd0 (0) 1dc0 (0) 1dec (0) 1add (0)\n004 5 096a 09b3 08e5 0e2b | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 6 0111 012b 0191 025d | 6 012b (0) 0111 (0) 0191 (0) 025d (0)\n006 1 07f5 | 1 07f5 (0)\n============ DEPTH: 7 ==========================================\n007 1 046c | 1 046c (0)\n008 1 0561 | 1 0561 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","private_key":"13a0aed3cdf03f83f823244e85cbe9e48d61303a1b41e446aadaaf74a2baf6b0","name":"node_05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","services":["bzz","pss"],"enable_msg_events":true,"port":45769},"up":true}},{"node":{"info":{"id":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","name":"node_6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","enode":"enode://191668a4f4a65da7ee37d46e341722e5a4732a0c63dd8b881141e9c281dc8d7f3f148af361d221bf7efa91709c24772b3a1e93236b9605d17fad43e159cbda30@127.0.0.1:0","enr":"0xf88fb840127e770bef790f2f06aeaf24547639a81249e512c9a9e3b2987bb161f1357f021587b4c9c833ef4c5d09f974548ac56b1b375d388486cbb12cd090e542ae43f30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102191668a4f4a65da7ee37d46e341722e5a4732a0c63dd8b881141e9c281dc8d7f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bV7Fka9JZroCTGsq60XgqriqF2L5ysMM45NNpSm3OOk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6d5ec5\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 f8ff ed42 97da 8854 | 130 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n001 3 18e0 09b3 0594 | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 4d91 402c 435d | 35 5987 (0) 5814 (0) 5bd8 (0) 5a26 (0)\n003 7 70f6 7660 741a 7e47 | 13 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n004 6 60c5 648a 6758 6790 | 6 60c5 (0) 648a (0) 6758 (0) 6790 (0)\n005 2 68cb 6b4e | 2 68cb (0) 6b4e (0)\n006 1 6e7f | 1 6e7f (0)\n007 1 6c01 | 1 6c01 (0)\n============ DEPTH: 8 ==========================================\n008 1 6dd3 | 1 6dd3 (0)\n009 1 6d3c | 1 6d3c (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","private_key":"1ce56a7fe145cc7c87edd8b2675d674db568652b226b80f6da7067c83cba55ec","name":"node_6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","services":["bzz","pss"],"enable_msg_events":true,"port":39153},"up":true}},{"node":{"info":{"id":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","name":"node_435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","enode":"enode://18eb16b8694f440ee7d57163d9cc8181ca5f025dacb16f9afb9e58ea8abdcbbaebed0ab1b856f73ab5ded12b5dd300849b1a721d73e0ac123cc5257373fee65a@127.0.0.1:0","enr":"0xf88fb84017e1348ced6a8488d50ff1773f2ad15c93bee9787be7b6795975b9e5ccb93d777c45645553471401c9fbd354d809e36f1abd98fff3f15723ffdd3f858086833e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10218eb16b8694f440ee7d57163d9cc8181ca5f025dacb16f9afb9e58ea8abdcbba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Q11yGlaOuQagPGnb1xM3JRpVBSGkAEq11KfetvMXBho=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 435d72\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8854 c8c8 | 130 a8b5 (0) a8ff (0) a8f4 (0) a970 (0)\n001 6 3cab 31e1 31e6 140d | 65 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n002 3 7e47 67f3 6d5e | 26 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n003 5 5d82 5a8b 5a26 5144 | 16 5ff0 (0) 5c7c (0) 5c37 (0) 5d82 (0)\n004 6 482e 4b79 4a95 4cec | 10 48b8 (0) 48f1 (0) 48de (0) 48d7 (0)\n005 4 46bf 44ad 447a 447c | 4 46bf (0) 44ad (0) 447a (0) 447c (0)\n006 2 4005 402c | 2 4005 (0) 402c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 43d4 43c9 | 2 43d4 (0) 43c9 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","private_key":"04326eafbd95ad027f8f4ffe10d64e65b512f2cc4905d138d81f6852b9b0dace","name":"node_435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","services":["bzz","pss"],"enable_msg_events":true,"port":44895},"up":true}},{"node":{"info":{"id":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","name":"node_c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","enode":"enode://c74190c0b1b29a5dd50900f0a04a79e60cdc6b3850d663aee32c681c279fe21cb701d8a3414eb18446e769ba8612766d1ed0240d80c3f6df1a1304d7326c21f0@127.0.0.1:0","enr":"0xf88fb8402b4c635d8867172a6c2a46b297fdd9c8bd917476a45883bc2cf7818442ff495622a30b7d13a6e26a66418c8572b882977e2535a91a46e244bed314001414664e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c74190c0b1b29a5dd50900f0a04a79e60cdc6b3850d663aee32c681c279fe21c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yMipN3nsTZrECSXoIIR4oA7if8Ig3dc9h3TPa/olXEY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8c8a9\npopulation: 23 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 140d 0594 435d | 126 1fd0 (0) 1dc0 (0) 1dec (0) 1b1d (0)\n001 3 be68 8854 97da | 75 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n002 3 ed42 f9de f8ff | 28 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n003 5 d959 dbd4 dad0 d209 | 11 ddb8 (0) d9cf (0) d959 (0) da36 (0)\n004 3 c74d c603 c6a8 | 8 c190 (0) c2d0 (0) c272 (0) c42e (0)\n005 3 cf52 cdb1 cd6c | 4 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c9c3 c961 | 2 c9c3 (0) c961 (0)\n008 0 | 0\n009 0 | 0\n010 1 c8ea | 1 c8ea (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","private_key":"4e1a61cde64af44b0dda77ec6ccf177754acdcf8296a2f6a28f809a3edd78a51","name":"node_c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","services":["bzz","pss"],"enable_msg_events":true,"port":37665},"up":true}},{"node":{"info":{"id":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","name":"node_97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","enode":"enode://e1a0b593eb6718290b19a241af012bcd050ba91442c444f9cb2728679fbaff94ae18b9344b896242f38d5cc5e5c71365c9b569d2b8c6e75c7237ad6399d03af0@127.0.0.1:0","enr":"0xf88fb8406126b86c32443771ffd4fe3aa1679a8627ee6dac7eb5d4ca51c1cea7b6742a093d407bde58a20a099b8dedea0066471ae30fbef9362c0a2d24ee87b0e22e50f80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e1a0b593eb6718290b19a241af012bcd050ba91442c444f9cb2728679fbaff94","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"l9ryy+A8gM5sTa45zQcd2TyzLtJFqpqncoXhIpaVfKM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 97daf2\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 67f3 6b4e 6d5e 4cec | 126 1fd0 (0) 1dc0 (0) 1dec (0) 1add (0)\n001 5 f8ff f9de ed42 c6a8 | 55 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n002 3 a505 bfc7 be68 | 37 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n003 5 80d7 834f 837f 84a9 | 21 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n004 4 9c8e 9f0e 9959 9948 | 9 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n005 2 9257 93ea | 3 9257 (0) 93c0 (0) 93ea (0)\n============ DEPTH: 6 ==========================================\n006 4 9464 955d 9518 95c0 | 4 9464 (0) 955d (0) 9518 (0) 95c0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","private_key":"65fbf9c544386bb7decc36886fba5c38238694e8e4ed0840b82ca0297e58b620","name":"node_97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","services":["bzz","pss"],"enable_msg_events":true,"port":33903},"up":true}},{"node":{"info":{"id":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","name":"node_885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","enode":"enode://53546a710a035309f1cbff35e8971bc7e690c23561599cf911a655235c34c063b6e49304da7dba56252e94bad64391e6e125b5e05162b0ddadf4822b5a2675b2@127.0.0.1:0","enr":"0xf88fb8407997f2172b5d153c60a8f8632c854da0dfb927a300de8988efc5d43eea68d0b035456f1e0f6f5cb8376ed14fe4c0d5884d94539a49bf8452ad524f86113a29740183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10253546a710a035309f1cbff35e8971bc7e690c23561599cf911a655235c34c063","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iFQnMYY0xFijBQ8vJutSRUp1zqShJjue1V5uuJl0OFQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 885427\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 0594 31e1 31e6 3cab | 126 012b (0) 0111 (0) 0191 (0) 025d (0)\n001 7 dbd4 d302 c6a8 c8c8 | 55 ddb8 (0) d959 (0) d9cf (0) da36 (0)\n002 7 a8ff acee a2a1 a606 | 37 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n003 7 9959 9948 9c8e 9f0e | 17 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n004 4 84a9 80d7 837f 834f | 12 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n005 5 8cc3 8d19 8f9a 8e28 | 6 8f9a (0) 8ea2 (0) 8e28 (0) 8e7b (0)\n============ DEPTH: 6 ==========================================\n006 1 8b43 | 1 8b43 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 8862 | 1 8862 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","private_key":"2dbbc994f617a8ec6183e97342de018005e6067b99283fdcef5b5d8dee384215","name":"node_885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","services":["bzz","pss"],"enable_msg_events":true,"port":36713},"up":true}},{"node":{"info":{"id":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","name":"node_ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","enode":"enode://a37137b1144735e571b2b0d8386ee87d4a549cfca4fd3fdddcb70745a7ce46fbc54b5d7b73e96de787896a234c4d22462e56a95a8dd6436cce4058d48847b44f@127.0.0.1:0","enr":"0xf88fb8409e3a3caf38d98642bade767220e7e62bad581c331b1e79c7a8fb576b7f80965e6d8d4d2163232397c431ac51260f72fee0862a1d49e2fab3b62f851a6f9a52430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a37137b1144735e571b2b0d8386ee87d4a549cfca4fd3fdddcb70745a7ce46fb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7UJNJNcCUgv3y19rq73EOgeENftKmITtgqk9ZCg54Sc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ed424d\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0594 397a 31e1 447c | 126 025d (0) 035f (0) 0314 (0) 0111 (0)\n001 5 be68 bfc7 ab3f 97da | 75 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n002 6 d302 dbd4 dad0 cd6c | 27 ddb8 (0) d959 (0) d9cf (0) da36 (0)\n003 3 f645 f8ff f9de | 14 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n004 2 e64d e277 | 7 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n============ DEPTH: 6 ==========================================\n006 3 eebd ef99 eff2 | 3 ef99 (0) eff2 (0) eebd (0)\n007 1 ec90 | 1 ec90 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","private_key":"88f389b4ef227125edc26120d238800734b5410e04322c15e248c5f216cc79c9","name":"node_ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","services":["bzz","pss"],"enable_msg_events":true,"port":39221},"up":true}},{"node":{"info":{"id":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","name":"node_67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","enode":"enode://cb89fe308a6760281a69d0737d0d373c9115feed0da089e0c2fcbc632089bf098dc65445404a53c75abf5006078392d46230c01bfbc96678614d72ba1f7ed94a@127.0.0.1:0","enr":"0xf88fb84062af8663cd95c946ddf91876f7724b51ef50c4562e116101de9830fa163e131e43857e1a002e03e8cffc1422472e7fc9638932823b58484aac2e28aba63484720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cb89fe308a6760281a69d0737d0d373c9115feed0da089e0c2fcbc632089bf09","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z1hd/YegBbrpv/wszLg8aVNyR8dIhrT6Uih/RseWvLY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67585d\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a505 eebd ed42 | 130 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n001 5 194e 0cfc 31e1 31e6 | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 2 447a 4cec | 35 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n003 4 7850 7933 7c46 7e47 | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 5 6b4e 6e7f 6c01 6dd3 | 7 6e7f (0) 6c01 (0) 6dd3 (0) 6d3c (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 3 67f3 6790 6795 | 3 6790 (0) 6795 (0) 67f3 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","private_key":"269bc398581870d669185abbe5f5c9b2f0e731c8e3f48a13c092c65822208065","name":"node_67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","services":["bzz","pss"],"enable_msg_events":true,"port":38253},"up":true}},{"node":{"info":{"id":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","name":"node_4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","enode":"enode://80e251b60502a0ca85c11875b9277729738dede4fe4d9da6aeac1bb93d7238ca81487fe9498180e00b10f3c24d030f8c399f02859b795d662a07dd7925bac295@127.0.0.1:0","enr":"0xf88fb8402acfbb34a162aefb2c548c72269c23643ae0c7bbc60406858fa6a60e304f225874d92d713f75b155bc9b1e2b135e732ae7a89a0f2dc1d4a1768bf1752a8b72ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10380e251b60502a0ca85c11875b9277729738dede4fe4d9da6aeac1bb93d7238ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TOzpvBNLwrCUAMn3+KTfknDS/jwHfF5EH//JEfz29C4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4cece9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f9de 97da 8854 | 130 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n001 4 0594 194e 140d 31e1 | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 5 7850 7933 7c46 7e47 | 26 7049 (0) 70f6 (0) 741a (0) 7660 (0)\n003 4 52a8 5ac0 5a8b 5d82 | 16 5538 (0) 56ca (0) 5663 (0) 50c1 (0)\n004 5 435d 43d4 402c 447a | 9 46bf (0) 44ad (0) 447a (0) 447c (0)\n005 7 48b8 48f1 48d7 48de | 7 48b8 (0) 48f1 (0) 48d7 (0) 48de (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 4d38 4d91 | 2 4d38 (0) 4d91 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","private_key":"745ab9f5dd6b46c5ac98c2548026c8c305b3a532b9a83e9721126e740be9bb3d","name":"node_4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","services":["bzz","pss"],"enable_msg_events":true,"port":40221},"up":true}},{"node":{"info":{"id":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","name":"node_31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","enode":"enode://f25dcda2d8dc59f4bd92c76bbc67662093243b8b2cfc966b9184fff854c66ec74507189ff7b3d4f89c266f79e8204f53b2ed2528ad9c3988b8d2e102ccd8ca05@127.0.0.1:0","enr":"0xf88fb840f2ed7d35799356b01b8172d9212f95f949f3ac3c3d9805388236bfae93eb4a0a2a4ea72335f7564107155b17384251f99007367bcd5afdea76fc4f8eee53b3920183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f25dcda2d8dc59f4bd92c76bbc67662093243b8b2cfc966b9184fff854c66ec7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MeEpqz334ILMJ8ZJ2e4po+pkbWqX0kF4dbgOP/V2wEc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 31e129\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 ed42 8854 97da | 130 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n001 3 6758 435d 4cec | 61 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n002 8 18e0 194e 0314 0191 | 37 025d (0) 035f (0) 0314 (0) 012b (0)\n003 2 2a50 298a | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 7 3a62 3b02 3980 397a | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 3 3411 36b9 3728 | 3 3411 (0) 36b9 (0) 3728 (0)\n006 1 32ff | 1 32ff (0)\n007 2 30fe 3051 | 2 30fe (0) 3051 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 3188 | 1 3188 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 31e6 | 1 31e6 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","private_key":"6f326011c258ea982e622f9e58986cda7a19e77bfef9c62969474eeca0a3d8bd","name":"node_31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","services":["bzz","pss"],"enable_msg_events":true,"port":41755},"up":true}},{"node":{"info":{"id":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","name":"node_31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","enode":"enode://f7c60635eb672476a7495b71f8dbcf2e50096b636d779195890b040d3a29f30617ac3ff34852bd1caadb9357ed844fd29cb9919f774986b1532f30e8fb5701f1@127.0.0.1:0","enr":"0xf88fb8401d011f6dc991e8d64cfd4b5595b6bcfa3a705c57e6f4494f8b1bc0ce443b738a6f0f975dbfaeda383333324db5b52840e0e34f48d194ee2ec25548336a6196aa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f7c60635eb672476a7495b71f8dbcf2e50096b636d779195890b040d3a29f306","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MeZwY4rLo9WPTGfz/y8/Jddp6KXXp4OJJ/TZ0WmoRAQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 31e670\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 97da 8854 f9de | 130 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n001 4 6b4e 6758 435d 4d91 | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 8 138d 140d 18e0 194e | 37 025d (0) 035f (0) 0314 (0) 012b (0)\n003 2 2a50 298a | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 6 3b02 3a62 397a 3f31 | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 2 36b9 3728 | 3 3411 (0) 3728 (0) 36b9 (0)\n006 1 32ff | 1 32ff (0)\n007 2 30fe 3051 | 2 30fe (0) 3051 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 3188 | 1 3188 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 31e1 | 1 31e1 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","private_key":"4d4953737261cf103a7e8d13c536e05949f4fc81404cbb94631badeed94837ae","name":"node_31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","services":["bzz","pss"],"enable_msg_events":true,"port":44433},"up":true}},{"node":{"info":{"id":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","name":"node_f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","enode":"enode://4cbf242837d8648b219a54398f6646ffe9e4729be3c43431284b27b6f6be2ee2f1267c6ea399699ca10b43dc11dcfb86fc2958e56b558b31d7679ae4493a37a9@127.0.0.1:0","enr":"0xf88fb840373f3de0559f7684b4ce5d159798f351f1bdf5f6792f3e506c2ccd904f07acae6955eaa902b5ad78809cebc0dc80ab7000ede03782617ca114ea23734f786c0b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034cbf242837d8648b219a54398f6646ffe9e4729be3c43431284b27b6f6be2ee2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+d7XuD5HPnG+L8AQHVdMRFIclvd/n4SjhHhaOvaxCT0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f9ded7\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 4cec 2a50 3cab 31e6 | 126 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n001 4 be68 95c0 97da 8854 | 75 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n002 9 ddb8 d9cf dad0 dbd4 | 27 d700 (0) d408 (0) d209 (0) d3e9 (0)\n003 6 e277 e64d e867 eff2 | 14 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n004 5 f756 f645 f1ed f215 | 7 f756 (0) f6c0 (0) f645 (0) f305 (0)\n005 4 feb3 ff75 fc39 fc51 | 4 ff75 (0) feb3 (0) fc39 (0) fc51 (0)\n============ DEPTH: 6 ==========================================\n006 1 fa24 | 1 fa24 (0)\n007 1 f8ff | 1 f8ff (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","private_key":"560da7a87ffd5a5bf49023d7b80398255aa1e028182ddc8fb2d8d256ecb672cf","name":"node_f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","services":["bzz","pss"],"enable_msg_events":true,"port":35959},"up":true}},{"node":{"info":{"id":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","name":"node_3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","enode":"enode://f292084e170293ef0d10591a7f596160c60090fb507add19279ae94ea15d4a935fee18917eb7afa876ce5961dccb0b6ab2e150bc746f0b6ce06b845fde8484d4@127.0.0.1:0","enr":"0xf88fb840aab20c00818aacbcf3d572ad9eb90bf3e50ed4ddeca68551ddaa751a781060ff1e937ba61f3905c35d7615ed44caed38be61740bf970af0c891c6da983e1dad90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f292084e170293ef0d10591a7f596160c60090fb507add19279ae94ea15d4a93","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PKvTpWf8Tm+Npm6zXZOP4emn8r3S02xNwtDg6RSfXlY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3cabd3\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9f0e 97da 8854 f9de | 130 a8b5 (0) a8f4 (0) a8ff (0) a970 (0)\n001 3 435d 6758 6b4e | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 4 194e 0594 09b3 0cfc | 37 025d (0) 035f (0) 0314 (0) 012b (0)\n003 4 26ab 2c85 298a 2a50 | 11 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n004 6 36b9 3728 3051 3188 | 9 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n005 5 3b02 3a62 3980 3938 | 5 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n============ DEPTH: 6 ==========================================\n006 1 3f31 | 1 3f31 (0)\n007 0 | 0\n008 1 3c5b | 1 3c5b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","private_key":"b5d0c48905d715632a6aaabb360e0f68e9cd27a16403c0a46de69e46c63ddcbd","name":"node_3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","services":["bzz","pss"],"enable_msg_events":true,"port":37601},"up":true}},{"node":{"info":{"id":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","name":"node_6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","enode":"enode://6489e2a9199837f8fb02ee32e8a8e76e29774f8596d0fdffe3d8b41ba49e47585c8ed3fd4fc87f5fe51217783eacc9f05e2b81b3388080fed75911cd15725490@127.0.0.1:0","enr":"0xf88fb840ac0ad126e5eaf3e3023aba08512eb98162e314d5a5bb8c9c237526d01a89099e074ee06f4d91f3f53b223df357b13d025dfc152842f36944651f957be64820720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026489e2a9199837f8fb02ee32e8a8e76e29774f8596d0fdffe3d8b41ba49e4758","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"a07htzlCztePl8DQ4iEgmTPmOuc1O7mrPTesQSdZLoY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6b4ee1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 eebd a505 be68 8854 | 130 af02 (0) aeb4 (0) acee (0) a970 (0)\n001 4 0cfc 31e6 3b02 3cab | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 2 447c 4d91 | 35 5538 (0) 56ca (0) 5663 (0) 52a8 (0)\n003 4 7e47 7c46 7850 7933 | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 6 60c5 648a 67f3 6790 | 6 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n============ DEPTH: 5 ==========================================\n005 5 6e7f 6c01 6dd3 6d3c | 5 6c01 (0) 6dd3 (0) 6d3c (0) 6d5e (0)\n006 1 68cb | 1 68cb (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","private_key":"55cabfb948c8655f9b1b9a73378029595cbbc8676d1e8109d34bed3ed4d363ec","name":"node_6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","services":["bzz","pss"],"enable_msg_events":true,"port":35557},"up":true}},{"node":{"info":{"id":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","name":"node_4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","enode":"enode://3047ce86e36b5df4ad3ba58da463012de954e7d23e30785281cd29a6cd9b53415ddca770f01615455e2191b2868a81fe90acb8c2c55af4d0b6a28cff220f27d0@127.0.0.1:0","enr":"0xf88fb8408ea2548809d57c51f6a345099fec0eb50bd94967e457cda4f7e809111d8191382d22aae732783fafb04e860e20a244e746261107b3adc670153e02d137b1dfca0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023047ce86e36b5df4ad3ba58da463012de954e7d23e30785281cd29a6cd9b5341","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TZFH47+Yy1mnZI9hbA1/cTqM87fSXjEVIz/1iDEovqs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d9147\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 be68 95c0 ed42 eebd | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 7 140d 1bd5 194e 0cfc | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 4 7e47 67f3 6d5e 6b4e | 26 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n003 2 5d82 5a8b | 16 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n004 4 447c 447a 435d 402c | 9 4005 (0) 402c (0) 43c9 (0) 43d4 (0)\n005 7 4a95 4b79 48b8 48d7 | 7 4b79 (0) 4a95 (0) 48b8 (0) 48f1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4cec | 1 4cec (0)\n008 1 4d38 | 1 4d38 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","private_key":"7dfa845b9c68e8058b6cff027cac1e713602c7d9e8ac4f04b0698a044871211e","name":"node_4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","services":["bzz","pss"],"enable_msg_events":true,"port":36001},"up":true}},{"node":{"info":{"id":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","name":"node_397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","enode":"enode://755abc3fa17f10b0c6bb93f9525352b3827f6e3f98bd74e4e52420017500a44983656b92a4a1253ead59da4030b30232f86d214431ad83949e6b218222c8c520@127.0.0.1:0","enr":"0xf88fb840486c18e5673883f3888ab658643d9e0012443ec6ca0c40e6876961396f39f722009fb44a458d56561c9ac5f302f47b069f97c94986e68ef69e0513431f4d0d9a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102755abc3fa17f10b0c6bb93f9525352b3827f6e3f98bd74e4e52420017500a449","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OXoKDp+ty1cazYmB9b/o4FnnB+D+roqcTGv+h7055mo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 397a0a\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 9f0e be68 ed42 eebd | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 3 7e47 7c46 4d91 | 61 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n002 5 0191 0594 09b3 1bd5 | 37 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n003 3 2e65 2a50 298a | 11 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n004 6 3411 36b9 3051 3188 | 9 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n005 3 3f31 3c5b 3cab | 3 3c5b (0) 3cab (0) 3f31 (0)\n006 2 3b02 3a62 | 2 3b02 (0) 3a62 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 3980 | 1 3980 (0)\n009 1 3938 | 1 3938 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","private_key":"e7af2fa49f44ec8fb20007e24a24e4d54f98188bf25d133631e2f2ae2455b7e5","name":"node_397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","services":["bzz","pss"],"enable_msg_events":true,"port":46385},"up":true}},{"node":{"info":{"id":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","name":"node_194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","enode":"enode://c55b0a9cce8421ed641876de3f9fed4b8a2fb2ef501cc2fa2c6c648609322114009de6258aa164d605ba2839658265bbb44a89d9ed9dbdbafa2f6d0451b75999@127.0.0.1:0","enr":"0xf88fb8406b407aefd0711536e0d1d66333664fef8325d87d5c12dcdfe5736ad122c4f05833ae95d2691865c2a66a8400c4112b32b073bb084564d49d1037bdfe563b3c890183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c55b0a9cce8421ed641876de3f9fed4b8a2fb2ef501cc2fa2c6c648609322114","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GU6j4U3F2Z+Y0VYH3ExAV2n1o3Gswi1Bpi0FN9cWvjI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 194ea3\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 95c0 ab3f be68 eebd | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 5 6758 5d82 4cec 4d91 | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 5 298a 31e6 31e1 3cab | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 6 0561 0594 07f5 0191 | 21 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n004 4 1049 1686 1484 140d | 7 138d (0) 1070 (0) 1049 (0) 1784 (0)\n005 2 1fd0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 1b1d 1bd5 1add | 3 1add (0) 1b1d (0) 1bd5 (0)\n============ DEPTH: 7 ==========================================\n007 1 18e0 | 1 18e0 (0)\n008 1 19ea | 1 19ea (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","private_key":"5ff701f0b31e5dfbd321b192941d8a7e41af8a30830fa9c299a338bbfd3a8ee6","name":"node_194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","services":["bzz","pss"],"enable_msg_events":true,"port":40883},"up":true}},{"node":{"info":{"id":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","name":"node_0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","enode":"enode://1c7485ed433143e6155988aead862aabcc93379a3897b443d75e1d2bce71c04cb75fea9591ed5e36b41949620e51fa8503ec72be6dd0b35a6405747b4dafc014@127.0.0.1:0","enr":"0xf88fb8402d44bd3da0be88d95e8011c9ae2754ea517a35bcf004b02da2673b824687e150720f9fc230cb05afe3de5214e1b1fc4da7501f86b228946800880e9f3af671580183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021c7485ed433143e6155988aead862aabcc93379a3897b443d75e1d2bce71c04c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DPxzCa+rzut9JIcU6XLPOYcgUyT1q40EjRe+pdyHNp0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0cfc73\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ddb8 d302 d408 95c0 | 130 d700 (0) d408 (0) d209 (0) d3e9 (0)\n001 6 5ac0 4d91 447c 6758 | 61 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n002 3 31e6 31e1 3cab | 28 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n003 5 140d 1dec 1bd5 18e0 | 16 138d (0) 1070 (0) 1049 (0) 1686 (0)\n004 6 0191 0111 0314 07f5 | 10 025d (0) 035f (0) 0314 (0) 012b (0)\n005 5 08bd 08f8 08e5 09b3 | 6 08e5 (0) 08f8 (0) 08bd (0) 09b3 (0)\n============ DEPTH: 6 ==========================================\n006 3 0e80 0e3b 0e2b | 3 0e80 (0) 0e2b (0) 0e3b (0)\n007 1 0d1c | 1 0d1c (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","private_key":"35dace76ca3522b7137c5d74398db392e8341bb9003f933fdc14452fd1750019","name":"node_0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","services":["bzz","pss"],"enable_msg_events":true,"port":44149},"up":true}},{"node":{"info":{"id":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","name":"node_95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","enode":"enode://098c38172926d2bea42728e3631de32062e6ec72da225a5737de50e5ec60e3eed42ee486959bdab553e465298a18c4ebf4c31dbdc77cfde7fe165cf86acb2695@127.0.0.1:0","enr":"0xf88fb84033fceafba7c7cd03f8de801dcdc01997dfe2a50ddb89b115c4d5ad40b7834b060eb29e4c2bd6811003ef36b75d39ed9c2effaca4138325ec3793c254b322f4880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103098c38172926d2bea42728e3631de32062e6ec72da225a5737de50e5ec60e3ee","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lcCjUft6pmgygNFZp7gIv6Y/Y7/5GhxZNulzsuXTlU8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 95c0a3\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6e7f 6b4e 4d91 194e | 126 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n001 6 dad0 cd6c c6a8 f8ff | 55 d700 (0) d408 (0) d209 (0) d3e9 (0)\n002 3 a505 bfc7 be68 | 37 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n003 6 8854 8e28 8cc3 80d7 | 21 8f9a (0) 8ea2 (0) 8e28 (0) 8e7b (0)\n004 5 9b8e 9948 9959 9c8e | 9 9b8e (0) 9948 (0) 9959 (0) 9ca1 (0)\n005 3 93ea 93c0 9257 | 3 9257 (0) 93c0 (0) 93ea (0)\n006 1 97da | 1 97da (0)\n007 1 9464 | 1 9464 (0)\n============ DEPTH: 8 ==========================================\n008 2 955d 9518 | 2 9518 (0) 955d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","private_key":"7c5cc685e77cf467257beb319c99f13ca9f2ba8294453271e7b01ae359184ca1","name":"node_95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","services":["bzz","pss"],"enable_msg_events":true,"port":38003},"up":true}},{"node":{"info":{"id":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","name":"node_eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","enode":"enode://e9ac9501ff66e4b8ea683a68019f6bf5a21283fbafd33abad3cd4def147e9ec20faed07f28001ad9a4cb0945ef8aab11edf8900123aa675bb29d6cbfb61ded08@127.0.0.1:0","enr":"0xf88fb8401e043e047731f0dcc2fa094bec2d3f0bebfdde7d067a07090d6e6a7ead1363fb2e8a68ddef0fdb8ed02a84edde2858d72a925a8c5e3f18ee29305be781dde3720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e9ac9501ff66e4b8ea683a68019f6bf5a21283fbafd33abad3cd4def147e9ec2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7r1Is2fL/pSjfA3rJ0ppfmKAdPlWC5CeZiKcXHbOaOs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eebd48\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 6758 6b4e 6e7f 447c | 126 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n001 6 ab3f a2a1 b78f bfc7 | 75 acee (0) af02 (0) aeb4 (0) a970 (0)\n002 6 c6a8 cd6c c961 d302 | 27 d700 (0) d408 (0) d209 (0) d3e9 (0)\n003 5 f645 fc51 fa24 f9de | 14 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n004 3 e09f e277 e64d | 7 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n006 2 ec90 ed42 | 2 ec90 (0) ed42 (0)\n============ DEPTH: 7 ==========================================\n007 2 ef99 eff2 | 2 ef99 (0) eff2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","private_key":"4f0005282a0cc3f4b0bbfbd57d4c18e1df8aee920756f2a469757e0670fb809e","name":"node_eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","services":["bzz","pss"],"enable_msg_events":true,"port":34859},"up":true}},{"node":{"info":{"id":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","name":"node_019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","enode":"enode://ac2123ba0df13d4d5dedbf061b751663af9ae100483d32007792511aba8ecca19b25c53b126dc1b230691c0f0e34057f622e2e4a1154f5eb34f872fc4651862d@127.0.0.1:0","enr":"0xf88fb840e6b23feb9b9d2bc1558c310f1a6d9fc8645da4e28517dbef118974963144e2cb477c6621f4cc9338fe7d53e749bd0bcf825ff2b6ae2ddb89ee2fd1963be821f60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ac2123ba0df13d4d5dedbf061b751663af9ae100483d32007792511aba8ecca1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AZEJMR1IiEl6oZTM5KibXvJDQhzw5+e7kRXQhuGh99c=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 019109\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 be68 eebd | 130 aeb4 (0) af02 (0) acee (0) a970 (0)\n001 2 6e7f 447c | 61 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n002 5 31e6 31e1 3051 397a | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 4 1686 1bd5 18e0 194e | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 4 0cfc 0e2b 09b3 096a | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 4 07f5 046c 0594 0561 | 4 046c (0) 0594 (0) 0561 (0) 07f5 (0)\n006 3 0314 035f 025d | 3 025d (0) 035f (0) 0314 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 012b 0111 | 2 012b (0) 0111 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","private_key":"8e22619e3e2e8484ded659b762691a898a0e95db9ecb04fac8c645f9cbaa1ff1","name":"node_019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","services":["bzz","pss"],"enable_msg_events":true,"port":35711},"up":true}},{"node":{"info":{"id":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","name":"node_447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","enode":"enode://256210b1641ad84c86fe1328a20490519df62a633e20426cb397dd62fc45b75971a55b94bb3a9b406e3fa0d56199c6290e89ec39b02021a462dd9ae8c1a74dc4@127.0.0.1:0","enr":"0xf88fb8408521fdc8311021e64bb28400fcfe6d060a33e4e5328f8cd52c882406b2502f1e5a48985f07c853ccba2176cf80d29128a0e61566df6c6b199c27ecf33e00a7fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102256210b1641ad84c86fe1328a20490519df62a633e20426cb397dd62fc45b759","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RHzb8f9GKqZ9akYIWxqE/cSVpBQqsXTI5psnGwlzK00=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 447cdb\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 cd6c ed42 eebd 834f | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 8 3051 3f31 140d 1bd5 | 65 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n002 4 7933 7e47 6b4e 6e7f | 26 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n003 2 5d82 5a8b | 16 5663 (0) 56ca (0) 5538 (0) 52a8 (0)\n004 5 482e 48de 4d91 4d38 | 10 4b79 (0) 4a95 (0) 482e (0) 48b8 (0)\n005 5 4005 402c 43d4 43c9 | 5 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n006 1 46bf | 1 46bf (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 44ad | 1 44ad (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 447a | 1 447a (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","private_key":"dfef090814210606651dad73b8ee233161b8f9bf9999725730de043d0e9af4e0","name":"node_447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","services":["bzz","pss"],"enable_msg_events":true,"port":41827},"up":true}},{"node":{"info":{"id":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","name":"node_be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","enode":"enode://974cfe63e11619004662fdf8336b028fbb9f22c98b67ae3e424f35d394030fb8a8ca8ce9412e1a4f349d6df174d3259431ca8a57ae3adf9f664b3a9c5ba9fd24@127.0.0.1:0","enr":"0xf88fb84098bddc1516cbbff113698681b95c27e15ee3b08e6510e799c6802496acf33e326ce1d60e740e9e37500a1b54d2ca357084a0648c7caa43f2a6584cd311682f6b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102974cfe63e11619004662fdf8336b028fbb9f22c98b67ae3e424f35d394030fb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vmgmfXf7UkJCJyZ8ZlyhGToBAzTKwFczisp3tJpLlNo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be6826\npopulation: 43 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 397a 194e 0191 6b4e | 126 244c (0) 24f8 (0) 26ac (0) 26ab (0)\n001 7 c8c8 cd6c e64d ed42 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 7 8cc3 8854 84a9 837f | 38 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n003 13 a8ff ab3f af02 aeb4 | 23 aeb4 (0) af02 (0) acee (0) a970 (0)\n004 3 b3f9 b5ea b78f | 6 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n005 2 b8e1 bbaf | 3 b8e1 (0) ba91 (0) bbaf (0)\n006 2 bcf8 bdc5 | 2 bcf8 (0) bdc5 (0)\n============ DEPTH: 7 ==========================================\n007 1 bfc7 | 1 bfc7 (0)\n008 1 bea1 | 1 bea1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","private_key":"6641d12829826045dddcad116be9a840aa14ba3542597d5cc4e71324fa29af40","name":"node_be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","services":["bzz","pss"],"enable_msg_events":true,"port":37231},"up":true}},{"node":{"info":{"id":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","name":"node_6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","enode":"enode://3821a5bff1a93183090d662d2451159ebe363ee2df3b361159cded82888ed46322fc6470eb09bfb736355e121b06092eb64120fb8e0448778b948559baa814d9@127.0.0.1:0","enr":"0xf88fb84051b3adb1ee656aaaad0cb4b241aa3c32ffceea4999429eddee1573f06d9477793034a1aa1b8f586fac2c2aba3e5f8ca79f6e01885eee40e0c70983c7ffe8ee950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033821a5bff1a93183090d662d2451159ebe363ee2df3b361159cded82888ed463","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bn8fPWU2Q5lhek2V/dBPLKmwB7I2aUPnulrNRhanpCU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e7f1f\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c961 cd6c eebd 95c0 | 130 f756 (0) f6c0 (0) f645 (0) f305 (0)\n001 7 07f5 0191 0cfc 096a | 65 138d (0) 1070 (0) 1049 (0) 1784 (0)\n002 3 5a8b 4d38 447c | 35 5144 (0) 50c1 (0) 52a8 (0) 5538 (0)\n003 5 7e47 7c46 7d16 7933 | 13 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n004 5 60c5 648a 6795 67f3 | 6 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n005 2 6b4e 68cb | 2 68cb (0) 6b4e (0)\n============ DEPTH: 6 ==========================================\n006 4 6c01 6dd3 6d3c 6d5e | 4 6c01 (0) 6dd3 (0) 6d3c (0) 6d5e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","private_key":"41525658ab059b89329f02a6c477cd77bc69b94ceae45e0e31f70bb6b70ee671","name":"node_6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","services":["bzz","pss"],"enable_msg_events":true,"port":38077},"up":true}},{"node":{"info":{"id":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","name":"node_bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","enode":"enode://d0595ae566e2dec77e37a408dcf8d7c3157cc52378c66fada8c78b588aa926d2f7350c17cd3f8586f36de2c55a9020e923262ad54d5b7530f063570cc46f3f6b@127.0.0.1:0","enr":"0xf88fb840c153e9a46508c43ea149e6f6f11d3d2077afd262f7b2bb8df75d999927705ad20554753898c4f1f275f901157620f8b3c2e4f9ea4ff600ac2e0fbba78fb70f270183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d0595ae566e2dec77e37a408dcf8d7c3157cc52378c66fada8c78b588aa926d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"v8cReTgwd59Jqlm8b3ogWrTm6uer/a+/O7WhFjp3irI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bfc711\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3f31 6e7f | 126 138d (0) 1070 (0) 1049 (0) 1784 (0)\n001 7 ed42 eebd d302 dad0 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 6 834f 84a9 95c0 97da | 38 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n003 15 ab3f a970 a8ff acee | 23 acee (0) aeb4 (0) af02 (0) a970 (0)\n004 4 b3f9 b5ea b6df b78f | 6 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n005 3 ba91 bbaf b8e1 | 3 bbaf (0) ba91 (0) b8e1 (0)\n006 2 bcf8 bdc5 | 2 bcf8 (0) bdc5 (0)\n============ DEPTH: 7 ==========================================\n007 2 be68 bea1 | 2 bea1 (0) be68 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","private_key":"98697e601711a0c2bc93c85db0434deba8428ccf604641af230ef188b176ceff","name":"node_bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","services":["bzz","pss"],"enable_msg_events":true,"port":46271},"up":true}},{"node":{"info":{"id":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","name":"node_3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","enode":"enode://cd82e53229cae0db1a40d6d3974aceff2b8223d817606879d4d4c82e93d851a5a41a488c441ff25a85dda297bf76cf3ffc924029112a5afc15ff35a1f49aaa6a@127.0.0.1:0","enr":"0xf88fb840a9166c078904cd0604d4a4a19f9884af9ba6a3c08f1da14902b3be746025dca87ef2d6ecc67dcbd2808df07f6a1a911e3f71936e779fba08bc74db71740c34290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102cd82e53229cae0db1a40d6d3974aceff2b8223d817606879d4d4c82e93d851a5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PzHsr/qmMRyCyaV1u8ONa8sWYwrIfhnRhTpkqpbJ3N4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3f31ec\npopulation: 21 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 834f bfc7 | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 2 447c 6e7f | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 4 096a 0561 07f5 0191 | 37 138d (0) 1070 (0) 1049 (0) 1784 (0)\n003 2 2a50 298a | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 5 36b9 3188 31e6 31e1 | 9 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n005 4 3b02 3a62 397a 3980 | 5 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n============ DEPTH: 6 ==========================================\n006 2 3c5b 3cab | 2 3c5b (0) 3cab (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","private_key":"3ed9ff27809a5c5e4f61f5343410a2a1291496221e7861971e6d48611b1a9abd","name":"node_3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","services":["bzz","pss"],"enable_msg_events":true,"port":42049},"up":true}},{"node":{"info":{"id":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","name":"node_834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","enode":"enode://69f51e1ebbbb38b8b161722c403f583d6141cff104f2da6dc21f21f0c50e4d41d031f8a4d0523d545691ebe7ba00050d25ac6ef88255fbc453fea197db95fffd@127.0.0.1:0","enr":"0xf88fb84074d162cf5aadfde184fd1c7884869ea76837d6e33b21bfd74ff53d66b50c055c3479080476f1e97ea070cf9ed88ef3445665a36e93f803078d5e4cdd738a77a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10369f51e1ebbbb38b8b161722c403f583d6141cff104f2da6dc21f21f0c50e4d41","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g08U6fMlSCre9iZR3fNoVpDdXr3RgBTyvSZrIUPCkP8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 834f14\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 447c 096a 3f31 | 126 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n001 4 cd6c c961 dad0 dbd4 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 6 a8ff a606 a505 b78f | 37 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n003 4 9f0e 93ea 97da 95c0 | 17 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n004 6 8cc3 8f9a 8e28 8e7b | 9 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n005 3 86d6 8402 84a9 | 4 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n006 5 81a5 8006 8073 8074 | 5 81a5 (0) 8006 (0) 8073 (0) 8074 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 837f | 1 837f (0)\n011 1 8358 | 1 8358 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","private_key":"1496abca4c41e1d57c812b53636296bdad2570659143afc188383905ad3a1d30","name":"node_834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","services":["bzz","pss"],"enable_msg_events":true,"port":44165},"up":true}},{"node":{"info":{"id":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","name":"node_096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","enode":"enode://ff8aff353bd9756ed7a631808ca59009f89f5db4ddc3938b05ea2cf4fef6855ace3f6873b2ee1a35b6bb524b9f310b19db97e635add9ed1075e9907da1b56157@127.0.0.1:0","enr":"0xf88fb84062ef2386cda8f32e286d22df7b0ee0daf321024107b0a4794abfe7b079de98083d2b860770dea2044c50072ee556e6d3ec1d217915acaa11a2dd6b1b31b1ad0b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ff8aff353bd9756ed7a631808ca59009f89f5db4ddc3938b05ea2cf4fef6855a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CWqDArbzacKO2dR3GaUH6tijzByk+h4yMYt/l4c5Vf4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 096a83\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a505 834f | 130 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n001 2 447c 6e7f | 61 5144 (0) 50c1 (0) 52a8 (0) 5538 (0)\n002 4 3f31 31e1 3188 3051 | 28 26ac (0) 26ab (0) 244c (0) 24f8 (0)\n003 5 1686 140d 1bd5 18e0 | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 4 0191 0594 0561 07f5 | 10 025d (0) 035f (0) 0314 (0) 012b (0)\n005 4 0e80 0e3b 0e2b 0cfc | 5 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 08bd 08f8 08e5 | 3 08bd (0) 08f8 (0) 08e5 (0)\n008 1 09b3 | 1 09b3 (0)\n009 0 | 0\n010 1 0942 | 1 0942 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","private_key":"396f35fa7f69257841f0b832cf5f655557fa1b060dbb859461a22429101230cb","name":"node_096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","services":["bzz","pss"],"enable_msg_events":true,"port":43747},"up":true}},{"node":{"info":{"id":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","name":"node_a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","enode":"enode://462c3ca5391ed837a169228797bea3d3f4585a7fb5cb938de1fc15649174b0156940060d152a8486deb4ccfe2c3ca460b5d9a184399db2f4a8b95ec015e86896@127.0.0.1:0","enr":"0xf88fb840dd4c1cd722f83d847e339b92de95082d1413d3b86944796fee5054d09a8390b052018a03749011927e56a0650aa9db5ade2a936687147004585d02d32fe1861b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102462c3ca5391ed837a169228797bea3d3f4585a7fb5cb938de1fc15649174b015","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pQU5WPDO/P8YJr8CUl/amMTclUzDhpDzxD7L8LKtV68=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a50539\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 6758 6b4e 3051 09b3 | 126 5144 (0) 50c1 (0) 52a8 (0) 5538 (0)\n001 4 dad0 dbd4 c961 cd6c | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 7 8854 837f 834f 9f0e | 38 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n003 5 b3f9 b78f b8e1 bfc7 | 14 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n004 3 aeb4 a8ff ab3f | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a0c8 a330 a327 a2e6 | 6 a1c8 (0) a0c8 (0) a330 (0) a327 (0)\n006 4 a742 a7a8 a616 a606 | 4 a7a8 (0) a742 (0) a616 (0) a606 (0)\n============ DEPTH: 7 ==========================================\n007 1 a4ee | 1 a4ee (0)\n008 1 a5ac | 1 a5ac (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","private_key":"550f3f019bfee28d84cbafd18523a10069faabebcbe9823512a4f0af5343b627","name":"node_a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","services":["bzz","pss"],"enable_msg_events":true,"port":36993},"up":true}},{"node":{"info":{"id":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","name":"node_305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","enode":"enode://c5f49027f8ad45e617b539a3242f31739ac950203b54ecf8dbe5b2160b85ee594bc40553728846692df15f6859547b5360e6cbf64dd1486b9d5272c378b958ac@127.0.0.1:0","enr":"0xf88fb840ad06f6a9761fd36b8a36707e80761bda29124da842be6b3eef6cb49227944a6709187c9a4d490219f8244eaaec1538b10720b042ad258a64bf7a09438d4673470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c5f49027f8ad45e617b539a3242f31739ac950203b54ecf8dbe5b2160b85ee59","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MFFixHLHHd7yMgsTgQK2fRziuLunni5Yf8gOCFyI5Uc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 305162\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 dbd4 a505 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 5 5a8b 4d91 4d38 447c | 61 5538 (0) 5663 (0) 56ca (0) 50c1 (0)\n002 5 18e0 0191 07f5 0561 | 37 138d (0) 1070 (0) 1049 (0) 1784 (0)\n003 3 26ab 298a 2a50 | 11 24f8 (0) 244c (0) 26ac (0) 26ab (0)\n004 8 3cab 3c5b 3f31 3a62 | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 2 36b9 3728 | 3 3411 (0) 36b9 (0) 3728 (0)\n006 1 32ff | 1 32ff (0)\n============ DEPTH: 7 ==========================================\n007 3 3188 31e6 31e1 | 3 31e1 (0) 31e6 (0) 3188 (0)\n008 1 30fe | 1 30fe (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","private_key":"3ccc59b4b2ef2146a73d043f665a3dec37990b81cf7e81c670ef586260aa4f45","name":"node_305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","services":["bzz","pss"],"enable_msg_events":true,"port":41853},"up":true}},{"node":{"info":{"id":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","name":"node_dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","enode":"enode://12b59aaec065fee81276d23336c7a839dfd34fa213d06a31fa3447894ed5afdefca89b783977333245f76c2e35b74504e51928af9586e4f288a870a6c0db0c2a@127.0.0.1:0","enr":"0xf88fb840c57b5dd80289305003c7726a173a5f1e93a911e51aa052b1ab38f38e9a102c1074a105d65dc177fdff430aeb2e9d2de42f87d2b32d7cc7fbd6b57647999ab64c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212b59aaec065fee81276d23336c7a839dfd34fa213d06a31fa3447894ed5afde","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"29TZDjNC74N7js9cbkkPfECfQZzza3cWKofLLPuK4zw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dbd4d9\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3188 3051 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 7 93ea 9f0e 8854 834f | 75 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n002 5 f645 fc51 f9de ed42 | 28 f756 (0) f645 (0) f6c0 (0) f1ed (0)\n003 8 c42e c6a8 c74d c961 | 16 c190 (0) c272 (0) c2d0 (0) c534 (0)\n004 3 d408 d209 d302 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n005 1 ddb8 | 1 ddb8 (0)\n006 2 d959 d9cf | 2 d959 (0) d9cf (0)\n============ DEPTH: 7 ==========================================\n007 2 da36 dad0 | 2 da36 (0) dad0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","private_key":"c2103de042f815312e3c17f6a1334bcbdbc1e4f58d39e436d463cf08b61b060d","name":"node_dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","services":["bzz","pss"],"enable_msg_events":true,"port":45509},"up":true}},{"node":{"info":{"id":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","name":"node_cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","enode":"enode://3f46a3f4016f9803ad015ff459b7b2d3ae3dc814ca3dce437d56046302b1bf2c143203755461e513a4ae4ed11d6548aeca82b83a3026662f06c7ebddeef20c7c@127.0.0.1:0","enr":"0xf88fb840aa6d2306927e37eb5add2079388ffeb2ad0bf5d36ad922dc7dfbbcae12b8511120a7ceaeb6685848468c6434e7add539507eb0305283e9881b35eb5b50cc699d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023f46a3f4016f9803ad015ff459b7b2d3ae3dc814ca3dce437d56046302b1bf2c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zWyLQqCwkvQeaSVXfJ3n0b6hcjG8s9CPPTzOnG/c8i0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cd6c8b\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 7933 6e7f 447c 5a8b | 126 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n001 11 834f 95c0 93ea 9f0e | 75 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n002 8 f2b4 f645 fc51 fa24 | 28 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n003 5 d302 d408 ddb8 d9cf | 11 d209 (0) d3e9 (0) d302 (0) d700 (0)\n004 3 c6a8 c603 c74d | 8 c272 (0) c2d0 (0) c190 (0) c42e (0)\n005 4 c961 c9c3 c8ea c8c8 | 4 c8ea (0) c8c8 (0) c9c3 (0) c961 (0)\n006 1 cf52 | 1 cf52 (0)\n============ DEPTH: 7 ==========================================\n007 1 cc33 | 1 cc33 (0)\n008 1 cdb1 | 1 cdb1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","private_key":"cd14c3cb4c268526af99a387d2e105f126f0d3e4368b46397cc117868140fbaa","name":"node_cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","services":["bzz","pss"],"enable_msg_events":true,"port":45357},"up":true}},{"node":{"info":{"id":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","name":"node_07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","enode":"enode://0214bfe7469b5ed146f1f11d937181680a8dea456f3586d08810ca756337e9fed3e46fe35c99af4496d072125f6b898ab97f5332e16399f3107d15912756daf6@127.0.0.1:0","enr":"0xf88fb840af0cb239eef4aef9f88cfc4a0241d95cb9ef1cbb14c5889164e2d27c2c09a433595a3366678b3e8e1f1933c2ea8bbbe26d0b5dc604e984a43e20e68e4dbd42300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020214bfe7469b5ed146f1f11d937181680a8dea456f3586d08810ca756337e9fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"B/XQlKSyLnPN1shUUrPZKNqbSxaHOCR1nLfopiJBf9U=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 07f5d0\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 c961 cd6c | 130 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n001 4 6e7f 7c46 7933 4d38 | 61 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n002 6 2c80 2ddf 298a 2a50 | 28 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n003 6 1049 1686 140d 1bd5 | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 5 0cfc 0e80 0e2b 09b3 | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 6 035f 0314 025d 0191 | 6 025d (0) 035f (0) 0314 (0) 012b (0)\n============ DEPTH: 6 ==========================================\n006 3 046c 0594 0561 | 3 046c (0) 0594 (0) 0561 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","private_key":"251c21ef6c12491657b20ba5898f537b45474fd62ce9f870aa98b7a2ce906096","name":"node_07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","services":["bzz","pss"],"enable_msg_events":true,"port":45285},"up":true}},{"node":{"info":{"id":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","name":"node_c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","enode":"enode://a32b355f09cbc5a2ccbffb7eea267721cdc1108cab1c29d2dd1e2e7fa7c5c20e04c6a024fa47373e830891a62576084c8bbae862c4044ad94a2c612189282db8@127.0.0.1:0","enr":"0xf88fb8408a9d74f8b002fe6e7cff4d593bbf3bae2a56a10b0f5d1a6187fe6c3387aaa0cf399c033c3390082c7a87ecb9c2e865ca708f2279eb75d132524d4bcb29cba63d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a32b355f09cbc5a2ccbffb7eea267721cdc1108cab1c29d2dd1e2e7fa7c5c20e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yWFG7kfsfNdFUc908AITvDN9ZDxDJzk/DmhI7NSg+NM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c96146\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6e7f 7c46 7933 3188 | 126 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n001 9 b78f bfc7 a606 a5ac | 75 8d19 (0) 8cc3 (0) 8ea2 (0) 8e7b (0)\n002 5 f645 fc51 f9de ed42 | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 6 d302 d408 ddb8 d9cf | 11 d209 (0) d3e9 (0) d302 (0) d700 (0)\n004 2 c603 c6a8 | 8 c272 (0) c2d0 (0) c190 (0) c42e (0)\n005 4 cf52 cd6c cdb1 cc33 | 4 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c8ea c8c8 | 2 c8ea (0) c8c8 (0)\n008 1 c9c3 | 1 c9c3 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","private_key":"11fc592c06dfe93bde5f4e4d007d2c7020e49d7e5ef8de72fb7ad0c39d96d2c2","name":"node_c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","services":["bzz","pss"],"enable_msg_events":true,"port":43471},"up":true}},{"node":{"info":{"id":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","name":"node_dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","enode":"enode://3a93f5d6282a4f76c82c17c35a6f8eac3a2b9b63ae0e3a532ab625fd4df7fa7f4357b01c8f6071b405a85b97e6832ba2b0d8eefc3afec46b0221bd15c2f4d5e6@127.0.0.1:0","enr":"0xf88fb840f5b726c896fc45a7d66c14a7ff0b8cffe4f443829996bcf4bf69388e9b4fb1445eddef566d406b613be72fb97eb94988db3f65a8eb1d51134b93c241fde80a460183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1023a93f5d6282a4f76c82c17c35a6f8eac3a2b9b63ae0e3a532ab625fd4df7fa7f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2tCJmc0u3DPP3FnqNMitzWo06qFfLoWwYi6YSLIVwdU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: dad089\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7c46 7933 3188 1bd5 | 126 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n001 6 a505 bfc7 834f 93ea | 75 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n002 4 f645 f9de ed42 eebd | 28 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n003 5 c190 c74d c8c8 c9c3 | 16 c2d0 (0) c272 (0) c190 (0) c534 (0)\n004 4 d209 d302 d700 d408 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n005 1 ddb8 | 1 ddb8 (0)\n006 2 d9cf d959 | 2 d959 (0) d9cf (0)\n============ DEPTH: 7 ==========================================\n007 1 dbd4 | 1 dbd4 (0)\n008 1 da36 | 1 da36 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","private_key":"ac54b72de76bbeab526b566706c5324bfab619ac9019078319474c8396bb36f3","name":"node_dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","services":["bzz","pss"],"enable_msg_events":true,"port":40305},"up":true}},{"node":{"info":{"id":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","name":"node_056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","enode":"enode://265ba137f94c59432e330185dfe26176b2833143e001d135ff9bdc74eb6a7dbf46a40c5f27a01cb176086b2a4bcd8b4df935a0e35fc331e5da556d2471d19b46@127.0.0.1:0","enr":"0xf88fb840e995a0df1f38fad4ffb6332b3ccf46fa213f3d0c5b746ecd7ab35dc36e928f8f16ebf9bee964f47e3ceb70b47261c82843d796a2d28785cdd521f7e7add6fbf40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102265ba137f94c59432e330185dfe26176b2833143e001d135ff9bdc74eb6a7dbf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BWFS3Z2uhcQmN400rKuNZkHaZl0vVzWaJ6D/ZS8/PQI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 056152\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a5ac dad0 | 130 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n001 3 7933 5a8b 4d38 | 61 60c5 (0) 648a (0) 6790 (0) 6795 (0)\n002 3 3f31 3188 3051 | 28 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n003 5 1049 1686 140d 194e | 16 138d (0) 1070 (0) 1049 (0) 1784 (0)\n004 4 0e2b 0cfc 09b3 096a | 11 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n005 5 0314 025d 012b 0111 | 6 025d (0) 035f (0) 0314 (0) 012b (0)\n006 1 07f5 | 1 07f5 (0)\n============ DEPTH: 7 ==========================================\n007 1 046c | 1 046c (0)\n008 1 0594 | 1 0594 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","private_key":"faad557bcbab6d34e58f844b5a368fc2c5a4d088352c0bc0d2363aec33462b69","name":"node_056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","services":["bzz","pss"],"enable_msg_events":true,"port":43665},"up":true}},{"node":{"info":{"id":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","name":"node_a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","enode":"enode://8cdb600efbfa331c7bcb78d899595726993e73d7aac802d61673d8b50f7766950f1907d11732fbac2e316d2d8f439f984f54164a7b2db098ae1b35540e8b2902@127.0.0.1:0","enr":"0xf88fb840d11b0126170eb4fee1197420356b363c9efc48d4f5f3ac3ec4139a53443f7d6c5d66e6edbc0a80d5d907f8aa5fba8247287ecc0d7a9e4910801655d67107a7fa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028cdb600efbfa331c7bcb78d899595726993e73d7aac802d61673d8b50f776695","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pawE1TtWnkGO9QB5YUMRVfLCJu4QFXswr3HqSDawgIk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a5ac04\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7933 4d38 1bd5 0561 | 126 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n001 3 dbd4 c961 cd6c | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 4 8854 837f 9f0e 93ea | 38 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n003 4 bfc7 be68 b3f9 b78f | 14 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n004 2 af02 a8ff | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a1c8 a330 a327 a2a1 | 6 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n006 4 a616 a606 a7a8 a742 | 4 a7a8 (0) a742 (0) a616 (0) a606 (0)\n============ DEPTH: 7 ==========================================\n007 1 a4ee | 1 a4ee (0)\n008 1 a505 | 1 a505 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","private_key":"0a918d168aacb95afe15f3eba1e762f144f5ffa60fa01155a81ec8cf4a5c5470","name":"node_a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","services":["bzz","pss"],"enable_msg_events":true,"port":36481},"up":true}},{"node":{"info":{"id":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","name":"node_4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","enode":"enode://98863ce3c7e18d15ece80b94033ae1825556b0a21f84ec04077e72f48df419e525b341d7bef239e3565754f57b3e9cf42b828667a8e0bffc5e9ef9d596888353@127.0.0.1:0","enr":"0xf88fb840c0c7e8479b7d62eac2089ba0a3436acd47f05a6410097ae49bcf77ec309c122a4b04acaa26fddfb564888a144346c8277e2459076aa8758bc1b31d17fdaa6e7b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10398863ce3c7e18d15ece80b94033ae1825556b0a21f84ec04077e72f48df419e5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TTgQFHg5gLL3fw1xFgrZ6dhGcrV29ENczbrhJ1I1DBw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4d3810\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 93ea a5ac | 130 f756 (0) f645 (0) f6c0 (0) f1ed (0)\n001 4 3051 3188 07f5 0561 | 65 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n002 4 6e7f 7933 7850 7c46 | 26 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n003 5 56ca 5d82 5ff0 5a8b | 16 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n004 5 402c 43d4 43c9 435d | 9 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n005 3 482e 48b8 48de | 7 4b79 (0) 4a95 (0) 48b8 (0) 48f1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 4cec | 1 4cec (0)\n008 1 4d91 | 1 4d91 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","private_key":"f83b2e95c445a50438af645a0f3dd41e2615d85bc9e28834a722b78081960743","name":"node_4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","services":["bzz","pss"],"enable_msg_events":true,"port":34823},"up":true}},{"node":{"info":{"id":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","name":"node_93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","enode":"enode://fb8e6ad0083dd5c9588924daa51194dfc6a4e8e5efd75fb3bd2f76d99c15df4aa355b2419a416d0be44ddabd404b7d503461312253bc36f9c8cb6acf86206faf@127.0.0.1:0","enr":"0xf88fb840de494f8808c9d4cb3dbbe95d92b77102bde20de29cb253862072e62ac37179767dd2aa1e587a6ddff1e42149b96842de7054b91c30a773c04c140030f83054e70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fb8e6ad0083dd5c9588924daa51194dfc6a4e8e5efd75fb3bd2f76d99c15df4a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"k+qO8lH9VrFZ4IDN9zPTPh/fs8euW9mmoyjQv1RYhns=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 93ea8e\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1bd5 3188 7c46 7850 | 126 2fd2 (0) 2e65 (0) 2ddf (0) 2c85 (0)\n001 4 dad0 dbd4 cd6c c961 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 6 bfc7 b78f a2a1 a606 | 37 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n003 4 8854 8e28 834f 837f | 21 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n004 5 9b8e 9948 9959 9ca1 | 9 9b8e (0) 9948 (0) 9959 (0) 9c21 (0)\n005 4 95c0 9518 955d 97da | 5 97da (0) 9464 (0) 9518 (0) 955d (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 9257 | 1 9257 (0)\n008 0 | 0\n009 0 | 0\n010 1 93c0 | 1 93c0 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","private_key":"60b514798a6f6a2f5cf7e85f798280d359067d82ca6c08dd3d5152c9325f8c11","name":"node_93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","services":["bzz","pss"],"enable_msg_events":true,"port":44155},"up":true}},{"node":{"info":{"id":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","name":"node_9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","enode":"enode://1a733925153e123a28e4c6ff215622e6f5f6e3603dd3ecac572db24c88743906db68f57c873814af3004eeee0cec5e7ea31c1fa450a6f60a4d682c5d36d4f7d6@127.0.0.1:0","enr":"0xf88fb8407124e4586da75d58f439871e4d6d59bf6cb2adffd121aa712eb670aa52d490b20045fdd401ff02688127caa8436744fae9ded418d490b1f6bdb678380f0839950183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021a733925153e123a28e4c6ff215622e6f5f6e3603dd3ecac572db24c88743906","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nw4r+KliFWyeCoPD1CrT3FrFw+UI8kIAv7FRqtTjlf8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9f0e2b\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 26ac 298a 2c80 3cab | 126 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n001 4 cd6c c961 dbd4 dad0 | 55 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n002 5 bfc7 a2a1 a606 a505 | 37 b3f9 (0) b4a1 (0) b5ea (0) b659 (0)\n003 3 8854 837f 834f | 21 8d19 (0) 8cc3 (0) 8f9a (0) 8ea2 (0)\n004 3 97da 95c0 93ea | 8 97da (0) 9464 (0) 9518 (0) 955d (0)\n005 3 9b8e 9948 9959 | 3 9b8e (0) 9948 (0) 9959 (0)\n006 2 9ca1 9c21 | 3 9c8e (0) 9ca1 (0) 9c21 (0)\n============ DEPTH: 7 ==========================================\n007 1 9ec8 | 1 9ec8 (0)\n008 0 | 0\n009 1 9f7d | 1 9f7d (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","private_key":"5e77db0ba785223e5c1e3ce73ecad087df783ddb123f13e44c126125e5320834","name":"node_9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","services":["bzz","pss"],"enable_msg_events":true,"port":36327},"up":true}},{"node":{"info":{"id":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","name":"node_5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","enode":"enode://78abddf561d75c3f8e4ee5cf729a4ca27a15261a2f7643ba4669070e37568388a95d9ba6ff45b86f63c11bb67c5f0816c8b8e1436db63342080d94b1ec98afe6@127.0.0.1:0","enr":"0xf88fb8404bd00e9812551717571255b2d27db8fdc87870fc9285e293ceb9921910e0c20f68658713acfd38ca573cae42d75bcd43a72edd6c7f0a363fccf5820d7c7b62990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10278abddf561d75c3f8e4ee5cf729a4ca27a15261a2f7643ba4669070e37568388","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WouE32UYcfznLRHLHCbIeuSgzGtMJ0035wUyyU8nKI4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5a8b84\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 cd6c a606 a2a1 9f0e | 130 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n001 4 1bd5 0561 3051 3188 | 65 2fd2 (0) 2e65 (0) 2c85 (0) 2c80 (0)\n002 5 6e7f 60c5 7c46 7850 | 26 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n003 8 435d 447a 447c 482e | 19 4005 (0) 402c (0) 43c9 (0) 43d4 (0)\n004 3 52a8 5663 56ca | 6 50c1 (0) 5144 (0) 52a8 (0) 5538 (0)\n005 3 5d82 5c7c 5ff0 | 4 5ff0 (0) 5c37 (0) 5c7c (0) 5d82 (0)\n006 2 5987 5814 | 2 5987 (0) 5814 (0)\n007 1 5bd8 | 1 5bd8 (0)\n============ DEPTH: 8 ==========================================\n008 1 5a26 | 1 5a26 (0)\n009 1 5ac0 | 1 5ac0 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","private_key":"213bd7466a810ef9f7851687f3b179a52046eb5522252297a6b1d6145b648669","name":"node_5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","services":["bzz","pss"],"enable_msg_events":true,"port":37077},"up":true}},{"node":{"info":{"id":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","name":"node_793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","enode":"enode://fb36dea27a60b8255d2a142d64db3fe03c31642226d5a683e50b509f351c947fba07533d9b9138973ff4b62119c4bf09a9ccc0519dfba63e01ad9e6fdb04ab04@127.0.0.1:0","enr":"0xf88fb8403034394794df0756ddc241fe1356ff416e555eacb7699f2908a393d11806c4e508ac26d9bfa21ef4c53295da07e7916ab9facfc097f0721e7af81bccf373caa10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fb36dea27a60b8255d2a142d64db3fe03c31642226d5a683e50b509f351c947f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eTMiYIBV1Ic3dqmgpsQLBDeb/S8omorUmn3EVrxl+HE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 793322\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 cd6c c961 dad0 93ea | 130 e681 (0) e64d (0) e471 (0) e09f (0)\n001 4 3980 07f5 0561 1bd5 | 65 26ab (0) 26ac (0) 24f8 (0) 244c (0)\n002 5 4d38 4cec 48de 447c | 35 402c (0) 4005 (0) 43c9 (0) 43d4 (0)\n003 6 6e7f 6d5e 6b4e 67f3 | 13 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n004 3 7049 70f6 741a | 4 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n005 4 7e47 7d16 7ce7 7c46 | 5 7e47 (0) 7d16 (0) 7ce7 (0) 7c7c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 7895 7850 | 2 7895 (0) 7850 (0)\n008 1 79e5 | 1 79e5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","private_key":"9af1743677da1b9215eb659bad537e2f657dbcafdf6b976262914f493b2f65b9","name":"node_793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","services":["bzz","pss"],"enable_msg_events":true,"port":37431},"up":true}},{"node":{"info":{"id":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","name":"node_1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","enode":"enode://104600d1fbf9e41d171d15f36749903ac370ecfe94329b32fbd3f7af774b1d72bc3f133476f5911bef453b17fd722cd5695eed65f7c0f5bf65dddf055bfd9e73@127.0.0.1:0","enr":"0xf88fb840c24991e175917d22a4a701e7eaec5e9384fd92f3dcb1cc9cc0a31364f5588fe0072fff15bcf451255fc65a48eef41cbe3ea148d76132009507c8ee91af5603cd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103104600d1fbf9e41d171d15f36749903ac370ecfe94329b32fbd3f7af774b1d72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"G9WIJjJ0VDcp1UUprp6b9FlttAZJocKj9zFo2BjzS2I=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1bd588\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 c961 dad0 93ea ab3f | 130 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n001 5 5a8b 447c 482e 4d91 | 61 43d4 (0) 43c9 (0) 435d (0) 4005 (0)\n002 4 26ac 397a 3980 3188 | 28 2ddf (0) 2c85 (0) 2c80 (0) 2fd2 (0)\n003 5 096a 0cfc 0191 07f5 | 21 0e80 (0) 0e3b (0) 0e2b (0) 0d1c (0)\n004 3 1049 140d 1686 | 7 138d (0) 1070 (0) 1049 (0) 1784 (0)\n005 2 1dc0 1dec | 3 1fd0 (0) 1dc0 (0) 1dec (0)\n006 3 18e0 19ea 194e | 3 18e0 (0) 19ea (0) 194e (0)\n============ DEPTH: 7 ==========================================\n007 1 1add | 1 1add (0)\n008 1 1b1d | 1 1b1d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","private_key":"55ac02ca6376a8c8ade280c4a965ee5c08e93550a6029562e8e86d7dbccf81e5","name":"node_1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","services":["bzz","pss"],"enable_msg_events":true,"port":42121},"up":true}},{"node":{"info":{"id":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","name":"node_318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","enode":"enode://872434e3239345e130ac211904d19315ea542bd330d22ac21629432fadb2635f790530b99c823b4a59df7a4acd5fbbc0a9fb1c2133b86f88473040d3efbd69a6@127.0.0.1:0","enr":"0xf88fb84082f955db5d6323c7cfd3bff029579b8cd70c25e9e9e520f73c3fedce47321114383d187aa1adece14d610b47db85463b6ff60a5ec00e945d211e3f6abd25d18f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102872434e3239345e130ac211904d19315ea542bd330d22ac21629432fadb2635f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MYgo+ok6KMwGUtP4HZfFuOAj6FNoX10+Zf3iBomrzFo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 318828\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 dbd4 dad0 cd6c c961 | 130 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n001 3 4d38 5a8b 7c46 | 61 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n002 3 096a 0561 1bd5 | 37 0d1c (0) 0cfc (0) 0e80 (0) 0e3b (0)\n003 5 298a 2a50 2e65 2ddf | 11 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n004 6 3f31 3cab 3a62 3b02 | 8 3b02 (0) 3a62 (0) 3980 (0) 3938 (0)\n005 2 3728 3411 | 3 36b9 (0) 3728 (0) 3411 (0)\n006 1 32ff | 1 32ff (0)\n007 2 30fe 3051 | 2 30fe (0) 3051 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 31e1 31e6 | 2 31e6 (0) 31e1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","private_key":"ab2d8316f989485b43a1f14a3b2736c9e506aa0ba33fbeae8fc45dfb0784b50e","name":"node_318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","services":["bzz","pss"],"enable_msg_events":true,"port":45097},"up":true}},{"node":{"info":{"id":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","name":"node_7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","enode":"enode://e9ce5ad62b69c60eaba82ede900643474a4316ff4fb9f8bbd15cc8ef3b5ac9eb2cfacbab6551b57423952f4be2990d95f539368954e42fc7fad8b1561af79002@127.0.0.1:0","enr":"0xf88fb840233a6d08e9c900370f4b86282cd0f45e172bbe22a6ddba170768665f2289363a04022e239dba04e74de46939a2fc3173ef7f8ec3a3c380bc4f96e0f8d57baa3f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e9ce5ad62b69c60eaba82ede900643474a4316ff4fb9f8bbd15cc8ef3b5ac9eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fEZAVOp7bJ6gx9TCCXackvKUqdssoVm47xaOMQoerDo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7c4640\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c961 d9cf dad0 93ea | 130 e681 (0) e64d (0) e471 (0) e09f (0)\n001 4 07f5 2fd2 397a 3188 | 65 0d1c (0) 0cfc (0) 0e80 (0) 0e3b (0)\n002 5 48de 4cec 4d38 5a26 | 35 4005 (0) 402c (0) 43d4 (0) 43c9 (0)\n003 5 6b4e 6e7f 6d5e 6758 | 13 68cb (0) 6b4e (0) 6c01 (0) 6dd3 (0)\n004 2 7660 741a | 4 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n005 3 79e5 7933 7850 | 4 79e5 (0) 7933 (0) 7895 (0) 7850 (0)\n006 1 7e47 | 1 7e47 (0)\n007 1 7d16 | 1 7d16 (0)\n============ DEPTH: 8 ==========================================\n008 1 7ce7 | 1 7ce7 (0)\n009 0 | 0\n010 1 7c7c | 1 7c7c (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","private_key":"fcc47163c2ab2f499cbb2f337ef53f49309b3865d8038bff9d2bc379d573c1e6","name":"node_7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","services":["bzz","pss"],"enable_msg_events":true,"port":38929},"up":true}},{"node":{"info":{"id":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","name":"node_a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","enode":"enode://3550f2c56a73defeb97f0536204448c4e3e1331335e6e3a3014a4abcc64baa713863be64fced29ef2a307d2dadad652ef223a9ccc585b280a4cc7fcc0c873f95@127.0.0.1:0","enr":"0xf88fb840de06617ae4d0d818ea821d1c9879aee77965e21e891045657c110f6dbfb3933b1e580ab1ec78fad61f0175343ddcf154cbf61d63b77419bfe6bd777d864a3b700183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033550f2c56a73defeb97f0536204448c4e3e1331335e6e3a3014a4abcc64baa71","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pgbHmgGKZTU3XYUfzILELMfJUnIKoSBDTO3M9KS+H1k=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a606c7\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1bd5 3188 5a8b 5d82 | 126 0d1c (0) 0cfc (0) 0e80 (0) 0e3b (0)\n001 4 fc51 c9c3 c961 cd6c | 55 e681 (0) e64d (0) e471 (0) e2d3 (0)\n002 4 834f 8854 93ea 9f0e | 38 8b43 (0) 8862 (0) 8854 (0) 8d19 (0)\n003 3 b78f bfc7 be68 | 14 ba91 (0) bbaf (0) b8e1 (0) bcf8 (0)\n004 2 a8ff ab3f | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a0c8 a1c8 a330 a2e6 | 6 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n006 3 a5ac a505 a4ee | 3 a4ee (0) a505 (0) a5ac (0)\n============ DEPTH: 7 ==========================================\n007 2 a742 a7a8 | 2 a7a8 (0) a742 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a616 | 1 a616 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","private_key":"8b6e5a593a7a12ebb029cd578efe25114f3cadc22a3cd3b007eb164cc0a403fe","name":"node_a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","services":["bzz","pss"],"enable_msg_events":true,"port":45851},"up":true}},{"node":{"info":{"id":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","name":"node_a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","enode":"enode://1ce0a6ac890fddf6089a062091b0f114fb6c01ac09e618ad4a23a3b985db8b695448be996b1b51dceb7341aba28d101f31aafe50d1d312d995c03ca64b907a8b@127.0.0.1:0","enr":"0xf88fb8402bd8ecaf0ec85c076464ba4a7314b9946c19a06746bfd1758516d4674fcff67a4f495420e48344d1870f99c43e5e56750a310e1f532fdc3a46b647a06c8fb4a80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031ce0a6ac890fddf6089a062091b0f114fb6c01ac09e618ad4a23a3b985db8b69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oqFjziywkrQRyZTMXV71VdU50tz05+GutSjSIW3EgeU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a2a163\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1bd5 3188 5d82 5a8b | 126 138d (0) 1070 (0) 1049 (0) 1484 (0)\n001 6 eebd f645 fc51 cd6c | 55 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n002 4 8854 8f9a 93ea 9f0e | 38 8b43 (0) 8862 (0) 8854 (0) 8cc3 (0)\n003 5 bbaf b8e1 be68 bfc7 | 14 ba91 (0) bbaf (0) b8e1 (0) bdc5 (0)\n004 4 af02 a8ff a8f4 ab3f | 10 acee (0) aeb4 (0) af02 (0) a970 (0)\n005 5 a4ee a5ac a505 a742 | 7 a4ee (0) a505 (0) a5ac (0) a7a8 (0)\n006 2 a0c8 a1c8 | 2 a0c8 (0) a1c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a330 a327 | 2 a330 (0) a327 (0)\n008 0 | 0\n009 1 a2e6 | 1 a2e6 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","private_key":"c7c3bdf809c4dddc3d69c2437ecee9174c62113e7183c42d4b735143382ca5f2","name":"node_a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","services":["bzz","pss"],"enable_msg_events":true,"port":40591},"up":true}},{"node":{"info":{"id":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","name":"node_b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","enode":"enode://411f2844b08f1aa72a27b2f54a551d3eed6c7b634162cb04ef093d52effa83efc2797db053ce1fb70105d9fc15331a0312d148dc0431310eb2c42c6114cb0d7c@127.0.0.1:0","enr":"0xf88fb8404517ad1475dcc5865807afaa0a472b5446b69dbcc2465732186fb2220224daa510beea5edfe3b120c3ee1f7e942904d4ca137b556ea6feada809a6a61e2788a50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102411f2844b08f1aa72a27b2f54a551d3eed6c7b634162cb04ef093d52effa83ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"t4/SHAYwBuLgM9HQD8IeGteteVG7ViHOybVmOXRdZfk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b78fd2\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 7850 5d82 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 10 f2b4 f645 fc51 eebd | 55 e09f (0) e0a0 (0) e277 (0) e2d3 (0)\n002 6 93ea 9948 9959 8e28 | 38 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n003 9 af02 a8ff ab3f a606 | 23 acee (0) aeb4 (0) af02 (0) a970 (0)\n004 4 bbaf b8e1 be68 bfc7 | 8 ba91 (0) bbaf (0) b8e1 (0) bcf8 (0)\n005 1 b3f9 | 1 b3f9 (0)\n006 2 b5ea b4a1 | 2 b4a1 (0) b5ea (0)\n============ DEPTH: 7 ==========================================\n007 2 b659 b6df | 2 b659 (0) b6df (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","private_key":"74aa90f3bd323ba9eb7d36c9d5d71fba2abcc8c139f09a30ae66ad200d31f31a","name":"node_b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","services":["bzz","pss"],"enable_msg_events":true,"port":45951},"up":true}},{"node":{"info":{"id":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","name":"node_5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","enode":"enode://45a546c77bd0b76e5a8c4cfa9b4ffb8e2124519e39fb9ac6862eef3a6b3ab36d2abb6edf5e822fc9e94a5f821a233fec02ed076b5394052bc3e5ac3f92382ef1@127.0.0.1:0","enr":"0xf88fb8406a321e44c0f6e7960b5f4a6d36376704b05c7a3ba49b1eb6acf89dedda8b5e267297203a9b15f97facaee8eaa5c3c25357451b6f70c3ea2c879c2c9c7a6b02b80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10345a546c77bd0b76e5a8c4cfa9b4ffb8e2124519e39fb9ac6862eef3a6b3ab36d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XYKkGGKc++fFcQUwkxmtaVoZhib+NXHeIToS3fYvcwg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5d82a4\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 d9cf ddb8 93ea 837f | 130 e681 (0) e64d (0) e471 (0) e0a0 (0)\n001 4 194e 1686 1049 3980 | 65 138d (0) 1070 (0) 1049 (0) 1484 (0)\n002 2 6dd3 7850 | 26 6b4e (0) 68cb (0) 6c01 (0) 6dd3 (0)\n003 9 435d 43d4 447a 447c | 19 4005 (0) 402c (0) 435d (0) 43c9 (0)\n004 5 52a8 50c1 5663 56ca | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 4 5814 5a26 5a8b 5ac0 | 6 5987 (0) 5814 (0) 5bd8 (0) 5a26 (0)\n006 1 5ff0 | 1 5ff0 (0)\n============ DEPTH: 7 ==========================================\n007 2 5c7c 5c37 | 2 5c7c (0) 5c37 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","private_key":"69766d2192a8d8f57768af92f8ff7baed8f3a52c22d97417f21e6a5fd3de4f42","name":"node_5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","services":["bzz","pss"],"enable_msg_events":true,"port":45337},"up":true}},{"node":{"info":{"id":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","name":"node_7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","enode":"enode://0c0ebe3bbeeb5597d947b1f7b5a2e127a5d6d3b63ef0f3e9729357e767470a8b462ec3cdd15997331c24a9152665d19273a3e79dfc447b7f50381bad46365a7e@127.0.0.1:0","enr":"0xf88fb84028a27a4976245ab6fe76c73b436192338af7ac71f5eb0fb25641c2ced4180b5b5f63f71d6ca7b7ce5129bf98a88efaf0231aba54207434478862b181f9430d2f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020c0ebe3bbeeb5597d947b1f7b5a2e127a5d6d3b63ef0f3e9729357e767470a8b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eFD17lBIlZVZs68PlWiWabJQ/Dqli8yVRNymHKnJdpw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7850f5\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 d9cf ddb8 93ea 837f | 130 e681 (0) e64d (0) e471 (0) e09f (0)\n001 4 1049 1686 0e2b 3980 | 65 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n002 5 482e 4cec 4d38 5a8b | 35 435d (0) 43c9 (0) 43d4 (0) 4005 (0)\n003 7 68cb 6b4e 6d5e 6dd3 | 13 6b4e (0) 68cb (0) 6c01 (0) 6d5e (0)\n004 3 7049 741a 7660 | 4 70f6 (0) 7049 (0) 741a (0) 7660 (0)\n005 5 7e47 7d16 7ce7 7c7c | 5 7e47 (0) 7d16 (0) 7ce7 (0) 7c7c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 79e5 7933 | 2 79e5 (0) 7933 (0)\n008 1 7895 | 1 7895 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","private_key":"40edb5f8d252880b90ba7fde9823f697100b67c90e06a29fc3ec7a5810ab62c1","name":"node_7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","services":["bzz","pss"],"enable_msg_events":true,"port":32987},"up":true}},{"node":{"info":{"id":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","name":"node_ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","enode":"enode://78199c63a76cbaf76cd9760f290345fb7a8a8a0598e99d6152136896aaf69a6894757d496cb59a95925c3a18fe730382766be78a9f0ed4f3f11f866eb8bcdbc9@127.0.0.1:0","enr":"0xf88fb840e42249c4aa731c39349c743bdccfbcb826dcab6b0976b0262879a51570c9605f2840fb4f81fc6d939000acd0b1047aa6ecb2774a78c7a3c74b6dfe5b9f5c47900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10378199c63a76cbaf76cd9760f290345fb7a8a8a0598e99d6152136896aaf69a68","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qz/5VQM8CiYVky+vhf0gCQuRIcftzI5vfOTE/eCpa4o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ab3ff9\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1049 194e 1bd5 7850 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 5 f2b4 ec90 ed42 eebd | 55 e0a0 (0) e09f (0) e2d3 (0) e277 (0)\n002 2 9959 837f | 38 97da (0) 9464 (0) 9518 (0) 955d (0)\n003 3 bfc7 be68 b78f | 14 bdc5 (0) bcf8 (0) bea1 (0) be68 (0)\n004 6 a327 a2e6 a2a1 a505 | 13 a505 (0) a5ac (0) a4ee (0) a7a8 (0)\n005 3 acee aeb4 af02 | 3 acee (0) aeb4 (0) af02 (0)\n006 4 a970 a8b5 a8f4 a8ff | 4 a970 (0) a8b5 (0) a8f4 (0) a8ff (0)\n============ DEPTH: 7 ==========================================\n007 1 aaf0 | 1 aaf0 (0)\n008 0 | 0\n009 1 ab71 | 1 ab71 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","private_key":"da16d3eec72f2e238edf7ba4f10364552eab2cefb316a7c76c8723d52989563d","name":"node_ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","services":["bzz","pss"],"enable_msg_events":true,"port":33141},"up":true}},{"node":{"info":{"id":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","name":"node_d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","enode":"enode://2042548f0f7c90b6cc2256c4d77e13ecd17a9f61272ad14494e2b21d9ac6029caebf34338de3872e5f3e447fa2ebf066ecd5ebbca76298324eccfade50751e7b@127.0.0.1:0","enr":"0xf88fb8406c1e73483cf923948ac9f54e2c047930e5ea66c902c1040e2c9d6b5a9a00a5c43110236e80ffd8ed3ee80e60f2f9b7395e5956aa2e30c6137271720864699cda0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032042548f0f7c90b6cc2256c4d77e13ecd17a9f61272ad14494e2b21d9ac6029c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2c8ZiV4BXLU02RWu2DwNJr9AoRJEAngS4Xw77G5kWo4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d9cf19\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 60c5 7850 7c46 5d82 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 8 8f9a 837f b8e1 b78f | 75 97da (0) 9464 (0) 9518 (0) 955d (0)\n002 5 f645 f2b4 f9de fa24 | 28 e471 (0) e681 (0) e64d (0) e2d3 (0)\n003 3 c9c3 c961 cd6c | 16 c534 (0) c42e (0) c74d (0) c603 (0)\n004 2 d700 d408 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n005 1 ddb8 | 1 ddb8 (0)\n============ DEPTH: 6 ==========================================\n006 3 dad0 da36 dbd4 | 3 dbd4 (0) da36 (0) dad0 (0)\n007 0 | 0\n008 1 d959 | 1 d959 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","private_key":"d168c43714b032d43709695043aaf1c5458b60b0e73717ccf008b5d9e6af9939","name":"node_d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","services":["bzz","pss"],"enable_msg_events":true,"port":41547},"up":true}},{"node":{"info":{"id":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","name":"node_837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","enode":"enode://ed39f75e6b5a22a7e8c6809ee4d870c133f22f4c93186e3c69457307c78fc12579cf7b7318723f40a0503f854e69da1de58ba5569bdf14e5b61f67446a138ed7@127.0.0.1:0","enr":"0xf88fb840c0e24ca2a2a76ce110f103428f1e7d60a3403afc52473a5aa71b9c63de5b4cb4379c41f9901442f5e2afb7f988f8a6bcc1ccfb6b2fd6494e5fba5c2ae7f45f420183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ed39f75e6b5a22a7e8c6809ee4d870c133f22f4c93186e3c69457307c78fc125","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g38Jk/Y3QDmlrURy1jE+ZHpMXbRYO9J8z6mNNEihdzE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 837f09\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5d82 7850 3980 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n001 3 c961 ddb8 d9cf | 55 e681 (0) e64d (0) e471 (0) e09f (0)\n002 7 be68 b78f a4ee a505 | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 7 97da 95c0 93ea 9f0e | 17 97da (0) 9464 (0) 9518 (0) 955d (0)\n004 6 8854 8cc3 8d19 8f9a | 9 8b43 (0) 8862 (0) 8854 (0) 8cc3 (0)\n005 4 84a9 8402 87a3 86d6 | 4 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n006 5 81a5 8006 8073 8074 | 5 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 2 8358 834f | 2 8358 (0) 834f (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","private_key":"9f0d233abf6f03526bd7a057b2f9064dfb5632022a186fcc902c6aa7a2600627","name":"node_837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","services":["bzz","pss"],"enable_msg_events":true,"port":41733},"up":true}},{"node":{"info":{"id":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","name":"node_ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","enode":"enode://23b26db5b1294383d9eea76f1d4a21a01a005282ec74c54d51f1d8d1c4ba9b19608cd921c5d735a101be0681eeaf5618e06460964f7d84656def7a07255111c8@127.0.0.1:0","enr":"0xf88fb84045e7162cf3f1ac630c92a7e123116d9b2e1666b1e895bede1122e243f0f35cdf2994006582400b1294fe4fef4deeac77bfe7bdb0e1ccd0e4ea8e52c1240509830183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10223b26db5b1294383d9eea76f1d4a21a01a005282ec74c54d51f1d8d1c4ba9b19","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"3bi+Ryw9SNxNPREkSObAxKgmoYrz87U/3++M0xBTx18=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ddb8be\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0cfc 3980 5d82 7850 | 126 402c (0) 4005 (0) 43c9 (0) 43d4 (0)\n001 8 b78f b8e1 a2a1 a8ff | 75 a505 (0) a5ac (0) a4ee (0) a7a8 (0)\n002 7 ec90 f645 f2b4 fa24 | 28 e471 (0) e681 (0) e64d (0) e2d3 (0)\n003 5 c534 c190 cd6c c961 | 16 c42e (0) c534 (0) c74d (0) c603 (0)\n004 3 d302 d700 d408 | 5 d209 (0) d3e9 (0) d302 (0) d700 (0)\n============ DEPTH: 5 ==========================================\n005 5 da36 dad0 dbd4 d959 | 5 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","private_key":"18bcdc56f12314ff79470029b0f3813f675978100fef3ddaca5023bc2f8dde78","name":"node_ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","services":["bzz","pss"],"enable_msg_events":true,"port":38607},"up":true}},{"node":{"info":{"id":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","name":"node_9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","enode":"enode://a3d56214ef40b3b64d2662d12f80d743f10da57b12601e31cbf572034244e1b299ce4be5f33a1b2f6c7eee9a79827c5d99e31d4f4b9cf64aa9ed02d901582fab@127.0.0.1:0","enr":"0xf88fb8404add71b1f22ba7a42f2b948ac2455c1e2a37e5d83ec2f50f0116cc91995cd31d2dc7ec48bc5ace7137fecaea8828738c17e66b551ca661a4f724b2ed1395ce3e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a3d56214ef40b3b64d2662d12f80d743f10da57b12601e31cbf572034244e1b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mVk4U4Wq3nKNP1djgGWWIivB57mUbCySQHlD0ICzL40=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 995938\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 60c5 0e2b | 126 6b4e (0) 68cb (0) 6c01 (0) 6d5e (0)\n001 2 fc51 ddb8 | 55 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n002 5 b78f a327 af02 ab3f | 37 bdc5 (0) bcf8 (0) bea1 (0) be68 (0)\n003 4 837f 8854 8f9a 8e28 | 21 8b43 (0) 8862 (0) 8854 (0) 8cc3 (0)\n004 4 955d 95c0 97da 93ea | 8 97da (0) 9464 (0) 9518 (0) 955d (0)\n005 6 9ca1 9c8e 9c21 9ec8 | 6 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n============ DEPTH: 6 ==========================================\n006 1 9b8e | 1 9b8e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 9948 | 1 9948 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","private_key":"011707e678d73ecf94ba7f710501f262764a152ffa7dbe48f5b7e7dbef86a807","name":"node_9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","services":["bzz","pss"],"enable_msg_events":true,"port":45157},"up":true}},{"node":{"info":{"id":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","name":"node_0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","enode":"enode://0b612a1ab5d916d8c26372863438f68d00efff720cb1a318c642e37ac4ddc0cbdc0f21d3d1935ad022323a317ef443741ee0e6ce46c01604b94783f86719582b@127.0.0.1:0","enr":"0xf88fb84072f6428c1949285e98cf3010a22fd4023bb5fe817a070b704d991522730917097a117d183bc0722f66f9d163f8eb714e74db79ad6fcb7ac5fca67930f49bd28c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030b612a1ab5d916d8c26372863438f68d00efff720cb1a318c642e37ac4ddc0cb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DitIVYzirx+/7jilV9VgcuMJHPyu6NeEfHydz3vvm/o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e2b48\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 fc51 d408 a8ff 9948 | 130 e471 (0) e681 (0) e64d (0) e09f (0)\n001 6 7850 60c5 56ca 5ac0 | 61 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n002 4 2c80 2ddf 26ac 3980 | 28 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n003 2 1049 1686 | 16 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n004 5 0314 0191 07f5 0594 | 10 025d (0) 035f (0) 0314 (0) 012b (0)\n005 3 08e5 09b3 096a | 6 08bd (0) 08f8 (0) 08e5 (0) 09b3 (0)\n006 2 0d1c 0cfc | 2 0d1c (0) 0cfc (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 0e80 | 1 0e80 (0)\n009 0 | 0\n010 0 | 0\n011 1 0e3b | 1 0e3b (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","private_key":"510468331a493c1c9e097b948955dfff54c130f51894aed02d4f46d1260021a2","name":"node_0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","services":["bzz","pss"],"enable_msg_events":true,"port":44575},"up":true}},{"node":{"info":{"id":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","name":"node_a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","enode":"enode://b7201bebbe44d4f065e0344f51747c686401af50a2bc1e4bad167b56d0f5b94eaa6e6d50bd5b2708510984708c155ac50ed29d14b941ab71d22312033bbb9a20@127.0.0.1:0","enr":"0xf88fb840a72c72b758119852724dc6373359756fc7224766b257144c15597ba291dfbf8b1d8e2cac36d326b4a0e1ce960e294438b019d49713d6232eeb5dfd63341c13b10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b7201bebbe44d4f065e0344f51747c686401af50a2bc1e4bad167b56d0f5b94e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qP+NadyzZGLREW2vpePQxyN79l2+zkgqMWhiyNZuNbY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a8ff8d\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 48de 0e2b | 126 7660 (0) 741a (0) 70f6 (0) 7049 (0)\n001 4 fc51 d408 d9cf ddb8 | 55 e681 (0) e64d (0) e471 (0) e277 (0)\n002 5 8854 8073 837f 834f | 38 87a3 (0) 86d6 (0) 8402 (0) 84a9 (0)\n003 4 be68 bfc7 b8e1 b78f | 14 bcf8 (0) bdc5 (0) bfc7 (0) bea1 (0)\n004 9 a327 a2e6 a2a1 a5ac | 13 a505 (0) a5ac (0) a4ee (0) a7a8 (0)\n005 3 acee aeb4 af02 | 3 acee (0) aeb4 (0) af02 (0)\n006 2 ab71 ab3f | 3 aaf0 (0) ab71 (0) ab3f (0)\n007 1 a970 | 1 a970 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 a8b5 | 1 a8b5 (0)\n010 0 | 0\n011 0 | 0\n012 1 a8f4 | 1 a8f4 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","private_key":"a3dc455b16cb040e97e400cbec5c77f9c6769a891569bafb9020595880600d14","name":"node_a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","services":["bzz","pss"],"enable_msg_events":true,"port":45235},"up":true}},{"node":{"info":{"id":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","name":"node_48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","enode":"enode://9422ff095b3dd7d5bb7caaf864015278473292f40803e5eab069fc7c270309b3386d001c249d10c2dde0f71ca459477ee74f149e5d7e1fe7ece9bf08237ab0dc@127.0.0.1:0","enr":"0xf88fb840df7b0ea5b6e73e0e48e983961669a7dc87cf47c6389512f75462e4d8f28e526567df2cdbb5da10b6d57e809894f1039e00f7f774c8fd1d1d14710dbae4bb8f520183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029422ff095b3dd7d5bb7caaf864015278473292f40803e5eab069fc7c270309b3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SN5VPhWv0+ika/w6W6iimBWKo9YPFA0nMCMK9czoCE0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48de55\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c9c3 d9cf d408 fc51 | 130 e09f (0) e0a0 (0) e2d3 (0) e277 (0)\n001 3 1686 0e2b 3980 | 65 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n002 5 7d16 7c46 7933 79e5 | 26 7049 (0) 70f6 (0) 7660 (0) 741a (0)\n003 5 56ca 5a8b 5ac0 5d82 | 16 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n004 3 447c 43c9 43d4 | 9 46bf (0) 44ad (0) 447a (0) 447c (0)\n005 3 4cec 4d91 4d38 | 3 4cec (0) 4d91 (0) 4d38 (0)\n006 2 4a95 4b79 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 1 48b8 | 1 48b8 (0)\n010 1 48f1 | 1 48f1 (0)\n011 0 | 0\n012 1 48d7 | 1 48d7 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","private_key":"fe29ef81976826aba3a92e42c6b3848892672ee26649d67650358d54e85982e9","name":"node_48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","services":["bzz","pss"],"enable_msg_events":true,"port":40001},"up":true}},{"node":{"info":{"id":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","name":"node_398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","enode":"enode://932586d99d84466fce1c3d7a331315a768c320b890811c2a00eae226a62c05023605308437407502d54d2e09910164e7a9c6343a935e4fdb8267d1661a4a11ad@127.0.0.1:0","enr":"0xf88fb840f777fcf141adaf513c8cd83b5b2ad8716fe3f0805c0b83c31d3ee8bc13347b6370696f994cdc0cab03b8363ed9da19e3717ff65f31244ca6a3f22719f3df605c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103932586d99d84466fce1c3d7a331315a768c320b890811c2a00eae226a62c0502","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OYA4gRwcdAL+LmmUyc4vFcgWa46Z83n+qu1mrIdwIGI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 398038\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 fc51 c9c3 d9cf ddb8 | 130 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n001 6 60c5 7933 7850 5ff0 | 61 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n002 5 1b1d 1bd5 1049 1686 | 37 1dec (0) 1dc0 (0) 1fd0 (0) 18e0 (0)\n003 6 24f8 26ac 2e65 2fd2 | 11 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n004 5 3411 32ff 3188 31e1 | 9 36b9 (0) 3728 (0) 3411 (0) 32ff (0)\n005 3 3c5b 3cab 3f31 | 3 3f31 (0) 3c5b (0) 3cab (0)\n006 2 3a62 3b02 | 2 3a62 (0) 3b02 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 3938 397a | 2 3938 (0) 397a (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","private_key":"571a1e200af7799e0d7295849ae3beaf1d75ccfa29216b243feedb21761d2bde","name":"node_398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","services":["bzz","pss"],"enable_msg_events":true,"port":43453},"up":true}},{"node":{"info":{"id":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","name":"node_8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","enode":"enode://0703457de466898f77a218b2253e4074f9d84ddc40a4d85a7677e03f1dc45090d8a5c0ae0f3bce42a249384f9f84ed92f79c7d71a80f97e4ea6787fec0979ef7@127.0.0.1:0","enr":"0xf88fb840d9529815a2188630f6e5a9a83b676cc923f44db1dce486279c916e75d9676afc6d6babb5690670e670141db7383ce8f862fe1828478493d343ad4d8e614bda370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030703457de466898f77a218b2253e4074f9d84ddc40a4d85a7677e03f1dc45090","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jigrDyfU+lb+FM/rafrFpT49iCx3eOsZBlPi6rfJP9I=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8e282b\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 60c5 3980 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 4 c9c3 d408 ddb8 fc51 | 55 e2d3 (0) e277 (0) e09f (0) e0a0 (0)\n002 7 b78f b5ea bbaf b8e1 | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 6 955d 95c0 93ea 9b8e | 17 97da (0) 9464 (0) 95c0 (0) 9518 (0)\n004 5 81a5 80d7 8073 834f | 12 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n005 3 8b43 8862 8854 | 3 8b43 (0) 8862 (0) 8854 (0)\n006 2 8d19 8cc3 | 2 8cc3 (0) 8d19 (0)\n007 1 8f9a | 1 8f9a (0)\n============ DEPTH: 8 ==========================================\n008 1 8ea2 | 1 8ea2 (0)\n009 1 8e7b | 1 8e7b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","private_key":"5ee46cbe7328b036aa2e3281aec50d734d3fa00761ec99b53bf5a30a940a2006","name":"node_8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","services":["bzz","pss"],"enable_msg_events":true,"port":45567},"up":true}},{"node":{"info":{"id":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","name":"node_994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","enode":"enode://e251495df5e012ceae31fcd4e011f13d611edf3549f6a33eda33b9acbf5757be44d865d329431079380d794b06c97fadb2535cc2f5dbdca5c5aeaec59905c430@127.0.0.1:0","enr":"0xf88fb840fb7050cef033c59b67f105ef731c850b3215a560ec374d2010a4bd2627d51dbb3197c902a18ab6e66e4cf1b7fff54b0f59f9a9ef96b27e68f9293883e3c80f6b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e251495df5e012ceae31fcd4e011f13d611edf3549f6a33eda33b9acbf5757be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mUg55fOluLI67YT7ApQTEkrxeAS3mwJj7Gv9WuxdrXg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 994839\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 48de 5ff0 1686 0e2b | 126 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n001 4 f645 f2b4 ec90 d408 | 55 e471 (0) e681 (0) e64d (0) e0a0 (0)\n002 5 b8e1 b78f b5ea a4ee | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 4 8073 837f 8854 8e28 | 21 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n004 4 93ea 955d 95c0 97da | 8 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n005 6 9c21 9c8e 9ca1 9ec8 | 6 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n============ DEPTH: 6 ==========================================\n006 1 9b8e | 1 9b8e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 9959 | 1 9959 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","private_key":"334ce36c1f8b4c0d2139b19e7e5bb3a3a15fb0ce90610d2e1d1482d7b645c2d8","name":"node_994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","services":["bzz","pss"],"enable_msg_events":true,"port":33079},"up":true}},{"node":{"info":{"id":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","name":"node_d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","enode":"enode://39f55004bcfcc2f16c4a1b4b723534c4c9e589ab5895a3cbe311aafd0c6e6de0bb47140ec73fdaa26a6b50f5227664e84e1e1a80db2796990116ad381c21a936@127.0.0.1:0","enr":"0xf88fb8405ae4c29ace5f03e6d651ba48886e1be64addab49c04c36ac806e5a5fd9788caf222b4d1266aa622022a3e58fd35aebcb70e30a50cbd2abb8826746fbe05420770183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10239f55004bcfcc2f16c4a1b4b723534c4c9e589ab5895a3cbe311aafd0c6e6de0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1Ai7b3rxWQ4fFizgLMAWsbhu3imFHKoyQ0IS/6Kjd8g=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d408bb\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5ff0 48de 482e 0cfc | 126 2a50 (0) 298a (0) 2fd2 (0) 2e65 (0)\n001 5 b8e1 a2e6 a8ff 8e28 | 75 b3f9 (0) b659 (0) b6df (0) b78f (0)\n002 7 ec90 f645 f2b4 f9de | 28 e471 (0) e681 (0) e64d (0) e09f (0)\n003 4 cf52 cd6c c961 c9c3 | 16 c534 (0) c42e (0) c74d (0) c603 (0)\n004 4 ddb8 dbd4 dad0 d9cf | 6 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n============ DEPTH: 5 ==========================================\n005 3 d209 d3e9 d302 | 3 d209 (0) d3e9 (0) d302 (0)\n006 1 d700 | 1 d700 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","private_key":"251a8df09943db0babcf770639c5ccce249b19a3b91f88c6beb4090f8d366ac0","name":"node_d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","services":["bzz","pss"],"enable_msg_events":true,"port":45605},"up":true}},{"node":{"info":{"id":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","name":"node_fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","enode":"enode://e92b9c292a29d8bfb7f4db4dbf539ed52534331fe43603f2c813dc801b4ec9364bff7fc962d375834ac6a1df1673c3615c40bef17b51f6debf2707acc9b17f58@127.0.0.1:0","enr":"0xf88fb840d952b221d3ae5c9e409850d227fa2dbd7c2e1db0634a5bbe1bc2ed2c46085d457766d51c388252a60d37b5490aa17cc4745f7bbe669b67e28838599f027738ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e92b9c292a29d8bfb7f4db4dbf539ed52534331fe43603f2c813dc801b4ec936","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/FFMQ8TrXGJ5hFjaXWIukkim5TDkKIzZAgGaoFxDdNg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fc514c\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0e2b 3980 48de 60c5 | 126 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n001 9 b78f a606 a4ee a2a1 | 75 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n002 7 cd6c c961 c9c3 dbd4 | 27 c534 (0) c42e (0) c74d (0) c603 (0)\n003 6 ec90 eebd ef99 eff2 | 14 e471 (0) e681 (0) e64d (0) e09f (0)\n004 3 f2b4 f6c0 f645 | 7 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n005 3 fa24 f8ff f9de | 3 f8ff (0) f9de (0) fa24 (0)\n============ DEPTH: 6 ==========================================\n006 2 ff75 feb3 | 2 ff75 (0) feb3 (0)\n007 0 | 0\n008 0 | 0\n009 1 fc39 | 1 fc39 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","private_key":"de7c0775a3921769035f59bb73e223f1b8dfa39617f5ee35cac84c7ded6a49a2","name":"node_fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","services":["bzz","pss"],"enable_msg_events":true,"port":44357},"up":true}},{"node":{"info":{"id":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","name":"node_60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","enode":"enode://6e5ef281f10a4795906b37800a284f193c6df512a1c03450197eca7bb6d9ce2d5a4878fb2bc42afc40cf28050d15a8e2888fdc544d06d6f13528265866a5f3a6@127.0.0.1:0","enr":"0xf88fb840ac7b31fb8f269a7992246ec994fbd4a2a7f22777ade012e4b89f058b0686fd46005eb0f24df29c1b5dd22f15fc54a20ef32b2d96a5ee581c1f7ab6e3da71f21d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026e5ef281f10a4795906b37800a284f193c6df512a1c03450197eca7bb6d9ce2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YMVkeu0VJgmXk2b7M9yLKPxgc2CY/2jSMkFYibQ9+lg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 60c564\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 9b8e 9959 8e28 d9cf | 130 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n001 4 26ac 3980 0e2b 1686 | 65 36b9 (0) 3728 (0) 3411 (0) 32ff (0)\n002 5 482e 48de 56ca 5a8b | 35 4005 (0) 402c (0) 435d (0) 43c9 (0)\n003 6 70f6 7d16 7c46 79e5 | 13 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n004 7 6b4e 68cb 6e7f 6c01 | 7 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n============ DEPTH: 5 ==========================================\n005 5 648a 6758 6790 6795 | 5 648a (0) 6790 (0) 6795 (0) 67f3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","private_key":"89bbc4a8fe5905ca2c155be018babb341d9441135f074af282a327e2977357c6","name":"node_60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","services":["bzz","pss"],"enable_msg_events":true,"port":39295},"up":true}},{"node":{"info":{"id":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","name":"node_16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","enode":"enode://d845540617736b1958a11594e15934337e7127add929bad0c013d12cd65bb64d7dcb2d8dd41977f03a22b4e86e71a1edde519259f5dca5668307527cfe16bcf0@127.0.0.1:0","enr":"0xf88fb840782b90fecea289d4c0215935b270fcc0fd83a631e1fb144bf3134dbf4582abd20975b3712cf657a6d9a1d6ea942967f04741f6c2916f23ddef51ce04bea2d2490183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d845540617736b1958a11594e15934337e7127add929bad0c013d12cd65bb64d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FoaOxdj0kKxz6ii06P3aVawUm7Gq+xd1RbVLhKWtU2c=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 16868e\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 f645 c9c3 d408 b5ea | 130 e277 (0) e2d3 (0) e0a0 (0) e09f (0)\n001 7 482e 48de 56ca 5d82 | 61 46bf (0) 44ad (0) 447a (0) 447c (0)\n002 4 2ddf 2c80 2e65 3980 | 28 2a50 (0) 298a (0) 2fd2 (0) 2e65 (0)\n003 6 0191 0561 07f5 096a | 21 025d (0) 035f (0) 0314 (0) 012b (0)\n004 6 1dec 18e0 19ea 194e | 9 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n005 3 138d 1070 1049 | 3 138d (0) 1070 (0) 1049 (0)\n============ DEPTH: 6 ==========================================\n006 2 1484 140d | 2 1484 (0) 140d (0)\n007 1 1784 | 1 1784 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","private_key":"bde6dc606a9dc59b55e66e91238cd63fc2c84b7edc67fa0321b927540331ca5e","name":"node_16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","services":["bzz","pss"],"enable_msg_events":true,"port":41853},"up":true}},{"node":{"info":{"id":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","name":"node_9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","enode":"enode://09589964a1f4465dee4d0ce2388504a335ccfb484711b50e3a9a80b8b0671acb75b7d6aac621bf17746a584d606bb0aa677c302a4d44653ae28f11b437df20a9@127.0.0.1:0","enr":"0xf88fb840095da26616eca877077703e0e2b51dd8b7dadf89e7da897184fa333b8cde3d123ae6c94cd31c163ce10dbbf39a9ce6bd32e51570e5aeb9f82ae57427fd2a9b440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10309589964a1f4465dee4d0ce2388504a335ccfb484711b50e3a9a80b8b0671acb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"m45rs6f+TcZayXQE5UbYt3fQaMlLwjVfTxpRCtbBGQU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9b8e6b\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 60c5 5ac0 5ff0 1686 | 126 46bf (0) 44ad (0) 447a (0) 447c (0)\n001 3 f645 fc51 c9c3 | 55 e277 (0) e2d3 (0) e0a0 (0) e09f (0)\n002 5 bbaf af02 a327 a2e6 | 37 bdc5 (0) bcf8 (0) bfc7 (0) bea1 (0)\n003 5 8073 837f 8d19 8f9a | 21 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n004 3 93ea 95c0 955d | 8 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n005 6 9ec8 9f7d 9f0e 9c21 | 6 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n============ DEPTH: 6 ==========================================\n006 2 9948 9959 | 2 9948 (0) 9959 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","private_key":"c540be3b3745151e75287e86c62db0fa68c68a13c06e511d9ccafa0b720969a9","name":"node_9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","services":["bzz","pss"],"enable_msg_events":true,"port":41055},"up":true}},{"node":{"info":{"id":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","name":"node_c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","enode":"enode://9022be2eafd1b596287e78101c820178a736461ebf18c02d293c56d67cc881daa6b234e7b7d1f37ac3f49ececef3b96edbdc462ce5f5fe2bf41079787a8093a5@127.0.0.1:0","enr":"0xf88fb840f7351379bc850fcc93ba2ef5af9d2f0407e068046473feb7b496ec6fa8f56c0151ed144e7a078a2160242e4793f0508666d82ac0bf8b809d7fb1b8c0becc07630183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039022be2eafd1b596287e78101c820178a736461ebf18c02d293c56d67cc881da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ycMC3kr+e03LtvPjZs50cIP53NfVxqAbk52lzcbMyHQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c9c302\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 3980 1049 1686 60c5 | 126 3411 (0) 36b9 (0) 3728 (0) 32ff (0)\n001 6 b78f a327 a606 af02 | 75 b3f9 (0) b659 (0) b6df (0) b78f (0)\n002 6 ec90 fa24 feb3 fc51 | 28 e471 (0) e681 (0) e64d (0) e2d3 (0)\n003 6 d9cf dbd4 dad0 ddb8 | 11 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n004 2 c272 c190 | 8 c534 (0) c42e (0) c74d (0) c603 (0)\n005 4 cf52 cc33 cdb1 cd6c | 4 cf52 (0) cc33 (0) cdb1 (0) cd6c (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c8ea c8c8 | 2 c8ea (0) c8c8 (0)\n008 1 c961 | 1 c961 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","private_key":"2d2c2ccb0a0c233399b577f4b799b0181de2cd4673c1207b189502c87c899154","name":"node_c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","services":["bzz","pss"],"enable_msg_events":true,"port":33367},"up":true}},{"node":{"info":{"id":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","name":"node_5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","enode":"enode://47a8bfa3642fb14aad3497d548cd0ff911bb2e2a2cb1690be88d88e3a6bf854a4cab67630b26b8aced1d96c0e4c0cea337456b5e7fda0712b0e63b17ce8566d6@127.0.0.1:0","enr":"0xf88fb840c2abefc8eb1e4331f1a75917b53d225e82282d262f0e4bb2f4b77c9bbe6efb7703a6ff2d0f874bd663d1ac50566237c65b0438059ff31730c896e201938003b50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10247a8bfa3642fb14aad3497d548cd0ff911bb2e2a2cb1690be88d88e3a6bf854a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"X/CcaFlzaq16gqO/s/GhqLPA1Y+DGGNUDZwwE901dF4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5ff09c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 af02 a4ee 9948 9b8e | 130 b3f9 (0) b6df (0) b659 (0) b78f (0)\n001 5 2ddf 3980 0e2b 1049 | 65 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n002 5 79e5 6dd3 6d3c 68cb | 26 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n003 5 43d4 43c9 4d38 48de | 19 46bf (0) 44ad (0) 447a (0) 447c (0)\n004 4 50c1 5538 5663 56ca | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 3 5814 5ac0 5a8b | 6 5987 (0) 5814 (0) 5bd8 (0) 5a26 (0)\n============ DEPTH: 6 ==========================================\n006 3 5c37 5c7c 5d82 | 3 5c37 (0) 5c7c (0) 5d82 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","private_key":"00702831aac71a1861099a693ff9a0eb5bbad3993d5054de5722027d2906dc32","name":"node_5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","services":["bzz","pss"],"enable_msg_events":true,"port":45801},"up":true}},{"node":{"info":{"id":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","name":"node_482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","enode":"enode://61e80e865b0692bff9618d89bec4178cc713d2efccfd0c9f11a94a3bb65f510ccae3af079e3ec0db026b08c0f41eef7440b0a04cbf7a88a8e948a7bbe0f09d4b@127.0.0.1:0","enr":"0xf88fb8408eae3376cda8894401f6a76ded081e214dbcdcc35516b057e7e27962ce8e71fb038d41811263fcd3e7ae470ebad950d4ce9de19c18246bbe58efd4e64cd0b4ea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10361e80e865b0692bff9618d89bec4178cc713d2efccfd0c9f11a94a3bb65f510c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SC7D3AVGBXnqm86HZ3vT2aGTDoAfq+umB7ira4cp/xU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 482ec3\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 a4ee c9c3 d408 f645 | 130 c74d (0) c6a8 (0) c603 (0) c534 (0)\n001 3 1bd5 1686 1049 | 65 36b9 (0) 3728 (0) 3411 (0) 32ff (0)\n002 5 60c5 68cb 79e5 7850 | 26 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n003 7 5663 56ca 5814 5a8b | 16 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n004 4 447c 435d 43d4 43c9 | 9 46bf (0) 44ad (0) 447a (0) 447c (0)\n005 3 4cec 4d91 4d38 | 3 4cec (0) 4d91 (0) 4d38 (0)\n006 2 4a95 4b79 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 4 48b8 48f1 48d7 48de | 4 48b8 (0) 48f1 (0) 48d7 (0) 48de (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","private_key":"914825085a6c709b5fb3130de8c9b6f9593efcb2fa9db695821c0ad50d637918","name":"node_482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","services":["bzz","pss"],"enable_msg_events":true,"port":41929},"up":true}},{"node":{"info":{"id":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","name":"node_1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","enode":"enode://16980066851e866b8eec7c10d0b26aa7c7839271112682530f4801d3c494f8eca313971c90b19590d0b4f4995e2c799e328795c06bc5c030d200d40c803bfccc@127.0.0.1:0","enr":"0xf88fb84015420addbd5c0cd32d328b36acc314ecc7a045c9197df579feed2a3e4d1db4d930917f78b1bd4a674d1aa7ba04e0e6e3420d30208274bcc61493281b08b9fdc60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10216980066851e866b8eec7c10d0b26aa7c7839271112682530f4801d3c494f8ec","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EEnTIaRQcmzznR186hwQi+O+wTemRLYs3HOoU/Wlois=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1049d3\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c9c3 d408 fa24 f645 | 130 c603 (0) c6a8 (0) c74d (0) c42e (0)\n001 6 7850 7d16 56ca 5d82 | 61 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n002 6 3980 2e65 2c80 2ddf | 28 3728 (0) 36b9 (0) 3411 (0) 32ff (0)\n003 4 0561 07f5 0e80 0e2b | 21 025d (0) 035f (0) 0314 (0) 012b (0)\n004 6 1dec 18e0 19ea 194e | 9 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n005 4 1484 140d 1784 1686 | 4 1484 (0) 140d (0) 1784 (0) 1686 (0)\n============ DEPTH: 6 ==========================================\n006 1 138d | 1 138d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1070 | 1 1070 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","private_key":"199675da9f4b1fd8e250d9ba36169cc5b10d83f69b39656a4b8e5c7536feaef2","name":"node_1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","services":["bzz","pss"],"enable_msg_events":true,"port":46623},"up":true}},{"node":{"info":{"id":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","name":"node_a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","enode":"enode://d9a019201fc917f5e3bb43c74a43fbdb9c66a2ecdc3e751f299e5a984d91e005be151f1d7d28a1c4fff2cec0ee358c79bf2f767e391d4f6ac110a3e268da7f15@127.0.0.1:0","enr":"0xf88fb840755a7a98e81b46c4f8effc43bf335c6043a85c0351fdcad60a80aa1b0033db4b569b0b9e452bf29597b83a24824ae11bca382614a3eaf87ceda9ff79d9de62f60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d9a019201fc917f5e3bb43c74a43fbdb9c66a2ecdc3e751f299e5a984d91e005","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oubJAFEXaMjJlHqw+i5zl1zypM7H/RUher26JcMpMX4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a2e6c9\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 26ac 1049 | 126 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n001 3 d408 fa24 f645 | 55 c534 (0) c42e (0) c74d (0) c603 (0)\n002 4 8073 8f9a 9948 9b8e | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 5 be68 b8e1 bbaf b78f | 14 b3f9 (0) b659 (0) b6df (0) b78f (0)\n004 4 a8ff a8f4 ab3f af02 | 10 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n005 6 a742 a616 a606 a505 | 7 a616 (0) a606 (0) a7a8 (0) a742 (0)\n006 2 a0c8 a1c8 | 2 a0c8 (0) a1c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a330 a327 | 2 a330 (0) a327 (0)\n008 0 | 0\n009 1 a2a1 | 1 a2a1 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","private_key":"4662f9a82f5f82c5aab562b02fffb40fe8b62834bae8104220f46efd89898980","name":"node_a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","services":["bzz","pss"],"enable_msg_events":true,"port":33333},"up":true}},{"node":{"info":{"id":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","name":"node_a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","enode":"enode://453ddc011affe7c5cf20098ebed634712f9be29be2f136db7321e21029a732ef5e9318f6500053225345d773e7fce47dd0e219b9c2a29a433e618c2471149840@127.0.0.1:0","enr":"0xf88fb8402c342bd3642c99cf153a0106b072c0342cea619d53b64076d24cf4d67838ed1a20e65fc7c73a613a6cbba324aaec9aa64fe96559e44ab51433b80746e933d9880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102453ddc011affe7c5cf20098ebed634712f9be29be2f136db7321e21029a732ef","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"pO5Juyyqu2uUSLzf8fw8xnOi2wTqufXGLReH8sJZkKA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a4ee49\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 1049 26ac 7d16 482e | 126 025d (0) 035f (0) 0314 (0) 012b (0)\n001 4 fc51 fa24 f2b4 f645 | 55 c534 (0) c42e (0) c74d (0) c603 (0)\n002 5 837f 8f9a 8e28 9948 | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 5 be68 bfc7 bbaf b78f | 14 b3f9 (0) b659 (0) b6df (0) b78f (0)\n004 3 a8ff ab3f af02 | 10 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n005 4 a1c8 a327 a2a1 a2e6 | 6 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n006 3 a606 a7a8 a742 | 4 a616 (0) a606 (0) a7a8 (0) a742 (0)\n============ DEPTH: 7 ==========================================\n007 2 a505 a5ac | 2 a505 (0) a5ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","private_key":"59ad354948f16052bee88884c787bea727cb225c8573f641845ac1ac2357d6a5","name":"node_a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","services":["bzz","pss"],"enable_msg_events":true,"port":36935},"up":true}},{"node":{"info":{"id":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","name":"node_f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","enode":"enode://af59e58eb60a9dc748725bc8525d5e216517bd1c27f15728d2959890b8b5997c33a6b7efea09f3ba50b0f8048cace4d001a24b5ac4287ef1721e0c78c577b448@127.0.0.1:0","enr":"0xf88fb8409a8b6d7253f6d169fb548b469ba22aff1ed726350e671757249d57cf12b9b1d54724906cae553e56619591a1da8e799760729eb50980d43b1544427ae48c8c370183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102af59e58eb60a9dc748725bc8525d5e216517bd1c27f15728d2959890b8b5997c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9kWqucsr0nCZmLOOV4nJxfaNQHZebL2TuS5jg+tnHbo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f645aa\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 1686 1049 26ac 7d16 | 126 07f5 (0) 046c (0) 0594 (0) 0561 (0)\n001 10 8f9a 9948 9b8e b78f | 75 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n002 10 d408 d700 ddb8 d9cf | 27 c534 (0) c42e (0) c74d (0) c603 (0)\n003 4 e0a0 eebd ed42 ec90 | 14 e471 (0) e681 (0) e64d (0) e277 (0)\n004 4 feb3 fc51 f9de fa24 | 7 fc39 (0) fc51 (0) ff75 (0) feb3 (0)\n005 4 f1ed f305 f215 f2b4 | 4 f1ed (0) f305 (0) f215 (0) f2b4 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f756 | 1 f756 (0)\n008 1 f6c0 | 1 f6c0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","private_key":"6ff11e7bc067a6cbe95f29b9359cd01605c91281829e73e543154f78ed8e7962","name":"node_f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","services":["bzz","pss"],"enable_msg_events":true,"port":41177},"up":true}},{"node":{"info":{"id":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","name":"node_5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","enode":"enode://8f9ce802b9786b4a1aa8b5644e566d23306c0d0eb77e6df2965b1e274d690b6e2502e7c011240b18cb138c87af5681de7a883889122b0615c0c638dc31dee213@127.0.0.1:0","enr":"0xf88fb840fa8500339bf2fbc498dadfc8621c437bdb9120747fabf305b106c05d497c3067734896952dafd120f87ca214cb31457fba84b83a7a0b61abd8f185ffe94970ee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038f9ce802b9786b4a1aa8b5644e566d23306c0d0eb77e6df2965b1e274d690b6e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WsDQC41kfexi0m4aaJ/QW4t6GnmrjENJO9bX0gmBbfE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5ac0d0\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 bbaf 8f9a 9b8e f2b4 | 130 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n001 4 0cfc 0e2b 0e80 26ac | 65 025d (0) 035f (0) 0314 (0) 012b (0)\n002 3 6d3c 79e5 7d16 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 6 43c9 43d4 4cec 4d38 | 19 46bf (0) 44ad (0) 447a (0) 447c (0)\n004 3 5538 56ca 5663 | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 3 5ff0 5c7c 5d82 | 4 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n006 2 5987 5814 | 2 5987 (0) 5814 (0)\n007 1 5bd8 | 1 5bd8 (0)\n============ DEPTH: 8 ==========================================\n008 1 5a26 | 1 5a26 (0)\n009 1 5a8b | 1 5a8b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","private_key":"37d0a7ae7d8c4e2d793d9abd755aad9a8b44f13935e905b00e1f3dfdf0f52095","name":"node_5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","services":["bzz","pss"],"enable_msg_events":true,"port":39637},"up":true}},{"node":{"info":{"id":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","name":"node_7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","enode":"enode://63b48abfe4bd6eb3bb9cd83e20c13d4e1155c4d0e67d9f0f1fd7aa134a3c70b07eff745b46eb65ce17a2586d6bbc99cfe2b09a909211d1bd906dc518c6d028a1@127.0.0.1:0","enr":"0xf88fb84060ab746693d04040fa4a967d48408a7121a17efbe8c2ab834db16aa034e76736313708f92b2c32f579368352ba5953b50658b408af972a1fd6db52ba8b5d31840183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10363b48abfe4bd6eb3bb9cd83e20c13d4e1155c4d0e67d9f0f1fd7aa134a3c70b0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fRYqEWYlhfjDjYj7JBYj5nus+QcDBl2ubAkrS1B9ZUM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7d162a\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f645 f2b4 fa24 a4ee | 130 c534 (0) c42e (0) c74d (0) c603 (0)\n001 3 1049 2fd2 26ac | 65 035f (0) 0314 (0) 025d (0) 0191 (0)\n002 5 43d4 48de 482e 56ca | 35 46bf (0) 44ad (0) 447a (0) 447c (0)\n003 5 60c5 68cb 6e7f 6d3c | 13 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n004 3 7660 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 4 7895 7850 7933 79e5 | 4 7895 (0) 7850 (0) 7933 (0) 79e5 (0)\n006 1 7e47 | 1 7e47 (0)\n============ DEPTH: 7 ==========================================\n007 3 7ce7 7c7c 7c46 | 3 7ce7 (0) 7c7c (0) 7c46 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","private_key":"9304de16b2dad1e33f2436981bb04e64cbfbd2b153362b7f99b6e8ed93f2e3c7","name":"node_7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","services":["bzz","pss"],"enable_msg_events":true,"port":43535},"up":true}},{"node":{"info":{"id":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","name":"node_af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","enode":"enode://7651426a392ebbda1e38bda8c61f84d23619acc84c23482c366aa93172e0e69d0db6cec3a0117a8b29b469cfb4867640c19cde672f97b8e0a898721fdfcf81d2@127.0.0.1:0","enr":"0xf88fb840b963eedc19e55fea385cb79ba3edb722a5c9cd6b3837cae1b8b5bd42752a174a1fe5c8c3e1f1317f3f7dbc12ea24d98f7f8c47251ada9f5f7e2ef957f22a4d880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027651426a392ebbda1e38bda8c61f84d23619acc84c23482c366aa93172e0e69d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rwLC9HHparje+9IpIVaVuV5k98eLFFtnk6I4lh9Vb78=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: af02c2\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1049 7d16 5ff0 56ca | 126 025d (0) 035f (0) 0314 (0) 012b (0)\n001 4 c9c3 f645 f2b4 fa24 | 55 c42e (0) c534 (0) c74d (0) c603 (0)\n002 4 955d 9959 9b8e 8f9a | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 8 bfc7 be68 bea1 b8e1 | 14 bcf8 (0) bdc5 (0) bfc7 (0) be68 (0)\n004 7 a7a8 a742 a5ac a4ee | 13 a0c8 (0) a1c8 (0) a330 (0) a327 (0)\n005 5 a970 a8b5 a8ff a8f4 | 7 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n============ DEPTH: 6 ==========================================\n006 1 acee | 1 acee (0)\n007 1 aeb4 | 1 aeb4 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","private_key":"db442bd6d5c398b9067accca6107d7b8e10ba8c679a04e038cbc5a31c15cb44a","name":"node_af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","services":["bzz","pss"],"enable_msg_events":true,"port":36073},"up":true}},{"node":{"info":{"id":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","name":"node_56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","enode":"enode://3977a7e2abfbb0b874ef30206cf7ae8dbd7ff49318570256ed3a8f50d5185bd2aa2c0a0b605e3b0983036e397760f8b6825426e1854b934902f881f1f2d5177b@127.0.0.1:0","enr":"0xf88fb840deafd8851984faee193023cc0f9b9afc4230fec5d8853a822d9f3af256ffd26c7c696165cdd9fa3bef3492bd9393b312bbb433aa86fcfbdf387c2e4d333607250183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033977a7e2abfbb0b874ef30206cf7ae8dbd7ff49318570256ed3a8f50d5185bd2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Vsqd2Ealig/6e0moiq1VmjOLpTWm9zhGi48UbJeJDLI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 56ca9d\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f645 f2b4 af02 | 130 c74d (0) c603 (0) c6a8 (0) c42e (0)\n001 6 0e80 0e2b 1686 1049 | 65 025d (0) 0314 (0) 035f (0) 0111 (0)\n002 3 60c5 79e5 7d16 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 5 43c9 43d4 4d38 48de | 19 46bf (0) 44ad (0) 447a (0) 447c (0)\n004 5 5814 5ac0 5a8b 5d82 | 10 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n005 3 52a8 50c1 5144 | 3 52a8 (0) 5144 (0) 50c1 (0)\n============ DEPTH: 6 ==========================================\n006 1 5538 | 1 5538 (0)\n007 0 | 0\n008 1 5663 | 1 5663 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","private_key":"4b58bf70006ecc4c786de6a7e24d312dbe2dd18a5c61cd2255e343b02f20bb24","name":"node_56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","services":["bzz","pss"],"enable_msg_events":true,"port":33231},"up":true}},{"node":{"info":{"id":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","name":"node_26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","enode":"enode://d555fe464791f46530284107d275f268600ac4b18c0cd90ff85c6b7c0af0050a8b42cf6e631500f750737be9621ba85fbbaab4b8ecc7dcb0dbb7d4c3bf45c066@127.0.0.1:0","enr":"0xf88fb84073b57f889ad85e60f317292c360ebdf010410087fdcdfe33202d93acab67d7f515b57d160ff1e3f046026e03970154f616c655ad78ebf85a16d3534d07e64bd60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d555fe464791f46530284107d275f268600ac4b18c0cd90ff85c6b7c0af0050a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JqzDw3PCkVCvMLvJJk0MRMfGBv9zdzmd34RGNel6/Po=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26acc3\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 9f0e 8f9a a2e6 a4ee | 130 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n001 5 6d3c 60c5 7d16 5ac0 | 61 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n002 4 0e80 0e2b 1bd5 1049 | 37 012b (0) 0111 (0) 0191 (0) 025d (0)\n003 3 3980 32ff 3188 | 17 36b9 (0) 3728 (0) 3411 (0) 30fe (0)\n004 7 298a 2a50 2fd2 2e65 | 7 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 24f8 244c | 2 244c (0) 24f8 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 26ab | 1 26ab (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","private_key":"4db62bb95214bf5041d1bcd4a73488fcdaaa5616fe4e911e2621181956f3deda","name":"node_26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","services":["bzz","pss"],"enable_msg_events":true,"port":35363},"up":true}},{"node":{"info":{"id":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","name":"node_fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","enode":"enode://5d3165b8480aceb9a29a4b61b3ab32269c0528b62f0c58315dec25b4567cffff0e9a6e0832a40f555b1f37d268bf1591a93b1fe8858c54d1c41b0786a5f82ed4@127.0.0.1:0","enr":"0xf88fb840384d6f2d0e7aeea7e17230d68adf6c986544d7e0ddb16a747f8ca2ff2e208b65632e299c8bcee387db034659bc60d6fe20be94eed139b54e1c33fea4f0b664c20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025d3165b8480aceb9a29a4b61b3ab32269c0528b62f0c58315dec25b4567cffff","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+iQEEbxPPkTfyj+u3REsd0Ome1IqkQvJlpbvCzFzLuI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fa2404\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 79e5 7d16 1049 2ddf | 126 648a (0) 67f3 (0) 6795 (0) 6790 (0)\n001 8 8f9a bbaf b8e1 b5ea | 75 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n002 6 d408 ddb8 d9cf c190 | 27 c603 (0) c6a8 (0) c74d (0) c534 (0)\n003 4 e0a0 ef99 eebd ec90 | 14 e471 (0) e681 (0) e64d (0) e2d3 (0)\n004 5 f756 f6c0 f645 f305 | 7 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n005 3 fc51 fc39 feb3 | 4 fc39 (0) fc51 (0) ff75 (0) feb3 (0)\n============ DEPTH: 6 ==========================================\n006 2 f8ff f9de | 2 f8ff (0) f9de (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","private_key":"211a1e252e6faf64120c7e80193de1fb9c8574e8839437085db6624c65afb2c3","name":"node_fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","services":["bzz","pss"],"enable_msg_events":true,"port":40123},"up":true}},{"node":{"info":{"id":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","name":"node_f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","enode":"enode://d7318bb4df307ed03251fed0ebc0b514ff6ce6b2953bfc2f41eebd1ed2cc03d3290b1abe8ac51e22661fa91f8cfcacc7e7bdb1405e5cac4cdbf56475483daa9b@127.0.0.1:0","enr":"0xf88fb840f435115eab43ea3daa96fcf671263bd99032cf92a48d2a4331d533663d34cd32064567c172c0bceb4e8160e59433053e1b2b558538748fbda084fd167120e7690183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d7318bb4df307ed03251fed0ebc0b514ff6ce6b2953bfc2f41eebd1ed2cc03d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8rSaIkfJxej291WDSjf+XBfyCPmUh44UtwAeQE9S4SU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f2b49a\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 7d16 5ac0 56ca 2e65 | 126 0191 (0) 012b (0) 0111 (0) 0314 (0)\n001 10 9948 8f9a a742 a4ee | 75 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n002 7 cd6c c9c3 c190 d9cf | 27 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n003 2 e0a0 ec90 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 6 feb3 fc39 fc51 f8ff | 7 fc39 (0) fc51 (0) ff75 (0) feb3 (0)\n005 3 f756 f6c0 f645 | 3 f756 (0) f6c0 (0) f645 (0)\n006 1 f1ed | 1 f1ed (0)\n============ DEPTH: 7 ==========================================\n007 1 f305 | 1 f305 (0)\n008 1 f215 | 1 f215 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","private_key":"6f4c1a8084c43a09372f46f2d9c9d47e946032ad4494c25e53ab442810dfb7fc","name":"node_f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","services":["bzz","pss"],"enable_msg_events":true,"port":46219},"up":true}},{"node":{"info":{"id":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","name":"node_b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","enode":"enode://f2200c6d168fd4bf3f5ed5ac408ee95b95a35365e8c342dcfcba922300690d24ca30314c5d635505791f54e2deded324817ffe3129c898cb4a426adf595eb724@127.0.0.1:0","enr":"0xf88fb84021725022f3ac59f570e89280f9dd63209a73639e93974cd54845b965aa169be11392f71f7989121c8b9ba986bcb11b10faa14be90ddaa9ee8a129f76f3e33d360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f2200c6d168fd4bf3f5ed5ac408ee95b95a35365e8c342dcfcba922300690d24","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"teq0hptMtlvcHlyrRcAwFtIC+fW2aL5QBmRRz8+e8pk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b5eab4\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1686 0e80 24f8 79e5 | 126 1fd0 (0) 1dec (0) 1dc0 (0) 18e0 (0)\n001 2 fa24 f2b4 | 55 c74d (0) c6a8 (0) c603 (0) c42e (0)\n002 3 9948 8e28 8f9a | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 5 af02 a4ee a742 a2e6 | 23 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n004 6 bfc7 be68 bea1 ba91 | 8 bdc5 (0) bcf8 (0) be68 (0) bea1 (0)\n005 1 b3f9 | 1 b3f9 (0)\n============ DEPTH: 6 ==========================================\n006 3 b78f b659 b6df | 3 b78f (0) b659 (0) b6df (0)\n007 1 b4a1 | 1 b4a1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","private_key":"481278a076dd22f579d2e3224ee46c4efb0adf98a25587e4047dbc41a531583d","name":"node_b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","services":["bzz","pss"],"enable_msg_events":true,"port":37951},"up":true}},{"node":{"info":{"id":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","name":"node_79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","enode":"enode://075d1af75650c9de403f935ba958bd36f2dcb4f54812a57032e064eacf6791b2fadabd15082534259be0de378b8ec19b5c5bece38fd2f85f6d61f696d4ac14e4@127.0.0.1:0","enr":"0xf88fb8403597b43e61519416d408305834e8a89ab71a0a61b3f4f053f11f5968299862341d5ec75769bbb4cf7480c8bef7b24e1b8e3aff66288460abd1ed368813e91d150183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102075d1af75650c9de403f935ba958bd36f2dcb4f54812a57032e064eacf6791b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eeXGxteMiMV5ADzaBEiC7LBFIPutH1/q2+e20j/hg8g=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 79e5c6\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fa24 8f9a a327 b5ea | 130 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n001 4 0e80 2fd2 2c80 2ddf | 65 1dc0 (0) 1dec (0) 1fd0 (0) 18e0 (0)\n002 7 482e 48de 43d4 43c9 | 35 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n003 4 60c5 68cb 6d3c 6dd3 | 13 648a (0) 6758 (0) 6790 (0) 6795 (0)\n004 2 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 5 7e47 7ce7 7c7c 7c46 | 5 7e47 (0) 7ce7 (0) 7c7c (0) 7c46 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 7850 7895 | 2 7895 (0) 7850 (0)\n008 1 7933 | 1 7933 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","private_key":"9457ffd6b462dc1c0231d33b4fb9815c915a5ece2c906083d0545bae269b1838","name":"node_79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","services":["bzz","pss"],"enable_msg_events":true,"port":44929},"up":true}},{"node":{"info":{"id":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","name":"node_8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","enode":"enode://0ba5f5e13ed3f24bcc90ac6187a06331385aa18072a6353970a149cb65da7f8408e3bd27fdc0f2d790ec7a2c5a4f5c645ef4a150cb4fdde987537a60c37142c0@127.0.0.1:0","enr":"0xf88fb8403e7501b357ca709034505ffc033677386293dabf95f8c427892c5366a7ae2e0f69e68bf5b49160bf671794419a71fdbdd1334e34f74f68f77575078e1e3c90f10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020ba5f5e13ed3f24bcc90ac6187a06331385aa18072a6353970a149cb65da7f84","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"j5qizTPRjny0SU0Rp1Msl+tKHK4XKyFlwmrk7SSIfA0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8f9aa2\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 26ac 2ddf 5ac0 43d4 | 126 1fd0 (0) 1dc0 (0) 1dec (0) 1add (0)\n001 7 d700 d9cf ddb8 fa24 | 55 da36 (0) dad0 (0) dbd4 (0) d959 (0)\n002 9 a8f4 af02 a2a1 a2e6 | 37 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n003 4 955d 9ca1 9959 9b8e | 17 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n004 3 8073 834f 837f | 12 86d6 (0) 87a3 (0) 8402 (0) 84a9 (0)\n005 2 8b43 8854 | 3 8b43 (0) 8862 (0) 8854 (0)\n006 2 8cc3 8d19 | 2 8cc3 (0) 8d19 (0)\n============ DEPTH: 7 ==========================================\n007 3 8ea2 8e7b 8e28 | 3 8ea2 (0) 8e7b (0) 8e28 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","private_key":"f83575bfe6442b53eb4d8c355e1200c4401c098583e660934bf9987f9300e6fc","name":"node_8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","services":["bzz","pss"],"enable_msg_events":true,"port":35903},"up":true}},{"node":{"info":{"id":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","name":"node_2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","enode":"enode://29e1ab89b8c45319b773556c3422348d68748120f103b1806eb3fa94fb57117771a4e9811a97855b4076957253cfda4e1d7e7d5548464708fa7ec7107eec12d5@127.0.0.1:0","enr":"0xf88fb840979111f3046ade721c9e294e8d0656436a86fbc0cf8b2838b30c39d61a12386f5d18e6f92931a25b2b78f7286b8d8ba013719c6b55a32cb5f035f4668f5a38310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329e1ab89b8c45319b773556c3422348d68748120f103b1806eb3fa94fb571177","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Ld/92/RS8MkmgFinOfV1f7kCgcv9Mb1vdgrMM5L+wSo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2ddffd\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fa24 f2b4 bbaf 8f9a | 130 da36 (0) dad0 (0) dbd4 (0) d959 (0)\n001 3 5ff0 6dd3 79e5 | 61 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n002 5 1686 1049 07f5 0e2b | 37 1fd0 (0) 1dc0 (0) 1dec (0) 18e0 (0)\n003 4 3980 3411 3188 32ff | 17 36b9 (0) 3728 (0) 3411 (0) 30fe (0)\n004 3 244c 24f8 26ac | 4 244c (0) 24f8 (0) 26ab (0) 26ac (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n006 2 2e65 2fd2 | 2 2fd2 (0) 2e65 (0)\n============ DEPTH: 7 ==========================================\n007 2 2c85 2c80 | 2 2c85 (0) 2c80 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","private_key":"3c16c760b1da414e3f0702e51bb7b991c9f8f24d6780298e7f1c4a2211e65148","name":"node_2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","services":["bzz","pss"],"enable_msg_events":true,"port":37059},"up":true}},{"node":{"info":{"id":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","name":"node_bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","enode":"enode://f7560694a563f7b8b45223d669cb0c3bb40c7d6d3c2c7a02edb265933a0cea0746f94f112043dd9614675b71e6aabda899b082aa80ce92a1c4bc2815f48d70ca@127.0.0.1:0","enr":"0xf88fb840dc4fa4b1749e43011079de3d46e7621a199adbd688f08a6430dac3a3a5a968d64ffad4738b308452154a2d6bbf4d88aea49250c65e68297d8e084c6992e98c910183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f7560694a563f7b8b45223d669cb0c3bb40c7d6d3c2c7a02edb265933a0cea07","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"u6+sW6WRXbPIDiiyScrSYLm12tH3KAY8SPqPYddVbhc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bbafac\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5ac0 6dd3 2ddf | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 4 ec90 fa24 feb3 f2b4 | 55 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n002 5 955d 9f7d 9b8e 8e28 | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 6 af02 a4ee a742 a2a1 | 23 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n004 5 b3f9 b6df b78f b4a1 | 6 b3f9 (0) b78f (0) b659 (0) b6df (0)\n005 5 bdc5 bcf8 bfc7 be68 | 5 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n============ DEPTH: 6 ==========================================\n006 1 b8e1 | 1 b8e1 (0)\n007 1 ba91 | 1 ba91 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","private_key":"92e3be78001b291633af182ae0eaa04e18135ff78f3f44ea1807ade09e09f9c4","name":"node_bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","services":["bzz","pss"],"enable_msg_events":true,"port":34263},"up":true}},{"node":{"info":{"id":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","name":"node_a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","enode":"enode://095fd8d08d7c8f838e4b0a8ae5d5dbc252f1f8fa2f4909b00c4e1a76abd7e97f55201ffac074124ec2de620f242c33f3a5a6716f0105311320328bfb71b37613@127.0.0.1:0","enr":"0xf88fb84023807c617fe27431d11170d14386c718cb44cc0bc380888e41340bc3a6b2fed73035c05d36ab2f0c51da29e46bd4188c4e1a10d987249dad7fa69d4e4a2ee2d70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103095fd8d08d7c8f838e4b0a8ae5d5dbc252f1f8fa2f4909b00c4e1a76abd7e97f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oydJ3E4TSk+7A4YYxYp8Bbu6oG8UNt43VDQa+GQCWBs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a32749\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2e65 43d4 79e5 6dd3 | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 6 d9cf c9c3 c190 f1ed | 55 c74d (0) c603 (0) c6a8 (0) c534 (0)\n002 5 9b8e 9959 9f7d 9ca1 | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 4 b4a1 b5ea b8e1 bbaf | 14 b3f9 (0) b78f (0) b659 (0) b6df (0)\n004 4 af02 a8ff a8f4 ab3f | 10 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n005 5 a5ac a505 a4ee a7a8 | 7 a505 (0) a5ac (0) a4ee (0) a616 (0)\n006 2 a0c8 a1c8 | 2 a0c8 (0) a1c8 (0)\n============ DEPTH: 7 ==========================================\n007 2 a2a1 a2e6 | 2 a2a1 (0) a2e6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a330 | 1 a330 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","private_key":"abf141d0f41d519d2f0bcfd4e1cab0e3d3b7f49bb2524ddfbcb4ed8087b83b39","name":"node_a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","services":["bzz","pss"],"enable_msg_events":true,"port":42795},"up":true}},{"node":{"info":{"id":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","name":"node_b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","enode":"enode://f04605b84e637cfebd8976e50b34cb2677a4314ffad3de5f827b256c5789bc9395bca075fdc7d093933f7a36b0086da67b41726ecd01f12473dc86a64d648d30@127.0.0.1:0","enr":"0xf88fb8407a74507655e5e4bccef3b4f4be2094d2dfa1f734606fc6fea7a7d5534117bdd212b9fbbc1b5190a3217e08c13dc5b1d5e33d16540dd469bccff2b61d00f169380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f04605b84e637cfebd8976e50b34cb2677a4314ffad3de5f827b256c5789bc93","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uOGoYiwlbvKazVLfezrOUIIPsaFHcWFl/4Yv3Jc6SM0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8e1a8\npopulation: 41 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6d3c 68cb 0e80 24f8 | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 9 d700 d408 ddb8 d9cf | 55 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n002 5 9948 955d 8d19 8e28 | 38 9c21 (0) 9c8e (0) 9ca1 (0) 9ec8 (0)\n003 9 af02 a8ff a505 a7a8 | 23 aaf0 (0) ab71 (0) ab3f (0) a970 (0)\n004 5 b3f9 b78f b6df b4a1 | 6 b3f9 (0) b78f (0) b659 (0) b6df (0)\n005 5 bcf8 bdc5 bfc7 be68 | 5 bcf8 (0) bdc5 (0) bfc7 (0) be68 (0)\n============ DEPTH: 6 ==========================================\n006 2 ba91 bbaf | 2 ba91 (0) bbaf (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","private_key":"16e0a5b28dd4eef0429cfee2457fefee326e70769d72a08220c987d895948535","name":"node_b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","services":["bzz","pss"],"enable_msg_events":true,"port":34709},"up":true}},{"node":{"info":{"id":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","name":"node_2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","enode":"enode://691ca9c06e10ad9e54772ff48bc4ae919f121bdc7c6ae4b100351ac29f5b9c0067cd758acd4b0e25f67dfa21718cc34aeffd02b40dff4f52ff37acbd00fd7501@127.0.0.1:0","enr":"0xf88fb8406bb758fd0d287e48c99c72280182a42c8e1fff4b42972876eb7d7d79532702475aa04a531f8efafd3652264038cd3910f2da1b312b91e88345a53b2ff877cc8a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103691ca9c06e10ad9e54772ff48bc4ae919f121bdc7c6ae4b100351ac29f5b9c00","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LIBCUX3+qgFYbpHkkd1BVPskwNhP7bBAS51RNvYNodk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2c8042\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c534 f2b4 9f0e a742 | 130 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n001 5 56ca 43d4 68cb 6dd3 | 61 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n002 5 1686 1049 07f5 0e2b | 37 1dc0 (0) 1dec (0) 1fd0 (0) 18e0 (0)\n003 3 3411 32ff 3980 | 17 36b9 (0) 3728 (0) 3411 (0) 30fe (0)\n004 4 24f8 244c 26ab 26ac | 4 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n006 2 2fd2 2e65 | 2 2fd2 (0) 2e65 (0)\n============ DEPTH: 7 ==========================================\n007 1 2ddf | 1 2ddf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 2c85 | 1 2c85 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","private_key":"c3f87c0c78bb12a86da6ad7d36c7291a3895a98586e6e8e099b279f077ffd478","name":"node_2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","services":["bzz","pss"],"enable_msg_events":true,"port":41807},"up":true}},{"node":{"info":{"id":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","name":"node_a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","enode":"enode://1f3ff2039504020c5625d4fbe5c447e27cfb3016aa9ec0e1837d44eaa2fe4172b2731d4ff02a80394e7e3d0f4a32f19cc239a3972f10eab45bf2c69d9d8c65ee@127.0.0.1:0","enr":"0xf88fb840f01697c24bc9fee368002b25d4480ee743229f9cbdc31dbaa122bca564f7c45b35b737cd14a1258f4e4eaded287d70183cc0d4584cd0b1cba3a7f55096fa87a30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f3ff2039504020c5625d4fbe5c447e27cfb3016aa9ec0e1837d44eaa2fe4172","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p0LoUCxhlwPOh4kBEPkIveMrWdxh13okd1nl0AVuDJQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a742e8\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 43d4 1070 0e80 2c80 | 126 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n001 4 ec90 f2b4 f645 feb3 | 55 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n002 3 9c21 8e28 8f9a | 38 9ec8 (0) 9f0e (0) 9f7d (0) 9c21 (0)\n003 5 b4a1 b5ea bfc7 b8e1 | 14 b3f9 (0) b78f (0) b659 (0) b6df (0)\n004 4 a8b5 a8f4 a8ff af02 | 10 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n005 4 a1c8 a2a1 a2e6 a327 | 6 a0c8 (0) a1c8 (0) a2a1 (0) a2e6 (0)\n006 3 a505 a5ac a4ee | 3 a505 (0) a5ac (0) a4ee (0)\n============ DEPTH: 7 ==========================================\n007 2 a616 a606 | 2 a616 (0) a606 (0)\n008 1 a7a8 | 1 a7a8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","private_key":"6f1c95c10b82cf6a4a6a6ffba536b6e4d17dca7e822de4e3b740149684932d39","name":"node_a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","services":["bzz","pss"],"enable_msg_events":true,"port":37625},"up":true}},{"node":{"info":{"id":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","name":"node_feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","enode":"enode://27ac651910b9394ef60deb8ececf68b82b3f2bff98cf45cc6dab2a0a0a271bf8f5cd18af48ec4a9eb79821487687a0dfb97af07de26b237f0194f1d1c84587f1@127.0.0.1:0","enr":"0xf88fb840dff98a9839c85f4ca1a944e19e2913b5a74f45e9701a6d6887f3b6fbdeb63db6104a51388fa37505749037788d83e0ed7d3dc9f9f37d696abb5aab32f13633200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10327ac651910b9394ef60deb8ececf68b82b3f2bff98cf45cc6dab2a0a0a271bf8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/rO8F+5zaaT6mInZJQ/tPBJXxwkWhxmW5uq9N03Y3C4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: feb3bc\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 2e65 43d4 68cb 6dd3 | 126 1dc0 (0) 1dec (0) 1fd0 (0) 18e0 (0)\n001 5 8f9a bbaf b8e1 a8f4 | 75 9948 (0) 9959 (0) 9b8e (0) 9ec8 (0)\n002 5 c9c3 c190 ddb8 d700 | 27 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n003 3 ec90 e471 e0a0 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 5 f1ed f2b4 f756 f645 | 7 f756 (0) f6c0 (0) f645 (0) f1ed (0)\n005 2 f9de fa24 | 3 f8ff (0) f9de (0) fa24 (0)\n============ DEPTH: 6 ==========================================\n006 2 fc39 fc51 | 2 fc51 (0) fc39 (0)\n007 1 ff75 | 1 ff75 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","private_key":"0612d46e6c5fe2d816f3fcc01eea18407ea659f41290d153e08a780a5313e54c","name":"node_feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","services":["bzz","pss"],"enable_msg_events":true,"port":36801},"up":true}},{"node":{"info":{"id":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","name":"node_6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","enode":"enode://33d552be8155690e7cbe2739fa74ca6e83ead5035cd9a8e26d187ef54b14ca924e3d5485f7bb095dc233d74758321997fe1ae52b5ce5dc070eb0589816b09442@127.0.0.1:0","enr":"0xf88fb8409b453570d61397d255334db062ee118d6af0cc79fd50cda1bb3830f187d56f506eaa18ca5d6dc753b0cf201bfe1614f777a497a0713d90ed07b3bf9f76920e7c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10233d552be8155690e7cbe2739fa74ca6e83ead5035cd9a8e26d187ef54b14ca92","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bdOsD9mgSiznWHXGg9E15S6qFnDLVeeHEWIHEuYP3kc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6dd3ac\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 8f9a bbaf a8f4 a327 | 130 9948 (0) 9959 (0) 9b8e (0) 9ec8 (0)\n001 4 0e80 2ddf 2c80 2e65 | 65 1fd0 (0) 1dec (0) 1dc0 (0) 18e0 (0)\n002 6 5663 5814 5ff0 5d82 | 35 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n003 4 70f6 7d16 7850 79e5 | 13 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n004 3 6758 67f3 60c5 | 6 648a (0) 6758 (0) 6790 (0) 6795 (0)\n005 2 6b4e 68cb | 2 6b4e (0) 68cb (0)\n006 1 6e7f | 1 6e7f (0)\n007 1 6c01 | 1 6c01 (0)\n============ DEPTH: 8 ==========================================\n008 2 6d3c 6d5e | 2 6d5e (0) 6d3c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","private_key":"798b1133c83f1bd8708da776e24e1068611422abe705d8209d07e88f4ae07873","name":"node_6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","services":["bzz","pss"],"enable_msg_events":true,"port":35411},"up":true}},{"node":{"info":{"id":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","name":"node_2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","enode":"enode://224027d2af542674e07dc64ec477cb324c9288d5b917bd302a8b994fb56effd5d4134f71de9dbe75d043d510c3df39b87f5590dd5e53d1512969e65bfc9debad@127.0.0.1:0","enr":"0xf88fb840cfb76c5419d68cf2f3a24256e9324a22f66fc4b5580a187070e857ba42d18a8921c69ca44e1570e72d7281e2ef3c9c2604a2ca5089bb11f8142664ad4552a2970183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103224027d2af542674e07dc64ec477cb324c9288d5b917bd302a8b994fb56effd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"LmXQVki3mPr7ybtYLAXm+PiRExJg6MkMpyXdy8gj8xU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2e65d0\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 ec90 f2b4 feb3 955d | 130 dbd4 (0) da36 (0) dad0 (0) d959 (0)\n001 2 43d4 6dd3 | 61 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n002 6 0e80 19ea 1b1d 1070 | 37 1484 (0) 140d (0) 1784 (0) 1686 (0)\n003 5 3980 397a 3411 3188 | 17 3f31 (0) 3c5b (0) 3cab (0) 3a62 (0)\n004 4 26ab 26ac 244c 24f8 | 4 26ab (0) 26ac (0) 244c (0) 24f8 (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n============ DEPTH: 6 ==========================================\n006 3 2ddf 2c85 2c80 | 3 2ddf (0) 2c85 (0) 2c80 (0)\n007 1 2fd2 | 1 2fd2 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","private_key":"2b229760916c74b6ac5f23ef8180077064de49ec26982a14a09a3d1382e474b0","name":"node_2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","services":["bzz","pss"],"enable_msg_events":true,"port":34851},"up":true}},{"node":{"info":{"id":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","name":"node_43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","enode":"enode://e7390b07e9257a295e97c15d41b54e09e2dcdfc3b9fc73b2b0f2e63a0713c9ded792f3a5ee9d6938d4f429c961b091715297661b560bac8df0449449c96346f6@127.0.0.1:0","enr":"0xf88fb8406a94ea3a25ea5935505a1d5b3df6880b4b51723a453f3fe497c93e6dddf6efed7794b6528b6c6e10790083a3893217933ff7b93745ca7a04b03e78564462c9fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e7390b07e9257a295e97c15d41b54e09e2dcdfc3b9fc73b2b0f2e63a0713c9de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Q9Q+nry860gw/B0tUCRlC5Bpgwa70sTQtIQaGo/QnJM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 43d43e\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 c190 ec90 feb3 955d | 130 da36 (0) dad0 (0) dbd4 (0) d959 (0)\n001 4 0e80 32ff 2c80 2e65 | 65 1dec (0) 1dc0 (0) 1fd0 (0) 18e0 (0)\n002 6 79e5 7895 7d16 6d3c | 26 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n003 6 5663 56ca 5ff0 5d82 | 16 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n004 4 4cec 4d38 482e 48de | 10 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n005 4 46bf 447c 447a 44ad | 4 46bf (0) 447a (0) 447c (0) 44ad (0)\n006 2 4005 402c | 2 4005 (0) 402c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 435d | 1 435d (0)\n009 0 | 0\n010 0 | 0\n011 1 43c9 | 1 43c9 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","private_key":"705846d6103b8dcde5526942f8da6f2206687604c468de841c1e3556e63e27f4","name":"node_43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","services":["bzz","pss"],"enable_msg_events":true,"port":33285},"up":true}},{"node":{"info":{"id":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","name":"node_68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","enode":"enode://a3d519e4a1788400163f2db9a838b8229a5d176f4b32736cc11d48510f60bfd57fe2b36b773121bed96bb701a34a777b9b0f9f0a6210a11a5267db32c5709c20@127.0.0.1:0","enr":"0xf88fb840b867c36933c9555cfb4f20df50e1fa2d1c86295c58b5348694874b92dcc369053ef0b25782dc4f892f9a7d6250dd1c42582a0f9a87ced83db2af67d0d5459e660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a3d519e4a1788400163f2db9a838b8229a5d176f4b32736cc11d48510f60bfd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"aMvEpTEwgNXcqK006L9SphROD/jvP3ldeunV9kT+IEI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 68cbc4\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 c190 feb3 ec90 b4a1 | 130 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n001 5 3411 2c80 24f8 19ea | 65 3cab (0) 3c5b (0) 3f31 (0) 3a62 (0)\n002 6 5663 5ff0 5814 482e | 35 5c37 (0) 5c7c (0) 5d82 (0) 5ff0 (0)\n003 5 70f6 79e5 7850 7895 | 13 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n004 2 67f3 60c5 | 6 648a (0) 6758 (0) 6795 (0) 6790 (0)\n============ DEPTH: 5 ==========================================\n005 5 6e7f 6c01 6dd3 6d5e | 5 6e7f (0) 6c01 (0) 6dd3 (0) 6d5e (0)\n006 1 6b4e | 1 6b4e (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","private_key":"8dc0ff9e95b0b85f24142f1082c900c64588c269a697412aabd41e4d80197de9","name":"node_68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","services":["bzz","pss"],"enable_msg_events":true,"port":37375},"up":true}},{"node":{"info":{"id":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","name":"node_6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","enode":"enode://39291783101f95a5ab0c6a5d372ab36be799b2f4dd241206519e00c6df4c01d16736ddcf75349c2fa7ee23395b536b4d60d40863664b2d9b15bcdf13a384856b@127.0.0.1:0","enr":"0xf88fb840c8714570044e40edeb9d032662ba2bdcc24c79d2f85ca264d6e7ca490de884235fccc9d43de5859321525bb25b2ed942d3dbfa2f72686bd09b8cad40b7d56cd70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10339291783101f95a5ab0c6a5d372ab36be799b2f4dd241206519e00c6df4c01d1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bTxtsVkA8llihvgcwGZNLIKR6tW60qo1utUVrwiKLkg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6d3c6d\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c190 a8f4 b6df b8e1 | 130 b3f9 (0) b78f (0) b659 (0) b6df (0)\n001 6 3411 26ac 244c 24f8 | 65 3cab (0) 3c5b (0) 3f31 (0) 3b02 (0)\n002 6 5663 5ff0 5ac0 5814 | 35 5c7c (0) 5c37 (0) 5d82 (0) 5ff0 (0)\n003 5 70f6 7d16 7c7c 7895 | 13 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n004 2 6795 60c5 | 6 648a (0) 6758 (0) 67f3 (0) 6790 (0)\n005 2 6b4e 68cb | 2 6b4e (0) 68cb (0)\n006 1 6e7f | 1 6e7f (0)\n007 1 6c01 | 1 6c01 (0)\n============ DEPTH: 8 ==========================================\n008 1 6dd3 | 1 6dd3 (0)\n009 1 6d5e | 1 6d5e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","private_key":"ae7658c745f0e65d13c11825a7164cb7336cc227bb4141dcb4f7a1b69abc8607","name":"node_6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","services":["bzz","pss"],"enable_msg_events":true,"port":46873},"up":true}},{"node":{"info":{"id":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","name":"node_0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","enode":"enode://4c66fe3197799ae8e8b7a9dc282966e1308115243346f02df98a818894f45783aeee959acc426df923f934b3a0948ab96460014c21435cd2a72745cc03f31986@127.0.0.1:0","enr":"0xf88fb840e699bbd1a5ea6afb58628146badd23319b3b2b6ed1e3cfa33efa77d040ac18f34f2d5aa2dba515d6d196f3414f3cfc8cb70045a92f88c46fad4bd4fef1bebd4f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024c66fe3197799ae8e8b7a9dc282966e1308115243346f02df98a818894f45783","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DoDbnfqM4pvt+y3gMWIr74gpvuUncTIran77R6/lQOc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0e80db\npopulation: 40 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 b8e1 b5ea b4a1 a8f4 | 130 bfc7 (0) be68 (0) bea1 (0) bdc5 (0)\n001 7 56ca 5ac0 43d4 79e5 | 61 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n002 9 3411 32ff 2e65 2fd2 | 28 3c5b (0) 3cab (0) 3f31 (0) 3b02 (0)\n003 5 19ea 1b1d 1686 1049 | 16 140d (0) 1484 (0) 1784 (0) 1686 (0)\n004 2 046c 07f5 | 10 035f (0) 0314 (0) 025d (0) 0191 (0)\n005 4 08f8 09b3 096a 0942 | 6 08bd (0) 08e5 (0) 08f8 (0) 09b3 (0)\n006 2 0cfc 0d1c | 2 0cfc (0) 0d1c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 0e3b 0e2b | 2 0e3b (0) 0e2b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","private_key":"b9190dcff292030b590acbf97d108aa5e5bdf506556ea496845cee35fdb941c6","name":"node_0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","services":["bzz","pss"],"enable_msg_events":true,"port":36041},"up":true}},{"node":{"info":{"id":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","name":"node_24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","enode":"enode://29812550052d6b16cc2b04fc247361209269007589ab11e66a4dc0928b09a158d46c84eb42f8150e45dc8a1507a2474372b311b26f743eeb615a36094d404313@127.0.0.1:0","enr":"0xf88fb840ea7a6a8262fab073a6840a7ee18670e090fea60cf597a27d2832802826b0a8f068c3ca88013d64b5ff02ccb4f2ff094c590329d9a24cf9a3d7856c6b6fd676070183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10329812550052d6b16cc2b04fc247361209269007589ab11e66a4dc0928b09a158","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JPgMQ3vkWJjllPghu6D1xi4MmgxyARjjYu5veEEGEr0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 24f80c\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 b8e1 b5ea b4a1 b6df | 130 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n001 2 68cb 6d3c | 61 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n002 5 1b1d 19ea 1049 1070 | 37 1484 (0) 140d (0) 1784 (0) 1686 (0)\n003 3 3980 3938 32ff | 17 3f31 (0) 3c5b (0) 3cab (0) 3b02 (0)\n004 7 2a50 298a 2c80 2c85 | 7 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 26ac 26ab | 2 26ab (0) 26ac (0)\n007 0 | 0\n008 1 244c | 1 244c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","private_key":"bd42db9dab0f618eb6ccbe9be985031a20cc1daa8157a90861ddd93c290047ab","name":"node_24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","services":["bzz","pss"],"enable_msg_events":true,"port":37751},"up":true}},{"node":{"info":{"id":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","name":"node_ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","enode":"enode://1afe1c8bb1a13bc5bc8ab9528f323597de5d3c7322397d611f7cfdee80cabaa6ee95222a551a9bfd627f595472bb227327a045306c75a25b75eb5d6240eb7b54@127.0.0.1:0","enr":"0xf88fb840a2ce29495c237a1d985a2865cbcacf2d5d3e6332f63ebbf01a8beeac0e5e2621504b30da39c19b73bc3cf1135905ab7c6fe71b1e90fc05dfd1fceea7ec3269ff0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021afe1c8bb1a13bc5bc8ab9528f323597de5d3c7322397d611f7cfdee80cabaa6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"7JCiL0HuZZ1XWaSXlGrCmRyRbwD+fK7usJCPOvH+YLY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ec90a2\npopulation: 39 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 43d4 68cb 0e80 2e65 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 10 b78f b8e1 bbaf ab3f | 75 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n002 5 ddb8 d408 d700 c9c3 | 27 d959 (0) d9cf (0) dbd4 (0) da36 (0)\n003 9 feb3 fc51 fc39 fa24 | 14 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n004 4 e471 e2d3 e09f e0a0 | 7 e471 (0) e64d (0) e681 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n============ DEPTH: 6 ==========================================\n006 3 eebd eff2 ef99 | 3 eebd (0) eff2 (0) ef99 (0)\n007 1 ed42 | 1 ed42 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","private_key":"89981ff407aefd00840d1b348382e6571fe033d8e0e93bdacff8d74ac1fbb465","name":"node_ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","services":["bzz","pss"],"enable_msg_events":true,"port":42753},"up":true}},{"node":{"info":{"id":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","name":"node_955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","enode":"enode://28ce8e8bd283c85d928eff07eb1fe95320e63ffecaeba76699cc6559b4e724ebab2f08fc20a3569022d9a14c0dc992ce97cb38b8031a6c170594ff80c0360a59@127.0.0.1:0","enr":"0xf88fb840599bae7bc68a1be369da49e6e4fc452277e838db6b140b288b1443accdfc5e7b68e44b4d5cf9c33cdbc1d0c7088b756639d98e9a4c055ee7589c982e720a68a30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10328ce8e8bd283c85d928eff07eb1fe95320e63ffecaeba76699cc6559b4e724eb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"lV2hXtrlCkxovIxXm5eZ1V9Bt8KmF49kX3nXcuARZmI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 955da1\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 2e65 0e80 43d4 6d3c | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 2 c190 ec90 | 55 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n002 4 bbaf b8e1 af02 a8f4 | 37 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n003 4 8e28 8f9a 8d19 8073 | 21 8b43 (0) 8862 (0) 8854 (0) 8ea2 (0)\n004 8 9948 9959 9b8e 9ec8 | 9 9959 (0) 9948 (0) 9b8e (0) 9ec8 (0)\n005 3 9257 93c0 93ea | 3 9257 (0) 93c0 (0) 93ea (0)\n006 1 97da | 1 97da (0)\n007 1 9464 | 1 9464 (0)\n============ DEPTH: 8 ==========================================\n008 1 95c0 | 1 95c0 (0)\n009 1 9518 | 1 9518 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","private_key":"37f0dfbc4bcabf9e11ec2090cd8fd558bd7784630fdac652e65e0e56e11fff47","name":"node_955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","services":["bzz","pss"],"enable_msg_events":true,"port":46557},"up":true}},{"node":{"info":{"id":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","name":"node_a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","enode":"enode://a387b1ae7d38f1e3bb1576e26b97a6f5bf1fc147160a59dd43b8184b0c23dde70d006b3e046f727c0d3d185db250fb1796d0c8c4a63921c8fa4fda6ec1feea1c@127.0.0.1:0","enr":"0xf88fb840f2d8228ae427fc1b5347e72a85e3f6fb50398b45a626c6521c677d449daa7f9f1f0b921ba8b3e600829957e2a3cfc8d98234f8a6d8395d56172c1c0c4c8855ea0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a387b1ae7d38f1e3bb1576e26b97a6f5bf1fc147160a59dd43b8184b0c23dde7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qPSehxVv2lUQiXYBaJzpaNdwMhNMUjY0kWuW3hY2b54=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a8f49e\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 0e80 1070 43d4 43c9 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 6 f1ed fa24 fc51 fc39 | 55 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n002 6 8d19 8f9a 8ea2 8e28 | 38 8862 (0) 8854 (0) 8b43 (0) 8ea2 (0)\n003 2 bea1 b6df | 14 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n004 6 a2e6 a2a1 a327 a1c8 | 13 a505 (0) a5ac (0) a4ee (0) a616 (0)\n005 2 aeb4 af02 | 3 acee (0) aeb4 (0) af02 (0)\n006 3 aaf0 ab71 ab3f | 3 aaf0 (0) ab71 (0) ab3f (0)\n007 1 a970 | 1 a970 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 1 a8b5 | 1 a8b5 (0)\n010 0 | 0\n011 0 | 0\n012 1 a8ff | 1 a8ff (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","private_key":"6bb6d8d705a40ba424923e49c1a5f2ea7ef65a8047cd69554f076497ad72abe8","name":"node_a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","services":["bzz","pss"],"enable_msg_events":true,"port":40983},"up":true}},{"node":{"info":{"id":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","name":"node_c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","enode":"enode://624fdcc04a4251fa0a5e452254deb09951e1c0e466046bb34ecfc5762881942842a1ad2ebe95d8a53fc13cf338b164aae811b96d19034914557485104f7cf8a6@127.0.0.1:0","enr":"0xf88fb840f541779d4363d2d110782b9208996593d8124c23e35c0c27c4a598881a445d896199da564f83d98e0d70a24b31b5995b979add943d98a2e3d0ede83d689bc0ad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102624fdcc04a4251fa0a5e452254deb09951e1c0e466046bb34ecfc57628819428","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wZD50Ix47W3/ra7zbnf+aqlgmeRFN1Owz8jsVC+pa50=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c190f9\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5814 43d4 6d3c 68cb | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 7 9f7d 9ca1 955d 8073 | 75 8b43 (0) 8854 (0) 8862 (0) 8ea2 (0)\n002 7 f645 f2b4 fa24 feb3 | 28 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n003 3 dad0 ddb8 d700 | 11 d959 (0) d9cf (0) dbd4 (0) da36 (0)\n004 3 cf52 c8ea c9c3 | 8 cc33 (0) cd6c (0) cdb1 (0) cf52 (0)\n005 4 c603 c6a8 c534 c42e | 5 c74d (0) c603 (0) c6a8 (0) c534 (0)\n============ DEPTH: 6 ==========================================\n006 2 c2d0 c272 | 2 c2d0 (0) c272 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","private_key":"8e85cf18cf9dd5c75878ddc75b26b567c6f213cd9cf41387232103a423215444","name":"node_c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","services":["bzz","pss"],"enable_msg_events":true,"port":42929},"up":true}},{"node":{"info":{"id":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","name":"node_80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","enode":"enode://fdcec2678f4772897ed0eb0ec54b7de122c22cbf31b6e501c00adeed3d80cc14351e6a4ca7677d22fc7bbd94db0e3302cf20e7f55c554bd4dbaa0bd4e8a50a7f@127.0.0.1:0","enr":"0xf88fb84005c6d37ffbbfde5c741d546335ecf1ee87f1fb33af5875d0c84b3fb9dc87329f16d6370725423a847f1eebb7bd3a21a8fb3c43b99ef030a6cda4e1e144d69a280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103fdcec2678f4772897ed0eb0ec54b7de122c22cbf31b6e501c00adeed3d80cc14","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gHNacocgu6CsCNqszQkzcNZyqPmlCEWteMzWz4aGw58=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 80735a\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 2fd2 5814 5663 43d4 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 2 d700 c190 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 5 a8ff a1c8 a327 a2e6 | 37 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n003 8 93c0 955d 9948 9b8e | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 5 8b43 8f9a 8ea2 8e28 | 9 8854 (0) 8862 (0) 8b43 (0) 8ea2 (0)\n005 2 87a3 86d6 | 4 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n006 3 837f 834f 8358 | 3 834f (0) 8358 (0) 837f (0)\n007 1 81a5 | 1 81a5 (0)\n008 1 80d7 | 1 80d7 (0)\n============ DEPTH: 9 ==========================================\n009 1 8006 | 1 8006 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 8074 | 1 8074 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","private_key":"8623a021033479cd7104a88188d9784ac5edeb95094c010547e615407d7a8973","name":"node_80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","services":["bzz","pss"],"enable_msg_events":true,"port":38855},"up":true}},{"node":{"info":{"id":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","name":"node_b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","enode":"enode://3057525034706ee1eee5958ad026f2f68f4bff18e95bec5db1e27e845df3c6b45b7a3d030786afab82b789cef41f9bc88bbb7c7238eb01ada275e9d294741643@127.0.0.1:0","enr":"0xf88fb84043499166c98cc953ba2a4b899aea5eba91503a235686406a2e5cc6f41156d01b6a9cfdab6cab3104c08d3b2fe340ea9b4504fde582847b46d2c4ebfc55e4639f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033057525034706ee1eee5958ad026f2f68f4bff18e95bec5db1e27e845df3c6b4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tKG2h/vbdU/WieJvCHCn3KtddhkMBvPqLqHhmPiqWrI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b4a1b6\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 68cb 43d4 43c9 0e80 | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 4 f1ed f6c0 fc39 d700 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 2 8d19 8073 | 38 9257 (0) 93c0 (0) 93ea (0) 97da (0)\n003 4 a742 a7a8 a327 a1c8 | 23 a2e6 (0) a2a1 (0) a330 (0) a327 (0)\n004 5 b8e1 bbaf bdc5 bcf8 | 8 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n005 1 b3f9 | 1 b3f9 (0)\n============ DEPTH: 6 ==========================================\n006 3 b78f b659 b6df | 3 b78f (0) b659 (0) b6df (0)\n007 1 b5ea | 1 b5ea (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","private_key":"2db46fccdc01ed22afb3e789ea51e706f96e02424e2883893536ac8941043985","name":"node_b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","services":["bzz","pss"],"enable_msg_events":true,"port":34987},"up":true}},{"node":{"info":{"id":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","name":"node_b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","enode":"enode://83bcb3c68dcde737d01e64be91562e08aa6d62823cce64889fe81f01f05c9678015ec02c8c36bb8f83beee9587374da90118a76a98289f5ebad1436b19035bc4@127.0.0.1:0","enr":"0xf88fb8405bc0154529713773273db32f0ea11698b2fb42edf643c702fa47f05b032ad0b2780c5793a4018e529b014c867bee95c6af034725f784cc7f4742f2b9dc6d87d30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10283bcb3c68dcde737d01e64be91562e08aa6d62823cce64889fe81f01f05c9678","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tt/6xLTrKXTtDtJBeZ+X0uXZvmceMRJmgm0Nz+z8wgk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b6dffa\npopulation: 24 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 43d4 43c9 68cb 6d3c | 126 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n001 3 e0a0 fc39 d700 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 2 9ca1 8d19 | 38 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n003 3 a7a8 af02 a8f4 | 23 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n004 5 bcf8 bfc7 bea1 bbaf | 8 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n005 1 b3f9 | 1 b3f9 (0)\n006 2 b5ea b4a1 | 2 b5ea (0) b4a1 (0)\n============ DEPTH: 7 ==========================================\n007 1 b78f | 1 b78f (0)\n008 1 b659 | 1 b659 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","private_key":"e24347072d11928511f53eef3f8e9a9734b3aaf2cb6205e653b42817451769b3","name":"node_b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","services":["bzz","pss"],"enable_msg_events":true,"port":46447},"up":true}},{"node":{"info":{"id":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","name":"node_d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","enode":"enode://410d63c57efb139f46850a8e0c7be2739099ace7e693848bb141c8cc7a9918f0ea1bb23bca1d292d38877c9fcd33d089ec39ba60ecfe1c8f10d5364e31196576@127.0.0.1:0","enr":"0xf88fb8408aa9045d36445a648a2d7468dfe7acea7f555e845341e000f782de3a667360ae2b494625fbc4c7ea45769984f4915b406d9241de31ef82d41bbeff3811d6d98f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102410d63c57efb139f46850a8e0c7be2739099ace7e693848bb141c8cc7a9918f0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1wDZbeEZNFbcC89JLHwRsJUQYpdK8vf0e4yQGxfCMWU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d700d9\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 0e80 19ea 2fd2 24f8 | 126 140d (0) 1484 (0) 1784 (0) 1686 (0)\n001 9 9f7d 9ca1 8073 8f9a | 75 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n002 10 e0a0 ef99 ec90 feb3 | 28 e64d (0) e681 (0) e471 (0) e277 (0)\n003 10 c9c3 c8ea cf52 cc33 | 16 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n004 3 ddb8 dad0 d9cf | 6 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n============ DEPTH: 5 ==========================================\n005 3 d209 d3e9 d302 | 3 d209 (0) d3e9 (0) d302 (0)\n006 1 d408 | 1 d408 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","private_key":"44cd8419094d50e78afb097502f16dcd9c28368eb0ac43ce3b6312f58b6a3176","name":"node_d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","services":["bzz","pss"],"enable_msg_events":true,"port":43567},"up":true}},{"node":{"info":{"id":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","name":"node_43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","enode":"enode://7041f32dd06a878b138bbfefc65706d09feb4d20fa70fdaec9b5e107e0b78fb17e7e0e925ac8e1de69e03d8ab6005d250b3988c1c0911dadfd14e07849bd556e@127.0.0.1:0","enr":"0xf88fb840d7d0ed8828dbcb293891f06bd62c1a8f8be6e41e64cdfd8c701332e185ae09782876283f3a7fb0bd32333fddb3890bf3afbbda703a86a9e2189b5d08811c410f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027041f32dd06a878b138bbfefc65706d09feb4d20fa70fdaec9b5e107e0b78fb1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Q8nhVxxGDLn1mfqO153dD5w6If0vpFXgYDEJxVAS92s=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 43c9e1\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 b6df b4a1 a8f4 a1c8 | 130 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n001 2 244c 2fd2 | 65 012b (0) 0111 (0) 0191 (0) 025d (0)\n002 5 79e5 7895 68cb 6dd3 | 26 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n003 7 5ff0 5ac0 5814 50c1 | 16 5d82 (0) 5c7c (0) 5c37 (0) 5ff0 (0)\n004 3 4d38 48de 482e | 10 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n005 2 447c 447a | 4 46bf (0) 44ad (0) 447c (0) 447a (0)\n006 2 4005 402c | 2 4005 (0) 402c (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 435d | 1 435d (0)\n009 0 | 0\n010 0 | 0\n011 1 43d4 | 1 43d4 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","private_key":"0be456eea926753ec7862f851dbd4b26ee5559316964d3411e6024e19a752138","name":"node_43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","services":["bzz","pss"],"enable_msg_events":true,"port":46243},"up":true}},{"node":{"info":{"id":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","name":"node_9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","enode":"enode://c9a8f470d438c9326b6d9e1f44bd2df3b9b4db56183efa7e23e2381f7499a94abcf1098ecf26221121fd113ea34eb8df3d183d5a3df359ebb5a93ef693f13923@127.0.0.1:0","enr":"0xf88fb840c1fa2933c23d1743f13988ec4d4c71a6d636eab7df047c52c265ea0086f72f550a1b2fd29579c42d2b4d7d3a9b2898b42b35ef897ebb203d6980bef0063402470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103c9a8f470d438c9326b6d9e1f44bd2df3b9b4db56183efa7e23e2381f7499a94a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nKH9XUGXWsuQXzN5l5IoSbQHA2DkeEm7T9jNG53bTXM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ca1fd\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 046c 0942 244c 2fd2 | 126 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n001 5 d700 c190 ec90 f6c0 | 55 e64d (0) e681 (0) e471 (0) e277 (0)\n002 4 b6df a327 a1c8 a7a8 | 37 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n003 3 8073 8f9a 8d19 | 21 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n004 3 93ea 93c0 955d | 8 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n005 3 9959 9948 9b8e | 3 9948 (0) 9959 (0) 9b8e (0)\n006 3 9ec8 9f0e 9f7d | 3 9ec8 (0) 9f0e (0) 9f7d (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 9c21 | 1 9c21 (0)\n009 0 | 0\n010 1 9c8e | 1 9c8e (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","private_key":"fbcd62592636cde3b1d26d9fd45dd2a45c8d1dfd4919ef05694e5c3a64330798","name":"node_9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","services":["bzz","pss"],"enable_msg_events":true,"port":39429},"up":true}},{"node":{"info":{"id":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","name":"node_8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","enode":"enode://222e619168c8502ad2677160abc513c09bfff4fc68adc96d2e7f0f7c4930abd567e863fe0472152a657c4ddd856612f5fb1dc02b056d9e8c1c159e098939dfe5@127.0.0.1:0","enr":"0xf88fb840930bf1a5288e587dffc9cebd12f017e5781d33ea16fe79da844003dba818a12e274142748fa13f0293ec802260c571d0052748b2d534197d123a968cfe5b46900183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103222e619168c8502ad2677160abc513c09bfff4fc68adc96d2e7f0f7c4930abd5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jRkrEVOActt1D3EgTi5q353AUI2cXPHrRX5OmWzZhbw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8d192b\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5814 2fd2 | 126 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n001 4 ec90 f6c0 fc39 d700 | 55 c8c8 (0) c8ea (0) c961 (0) c9c3 (0)\n002 6 a8f4 a1c8 bea1 b8e1 | 37 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n003 6 955d 9b8e 9ec8 9f7d | 17 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n004 5 87a3 86d6 8358 837f | 12 8402 (0) 84a9 (0) 87a3 (0) 86d6 (0)\n005 3 8854 8862 8b43 | 3 8854 (0) 8862 (0) 8b43 (0)\n============ DEPTH: 6 ==========================================\n006 4 8ea2 8e28 8e7b 8f9a | 4 8ea2 (0) 8e7b (0) 8e28 (0) 8f9a (0)\n007 1 8cc3 | 1 8cc3 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","private_key":"edbbc3a484e366a33c8f6c00e9c02ac566737d8e91db651bc236921021651832","name":"node_8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","services":["bzz","pss"],"enable_msg_events":true,"port":42737},"up":true}},{"node":{"info":{"id":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","name":"node_2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","enode":"enode://d90aedfb65dd9e291e3c4407969177cc0003f7aeefea62a5fda7e78a2f8e57503ea0542d07a9ca08fc77b1c140394f0b96403ee29b9ef7e77220e8349d89d727@127.0.0.1:0","enr":"0xf88fb840fb7cf57abda6762cac6ad86cec07e3614162d910e4bfaac92260335eb590c78248534c6fb3f6579c4d43dda86da3aac0bf57486a520ce42420a4348d33eca50c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d90aedfb65dd9e291e3c4407969177cc0003f7aeefea62a5fda7e78a2f8e5750","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"L9L3fXbMpICsGOmvekYvKX2xaMM3CzvA4sBKoAbE0Dc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2fd2f7\npopulation: 37 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 11 d700 c534 c190 fc39 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 7 7895 79e5 7d16 7c46 | 61 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n002 5 046c 0e80 0942 1b1d | 37 08e5 (0) 08f8 (0) 08bd (0) 09b3 (0)\n003 4 3980 3938 3411 32ff | 17 3f31 (0) 3c5b (0) 3cab (0) 3b02 (0)\n004 4 26ab 26ac 24f8 244c | 4 26ab (0) 26ac (0) 24f8 (0) 244c (0)\n005 2 2a50 298a | 2 2a50 (0) 298a (0)\n============ DEPTH: 6 ==========================================\n006 3 2ddf 2c85 2c80 | 3 2ddf (0) 2c85 (0) 2c80 (0)\n007 1 2e65 | 1 2e65 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","private_key":"7f01ef5d73b7a1621cf1a50134d0e446cde7c2685c35b818d64476d6cda01227","name":"node_2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","services":["bzz","pss"],"enable_msg_events":true,"port":32949},"up":true}},{"node":{"info":{"id":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","name":"node_f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","enode":"enode://ffc371f4f10ff50bcf4e7340bdc527dfcb0999c56a8ad077681dda0e5af313e62507524e2ff696ece4cb8eb97aac54f27d233260cb7ca5c4154e7afdfbdf96e5@127.0.0.1:0","enr":"0xf88fb84078e3e0d2b74bdd55983a052ed78591ee0915da8578fd5b0a91956d6b269bf3d81d3db48178b5eaee67ea280e6f5f0d246d756fc5abf350ae9397534bf91281da0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ffc371f4f10ff50bcf4e7340bdc527dfcb0999c56a8ad077681dda0e5af313e6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9sAo1qK2QI6QFpFR9FGbVh7Rg72JJe2aFwKAbzl2Zuc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f6c028\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7895 5814 43c9 244c | 126 7660 (0) 741a (0) 7049 (0) 70f6 (0)\n001 4 8d19 9ca1 b4a1 a7a8 | 75 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n002 5 c272 c42e c534 cf52 | 27 c8c8 (0) c8ea (0) c961 (0) c9c3 (0)\n003 5 e2d3 e471 e681 ef99 | 14 e867 (0) eb68 (0) eebd (0) eff2 (0)\n004 4 fa24 fc39 fc51 feb3 | 7 f9de (0) f8ff (0) fa24 (0) ff75 (0)\n005 4 f1ed f215 f2b4 f305 | 4 f1ed (0) f215 (0) f2b4 (0) f305 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 f756 | 1 f756 (0)\n008 1 f645 | 1 f645 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","private_key":"c2001db1b7540d6a72ed993e4a136476e6ca041a2240675f06b1a4e86e3424b0","name":"node_f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","services":["bzz","pss"],"enable_msg_events":true,"port":42857},"up":true}},{"node":{"info":{"id":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","name":"node_a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","enode":"enode://5e72e16dc757645afb111309a937a4366004991283411fd3c3d50c52778232ea7e7719d3cd0b1cc369bacf31c031b3a68472fd6fc03614d1986778f4e75140d9@127.0.0.1:0","enr":"0xf88fb840e8f42e427291a54799a4ef9798e106974722cc80a6cfd96431e683e82ca8ec92476544d118c7c93cde8d566d6bf48318fa85a0caa46c9abac29b1444055438090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035e72e16dc757645afb111309a937a4366004991283411fd3c3d50c52778232ea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"p6hWpDKTqjAEhIqG8Yfgk0O9YF4ak+hTpva2sQMb1mc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a7a856\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1070 1b1d 244c 43c9 | 126 648a (0) 6758 (0) 67f3 (0) 6795 (0)\n001 3 fc39 f1ed f6c0 | 55 c8c8 (0) c8ea (0) c9c3 (0) c961 (0)\n002 2 9f7d 9ca1 | 38 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n003 6 b659 b6df b4a1 b8e1 | 14 bdc5 (0) bcf8 (0) bfc7 (0) be68 (0)\n004 4 af02 a8b5 a8ff a8f4 | 10 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n005 3 a327 a0c8 a1c8 | 6 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n006 3 a505 a5ac a4ee | 3 a505 (0) a5ac (0) a4ee (0)\n============ DEPTH: 7 ==========================================\n007 2 a616 a606 | 2 a616 (0) a606 (0)\n008 1 a742 | 1 a742 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","private_key":"aaadb3be16a7097261fed25f08f292e5be9b99c1bf3e70cdbb76066aa605151b","name":"node_a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","services":["bzz","pss"],"enable_msg_events":true,"port":43911},"up":true}},{"node":{"info":{"id":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","name":"node_fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","enode":"enode://afc7a62e260657fc0f72b68057c239d562dd553789cb3906dab521c2a0020c4d2e34f72e5c3b4bffc3c6d5a025ec22131d20c572b0667120bb9d6ff131368aa7@127.0.0.1:0","enr":"0xf88fb840b433a55822deba2cb67c49773ac6e9f6f916feeead46453ea70f7b6fb891e1b170b3ddf9a5f427aba0d47f36094e0bd0d8b00b31a2e816c4a06a6983e83e6c310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103afc7a62e260657fc0f72b68057c239d562dd553789cb3906dab521c2a0020c4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/DkROD90qYL2r4q5WmNCa1YRfUXxU7PBRBRZ2Rkdqv8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fc3911\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5814 1b1d 2fd2 244c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 9 8d19 9f7d 9ca1 b6df | 75 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n002 2 c190 d700 | 27 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n003 4 ec90 ef99 e471 e0a0 | 14 e867 (0) eb68 (0) eebd (0) eff2 (0)\n004 6 f1ed f2b4 f215 f305 | 7 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n005 2 f9de fa24 | 3 f8ff (0) f9de (0) fa24 (0)\n============ DEPTH: 6 ==========================================\n006 2 ff75 feb3 | 2 ff75 (0) feb3 (0)\n007 0 | 0\n008 0 | 0\n009 1 fc51 | 1 fc51 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","private_key":"0ab4f963705bd1ecac1ddfc070baf12e433c412c0dd7fda5ec1153e31f06d4c2","name":"node_fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","services":["bzz","pss"],"enable_msg_events":true,"port":33103},"up":true}},{"node":{"info":{"id":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","name":"node_a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","enode":"enode://62b2eb13717066427ba05db84603b330fb3b693d2bd1813d8e9a4c827fd48f746e425420802c437d4d617dacfe21133a47c98445bda61d435b1f1b25d3e430a4@127.0.0.1:0","enr":"0xf88fb8403d5ad691524cfb1b6da3dab6ee3570ad1ade29f4b42fcc3a0603f12596af26e82166d74d480e460f21c4f63ba82529d08d4089ffcb9667ab5f98b7ae05b09c6e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10262b2eb13717066427ba05db84603b330fb3b693d2bd1813d8e9a4c827fd48f74","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oche517bgHoB9M6TAIbJSJGKreMkdSYJsHjCiZHAToY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a1c85e\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 43c9 2fd2 244c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 5 c534 e0a0 f1ed f756 | 55 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n002 6 86d6 8073 8d19 9ca1 | 38 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n003 6 b659 b4a1 ba91 b8e1 | 14 ba91 (0) bbaf (0) b8e1 (0) bdc5 (0)\n004 2 a8b5 a8f4 | 10 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n005 6 a4ee a5ac a616 a606 | 7 a505 (0) a5ac (0) a4ee (0) a616 (0)\n============ DEPTH: 6 ==========================================\n006 4 a2e6 a2a1 a330 a327 | 4 a2a1 (0) a2e6 (0) a330 (0) a327 (0)\n007 1 a0c8 | 1 a0c8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","private_key":"2d5200058e0137ed16e823b77f132dec259ba1ba4237b3c7d64b6077dac98f24","name":"node_a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","services":["bzz","pss"],"enable_msg_events":true,"port":46031},"up":true}},{"node":{"info":{"id":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","name":"node_244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","enode":"enode://bc965245672290bb814412e8c14997e91efee12a0980a8ad30a49cafcdc350a149112bb4c07d92fa648bfb87d0e04b0d49dd5876fb503689dc29f894f9afc11c@127.0.0.1:0","enr":"0xf88fb8406db7bfa6b9d5aa889571c5a4bfcdcef571a6e1c7f1b13ae8bd42e882bdcb10f35429b014724321e75ef0725af408123a88b9fefcbf9cc4b8333c556d683067c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bc965245672290bb814412e8c14997e91efee12a0980a8ad30a49cafcdc350a1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JEw8lUrGEuUdSUWrm3fwtKOYMoXordeSF3fgxFob8zg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 244c3c\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 cf52 c534 d700 e0a0 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 4 6d3c 7895 43c9 5814 | 61 648a (0) 6758 (0) 67f3 (0) 6790 (0)\n002 5 046c 0942 0e80 0d1c | 37 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n003 4 3938 32ff 30fe 3411 | 17 3f31 (0) 3cab (0) 3c5b (0) 3a62 (0)\n004 6 2a50 2ddf 2c85 2c80 | 7 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 26ac 26ab | 2 26ac (0) 26ab (0)\n007 0 | 0\n008 1 24f8 | 1 24f8 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","private_key":"756bc2386944320552b690fdf2118ce4d2ebcec85975547ada771a0683526e39","name":"node_244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","services":["bzz","pss"],"enable_msg_events":true,"port":41177},"up":true}},{"node":{"info":{"id":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","name":"node_5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","enode":"enode://df45993237c885437698b9b42e4207115ff5f58aa44c86dec586013c408bddc56e44ca3c85a503ba4124ea6b825e510ca0c3aff8ffea771c186ddeec9282eaed@127.0.0.1:0","enr":"0xf88fb84046bd2bda155f5a7e7f14f680ffaef48b1222058233bac7457c919b20cd5bef383be59f22ce7613605070fe9bdca1f816c15e80c9c8b7c1c3b0b1928f383314d90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df45993237c885437698b9b42e4207115ff5f58aa44c86dec586013c408bddc5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WBS+E8hVC5pag9COevYCIAKo/ao4umwsML5YCZqfd0Q=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5814be\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 c190 f6c0 fc39 e0a0 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 4 0942 1b1d 1070 244c | 65 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n002 4 68cb 6dd3 6d3c 7895 | 26 648a (0) 6758 (0) 6795 (0) 6790 (0)\n003 3 482e 43d4 43c9 | 19 4cec (0) 4d38 (0) 4d91 (0) 4b79 (0)\n004 4 50c1 5663 56ca 5538 | 6 52a8 (0) 5144 (0) 50c1 (0) 5538 (0)\n005 4 5ff0 5d82 5c7c 5c37 | 4 5d82 (0) 5c7c (0) 5c37 (0) 5ff0 (0)\n============ DEPTH: 6 ==========================================\n006 4 5bd8 5a26 5a8b 5ac0 | 4 5bd8 (0) 5a26 (0) 5a8b (0) 5ac0 (0)\n007 1 5987 | 1 5987 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","private_key":"3272db2e0cc941ae4242b75d527d37070acfd72d8565878230b23cdd5ba9aeeb","name":"node_5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","services":["bzz","pss"],"enable_msg_events":true,"port":35259},"up":true}},{"node":{"info":{"id":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","name":"node_bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","enode":"enode://05327ec5fb8fa18f4d157d91b796c4d75a86f76159dd10ba2a14be7924a7fb58d20ea137bfea3f319d779b05c1297ecf50517ee627fc419c0fe82aa9dbab5ebe@127.0.0.1:0","enr":"0xf88fb840a5e1e04d2823e9b4c938872330f7c5e0576dbad0404136ef57aa33a3fbc8b59263359ab46fbf691c6df00e06b7f475636a04c60d62cb7ebb12e72d9f412b0d940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10205327ec5fb8fa18f4d157d91b796c4d75a86f76159dd10ba2a14be7924a7fb58","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vqEIaNXaUGwYAd6EXBSMLwl2GJMROskT/mZnSo9DwXg=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bea108\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5663 5814 3411 1b1d | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 2 fc39 e0a0 | 55 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n002 2 8d19 9f7d | 38 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n003 5 af02 a8b5 a8f4 a7a8 | 23 acee (0) aeb4 (0) af02 (0) ab3f (0)\n004 5 b3f9 b5ea b4a1 b6df | 6 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n005 3 b8e1 ba91 bbaf | 3 bbaf (0) ba91 (0) b8e1 (0)\n006 2 bcf8 bdc5 | 2 bdc5 (0) bcf8 (0)\n============ DEPTH: 7 ==========================================\n007 1 bfc7 | 1 bfc7 (0)\n008 1 be68 | 1 be68 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","private_key":"d527efdb2ac85143b0e802a24844dd9c3aecc99bd77e0612baf6acb83decc3cf","name":"node_bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","services":["bzz","pss"],"enable_msg_events":true,"port":38981},"up":true}},{"node":{"info":{"id":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","name":"node_1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","enode":"enode://0b6b4bae7d34ebd01146d2c3912e36c6dc68c3fdcaeefb53789698c96d68142a7dea20ecc04141de176514183530bd52dd602fbb143e003f9629b58c12e5cc33@127.0.0.1:0","enr":"0xf88fb840bf5689088694d9e70533fcb09c6ce37880f92cc12326d6e446217bcc664b09e64f6cda48b1981c6bbc9c862fb2e06fd3946de83f4324bcca41a2650ee23899ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030b6b4bae7d34ebd01146d2c3912e36c6dc68c3fdcaeefb53789698c96d68142a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Gx3D+TEt8UGFXFRd0WruMl+aYJIw7GFlvbuwfQwIYvY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1b1dc3\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 fc39 9f7d a7a8 bea1 | 130 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n001 3 7895 5663 5814 | 61 648a (0) 67f3 (0) 6795 (0) 6790 (0)\n002 6 3938 3980 2e65 2fd2 | 28 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n003 4 046c 0d1c 0e80 0942 | 21 0cfc (0) 0d1c (0) 0e3b (0) 0e2b (0)\n004 3 1686 1070 1049 | 7 140d (0) 1484 (0) 1784 (0) 1686 (0)\n005 3 1fd0 1dec 1dc0 | 3 1fd0 (0) 1dec (0) 1dc0 (0)\n006 3 18e0 194e 19ea | 3 18e0 (0) 194e (0) 19ea (0)\n============ DEPTH: 7 ==========================================\n007 1 1add | 1 1add (0)\n008 1 1bd5 | 1 1bd5 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","private_key":"c3aeeb9b4511f6c9ea3f8db8e4276b10196cc6c2a60e302f5bbb89b9ef64f347","name":"node_1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","services":["bzz","pss"],"enable_msg_events":true,"port":33901},"up":true}},{"node":{"info":{"id":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","name":"node_9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","enode":"enode://d362f99f7e00ec84f6ccd67dced7aa2e96e5dd50cddeaee8905cf072d71c8d723fc4781ace6da7e5e8b9730b793e53d447bf5d2b8fb2b8789fbef10c8068a46e@127.0.0.1:0","enr":"0xf88fb84077e35d00c12dc0bd099fd21289a49989ea8fd68a36842bb056f10263234ce083009f796590e6bbf22e4cc3d1763969b34838da241b9f68d571aa56d33299ee5c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102d362f99f7e00ec84f6ccd67dced7aa2e96e5dd50cddeaee8905cf072d71c8d72","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"n31yt9mEOHKQS4QeQhmFCCQo+6UBDbJ92HHtdmMKHh0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9f7d72\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 7895 5663 3411 1b1d | 126 648a (0) 6758 (0) 67f3 (0) 6795 (0)\n001 4 c190 d700 fc39 e0a0 | 55 cc33 (0) cd6c (0) cdb1 (0) cf52 (0)\n002 7 b659 bbaf bcf8 bea1 | 37 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n003 2 8073 8d19 | 21 84a9 (0) 8402 (0) 87a3 (0) 86d6 (0)\n004 4 93c0 9464 9518 955d | 8 9257 (0) 93ea (0) 93c0 (0) 97da (0)\n005 3 9b8e 9959 9948 | 3 9b8e (0) 9959 (0) 9948 (0)\n006 3 9c21 9c8e 9ca1 | 3 9c21 (0) 9c8e (0) 9ca1 (0)\n============ DEPTH: 7 ==========================================\n007 1 9ec8 | 1 9ec8 (0)\n008 0 | 0\n009 1 9f0e | 1 9f0e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","private_key":"f6395d3f2dfff6a01fa0f1143c3c6ba9b31b776fe6ae409050d911d23a137868","name":"node_9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","services":["bzz","pss"],"enable_msg_events":true,"port":37587},"up":true}},{"node":{"info":{"id":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","name":"node_e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","enode":"enode://422a22e066ae056507308bb1fecc971ca826bab52f6cb3b34b0589a2fc48a0408fdba15209748268cf34fac6bf4c209e24eda88a244a86828d194275ebe46f7f@127.0.0.1:0","enr":"0xf88fb8400775cf65da7c43b86728c2df5afa5e9c4c3f8f090a4adc01b3a5efa7baa889b372ff1fa45e2c44d87865585cd877390cdde993202b72699fc3adaf68ca1760bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103422a22e066ae056507308bb1fecc971ca826bab52f6cb3b34b0589a2fc48a040","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4KC6fn6Jp6+AXiSr3hpaW0iboZdYUFGodV6MI0XD1Xs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e0a0ba\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 7895 5663 5814 244c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 4 a1c8 b6df bea1 9f7d | 75 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n002 5 cf52 c42e c190 c272 | 27 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n003 7 f645 f2b4 f215 f1ed | 14 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n004 2 ec90 ef99 | 7 eb68 (0) e867 (0) ed42 (0) ec90 (0)\n005 2 e681 e471 | 3 e64d (0) e681 (0) e471 (0)\n============ DEPTH: 6 ==========================================\n006 2 e277 e2d3 | 2 e277 (0) e2d3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 e09f | 1 e09f (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","private_key":"b0d5109a4802c73c946c7a258870bd410c63771abdb96a9270ef013cf2c988de","name":"node_e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","services":["bzz","pss"],"enable_msg_events":true,"port":43807},"up":true}},{"node":{"info":{"id":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","name":"node_1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","enode":"enode://111c70fb9b2eb78fd08286a0101565ce175084379f0d8449515001d42a158dc1bbaec026062de57a300ef9127fd4aca4cd98f12526ac8ebf4564dc7eb62d2861@127.0.0.1:0","enr":"0xf88fb84027a4b499ed66fe3c260acb1384fd562864ab2ea5be83229701ac73ad6916a91b0d8d1c6e3e112ba9b03b133077d6e109f47ddfa35dbd20d934c9305cafe06b8d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103111c70fb9b2eb78fd08286a0101565ce175084379f0d8449515001d42a158dc1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"EHDfXpBOOGUIWwMZqBdh5ZFGSUxonnVn7+dGX8gZros=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1070df\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 a742 a7a8 a8f4 c272 | 130 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n001 3 7895 5663 5814 | 61 648a (0) 6758 (0) 67f3 (0) 6795 (0)\n002 5 24f8 2e65 2fd2 3938 | 28 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n003 4 0942 0e80 0d1c 046c | 21 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n004 3 1dc0 1b1d 19ea | 9 1fd0 (0) 1dec (0) 1dc0 (0) 1add (0)\n005 4 140d 1484 1784 1686 | 4 140d (0) 1484 (0) 1784 (0) 1686 (0)\n============ DEPTH: 6 ==========================================\n006 1 138d | 1 138d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1049 | 1 1049 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","private_key":"e257c3e07a2c0a5fb86fd8a37ab0d9ff743e74798f3f353ec68c2035dc86b111","name":"node_1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","services":["bzz","pss"],"enable_msg_events":true,"port":46317},"up":true}},{"node":{"info":{"id":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","name":"node_34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","enode":"enode://9f8abe5231a45fd20487a9b4121d524d3b7a84e8ba84e4172bdba5b9e0fd7c950aeeb9d50e3747eeccfaabb4b97f23b01b5de7db38bb79720461d2e07f6fd21c@127.0.0.1:0","enr":"0xf88fb840db60fc10ad69f264ddc0aa2c696ca00930d8509a5150488041b12ccff8a0f4546a98344daf7ccf1d4cc42b130fbbc59bee03d2c1cd405e2081227557266da9680183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029f8abe5231a45fd20487a9b4121d524d3b7a84e8ba84e4172bdba5b9e0fd7c95","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NBGBZoRcGF0Vwoa35UM1Oe6Y7WNLqr1TTVc2n9X3xoE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 341181\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f756 9f7d bea1 | 130 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n001 5 68cb 6d3c 70f6 7895 | 61 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n002 5 046c 0e80 0d1c 0942 | 37 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n003 6 2e65 2fd2 2ddf 2c80 | 11 2a50 (0) 298a (0) 2c85 (0) 2c80 (0)\n004 3 3980 397a 3938 | 8 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n005 4 31e1 3188 30fe 32ff | 6 31e6 (0) 31e1 (0) 3188 (0) 3051 (0)\n============ DEPTH: 6 ==========================================\n006 2 3728 36b9 | 2 3728 (0) 36b9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","private_key":"6aebf51d37cedb0b4d755280a22852af0bac9f6f3d355b43bbc8464947552e34","name":"node_34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","services":["bzz","pss"],"enable_msg_events":true,"port":33159},"up":true}},{"node":{"info":{"id":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","name":"node_56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","enode":"enode://bce79d844c8a5bf30fdabb154e156c9b572e1ae5cde1df2f778557d19f720bc830a47ae4678a962fd7f80d4868fda0658bad614a36a18d0ad2cdff495832699c@127.0.0.1:0","enr":"0xf88fb840e2fb45ac13932cdc0858fd63065cf2542a47b9c76331ea177fd36fa8df7938fc069e18891af924b9717bf4598486f9b4d0cbc8e354fdc0c601f9744bf9fcdad00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bce79d844c8a5bf30fdabb154e156c9b572e1ae5cde1df2f778557d19f720bc8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VmNWmb07x4GTrb246LfCyR2rQUD9qlBv6iMA7obEuoE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 566356\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 8073 9f7d bea1 f1ed | 130 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n001 6 046c 0942 1070 1b1d | 65 0e2b (0) 0e3b (0) 0e80 (0) 0cfc (0)\n002 6 6d3c 6dd3 68cb 6790 | 26 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n003 3 482e 43d4 43c9 | 19 4d91 (0) 4d38 (0) 4cec (0) 4b79 (0)\n004 7 5d82 5ff0 5a8b 5ac0 | 10 5ff0 (0) 5d82 (0) 5c7c (0) 5c37 (0)\n005 2 5144 50c1 | 3 52a8 (0) 5144 (0) 50c1 (0)\n============ DEPTH: 6 ==========================================\n006 1 5538 | 1 5538 (0)\n007 0 | 0\n008 1 56ca | 1 56ca (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","private_key":"98f06aa013ffdc1dc622e6180a8b868dcb22f51d0e11dddc2994bd02016cd2d8","name":"node_56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","services":["bzz","pss"],"enable_msg_events":true,"port":39073},"up":true}},{"node":{"info":{"id":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","name":"node_19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","enode":"enode://25da9f823f6a53ece92ba5f5a8fd5f6e819defef89a1d3dca5ab85ea24f52320c59331446c7863ea2a9161b19c2d37abe3af6a9a6961ba1003d5783b6d35ac27@127.0.0.1:0","enr":"0xf88fb8406cdb82ce95d6e0c4222880a7cd7e50ca502bacad52f5afc7c4b72b8dbda35b466718ed4f8f11f2a4342a3f4e1aafefb6869ce7e77d94e6dc1901344e69a07bf80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10325da9f823f6a53ece92ba5f5a8fd5f6e819defef89a1d3dca5ab85ea24f52320","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"GeoKaF/E7dKYtzbceneMnsQ2LeN4h2kREF+puizpAgQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 19ea0a\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 d700 c272 f756 f1ed | 130 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n001 5 6d3c 68cb 7c7c 70f6 | 61 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n002 4 2e65 24f8 3938 32ff | 28 298a (0) 2a50 (0) 2c85 (0) 2c80 (0)\n003 4 046c 0d1c 0e80 0942 | 21 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n004 3 1686 1049 1070 | 7 140d (0) 1484 (0) 1784 (0) 1686 (0)\n005 3 1dc0 1dec 1fd0 | 3 1fd0 (0) 1dec (0) 1dc0 (0)\n006 3 1add 1bd5 1b1d | 3 1add (0) 1bd5 (0) 1b1d (0)\n============ DEPTH: 7 ==========================================\n007 1 18e0 | 1 18e0 (0)\n008 1 194e | 1 194e (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","private_key":"ac8b9e1b4cfbd81595b636bdadfff8bb5f50cd77c2d6dcb05ae20e8ec4c63c1d","name":"node_19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","services":["bzz","pss"],"enable_msg_events":true,"port":43067},"up":true}},{"node":{"info":{"id":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","name":"node_32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","enode":"enode://dc181c079cf6ec82d82772bc7ae94bffff7d8120914030631b14e2a1e91a2979c02e119f03635cdf5d3e001c2b0370eeb626c2aea142bcd446fcb9671a2503e1@127.0.0.1:0","enr":"0xf88fb84052f9b4ee198b6110c708f59268694515e9488cb46efc9f9be015665e9990c36d04f94605b4f0cabf5462667106ddae15421dc9edfc990e6517c0d59d90555f980183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dc181c079cf6ec82d82772bc7ae94bffff7d8120914030631b14e2a1e91a2979","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Mv8ZadkKqlqO0iYJaKjiusLRyuWXyQb5BJXx3F3n+NM=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 32ff19\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b659 c42e cf52 f305 | 130 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n001 3 43d4 5538 7895 | 61 4cec (0) 4d38 (0) 4d91 (0) 4b79 (0)\n002 4 0e80 0942 046c 19ea | 37 0e3b (0) 0e2b (0) 0e80 (0) 0cfc (0)\n003 8 2c80 2ddf 2e65 2fd2 | 11 298a (0) 2a50 (0) 2c85 (0) 2c80 (0)\n004 2 3980 3938 | 8 3f31 (0) 3c5b (0) 3cab (0) 3b02 (0)\n005 2 36b9 3411 | 3 3728 (0) 36b9 (0) 3411 (0)\n============ DEPTH: 6 ==========================================\n006 5 30fe 3051 31e1 31e6 | 5 31e1 (0) 31e6 (0) 3188 (0) 3051 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","private_key":"b1c850ed51e29dd00bfd57bfed2e5d99cc9f9631301bd8fd28164014f4d70f33","name":"node_32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","services":["bzz","pss"],"enable_msg_events":true,"port":45657},"up":true}},{"node":{"info":{"id":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","name":"node_7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","enode":"enode://a68c7f6ec8a1dcf423bc83c0b592ee6ceaae76d432cd461b10b26f7450cb6f9f444cc86d3d4c99242f12f40dee10f0afb1e72ebee5e1b366d9b8b5f9655f7113@127.0.0.1:0","enr":"0xf88fb8406b7afa5e6f4769c19841e7d3ba40ddbb85b498bb51aabc56a435c0f46703037f63cd6cb222e5da5d92df503476767da8fe86181a30ff028b09d6f045fa46e58c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a68c7f6ec8a1dcf423bc83c0b592ee6ceaae76d432cd461b10b26f7450cb6f9f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eJWyy5e0c/iJPMcKRCHg+L4cAzsnzXMPoTQ4t6jz/LU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7895b2\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 9f7d e0a0 f6c0 f756 | 130 ddb8 (0) da36 (0) dad0 (0) dbd4 (0)\n001 8 1b1d 1070 046c 2fd2 | 65 1784 (0) 1686 (0) 140d (0) 1484 (0)\n002 6 43d4 43c9 5814 50c1 | 35 4cec (0) 4d91 (0) 4d38 (0) 4b79 (0)\n003 3 6790 68cb 6d3c | 13 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n004 2 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 3 7d16 7ce7 7c7c | 5 7e47 (0) 7d16 (0) 7ce7 (0) 7c46 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 7933 79e5 | 2 7933 (0) 79e5 (0)\n008 1 7850 | 1 7850 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","private_key":"4e69a8b973ab817bc7714a637ec947dd608ee56d981c0d77f7c99a6aa5f6ac6c","name":"node_7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","services":["bzz","pss"],"enable_msg_events":true,"port":33345},"up":true}},{"node":{"info":{"id":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","name":"node_046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","enode":"enode://183b5b7be84ebacec7a72dc825fc12441895754ccc15e53f4aec88278bae9da625acc2a8ad692479985552cb9e2afa799a5d8915933fae79bc3c24a525beda63@127.0.0.1:0","enr":"0xf88fb840a134fc16f24fd19fc3b2f61ed683f8c65a6fca5513dd3c7d6aac3a81855ef1484bc3b37e5482fcecbcf469c07477e57fd0af25ae5ee67e1a07f9ba2b40a2f9330183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103183b5b7be84ebacec7a72dc825fc12441895754ccc15e53f4aec88278bae9da6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BGylQWXw3U1i/X2O6el8ZV2z019UUqDMsN/8ecBHl4w=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 046ca5\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 c272 c42e ef99 f756 | 130 ddb8 (0) dbd4 (0) da36 (0) dad0 (0)\n001 5 5987 50c1 5663 70f6 | 61 4cec (0) 4d38 (0) 4d91 (0) 4a95 (0)\n002 6 2fd2 244c 3938 3411 | 28 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n003 3 1b1d 19ea 1070 | 16 1784 (0) 1686 (0) 1484 (0) 140d (0)\n004 3 0e80 0d1c 0942 | 11 0e2b (0) 0e3b (0) 0e80 (0) 0cfc (0)\n005 5 0191 0111 012b 025d | 6 0191 (0) 0111 (0) 012b (0) 025d (0)\n006 1 07f5 | 1 07f5 (0)\n============ DEPTH: 7 ==========================================\n007 2 0594 0561 | 2 0561 (0) 0594 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","private_key":"bc2961c291d9547bc0a390f7c929583558824d7047195fcd2cb026be0c9e0509","name":"node_046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","services":["bzz","pss"],"enable_msg_events":true,"port":35721},"up":true}},{"node":{"info":{"id":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","name":"node_094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","enode":"enode://34b32e374d0cb1f5f1066e330600cb29a8c74400fa6b4e4cb7115a3ca378f605cba1434fceb05ce465f624ab6b77630026597000caea4bce2d96b3b6fb2508ad@127.0.0.1:0","enr":"0xf88fb84097508e3f96233a8a9233a357aa263237d1c15a1d3b78f6b535adbb51249f097b0ae9437277cdeda5fd8ac5416b37b3e9d769ae8802cf22908fd3ab751ecd035e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10334b32e374d0cb1f5f1066e330600cb29a8c74400fa6b4e4cb7115a3ca378f605","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CUJWgSCExgUqJgQUmqOrojecSDv07CUWL2tDk0lCd1o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 094256\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 9ca1 b659 | 130 ddb8 (0) da36 (0) dad0 (0) dbd4 (0)\n001 5 70f6 5814 5663 5538 | 61 4cec (0) 4d38 (0) 4d91 (0) 4b79 (0)\n002 5 244c 2fd2 3938 3411 | 28 298a (0) 2a50 (0) 2ddf (0) 2c85 (0)\n003 3 1070 1b1d 19ea | 16 1784 (0) 1686 (0) 140d (0) 1484 (0)\n004 2 025d 046c | 10 0191 (0) 0111 (0) 012b (0) 035f (0)\n005 3 0d1c 0e3b 0e80 | 5 0e2b (0) 0e3b (0) 0e80 (0) 0cfc (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 3 08bd 08e5 08f8 | 3 08bd (0) 08e5 (0) 08f8 (0)\n008 1 09b3 | 1 09b3 (0)\n009 0 | 0\n010 1 096a | 1 096a (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","private_key":"c5996d97ff53b644b9c191150d78304a45d9874040fb778ddc5bb65779d86bc8","name":"node_094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","services":["bzz","pss"],"enable_msg_events":true,"port":43233},"up":true}},{"node":{"info":{"id":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","name":"node_b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","enode":"enode://58735e5ecf597295cd19c074c7192858e890ceb98016f0e325cec4778d0218a9389a701caf242f4e40d8a3c9eb6b1f00a3174d7d2937fa28f16a12a8c78f9b18@127.0.0.1:0","enr":"0xf88fb84098020ea2d7d1fa04750b97764d931d2e91a9bd545f4d88bb37ca4bef38b7549a4c442d4f9a38ba4a8330780e9971528497eb7f33360afe06246098af41f622c20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10258735e5ecf597295cd19c074c7192858e890ceb98016f0e325cec4778d0218a9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tllBiIUDKQXqIK1H1wRw5APn5Afg6ev5J3+aLYHsEhw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b65941\npopulation: 22 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 32ff 19ea 0942 | 126 4d38 (0) 4d91 (0) 4cec (0) 482e (0)\n001 4 d700 cf52 e09f f305 | 55 ddb8 (0) da36 (0) dad0 (0) dbd4 (0)\n002 3 8358 9f7d 9c21 | 38 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n003 3 a8b5 a7a8 a1c8 | 23 acee (0) aeb4 (0) af02 (0) ab3f (0)\n004 4 ba91 bea1 bdc5 bcf8 | 8 b8e1 (0) bbaf (0) ba91 (0) bfc7 (0)\n005 1 b3f9 | 1 b3f9 (0)\n006 2 b5ea b4a1 | 2 b5ea (0) b4a1 (0)\n============ DEPTH: 7 ==========================================\n007 1 b78f | 1 b78f (0)\n008 1 b6df | 1 b6df (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","private_key":"6f63b7184c7a59615a5a9236a580d00b48d321b742cf81ae7310b20bc9f46f2f","name":"node_b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","services":["bzz","pss"],"enable_msg_events":true,"port":36979},"up":true}},{"node":{"info":{"id":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","name":"node_f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","enode":"enode://d218f0e8c660ea02f34733c763f5ded66b745176058a141d5c3bedb3485fcdedc87b59cd8d7a48a8fd21db93c553cead53a9ac4aaf2f033a3ab072c3d256c511@127.0.0.1:0","enr":"0xf88fb84016a186737b4c1ca5f0aea03b84f96ec62714e7e5da2d64be6b2440ac1c2748ed6fe3708f82254d114172bda4aa9b90e52648fdf8a4965407adcf8299ba7e616e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d218f0e8c660ea02f34733c763f5ded66b745176058a141d5c3bedb3485fcded","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8wUnOn0I5y9psLFThV6CLyUsu/NKGPMFE07tnR63tYo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f30527\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 19ea 046c 32ff 3938 | 126 4d38 (0) 4d91 (0) 4cec (0) 4b79 (0)\n001 2 9c21 b659 | 75 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n002 4 d700 cf52 c42e c272 | 27 ddb8 (0) d959 (0) d9cf (0) dad0 (0)\n003 4 e471 e2d3 ec90 ef99 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 4 f8ff fa24 ff75 fc39 | 7 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n005 3 f645 f6c0 f756 | 3 f645 (0) f6c0 (0) f756 (0)\n006 1 f1ed | 1 f1ed (0)\n============ DEPTH: 7 ==========================================\n007 2 f2b4 f215 | 2 f2b4 (0) f215 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","private_key":"39d3913d08835ee0310d15c086d9d2b5bdfe93c590ffeb6d94d0a053770a938a","name":"node_f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","services":["bzz","pss"],"enable_msg_events":true,"port":43471},"up":true}},{"node":{"info":{"id":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","name":"node_f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","enode":"enode://f20b87c432491558cc8aebd5ea9ee25b89c6f93f08f1dbfdd8f5ce5b442263099d8f903e2a82b4c31c15c24e3763f335643014c943dac9dba80bb99b2bf7fab7@127.0.0.1:0","enr":"0xf88fb84014f4b222ba6b5de9fd84dbf8714c734b2273549ffd1e5d785589072c106e628a1a8c4cf1ed22b0b33864347ed1d46b4a941e32a0d27b46c3bdb1af2f742acb3b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f20b87c432491558cc8aebd5ea9ee25b89c6f93f08f1dbfdd8f5ce5b44226309","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"91YctnQOF+x8fRcGglGyyVHZVMd4BKpa9gRk6cOWTlc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f7561c\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 5c37 5663 7895 046c | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 4 a8b5 a1c8 93c0 9c21 | 75 aeb4 (0) af02 (0) acee (0) ab3f (0)\n002 6 d700 c8ea cf52 cdb1 | 27 ddb8 (0) d959 (0) d9cf (0) da36 (0)\n003 6 e471 e277 e09f e867 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 6 f9de f8ff fa24 ff75 | 7 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n005 4 f1ed f2b4 f215 f305 | 4 f1ed (0) f2b4 (0) f215 (0) f305 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 f645 f6c0 | 2 f645 (0) f6c0 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","private_key":"ecae59b9fef453fa7d5352f8aa56d8af8ae96d6846b15e9aaff107d1031cdd4c","name":"node_f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","services":["bzz","pss"],"enable_msg_events":true,"port":45253},"up":true}},{"node":{"info":{"id":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","name":"node_9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","enode":"enode://437f633a70046ae9419cb2ddabf116dab0954965e968a6f007e228a7a7be8ce3d03010480c1b6e5d493d696d883920532e1bdb07b996dc70406fde018db10948@127.0.0.1:0","enr":"0xf88fb84021a7f662e426de82de76fe3fb5a9358593b06425d494639aaf2886f7d0cd4c2f09f3b746b5071fccca870524abebba751c338e44dd9c8af378c6f81bfa6b8b090183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102437f633a70046ae9419cb2ddabf116dab0954965e968a6f007e228a7a7be8ce3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nCHLPlb4rGankXqboU5Y936ZiscMF4uItQU9msJ3fmA=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9c21cb\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 50c1 3938 | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 9 cf52 c272 c42e e2d3 | 55 ddb8 (0) dad0 (0) da36 (0) dbd4 (0)\n002 7 a742 a616 a970 a8f4 | 37 af02 (0) aeb4 (0) acee (0) ab3f (0)\n003 7 8b43 8d19 8ea2 8073 | 21 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n004 3 955d 9257 93c0 | 8 97da (0) 9464 (0) 95c0 (0) 9518 (0)\n005 3 9959 9948 9b8e | 3 9959 (0) 9948 (0) 9b8e (0)\n006 3 9f0e 9f7d 9ec8 | 3 9ec8 (0) 9f0e (0) 9f7d (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 2 9c8e 9ca1 | 2 9c8e (0) 9ca1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","private_key":"7eef00d143ca4d22aa8920afb1093aeee46b08939a3cfefeab24e6465f3d7523","name":"node_9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","services":["bzz","pss"],"enable_msg_events":true,"port":45091},"up":true}},{"node":{"info":{"id":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","name":"node_f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","enode":"enode://1f605d05b467e52497e1862559e2ea806c76b9b68e4afb936b675a7afa72346881e26390a04e9afcda1a11fbefd20fd50c0762ce93772dac8c8498e6c301da9c@127.0.0.1:0","enr":"0xf88fb84092227639c78910be0212f1396d95453dd49c75961b2d39d43b6dbe94b6be413b25e0d6ae86588ec165a1c7881d660a1621459959cc457247cd1ab90403fbf3730183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021f605d05b467e52497e1862559e2ea806c76b9b68e4afb936b675a7afa723468","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8e2dRWIv+XSh45bNh4st64njGqXQjadzQj8pKujby7Y=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f1ed9d\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 5c37 50c1 5663 7895 | 126 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n001 6 b4a1 a7a8 a1c8 a327 | 75 acee (0) aeb4 (0) af02 (0) aaf0 (0)\n002 3 c8ea c42e c272 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 7 ef99 eb68 e681 e471 | 14 e64d (0) e681 (0) e471 (0) e277 (0)\n004 4 f9de feb3 ff75 fc39 | 7 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n005 3 f645 f6c0 f756 | 3 f645 (0) f6c0 (0) f756 (0)\n============ DEPTH: 6 ==========================================\n006 3 f2b4 f215 f305 | 3 f2b4 (0) f215 (0) f305 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","private_key":"43438f5d37cc4d101776db9c837b45c0348d0fb3ee2b4d66b66ea68193a67634","name":"node_f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","services":["bzz","pss"],"enable_msg_events":true,"port":42225},"up":true}},{"node":{"info":{"id":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","name":"node_3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","enode":"enode://d65c386d5a9eb699e325a7b173f89ced8caed9f813009e1949ae1c727decbb605d94eecc4f1b8733edb8dbd4c29d3b85d0de50abdab36072250f3de5cd28ac35@127.0.0.1:0","enr":"0xf88fb840eb07d284d45af49b9534f8d95e093e90eb86595cf13b63dab9984c6430a9ba0845a201ee9f0eaea3d91a875fba3a36474eebdebef6154e1227ce0f12d011b6f30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d65c386d5a9eb699e325a7b173f89ced8caed9f813009e1949ae1c727decbb60","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OTjmssCVCE3Jl1o+hkkTNVdJXTSsbfh0xtkpJm4//m8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3938e6\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9c21 bcf8 c42e f305 | 130 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n001 6 70f6 7895 5c37 5987 | 61 60c5 (0) 648a (0) 6758 (0) 67f3 (0)\n002 8 1070 138d 1dc0 1b1d | 37 1686 (0) 1784 (0) 1484 (0) 140d (0)\n003 4 2fd2 26ab 24f8 244c | 11 2a50 (0) 298a (0) 2c85 (0) 2c80 (0)\n004 5 36b9 3411 30fe 3051 | 9 3728 (0) 36b9 (0) 3411 (0) 3188 (0)\n005 2 3cab 3c5b | 3 3f31 (0) 3cab (0) 3c5b (0)\n006 2 3b02 3a62 | 2 3b02 (0) 3a62 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 3980 | 1 3980 (0)\n009 1 397a | 1 397a (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","private_key":"fbe0ae960205a2db352664d1d04b5bba8f4ba47cd2fe72d6ade101914a4ccaeb","name":"node_3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","services":["bzz","pss"],"enable_msg_events":true,"port":44129},"up":true}},{"node":{"info":{"id":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","name":"node_bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","enode":"enode://e6c340b1a3696a5038e4d658f970cac4bda141f463f92b1b44ee1cb7f7f6868ffdde7757ef00b0ff3b271a9a9ecc8ab2e5875c42cb87e496405bc922e6fa64d0@127.0.0.1:0","enr":"0xf88fb840c9a15fff14a8ea3abbc9aedcba9b73f5e824da4b1a9e08fcf571cab264f32d8e7a24034ff41cfab6ecfd8ac3d535031401c463fdbd7e54919a443452c29c81ae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e6c340b1a3696a5038e4d658f970cac4bda141f463f92b1b44ee1cb7f7f6868f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vPhez0Ibhx/KAkenCBGIqOLAh3i4j/rRbbN+8CT+wPw=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bcf85e\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 50c1 046c 3938 | 126 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n001 3 cf52 c272 ef99 | 55 ddb8 (0) dbd4 (0) dad0 (0) da36 (0)\n002 8 8ea2 8358 87a3 86d6 | 38 80d7 (0) 8073 (0) 8074 (0) 8006 (0)\n003 4 a970 a8b5 a7a8 a1c8 | 23 acee (0) aeb4 (0) af02 (0) ab3f (0)\n004 4 b3f9 b4a1 b6df b659 | 6 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n005 3 b8e1 bbaf ba91 | 3 b8e1 (0) bbaf (0) ba91 (0)\n============ DEPTH: 6 ==========================================\n006 3 be68 bea1 bfc7 | 3 bfc7 (0) be68 (0) bea1 (0)\n007 1 bdc5 | 1 bdc5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","private_key":"0e3de03ec47c112197b5ce9f4876cc7e0328950172cb9bdcdbf176c7b1e8f4ad","name":"node_bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","services":["bzz","pss"],"enable_msg_events":true,"port":40251},"up":true}},{"node":{"info":{"id":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","name":"node_ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","enode":"enode://a32bf13f4f87b1e4791889257bd457b480d36efd85c79fbdeafa0cd700b80d68203a12c8c8dc06bc7fe6784e017ed5beaf08fa18498f6b4a7014b292c79ad657@127.0.0.1:0","enr":"0xf88fb84090a9fff8d7f284263393a75dbe4c5ffa3baf41b98a66f2556dcceeba191c4f70370008eb731f510bf571448c132df27f82771b519fb3ad204ad2d0689fa0781d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a32bf13f4f87b1e4791889257bd457b480d36efd85c79fbdeafa0cd700b80d68","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"75m2zcBTRaHugiZ4kOPMru8fK9L+euiwK2sguaXvhbs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ef99b6\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 046c 50c1 | 126 298a (0) 2a50 (0) 2c85 (0) 2c80 (0)\n001 4 87a3 86d6 8358 bcf8 | 75 81a5 (0) 80d7 (0) 8006 (0) 8074 (0)\n002 4 d3e9 d700 c8ea c272 | 27 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n003 8 fa24 fc51 fc39 f1ed | 14 f8ff (0) f9de (0) fa24 (0) feb3 (0)\n004 6 e681 e471 e09f e0a0 | 7 e64d (0) e681 (0) e471 (0) e277 (0)\n005 2 eb68 e867 | 2 eb68 (0) e867 (0)\n006 2 ed42 ec90 | 2 ed42 (0) ec90 (0)\n============ DEPTH: 7 ==========================================\n007 1 eebd | 1 eebd (0)\n008 0 | 0\n009 1 eff2 | 1 eff2 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","private_key":"3831e217095e4b4c3136779fd48aa121431f6a092eb73e195733ff54b1173150","name":"node_ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","services":["bzz","pss"],"enable_msg_events":true,"port":44801},"up":true}},{"node":{"info":{"id":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","name":"node_c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","enode":"enode://58ac0bf5776e7efc0260166f939bfdf2dde78fe6180b3d8aa44837f05cec80d837921c8066f45d495bfbe49ffeeca03fe962b8a7da5ccab5317ea019d665218e@127.0.0.1:0","enr":"0xf88fb840478fb2b3a4ab8e3cd050916898983baa1a6896bd48d38cc281048c9f916b9e493bc8b5aa56c0c2fc28e8aec7f9fcb6b6245cbd205c39861c37f7980d982af09a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10258ac0bf5776e7efc0260166f939bfdf2dde78fe6180b3d8aa44837f05cec80d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wnKxL0Agrlsg49Kc0J3gP6AIjj7rXweqdyiymj6Q5oc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c272b1\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 1070 19ea 046c 50c1 | 126 140d (0) 1484 (0) 1784 (0) 1686 (0)\n001 3 bcf8 9c21 9ec8 | 75 af02 (0) aeb4 (0) acee (0) aaf0 (0)\n002 7 ff75 f6c0 f756 f305 | 28 f9de (0) f8ff (0) fa24 (0) feb3 (0)\n003 2 d3e9 d700 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 5 c9c3 c8ea cdb1 cc33 | 8 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n005 5 c6a8 c603 c74d c534 | 5 c6a8 (0) c603 (0) c74d (0) c534 (0)\n============ DEPTH: 6 ==========================================\n006 1 c190 | 1 c190 (0)\n007 0 | 0\n008 1 c2d0 | 1 c2d0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","private_key":"5ba984dd53fd38ef7d9f085d4d2f71bf5e57cebbcf57a991cdfc6f90de3bf1e2","name":"node_c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","services":["bzz","pss"],"enable_msg_events":true,"port":36391},"up":true}},{"node":{"info":{"id":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","name":"node_c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","enode":"enode://50c60560f3e788431adda5f3ee4a65d462996a8a36a801d446f2d7d9e5a2d6dbc87d22941f4533589788d323a941f0f70a6c9b3b8c70f9984c1493879b56a3d6@127.0.0.1:0","enr":"0xf88fb840b2c5ef4495d49d374e60fa0e85dc6a8e48f5004aebec4bc746bfae6c2fe8e1180e0ba56367464f0e396f9d98f8e999544031948efb5659f3f33130eee1e8bb230183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10250c60560f3e788431adda5f3ee4a65d462996a8a36a801d446f2d7d9e5a2d6db","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xC5kkoeUOe7s2ZONF/8oP9j18kIGkGylErTapIA7eLQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c42e64\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 08f8 046c 32ff 3938 | 126 140d (0) 1484 (0) 1686 (0) 1784 (0)\n001 2 9c21 9ec8 | 75 a5ac (0) a505 (0) a4ee (0) a742 (0)\n002 8 e2d3 e0a0 ff75 f6c0 | 28 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n003 4 dbd4 da36 d3e9 d700 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 4 c8ea cf52 cc33 cdb1 | 8 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n005 3 c190 c2d0 c272 | 3 c190 (0) c2d0 (0) c272 (0)\n============ DEPTH: 6 ==========================================\n006 3 c74d c6a8 c603 | 3 c74d (0) c6a8 (0) c603 (0)\n007 1 c534 | 1 c534 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","private_key":"49943ef9cb5cfe1f6f01ab1a1f9fa8d6de40a8c49ed24b1ae244aff5459c9da0","name":"node_c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","services":["bzz","pss"],"enable_msg_events":true,"port":36607},"up":true}},{"node":{"info":{"id":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","name":"node_f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","enode":"enode://914631182a42d1219b9b28e6b5da1bd8c08e539575c6a7a85fa1d4222e9dc5c26156834d4dda7260174a844f276747baf4fbb4c75d6497ed9fc55f1300ad99df@127.0.0.1:0","enr":"0xf88fb840799f4f4b2fd08a7f68922afcbc7694953e771f3d0bfb81ee89d9f3c15bd5750b6e7e379849906088a02b409e2c46ef95e0f2169d796e86b7082d85ec6b99114e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103914631182a42d1219b9b28e6b5da1bd8c08e539575c6a7a85fa1d4222e9dc5c2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8hW8CSaOYOu+x290O+vQnX5y1Mvu3AudNBe7Si70KTU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f215bc\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5c37 5538 50c1 | 126 2a50 (0) 298a (0) 2ddf (0) 2c80 (0)\n001 3 ba91 9c21 9ec8 | 75 af02 (0) aeb4 (0) acee (0) ab3f (0)\n002 4 d3e9 cc33 cdb1 c42e | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 9 e867 eb68 ef99 e471 | 14 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n004 3 f9de ff75 fc39 | 7 fa24 (0) f8ff (0) f9de (0) feb3 (0)\n005 3 f645 f6c0 f756 | 3 f645 (0) f6c0 (0) f756 (0)\n006 1 f1ed | 1 f1ed (0)\n============ DEPTH: 7 ==========================================\n007 1 f305 | 1 f305 (0)\n008 1 f2b4 | 1 f2b4 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","private_key":"1fed8e5946a97ef10fbabe578590010445e49851e010e422c67c268755300ba7","name":"node_f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","services":["bzz","pss"],"enable_msg_events":true,"port":46479},"up":true}},{"node":{"info":{"id":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","name":"node_50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","enode":"enode://7e0efcde01784575e4464fcd19486068e81004e45914861571c763aab72c40fd7de3be474040f71ccb0daa1d9bbb197140dad13d641b98fed6ffbc50b322e2d4@127.0.0.1:0","enr":"0xf88fb8402fd5df06a939249a9fd0804b4b2f40564565802cf963bde27cbc3f4504997ac970f523add3a785ca408dbf18c0de819dd1f6ae8b65c540fbafe08e578e5673c40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027e0efcde01784575e4464fcd19486068e81004e45914861571c763aab72c40fd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UMGoAjv+z/sJRy/cUImPTQUKMUQ9QKbAe2KQkL6w3z0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 50c1a8\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 10 bcf8 9c21 9ec8 c42e | 130 af02 (0) aeb4 (0) acee (0) aaf0 (0)\n001 4 046c 0942 0d1c 3938 | 65 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n002 3 70f6 7c7c 7895 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 5 46bf 43c9 4a95 48d7 | 19 402c (0) 4005 (0) 435d (0) 43d4 (0)\n004 7 5ff0 5d82 5c37 5c7c | 10 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n005 3 56ca 5663 5538 | 3 56ca (0) 5663 (0) 5538 (0)\n============ DEPTH: 6 ==========================================\n006 1 52a8 | 1 52a8 (0)\n007 1 5144 | 1 5144 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","private_key":"d0239dc44e8e56fc8a14b93a43280c425ab0988a63c4fa8d558b6b61b972ccbc","name":"node_50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","services":["bzz","pss"],"enable_msg_events":true,"port":35321},"up":true}},{"node":{"info":{"id":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","name":"node_cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","enode":"enode://e384773f94b9f4af8300be9d39cc581c8fd208e7fe459b0457b672457797b8c548dd064bb5361fcfc8587bf356c8499f98a5bd8b2271ffe616f070f8fe479178@127.0.0.1:0","enr":"0xf88fb8401939cbdd1ef26b61abcaf49b3902648650033c3decced5af79fdd44e154207b01ba84f8e62658f91e9386318c11267895180beaa28dec6fb4bbcd4355b6e733b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e384773f94b9f4af8300be9d39cc581c8fd208e7fe459b0457b672457797b8c5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"z1Kz/ILsJMPptASI18X3rIr3MdFZoQNhm+6TLsdNXpI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cf52b3\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 244c 32ff 50c1 | 126 298a (0) 2a50 (0) 2ddf (0) 2c80 (0)\n001 4 bcf8 b659 9c21 9ec8 | 75 a4ee (0) a505 (0) a5ac (0) a742 (0)\n002 8 ff75 f305 f6c0 f756 | 28 f9de (0) f8ff (0) fa24 (0) feb3 (0)\n003 4 dbd4 d700 d408 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dad0 (0)\n004 6 c603 c42e c534 c190 | 8 c190 (0) c2d0 (0) c272 (0) c74d (0)\n005 4 c961 c9c3 c8c8 c8ea | 4 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n============ DEPTH: 6 ==========================================\n006 3 cd6c cdb1 cc33 | 3 cc33 (0) cd6c (0) cdb1 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","private_key":"53a2e6b259e67e80a322fb0917b85f97860e8d37711d29f1964170d6b45d30cf","name":"node_cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","services":["bzz","pss"],"enable_msg_events":true,"port":36313},"up":true}},{"node":{"info":{"id":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","name":"node_e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","enode":"enode://a1889a38f3b1e9100f7626ad54d9622d503f7b1a9014ec13cd5215336196fc7bf27333448336381ec7c86db4006d245abb48c0f58940760bbb9deba79ca40c98@127.0.0.1:0","enr":"0xf88fb840aa1a2025c453351a72aae064d06aea3bd2d1804bd65cef80301c79f24934fbf94a35606db5f3a38a983d33c340db4c1f4c573ccf0b492159aa9bea1e78b3c8bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a1889a38f3b1e9100f7626ad54d9622d503f7b1a9014ec13cd5215336196fc7b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4J+YEU2mTnVHs1FjcZD2YhofdVaM+plgmA/Hdhj4hVs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e09f98\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0d1c 5987 5538 | 126 298a (0) 2a50 (0) 2c80 (0) 2c85 (0)\n001 6 a8b5 b659 ba91 93c0 | 75 a4ee (0) a505 (0) a5ac (0) a606 (0)\n002 2 c534 cf52 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 3 f756 f1ed f215 | 14 fa24 (0) f8ff (0) f9de (0) feb3 (0)\n004 5 e867 eb68 ec90 eebd | 7 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n005 3 e64d e681 e471 | 3 e64d (0) e681 (0) e471 (0)\n============ DEPTH: 6 ==========================================\n006 2 e277 e2d3 | 2 e277 (0) e2d3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 e0a0 | 1 e0a0 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","private_key":"0c21558e199ac8f8279ccba752dfce4a160302de5147dcf00d462d131b117293","name":"node_e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","services":["bzz","pss"],"enable_msg_events":true,"port":36519},"up":true}},{"node":{"info":{"id":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","name":"node_e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","enode":"enode://811ff91b658315c4fe2d501370f6e0a5c2a4e87fd7705b110ffd9f5b560a6cbf6a57694806e4a1371ae4ac682b8ef5eb4948f3f8798bde7bae62478ce8b29187@127.0.0.1:0","enr":"0xf88fb840a4ca41dc96fb07375e8655b138b07ef3e43a3cd6824b9b03a1bfbfd5dbffe8514a9522377d1e78474799dd1121831879798540a60453e10b5808f881eb4c12ec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103811ff91b658315c4fe2d501370f6e0a5c2a4e87fd7705b110ffd9f5b560a6cbf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4tNvM12QrWMUjbjjU6eKMNjZwKvhB74s+GhfagHOdLk=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e2d36f\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 70f6 50c1 5987 0d1c | 126 2a50 (0) 298a (0) 2ddf (0) 2c80 (0)\n001 3 a8b5 9c21 9ec8 | 75 a5ac (0) a505 (0) a4ee (0) a742 (0)\n002 3 c42e c534 cf52 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 5 ff75 f6c0 f1ed f305 | 14 fa24 (0) f8ff (0) f9de (0) feb3 (0)\n004 4 e867 eb68 ec90 ef99 | 7 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n005 3 e64d e681 e471 | 3 e64d (0) e681 (0) e471 (0)\n============ DEPTH: 6 ==========================================\n006 2 e0a0 e09f | 2 e0a0 (0) e09f (0)\n007 0 | 0\n008 1 e277 | 1 e277 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","private_key":"85e06d183c4f5bd671a46232c0f291076bda62d6d879496e84ae6c378d966174","name":"node_e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","services":["bzz","pss"],"enable_msg_events":true,"port":39311},"up":true}},{"node":{"info":{"id":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","name":"node_9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","enode":"enode://4dd9a25575645b97012af13c2b562b1fdfc4444922998e1d08ac31e94030800ec40d6c48d4f3fd76c25ed0882398d9620390cbad7c72618375520f348552e966@127.0.0.1:0","enr":"0xf88fb8408fa9c2bc6983316b1331a0fbc8cd6fdb72a55deec652bdb9de328b24b60e78c51aca35ac84c776df03949c9a90e376a21a4e15f4b334551da12477a8eb16cd470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024dd9a25575645b97012af13c2b562b1fdfc4444922998e1d08ac31e94030800e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nsgx2XQYkW/ZaVRl4EHK8ngk27Udb/dNa3DzvVYecOY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9ec831\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0d1c 70f6 5987 50c1 | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 7 c42e c272 cdb1 cf52 | 55 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n002 3 a1c8 ba91 bcf8 | 37 a5ac (0) a505 (0) a4ee (0) a742 (0)\n003 8 8b43 8ea2 8d19 8358 | 21 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n004 4 955d 9518 9464 93c0 | 8 97da (0) 95c0 (0) 9518 (0) 955d (0)\n005 3 9b8e 9959 9948 | 3 9b8e (0) 9959 (0) 9948 (0)\n006 3 9c8e 9ca1 9c21 | 3 9c8e (0) 9ca1 (0) 9c21 (0)\n============ DEPTH: 7 ==========================================\n007 2 9f7d 9f0e | 2 9f0e (0) 9f7d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","private_key":"1448c304f2af7e48ae443402703fb0a3b1e1f2d2bfef6a6456141daa73c558f6","name":"node_9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","services":["bzz","pss"],"enable_msg_events":true,"port":46859},"up":true}},{"node":{"info":{"id":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","name":"node_553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","enode":"enode://f82e099fec04ce2be67700e463707728eb144ee2a7cf821945ec03d4b8166298749bed9860b4348e5a202bd5bff1957dc60d943fbf065aeed536e8baa6e18492@127.0.0.1:0","enr":"0xf88fb840f8de9483b97759f1daf327a569a475175e424a75efbc3654978adf85d062bc605b9880637ca11a772ac5e122d91c1acf3f95096d0ceea3935048f40ac35b28990183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f82e099fec04ce2be67700e463707728eb144ee2a7cf821945ec03d4b8166298","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VTgk73AdPNAZGuOmfeVk7Qz1U+dL1g7Z3jIfkwJzK6Y=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 553824\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f215 e09f 9ec8 | 130 fa24 (0) f9de (0) f8ff (0) fc51 (0)\n001 5 30fe 32ff 3938 0942 | 65 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n002 5 6790 70f6 7895 7ce7 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 7 4a95 48d7 48f1 48b8 | 19 4d38 (0) 4d91 (0) 4cec (0) 4b79 (0)\n004 8 5ff0 5d82 5c37 5c7c | 10 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n005 3 52a8 5144 50c1 | 3 52a8 (0) 5144 (0) 50c1 (0)\n============ DEPTH: 6 ==========================================\n006 2 56ca 5663 | 2 56ca (0) 5663 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","private_key":"cf91bb0fea150fbf8705d939da029fdefebdd1076d1f645864e8d53e99501f66","name":"node_553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","services":["bzz","pss"],"enable_msg_events":true,"port":36171},"up":true}},{"node":{"info":{"id":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","name":"node_0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","enode":"enode://8963c10c3899dce73c253820c99702353f5b64a1fcd1e94e3c60e8fa36a84d51e3155fe96a087599495c893da0da9d41148ab85235b65124f03236d23543e0eb@127.0.0.1:0","enr":"0xf88fb8404dcbbcadbab5ddfd4e10d68ffabb6b5c5038e323a062c9153dcb26b97422e6dc051d2044717c22e8f9279c57776cf04de0184acc5b55f05525303d87739498fb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038963c10c3899dce73c253820c99702353f5b64a1fcd1e94e3c60e8fa36a84d51","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DRw1xupIXLM4V7eQ7iYvl0zw1Uz4zjAD+DCKwuh8LCU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d1c35\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 e09f e2d3 c8ea cdb1 | 130 a4ee (0) a5ac (0) a505 (0) a742 (0)\n001 5 7c7c 70f6 5987 50c1 | 61 6e7f (0) 6c01 (0) 6dd3 (0) 6d5e (0)\n002 4 244c 3938 3411 30fe | 28 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n003 6 19ea 1b1d 1dc0 1784 | 16 140d (0) 1484 (0) 1686 (0) 1784 (0)\n004 3 035f 025d 046c | 10 0191 (0) 0111 (0) 012b (0) 025d (0)\n005 4 0942 08bd 08f8 08e5 | 6 08bd (0) 08f8 (0) 08e5 (0) 09b3 (0)\n============ DEPTH: 6 ==========================================\n006 3 0e80 0e2b 0e3b | 3 0e80 (0) 0e2b (0) 0e3b (0)\n007 1 0cfc | 1 0cfc (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","private_key":"ef22b9afd09135d969cbfaa3c7f02beacec87dc03fc514f0565a8fdee536fab4","name":"node_0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","services":["bzz","pss"],"enable_msg_events":true,"port":40431},"up":true}},{"node":{"info":{"id":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","name":"node_59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","enode":"enode://7720368c45d12af9a222ed1304cec25526c3f521dc8bdbdad1a966ab1b0bd4169a905fe56bec7845f8be9ddb4a1302c8c13d61273415db4ae840c8662272be45@127.0.0.1:0","enr":"0xf88fb84034abc65244d703a8f51ccf0ea8c8099e02c759dbf7c0b19434d08a4c72e9836629a6c3f2dad2881e6e85fc9aade07106ee0fbd25d2d04233ee4cbe90748a1ef10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037720368c45d12af9a222ed1304cec25526c3f521dc8bdbdad1a966ab1b0bd416","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WYduf/npIkOFba0jEm4dONml3a55dy7Rsr25HzOkpLU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 59876e\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9ec8 e09f e2d3 cdb1 | 130 a4ee (0) a5ac (0) a505 (0) a7a8 (0)\n001 4 30fe 3938 046c 0d1c | 65 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n002 2 7c7c 70f6 | 26 6b4e (0) 68cb (0) 6e7f (0) 6c01 (0)\n003 4 4a95 48b8 48f1 48d7 | 19 46bf (0) 447c (0) 447a (0) 44ad (0)\n004 4 52a8 50c1 5663 5538 | 6 52a8 (0) 5144 (0) 50c1 (0) 56ca (0)\n005 2 5c37 5c7c | 4 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n============ DEPTH: 6 ==========================================\n006 4 5a8b 5ac0 5a26 5bd8 | 4 5a8b (0) 5ac0 (0) 5a26 (0) 5bd8 (0)\n007 1 5814 | 1 5814 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","private_key":"d68e5f6712ad13a5f18afe7ea604194bc75d700d868489882a6d439f62d3319f","name":"node_59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","services":["bzz","pss"],"enable_msg_events":true,"port":43863},"up":true}},{"node":{"info":{"id":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","name":"node_c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","enode":"enode://ed050956c10a60194bdfcc79bc927b7864a5ccd487521a7764441e4146defd9147ba153983e148a136ae5bde225df9eec974f956dcbd4c837b61013ce32a13fb@127.0.0.1:0","enr":"0xf88fb840d1ba87a7f202b2d69d25fe1c48a6386c6e96f4b473922d59cebadff7c92d58b528bf3e59e6f57acb30587ce613e1bb64b9f483d837420b47e669533583256c650183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ed050956c10a60194bdfcc79bc927b7864a5ccd487521a7764441e4146defd91","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xTQX8AjkVQ4cTLmj4pVbOvZAPgWbe0tMM4adntSlgKU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c53417\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 2c85 2c80 2fd2 244c | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 5 a1c8 ba91 8358 87a3 | 75 a4ee (0) a505 (0) a5ac (0) a742 (0)\n002 4 f6c0 e471 e09f e2d3 | 28 f8ff (0) f9de (0) fa24 (0) ff75 (0)\n003 4 da36 ddb8 d700 d3e9 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 3 c8ea cf52 cdb1 | 8 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n005 3 c190 c2d0 c272 | 3 c190 (0) c2d0 (0) c272 (0)\n============ DEPTH: 6 ==========================================\n006 3 c74d c6a8 c603 | 3 c74d (0) c6a8 (0) c603 (0)\n007 1 c42e | 1 c42e (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","private_key":"a4ea2b639e280337e8009d2b54e9a11f76f523e1ef1ba9619f03ba35ee15abd8","name":"node_c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","services":["bzz","pss"],"enable_msg_events":true,"port":39971},"up":true}},{"node":{"info":{"id":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","name":"node_cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","enode":"enode://c272080f38dac498765747523f4926457465e2941b3ddc08b62aa1affedc7f8e16f0e038d1a474ff133dfbbfc366fe750e99c2b75a184d40debca8913add7f88@127.0.0.1:0","enr":"0xf88fb840b2235f35efc093f6baac2bfe925b6f021eb803ca0488b4174d2a7ecc21921e124f99929c0f151ebdb9472db8350ab836dba4759f9aa6aad06a78f9c3bed45f7c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c272080f38dac498765747523f4926457465e2941b3ddc08b62aa1affedc7f8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zbE4c6wFiGHylevKXZWL8rt5Pj+eJ0z1pzpjNCWpJ28=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cdb138\npopulation: 26 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 08f8 0d1c 5987 70f6 | 126 2ddf (0) 2c80 (0) 2c85 (0) 2e65 (0)\n001 5 9ec8 8ea2 8358 ba91 | 75 a5ac (0) a505 (0) a4ee (0) a742 (0)\n002 3 e471 f756 f215 | 28 f8ff (0) f9de (0) fa24 (0) fc51 (0)\n003 3 da36 d3e9 d700 | 11 ddb8 (0) d959 (0) d9cf (0) dbd4 (0)\n004 4 c2d0 c272 c42e c534 | 8 c190 (0) c2d0 (0) c272 (0) c74d (0)\n005 4 c961 c9c3 c8c8 c8ea | 4 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n006 1 cf52 | 1 cf52 (0)\n============ DEPTH: 7 ==========================================\n007 1 cc33 | 1 cc33 (0)\n008 1 cd6c | 1 cd6c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","private_key":"276e93bd6b53db81cd162f42fb634b4f3910e6d45ec7079c645a69e4bb5afca8","name":"node_cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","services":["bzz","pss"],"enable_msg_events":true,"port":45371},"up":true}},{"node":{"info":{"id":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","name":"node_70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","enode":"enode://8f535591758ee98b2ac41582a7d8642366706bd60b1e98b68f9a4019f653977b5d0973cee6fff3ec29c71ad9699d7e456f0ce29a85517f76f9876fdb6ff30a1d@127.0.0.1:0","enr":"0xf88fb840b1187ebcb96b2d46f5160c07357e2fb4ea69464366c7db75aacaa3b5c296724b5eff7e0985615cc94bf3aa4fe85bfaed822dd031b5d5b00e56937de9f27d922b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038f535591758ee98b2ac41582a7d8642366706bd60b1e98b68f9a4019f653977b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cPaFYnM9pOOxw5SftuEawL3UnqfnMpJfk3+H31r2mNY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 70f685\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 9ec8 8ea2 e2d3 e471 | 130 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n001 8 2fd2 3938 3411 30fe | 65 298a (0) 2a50 (0) 2ddf (0) 2c80 (0)\n002 5 48d7 48b8 5538 50c1 | 35 46bf (0) 44ad (0) 447c (0) 447a (0)\n003 6 6790 60c5 6dd3 6d5e | 13 6e7f (0) 6c01 (0) 6dd3 (0) 6d5e (0)\n004 6 7933 79e5 7895 7d16 | 9 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 7660 741a | 2 7660 (0) 741a (0)\n006 0 | 0\n007 0 | 0\n008 1 7049 | 1 7049 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","private_key":"0e58ed0a2b5955aa47fe1c7b185856a83cdf3966967becea9ac671a883a80100","name":"node_70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","services":["bzz","pss"],"enable_msg_events":true,"port":38721},"up":true}},{"node":{"info":{"id":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","name":"node_e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","enode":"enode://a39dec81162f336a51198d012a49706e42117ca42cf3d483d9ac74f65e01eab80f2164489ad2fffb217106e4f1e877d3ff2653643519569aa3f6b44becffccc7@127.0.0.1:0","enr":"0xf88fb8403f1d47db38a57c5f187e93e73913d7d9164793ebf66aa94e6e1eb9bec7be36de323d165610bbdde527989f06ff19902a0d7e342985034c0d1798277c0f9dd2ee0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a39dec81162f336a51198d012a49706e42117ca42cf3d483d9ac74f65e01eab8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5HHvvPHe85FbPdotxlqGlFxge+VKM+MeliVUm+ysDjQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e471ef\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 30fe 70f6 | 126 2a50 (0) 298a (0) 2ddf (0) 2c85 (0)\n001 2 ba91 8ea2 | 75 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n002 7 d3e9 c2d0 c534 cdb1 | 27 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n003 7 feb3 fc39 f756 f6c0 | 14 f9de (0) f8ff (0) fa24 (0) feb3 (0)\n004 4 eb68 e867 ec90 ef99 | 7 e867 (0) eb68 (0) ed42 (0) ec90 (0)\n005 4 e277 e2d3 e0a0 e09f | 4 e0a0 (0) e09f (0) e277 (0) e2d3 (0)\n============ DEPTH: 6 ==========================================\n006 2 e64d e681 | 2 e64d (0) e681 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","private_key":"8e34bf0af71dad627841518807b1d0dd56349eafd2c3b416704905a478f24628","name":"node_e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","services":["bzz","pss"],"enable_msg_events":true,"port":33051},"up":true}},{"node":{"info":{"id":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","name":"node_8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","enode":"enode://7efcc0a5b110a3d47e6b3e9b74e485a18770d757efb293ac544941a244e1764eef9534fb52dd16769014c5d3591266da5d6816885513985fd4d9eb1ff29225b2@127.0.0.1:0","enr":"0xf88fb840af3e7481de1a628caeff3e925e26c7ec284791874d83ca00a34365321e53458a61c6d4e0dd1e3a7e816d3ba5b038820ca851aae32ea491173f4a090486d1a1440183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027efcc0a5b110a3d47e6b3e9b74e485a18770d757efb293ac544941a244e1764e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jqLIrMER841bSl7WAlLug/MS0Pg1kmXVuSZtVHNQUv4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8ea2c8\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 0d1c 30fe 70f6 7c7c | 126 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n001 3 cdb1 c534 e471 | 55 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n002 6 a8b5 a8f4 a616 bcf8 | 37 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n003 6 93c0 9257 9464 9ec8 | 17 97da (0) 95c0 (0) 955d (0) 9518 (0)\n004 7 84a9 8402 87a3 86d6 | 12 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n005 2 8862 8b43 | 3 8854 (0) 8862 (0) 8b43 (0)\n006 2 8d19 8cc3 | 2 8cc3 (0) 8d19 (0)\n007 1 8f9a | 1 8f9a (0)\n============ DEPTH: 8 ==========================================\n008 2 8e28 8e7b | 2 8e28 (0) 8e7b (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","private_key":"c77c425da926ed3f45911d96e5d2ed01784a1e16987bbf8049d8c2b9a37eab26","name":"node_8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","services":["bzz","pss"],"enable_msg_events":true,"port":45075},"up":true}},{"node":{"info":{"id":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","name":"node_8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","enode":"enode://a6221058c98285416177d220a2f3ad4f8fad14bb72b226b6eca678a156da263ca8026a756a1e54ac812e6cf9db5279df4616c839b8d1d1f19a158783fcca1ad4@127.0.0.1:0","enr":"0xf88fb840c04a30337e262366540d7c35ecd07ff64b9083fd1f2b5195c205fda603295a375950c2ab3c8ab2fb2494ed5ca1346133fa181d56577a6918d49941fdaaed2cec0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a6221058c98285416177d220a2f3ad4f8fad14bb72b226b6eca678a156da263c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"g1inT8jY45zMQLTTohK3pppqj2r8Jc/yyce0S7r57II=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8358a7\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0d1c 1dc0 7c7c | 126 140d (0) 1484 (0) 1686 (0) 1784 (0)\n001 4 ef99 c534 cdb1 c8ea | 55 fa24 (0) f9de (0) f8ff (0) fc51 (0)\n002 4 b659 bcf8 bdc5 a8b5 | 37 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n003 5 9ec8 9c21 9464 9257 | 17 97da (0) 95c0 (0) 955d (0) 9518 (0)\n004 5 8862 8b43 8d19 8e7b | 9 8854 (0) 8862 (0) 8b43 (0) 8cc3 (0)\n005 4 84a9 8402 87a3 86d6 | 4 84a9 (0) 8402 (0) 86d6 (0) 87a3 (0)\n006 5 80d7 8006 8074 8073 | 5 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 837f | 1 837f (0)\n011 1 834f | 1 834f (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","private_key":"39642ed937f1adee6d9034810e644cf755f21dc9f06efda6535d19c78001af83","name":"node_8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","services":["bzz","pss"],"enable_msg_events":true,"port":32777},"up":true}},{"node":{"info":{"id":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","name":"node_a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","enode":"enode://6a681a2c60f7c7e2a832251ea4b54c1e7a75f5299e7a9bd343b3a8e6f147b41eb91a7fe95bd24adb2928b69018edf9eb146c92314b9d42964758449f767fb17a@127.0.0.1:0","enr":"0xf88fb84077f8314567599da083128579bdb43586da96cdd21d570ae4272c4a643ae5ef8d7bcc874624ab16e56b638270bf85aaabe97221c96f69bb9a7c487d9ad3c407880183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a681a2c60f7c7e2a832251ea4b54c1e7a75f5299e7a9bd343b3a8e6f147b41e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qLWAE/+RGHHRqmwrvqbC5u+bALh7gKQdwEckrQSI4v8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a8b580\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 138d 1dc0 0d1c 7c7c | 126 1686 (0) 1784 (0) 140d (0) 1484 (0)\n001 5 f756 e2d3 e09f cdb1 | 55 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n002 7 9c21 93c0 9464 8ea2 | 38 97da (0) 95c0 (0) 955d (0) 9518 (0)\n003 5 b659 ba91 bea1 bcf8 | 14 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n004 4 a616 a742 a7a8 a1c8 | 13 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n005 3 acee af02 aeb4 | 3 af02 (0) aeb4 (0) acee (0)\n006 3 ab3f ab71 aaf0 | 3 ab3f (0) ab71 (0) aaf0 (0)\n007 1 a970 | 1 a970 (0)\n============ DEPTH: 8 ==========================================\n008 0 | 0\n009 2 a8ff a8f4 | 2 a8ff (0) a8f4 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","private_key":"8e39367b51358d04e71f5883ad1dbd70eee27b4ef493509df2377fbce04ad168","name":"node_a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","services":["bzz","pss"],"enable_msg_events":true,"port":33233},"up":true}},{"node":{"info":{"id":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","name":"node_7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","enode":"enode://57465744f0e2ac055f9d29be31e53d6939f20a6038e2c66834a7967ecc44341d90aa115fb5255fd137271f992d89629cbf514bbbd904c9b935e2068f22852fab@127.0.0.1:0","enr":"0xf88fb840b9d47b0a5d48db8adef386ac49f3dc8c9eb545bdd756d6d1ab18b92b1299e94a295d530c29791eaa0942296992e5b5e2de9b435fd1b0c1b9267fa049259b2a120183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10357465744f0e2ac055f9d29be31e53d6939f20a6038e2c66834a7967ecc44341d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fHylp1IqBPYvK+vWGXoD148lXQF1w9/OtdkraENlsqo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7c7ca5\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c8ea 8ea2 8358 a8b5 | 130 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n001 5 0d1c 19ea 1dc0 2fd2 | 65 1686 (0) 1784 (0) 140d (0) 1484 (0)\n002 4 5bd8 5987 50c1 5538 | 35 402c (0) 4005 (0) 435d (0) 43c9 (0)\n003 5 6d3c 6c01 648a 6795 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 4 7660 741a 7049 70f6 | 4 741a (0) 7660 (0) 7049 (0) 70f6 (0)\n005 3 79e5 7850 7895 | 4 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n006 1 7e47 | 1 7e47 (0)\n007 1 7d16 | 1 7d16 (0)\n============ DEPTH: 8 ==========================================\n008 1 7ce7 | 1 7ce7 (0)\n009 0 | 0\n010 1 7c46 | 1 7c46 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","private_key":"06b02c6e2c9d37cd4b50dedfe3e86594cbfd243d764ed379df53eb3392911dda","name":"node_7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","services":["bzz","pss"],"enable_msg_events":true,"port":37295},"up":true}},{"node":{"info":{"id":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","name":"node_c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","enode":"enode://585e9760962e0f911be40a1a465b83c6ad84f45a4e2b2f9e06640352970e28cd99d8e407c455e5e265f9bda6cd4b542223ff8c8bdc4964ea89d72298640b1284@127.0.0.1:0","enr":"0xf88fb840654b3875a2b357e41fb9bacc6e4de76b7aa6d3718a157dcb098ca478b61e9a350c90fb9a21b15df60c21decd1c97d75a9c0bde7641cde5b3736d54ea855f1cae0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102585e9760962e0f911be40a1a465b83c6ad84f45a4e2b2f9e06640352970e28cd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"yOpBd0IHhZJuCSlwH150x0SSA4bypDuJ2DyCgRBsuV4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c8ea41\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 30fe 08f8 0d1c 1dc0 | 126 1686 (0) 1784 (0) 140d (0) 1484 (0)\n001 6 ba91 a8b5 8b43 8358 | 75 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n002 5 ff75 f1ed f756 ef99 | 28 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n003 3 da36 d700 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n004 5 c534 c42e c190 c2d0 | 8 c190 (0) c2d0 (0) c272 (0) c74d (0)\n005 4 cf52 cd6c cdb1 cc33 | 4 cf52 (0) cc33 (0) cd6c (0) cdb1 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 2 c961 c9c3 | 2 c961 (0) c9c3 (0)\n008 0 | 0\n009 0 | 0\n010 1 c8c8 | 1 c8c8 (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","private_key":"00c912a815d056b04de18334e53d8facff8ea04075ae869401191b0c74503fe2","name":"node_c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","services":["bzz","pss"],"enable_msg_events":true,"port":44523},"up":true}},{"node":{"info":{"id":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","name":"node_87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","enode":"enode://7f46de8585a9766537267742cba2418426c637ca4c1973bac22d320ab3a432ed5e835edc53e2ab828ffd47c66137875d3b05da6577d637ab13bce3866fba58ef@127.0.0.1:0","enr":"0xf88fb840e4762001029c0140b891c3b53ef932dd40e210cccfd3fb490876ce81ae5275d766e2714b415a03bfc54f11d0392862d70f600927e39c35361191a937267f86c70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037f46de8585a9766537267742cba2418426c637ca4c1973bac22d320ab3a432ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"h6M3YiRVrmXa86slVc7omF6aoUusJFVF2YUpYGDkqN4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 87a337\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 5c7c 30fe | 126 43c9 (0) 43d4 (0) 435d (0) 402c (0)\n001 3 ef99 c534 c8ea | 55 fa24 (0) f8ff (0) f9de (0) fc51 (0)\n002 4 a8b5 bcf8 bdc5 ba91 | 37 a327 (0) a330 (0) a2e6 (0) a2a1 (0)\n003 6 9464 9257 93c0 9c21 | 17 9b8e (0) 9948 (0) 9959 (0) 9ca1 (0)\n004 3 8b43 8d19 8ea2 | 9 8854 (0) 8862 (0) 8b43 (0) 8cc3 (0)\n005 7 837f 8358 81a5 80d7 | 8 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n============ DEPTH: 6 ==========================================\n006 2 84a9 8402 | 2 84a9 (0) 8402 (0)\n007 1 86d6 | 1 86d6 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","private_key":"0e812f155b3fec855e829701b7616d3bdc18fe020e679796ff10b79f74fce66a","name":"node_87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","services":["bzz","pss"],"enable_msg_events":true,"port":39229},"up":true}},{"node":{"info":{"id":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","name":"node_30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","enode":"enode://2d755da5dfdc21d6f3961f2beaab5613c412abd44276d5d050ef451b9bafb084a6afd797665c74c3ae6c0a33a52abf6c04504fd80a7fdd34ad91ffc3c671faae@127.0.0.1:0","enr":"0xf88fb8407a7294535524363392f62b42a82b13c5cfdfbc7e9e3710c54300cd606d41411000d4e002440679ca9f24fa5c4d8893f09f513ccde4545fa8b80580d1f46bf9360183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022d755da5dfdc21d6f3961f2beaab5613c412abd44276d5d050ef451b9bafb084","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MP7KYx8GBByxTOrThN+qX/+m3DSwzuVCMO++FeVqWIQ=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 30feca\npopulation: 36 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c8ea e471 ba91 8ea2 | 130 f9de (0) f8ff (0) fa24 (0) fc51 (0)\n001 8 48d7 5538 5bd8 5987 | 61 435d (0) 43c9 (0) 43d4 (0) 402c (0)\n002 8 046c 012b 025d 035f | 37 07f5 (0) 0561 (0) 0594 (0) 046c (0)\n003 3 2c85 244c 26ab | 11 2a50 (0) 298a (0) 2fd2 (0) 2e65 (0)\n004 4 3c5b 3938 3b02 3a62 | 8 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n005 3 36b9 3728 3411 | 3 36b9 (0) 3728 (0) 3411 (0)\n006 1 32ff | 1 32ff (0)\n============ DEPTH: 7 ==========================================\n007 3 3188 31e6 31e1 | 3 3188 (0) 31e6 (0) 31e1 (0)\n008 1 3051 | 1 3051 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","private_key":"0089202cbcad4ef35d5c4c18ac7f67f68b5c9f00a9ab8d1b7bfd57334bf95d95","name":"node_30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","services":["bzz","pss"],"enable_msg_events":true,"port":35121},"up":true}},{"node":{"info":{"id":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","name":"node_ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","enode":"enode://7a6e6ee730715ba07c013afa4adfa96b44af80ca9127d218d82b85f8f9a0f0d33a8650d3a482ab78523d91c1cf526d88087a2b352298ee29c2b060520436b2a5@127.0.0.1:0","enr":"0xf88fb84097647754d54945eb66061b25a00288c9cc9759b1b244c15785469f43e3cb3a1b0446356d42248da85d3b151c9d6ce61a9a8627dd5b6478e8e196150f8bf2b7ad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037a6e6ee730715ba07c013afa4adfa96b44af80ca9127d218d82b85f8f9a0f0d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"upERddOqP8wmbipaoy+3BiCLiptQIaXzfAuF9UfrN10=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ba9111\npopulation: 38 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 48f1 4a95 4b79 44ad | 126 435d (0) 43c9 (0) 43d4 (0) 402c (0)\n001 9 f215 e09f e471 d3e9 | 55 f8ff (0) f9de (0) fa24 (0) fc51 (0)\n002 5 9464 9ec8 8ea2 87a3 | 38 9b8e (0) 9948 (0) 9959 (0) 9ca1 (0)\n003 8 acee a970 a8b5 aaf0 | 23 a330 (0) a327 (0) a2a1 (0) a2e6 (0)\n004 3 b3f9 b5ea b659 | 6 b3f9 (0) b5ea (0) b4a1 (0) b78f (0)\n005 4 bfc7 bea1 bcf8 bdc5 | 5 bfc7 (0) be68 (0) bea1 (0) bcf8 (0)\n============ DEPTH: 6 ==========================================\n006 1 b8e1 | 1 b8e1 (0)\n007 1 bbaf | 1 bbaf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","private_key":"455cfde9eb8d35e128fc05e1b1e697250397c4baa4d0609935427370e67e9567","name":"node_ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","services":["bzz","pss"],"enable_msg_events":true,"port":43089},"up":true}},{"node":{"info":{"id":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","name":"node_86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","enode":"enode://e11ad71a76ca345cb05b4689991a27df0d90136ab34404f7ac6659115281c0caebfb6c47af02b784a8dbd15632906ea81e935e5d68a0d818f86356d4098e2683@127.0.0.1:0","enr":"0xf88fb840ae4e55821d468925a34d498ef69d95cd2812772fc3333ffa4818f050f74bbe6c51618438af3372928bc751bc170fa31238feea5b167507551f583e2a8a15253d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e11ad71a76ca345cb05b4689991a27df0d90136ab34404f7ac6659115281c0ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"htb2jsC44bNAaUN4f5GL7nTdGCeZi9sT7Oj2kNotKWo=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 86d6f6\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 1dc0 6790 | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 4 ef99 d3e9 cc33 c8ea | 55 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n002 5 a616 a1c8 a0c8 bcf8 | 37 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n003 4 93c0 9c8e 9c21 9ec8 | 17 9959 (0) 9948 (0) 9b8e (0) 9ca1 (0)\n004 4 8862 8b43 8d19 8ea2 | 9 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n005 8 81a5 80d7 8006 8073 | 8 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n============ DEPTH: 6 ==========================================\n006 2 84a9 8402 | 2 84a9 (0) 8402 (0)\n007 1 87a3 | 1 87a3 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","private_key":"462383c857370af2c4903fae5e5b3380ba12f14ac972e2a57fb03d60d53be99c","name":"node_86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","services":["bzz","pss"],"enable_msg_events":true,"port":34901},"up":true}},{"node":{"info":{"id":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","name":"node_67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","enode":"enode://9062625e5fd25e5b95d2fb131bd9836c17a278d08fd26d556c2ff3e82375b7739963d7dc46cf90a82a3ec3a51610de42e11daa5439de02fce2239d11c5100ca8@127.0.0.1:0","enr":"0xf88fb840a6e4f385ee971a0e10914ccd098a592003d39eb308e35914192339eeb67e99f505f75a47fe66fcd6baf71a8a5d2bb584480b07f6546f35ec5a1d7ef8a7d99f410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029062625e5fd25e5b95d2fb131bd9836c17a278d08fd26d556c2ff3e82375b773","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Z5Cb3K7yMw7xIOUkx24eOCtHTzMy2G9lKCAo4FHzTHU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 67909b\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c8ea cc33 8b43 86d6 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 3 30fe 035f 1dc0 | 65 298a (0) 2a50 (0) 2fd2 (0) 2e65 (0)\n002 10 4005 44ad 4a95 48d7 | 35 43c9 (0) 43d4 (0) 435d (0) 402c (0)\n003 7 70f6 7049 7660 741a | 13 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n004 2 6b4e 6d5e | 7 68cb (0) 6b4e (0) 6e7f (0) 6c01 (0)\n005 1 60c5 | 1 60c5 (0)\n006 1 648a | 1 648a (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 6758 | 1 6758 (0)\n009 1 67f3 | 1 67f3 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 6795 | 1 6795 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","private_key":"e9d719353a6fb5bcae29ae98425718128b81ecc12560e8010bd8f63f2eedd79c","name":"node_67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","services":["bzz","pss"],"enable_msg_events":true,"port":42515},"up":true}},{"node":{"info":{"id":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","name":"node_8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","enode":"enode://6ab1e0f44fc24a1a9f01b103ed29a36d9344168d3760528da384ed0217fea7f37c77f54f1f91f510c0639c5aca4ad1eecba807e7643ac2426f92ac23617de8f0@127.0.0.1:0","enr":"0xf88fb840c6bf13d71510c296358d2e7025b910b959dd7cda4c3ab34d014fa342222ce5842055d0dcd799e79e004c9236268d6a1ed3c28eb4668ffe87b55b7c2f0c5054d60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026ab1e0f44fc24a1a9f01b103ed29a36d9344168d3760528da384ed0217fea7f3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"i0MY+GrUeXYyGvl7+/lc0KOwqiJEeusGEe0am/HmpL8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8b4318\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1dc0 7049 6790 | 126 298a (0) 2a50 (0) 2e65 (0) 2fd2 (0)\n001 4 d3e9 c2d0 c8ea cc33 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 2 a8b5 bdc5 | 37 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n003 7 9c21 9c8e 9ec8 9518 | 17 9959 (0) 9948 (0) 9b8e (0) 9ca1 (0)\n004 8 8358 81a5 80d7 8073 | 12 81a5 (0) 80d7 (0) 8006 (0) 8073 (0)\n005 6 8d19 8cc3 8f9a 8e28 | 6 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n============ DEPTH: 6 ==========================================\n006 2 8854 8862 | 2 8854 (0) 8862 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","private_key":"5dedb1f9d69c2c6fe7a3aec668fac4e9c9615812829c7387000d87cbcd60aa41","name":"node_8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","services":["bzz","pss"],"enable_msg_events":true,"port":36035},"up":true}},{"node":{"info":{"id":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","name":"node_7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","enode":"enode://e430705ea5c1c11d55e6dc7d7738fc78a6b5e0b4b1833e6bd702d1227e5b8171505eb28c01546a2b0c9cffbc076b31b7bd1ee7f829b422bdae9b868a3d60055d@127.0.0.1:0","enr":"0xf88fb840bb450b66718c989ef173b71454ce6fcd33c94847190c06755cede1b16d7e05c551a88ba5700ef5828f74ded46693aaaf580f31c2249eff900c07824c8531d5a10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e430705ea5c1c11d55e6dc7d7738fc78a6b5e0b4b1833e6bd702d1227e5b8171","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cEnpKjljEfvy9KVbtb0v4/e7PBpj9Bu4jrgA7dRaxuU=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7049e9\npopulation: 23 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 cc33 bdc5 8b43 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 2 30fe 1dc0 | 65 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n002 4 48b8 5bd8 5c37 5c7c | 35 435d (0) 43c9 (0) 43d4 (0) 402c (0)\n003 4 6c01 6790 6795 648a | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 7 7933 79e5 7850 7895 | 9 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n============ DEPTH: 5 ==========================================\n005 2 741a 7660 | 2 7660 (0) 741a (0)\n006 0 | 0\n007 0 | 0\n008 1 70f6 | 1 70f6 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","private_key":"55f5ca8c609ad483be093fad4614abf484adc370763bf034321dc9b5d7bd8896","name":"node_7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","services":["bzz","pss"],"enable_msg_events":true,"port":40911},"up":true}},{"node":{"info":{"id":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","name":"node_1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","enode":"enode://3d69646df064c701b33bd040a7d35477e31bf7a56abb00bc2aead70938ab35f8399aaa1909e3c2bf41afc68a07292224110c8bc18d1eb5eb50df6b572361cd07@127.0.0.1:0","enr":"0xf88fb8408754060a82ff7e9fb41134faaa3a2ed4e6a5c27a819fc9fdd3aaaa0a1e74a1ba5f09b85c3433b0c3a49c7bfd7fdcaaf544be0a8e25ea79f8eeff4401c3fee5310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d69646df064c701b33bd040a7d35477e31bf7a56abb00bc2aead70938ab35f8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"HcDvHOaNxoEpgXe96AivUU76UqWtOMnNK9YZaM3xnPs=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1dc0ef\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 9 d3e9 c2d0 c8ea cc33 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 3 6790 7c7c 7049 | 61 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n002 6 26ab 3a62 3938 3c5b | 28 2ddf (0) 2c80 (0) 2c85 (0) 2fd2 (0)\n003 5 035f 025d 012b 08f8 | 21 096a (0) 0942 (0) 09b3 (0) 08bd (0)\n004 5 1784 1484 140d 1070 | 7 1686 (0) 1784 (0) 140d (0) 1484 (0)\n005 5 19ea 18e0 1add 1bd5 | 6 1add (0) 1bd5 (0) 1b1d (0) 18e0 (0)\n============ DEPTH: 6 ==========================================\n006 1 1fd0 | 1 1fd0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 1 1dec | 1 1dec (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","private_key":"067a43a21c4c9595ff81c7c87cc15ed7b5c5e62d85308e2e0b77c52c27a5d30f","name":"node_1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","services":["bzz","pss"],"enable_msg_events":true,"port":42187},"up":true}},{"node":{"info":{"id":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","name":"node_bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","enode":"enode://fa6deb61cc0b3f0d346f0a5f28f03b1deeab9de673b4843fffd14b87704b7d97074be58116c187408d0bca73a025cd911274ff51c3837206884713fcb57b639a@127.0.0.1:0","enr":"0xf88fb8409b31a5f75a714e32770fb9bfb24b2603601041ca8d8b98f953a48f932ec9750404cbec7ff1a44c7e7a9f89af7fbb85bfaa9e92361eecb63512fa33798f3391b20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fa6deb61cc0b3f0d346f0a5f28f03b1deeab9de673b4843fffd14b87704b7d97","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vcXeASdhV6Dz/EOpzDtBssrMhHkRi3WuxLqbK3+obV4=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bdc5de\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5bd8 7049 1dc0 | 126 435d (0) 43d4 (0) 43c9 (0) 402c (0)\n001 3 d3e9 c2d0 cc33 | 55 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n002 8 9464 9257 93c0 8358 | 38 9b8e (0) 9948 (0) 9959 (0) 9c8e (0)\n003 7 a0c8 a616 acee aaf0 | 23 acee (0) af02 (0) aeb4 (0) aaf0 (0)\n004 3 b3f9 b659 b4a1 | 6 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n005 3 b8e1 bbaf ba91 | 3 b8e1 (0) bbaf (0) ba91 (0)\n============ DEPTH: 6 ==========================================\n006 3 bfc7 be68 bea1 | 3 bfc7 (0) be68 (0) bea1 (0)\n007 1 bcf8 | 1 bcf8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","private_key":"129a7a69ba65fd74ba294f66ea025ca335d94c7a05e91aaf3c24cf3f9f7e0972","name":"node_bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","services":["bzz","pss"],"enable_msg_events":true,"port":42761},"up":true}},{"node":{"info":{"id":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","name":"node_cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","enode":"enode://3d2a0536cb0fb672ffcc469c8a71d4ff9b33a2b48e749c64d32c8fdf6c704e695b3d6699f04baf4e6299b694f36c309308f9fca69859148ae8c7ef71c20df4f1@127.0.0.1:0","enr":"0xf88fb8404f40bae7e0adcf8abafd249d8dad969a599ccb2f825ac5a56a8ef652452bfc1146f1510ab3db60fed9e49b1332c606423f169adf9c7841aead732652178119c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033d2a0536cb0fb672ffcc469c8a71d4ff9b33a2b48e749c64d32c8fdf6c704e69","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zDOX6eEfdSc9P4HZH5gPRQR1X4CyehgyEt5WzFCF5Y0=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cc3397\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 08f8 1dc0 6790 7049 | 126 3b02 (0) 3a62 (0) 3980 (0) 397a (0)\n001 6 93c0 8074 86d6 8b43 | 75 9948 (0) 9959 (0) 9b8e (0) 9ca1 (0)\n002 5 eb68 e471 e681 f215 | 28 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n003 3 da36 d700 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n004 4 c603 c42e c272 c2d0 | 8 c42e (0) c534 (0) c74d (0) c6a8 (0)\n005 3 c961 c9c3 c8ea | 4 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n006 1 cf52 | 1 cf52 (0)\n============ DEPTH: 7 ==========================================\n007 2 cd6c cdb1 | 2 cd6c (0) cdb1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","private_key":"617246021b48922c971765385e8d46d55d22849c49a2b2a58c9e108c53f08b6a","name":"node_cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","services":["bzz","pss"],"enable_msg_events":true,"port":44073},"up":true}},{"node":{"info":{"id":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","name":"node_5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","enode":"enode://81ccd85acd650e9264c02ea67a5c7743051afe4099a4013603c99b81cbc8ce3e18de1601c3e4bbe795262637c94798a502b7b87759c71bc9635c5f5763741ce3@127.0.0.1:0","enr":"0xf88fb84095b8956864f5e16f73f6caacda54957b5e3ab227e77c7b6a4f90d81ee18393e41d774af6765a97f6c71d2455d432959d81eb8a404400829bfacddf9d497112b20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10381ccd85acd650e9264c02ea67a5c7743051afe4099a4013603c99b81cbc8ce3e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"W9j6+TvK0HAG6UJrRfXMWZ8ZY6t5HerE/2PWc5zWKhc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5bd8fa\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 bdc5 cc33 c2d0 | 130 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n001 4 26ab 3728 30fe 138d | 65 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n002 5 7049 7660 7c7c 7ce7 | 26 7933 (0) 79e5 (0) 7850 (0) 7895 (0)\n003 6 4005 447a 44ad 4a95 | 19 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n004 4 50c1 5144 5538 5663 | 6 52a8 (0) 50c1 (0) 5144 (0) 56ca (0)\n005 2 5c7c 5c37 | 4 5ff0 (0) 5d82 (0) 5c37 (0) 5c7c (0)\n006 2 5814 5987 | 2 5814 (0) 5987 (0)\n============ DEPTH: 7 ==========================================\n007 3 5a8b 5ac0 5a26 | 3 5a8b (0) 5ac0 (0) 5a26 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","private_key":"26ef88a18d2d40a51bfabd66c6d93698f7fb8ae73c0efe4be8504f76081c7f85","name":"node_5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","services":["bzz","pss"],"enable_msg_events":true,"port":45545},"up":true}},{"node":{"info":{"id":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","name":"node_c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","enode":"enode://0d8d82144d964d2235866b8f1ed08a27c362598490e3745a6bbfa3ba90241e098abdaa05715666f02a4ac86fe384307431a69f83d66b3de2dfbe7b1d8f8bf374@127.0.0.1:0","enr":"0xf88fb84080a73499a87c86c9c8f7a3432690866a7941a3001f228e0dd3920b9848aae5f641db07c25860ddcc3124563fa497fa1137ee5f9ea9fa548e8c7b0756275e1fc40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020d8d82144d964d2235866b8f1ed08a27c362598490e3745a6bbfa3ba90241e09","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wtAMfZYBdMCTQSn9zsY1Jb+nKPePtwt8UgNrdy1il60=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c2d00c\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 08f8 1dc0 138d 48b8 | 126 3f31 (0) 3c5b (0) 3cab (0) 3980 (0)\n001 6 a616 b3f9 ba91 bdc5 | 75 acee (0) af02 (0) aeb4 (0) ab3f (0)\n002 4 ff75 eb68 e471 e681 | 28 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n003 3 da36 d700 d3e9 | 11 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n004 4 c8ea cf52 cdb1 cc33 | 8 c9c3 (0) c961 (0) c8c8 (0) c8ea (0)\n005 5 c534 c42e c74d c6a8 | 5 c534 (0) c42e (0) c74d (0) c6a8 (0)\n============ DEPTH: 6 ==========================================\n006 1 c190 | 1 c190 (0)\n007 0 | 0\n008 1 c272 | 1 c272 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","private_key":"f34329763f790689554fda7332d50df283663d26d6b7934322a4997f28ad4a70","name":"node_c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","services":["bzz","pss"],"enable_msg_events":true,"port":41949},"up":true}},{"node":{"info":{"id":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","name":"node_138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","enode":"enode://df33b1f0c1352c293d74d4b9b031141777ea5ea361a67862b312e14930160bea0489c08aac497214355e3c4702f1b31c1e74034f495d9cd59a19d893ce1d2bb4@127.0.0.1:0","enr":"0xf88fb840284f8900282f63e433dce06ae23eeb10839c72958e31168d974b1e3fad8efeab583f8ebc19fe0305c26f34560b4f16f2f246227220300c31ed1d2df4b58520dd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102df33b1f0c1352c293d74d4b9b031141777ea5ea361a67862b312e14930160bea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"E428FmLEzpsrMO9QNZFMxwRlZm/hjzEzGOZi0T8JliE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 138dbc\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a8b5 d3e9 c2d0 | 130 acee (0) af02 (0) aeb4 (0) aaf0 (0)\n001 4 7ce7 5c37 5c7c 5bd8 | 61 7660 (0) 741a (0) 70f6 (0) 7049 (0)\n002 7 3938 3b02 30fe 31e6 | 28 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n003 5 035f 0d1c 0e3b 08bd | 21 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n004 4 18e0 1dec 1dc0 1fd0 | 9 1bd5 (0) 1b1d (0) 1add (0) 194e (0)\n005 4 1686 1784 140d 1484 | 4 1686 (0) 1784 (0) 140d (0) 1484 (0)\n============ DEPTH: 6 ==========================================\n006 2 1049 1070 | 2 1049 (0) 1070 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","private_key":"fea6806c3b8e5f07d86ecd3870391f3145d05518f0f2da0b48ba753f8454ad24","name":"node_138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","services":["bzz","pss"],"enable_msg_events":true,"port":43695},"up":true}},{"node":{"info":{"id":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","name":"node_d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","enode":"enode://5c269acede83f81f0a59a02e10764ac1cef987f398a7ae38228c12862ac5a6aadfbc89c7e0a02ba60019ae7a855be61a68e2964a0d36632a798a8410cf28b6bd@127.0.0.1:0","enr":"0xf88fb84076ebf3a52c4ed0e3af7e5f134b50f6537548b5a9781344afa5a5a84989ae3fbb0912b048b5c21e7c318132d7e2fcb35a8cfc00997a6e63dd68dcd4919f7e321a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035c269acede83f81f0a59a02e10764ac1cef987f398a7ae38228c12862ac5a6aa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0+kTz0p9q/tWmRMbZeUzpArbRuo34O1M6UM/mQFZhu8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3e913\npopulation: 32 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5c7c 1dc0 138d | 126 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n001 8 a616 ba91 bdc5 86d6 | 75 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n002 6 f215 ff75 e471 e681 | 28 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n003 9 c603 c42e c534 c272 | 16 c961 (0) c9c3 (0) c8c8 (0) c8ea (0)\n004 2 d959 da36 | 6 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n005 2 d700 d408 | 2 d700 (0) d408 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 d209 | 1 d209 (0)\n008 1 d302 | 1 d302 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","private_key":"e8cb3c33050ebe9bd3e750e4b8f55fa35e538fd293395b06710db344fa8f480c","name":"node_d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","services":["bzz","pss"],"enable_msg_events":true,"port":45149},"up":true}},{"node":{"info":{"id":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","name":"node_5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","enode":"enode://7a0333ebcda5040e71cb74335af5f9434b53912b7918af8fddf3acbb2341a4091d7cbd9c4839061dd5390b11f0e988c24ac645003bca8092070c6d3f171ae68e@127.0.0.1:0","enr":"0xf88fb840e36636443db94a3278ad7e1c41abe6d90576990dca1c3b85c64f49472b0b4cfd029f18575656b1febfe27c53a79d62d703019939082d6a61fe480be68f9c63660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027a0333ebcda5040e71cb74335af5f9434b53912b7918af8fddf3acbb2341a409","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XHwVeY6G/nlLsgFhTUY2bqltxRCR9bGfFJmV4NQN8KY=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5c7c15\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 87a3 d3e9 | 130 b78f (0) b6df (0) b659 (0) b5ea (0)\n001 2 138d 035f | 65 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n002 4 6790 7ce7 741a 7049 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 4005 4b79 4a95 48b8 | 19 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n004 4 52a8 5144 50c1 5538 | 6 52a8 (0) 5144 (0) 50c1 (0) 56ca (0)\n005 6 5814 5987 5ac0 5a8b | 6 5814 (0) 5987 (0) 5ac0 (0) 5a8b (0)\n006 1 5ff0 | 1 5ff0 (0)\n============ DEPTH: 7 ==========================================\n007 1 5d82 | 1 5d82 (0)\n008 0 | 0\n009 1 5c37 | 1 5c37 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","private_key":"bb0921c7331c6ee15280ac5573b08e824e5c7248b1e5539eefb80c55c8702459","name":"node_5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","services":["bzz","pss"],"enable_msg_events":true,"port":38107},"up":true}},{"node":{"info":{"id":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","name":"node_5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","enode":"enode://8f0560f5e755cbf619660e72ba73a02998bca53e860cbdcc69bee129bf16923258b851c65723649d670dbf0e1166f14cfdfe1cb8c8c73eb2906f20e78edcea8e@127.0.0.1:0","enr":"0xf88fb840d2ea5eb11567c49114dd285962beba545d8adecc62156b334bc08bd946887cad22435f4a2b2d944fd7a37cd1f8a7a27bbb6eed794505b3b5000a8f607a7502610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1028f0560f5e755cbf619660e72ba73a02998bca53e860cbdcc69bee129bf169232","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XDcwNHcOQT5wCxzQOyA192ns2auOtU0y97JkW+GZH+U=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5c3730\npopulation: 33 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f1ed f215 f305 f756 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 6 3938 3b02 3a62 3c5b | 65 3f31 (0) 3cab (0) 3c5b (0) 3a62 (0)\n002 3 6790 7ce7 7049 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 8 447a 44ad 4005 4b79 | 19 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n004 4 5538 52a8 50c1 5144 | 6 52a8 (0) 50c1 (0) 5144 (0) 56ca (0)\n005 4 5814 5987 5a26 5bd8 | 6 5814 (0) 5987 (0) 5a8b (0) 5ac0 (0)\n006 1 5ff0 | 1 5ff0 (0)\n============ DEPTH: 7 ==========================================\n007 1 5d82 | 1 5d82 (0)\n008 0 | 0\n009 1 5c7c | 1 5c7c (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","private_key":"0c2c7d021de7510363cf5e2641eaa5f9378a5b212ffebbb2759c636e6eb1f581","name":"node_5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","services":["bzz","pss"],"enable_msg_events":true,"port":39663},"up":true}},{"node":{"info":{"id":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","name":"node_93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","enode":"enode://4fcf131746aae7e3b07348194ea8e617a5d50f3efacae7946f8ee5afc235f8ba437adfd9cd3411470f4cea27041ec717a816e46771aab4b057b191859ed04f79@127.0.0.1:0","enr":"0xf88fb8405f99513aca9b2504c8789a4395c454ad8201930dedfefb376fa80d8edb93790943b526ced56eb76753d377faf7819e9f2fa859c515903bb04604e0ba6d9a04bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034fcf131746aae7e3b07348194ea8e617a5d50f3efacae7946f8ee5afc235f8ba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"k8DhrfI/3xYjNZ64jFF7xSHVomMlVU34kMwEwfoXpd8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 93c0e1\npopulation: 34 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 035f 48b8 48d7 5c37 | 126 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n001 8 ff75 f756 e09f eb68 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 3 bdc5 a8b5 a616 | 37 b78f (0) b6df (0) b659 (0) b5ea (0)\n003 8 8cc3 8ea2 8b43 87a3 | 21 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n004 5 9c8e 9ca1 9c21 9f7d | 9 9959 (0) 9948 (0) 9b8e (0) 9c21 (0)\n005 4 95c0 9518 955d 9464 | 5 97da (0) 95c0 (0) 955d (0) 9518 (0)\n============ DEPTH: 6 ==========================================\n006 0 | 0\n007 1 9257 | 1 9257 (0)\n008 0 | 0\n009 0 | 0\n010 1 93ea | 1 93ea (0)\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","private_key":"e9b9e5f77b823f754cc953b6e8bb3f29875b25f3f07294dc648aad09741eae5d","name":"node_93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","services":["bzz","pss"],"enable_msg_events":true,"port":39455},"up":true}},{"node":{"info":{"id":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","name":"node_035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","enode":"enode://a2ea0d984eb8c2a044d8d57b6b34ac49f7e319cd0ce8c9ad882e352f681e73bf1212f8c9b4155d9413384324db4dc6e0430b23bd9ebe32dc3694d927c34e07ef@127.0.0.1:0","enr":"0xf88fb84021c14a87840a5a62b181c58ce71769ae7998b9182a812551fba5dd2798c30a6228770d3463f5bd7428e5f81dd35ce8f649571ec472eb1f870a82386058e3756a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a2ea0d984eb8c2a044d8d57b6b34ac49f7e319cd0ce8c9ad882e352f681e73bf","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"A18VSZzbDwebPjWK1UphImgUQqUpPDri/fbFJwBLNtI=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 035f15\npopulation: 25 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a616 8074 93c0 | 130 f6c0 (0) f645 (0) f756 (0) f1ed (0)\n001 4 6790 7ce7 5c7c 5c37 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 2 30fe 26ab | 28 3f31 (0) 3cab (0) 3c5b (0) 3a62 (0)\n003 5 138d 1784 1484 1dc0 | 16 18e0 (0) 194e (0) 19ea (0) 1bd5 (0)\n004 3 08bd 0d1c 0e3b | 11 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n005 3 07f5 0594 046c | 4 07f5 (0) 0561 (0) 0594 (0) 046c (0)\n006 3 0191 012b 0111 | 3 0191 (0) 0111 (0) 012b (0)\n============ DEPTH: 7 ==========================================\n007 1 025d | 1 025d (0)\n008 0 | 0\n009 1 0314 | 1 0314 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","private_key":"595254b7c40bf18ec4d789cf500b58c5850ad2f21460f58230cd8e53b428c0bb","name":"node_035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","services":["bzz","pss"],"enable_msg_events":true,"port":41613},"up":true}},{"node":{"info":{"id":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","name":"node_807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","enode":"enode://4ae810f37f174c8ffe4c90d5590e2bdc3677a1f413738a94776bbe63f1f45b08043188e3f2366b245c0e285f02ac759329e37760bc3c797ba7d70479dd8f9490@127.0.0.1:0","enr":"0xf88fb84006c5b23f700d5d387dc4a8d96c97cb9b9415cce70e955133a5f006e2b37011047da680b267227e5646409503737c6d382fa97364e60c24095320efbca3056ac70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1024ae810f37f174c8ffe4c90d5590e2bdc3677a1f413738a94776bbe63f1f45b08","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gHQWzHDwLUgaGIAn95MrSOj3teglj36WI/P24phdj2o=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 807416\npopulation: 29 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 48d7 48b8 7ce7 035f | 126 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n001 3 eb68 cc33 d3e9 | 55 f305 (0) f2b4 (0) f215 (0) f1ed (0)\n002 2 bdc5 a616 | 37 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n003 4 9ec8 9c8e 9257 93c0 | 17 9b8e (0) 9959 (0) 9948 (0) 9c21 (0)\n004 5 8cc3 8e7b 8ea2 8862 | 9 8d19 (0) 8cc3 (0) 8f9a (0) 8e28 (0)\n005 4 8402 84a9 86d6 87a3 | 4 87a3 (0) 86d6 (0) 84a9 (0) 8402 (0)\n006 3 837f 8358 834f | 3 837f (0) 834f (0) 8358 (0)\n007 1 81a5 | 1 81a5 (0)\n008 1 80d7 | 1 80d7 (0)\n============ DEPTH: 9 ==========================================\n009 1 8006 | 1 8006 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 8073 | 1 8073 (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","private_key":"421902540a521af21b446884bc2ff3f606e8e7814ffad298bdb1200502aa73f8","name":"node_807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","services":["bzz","pss"],"enable_msg_events":true,"port":37835},"up":true}},{"node":{"info":{"id":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","name":"node_a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","enode":"enode://51ff87ed33ddf13e429d933fa411ad53dfdaf4f83d2d156ee20fc759f1900fbe70b000ad9891f8a5e79fa93673839682c50273f4012eae003b40c8bef34e0542@127.0.0.1:0","enr":"0xf88fb8402fd3e3ba496c67f81c4704bbedcb048e9985d8e2fa0d26e8aadf582cc5bdab7428098d781ee942ecc983bd6c645ee494759d9fc3aacc50957db0ac276b93ea8c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10251ff87ed33ddf13e429d933fa411ad53dfdaf4f83d2d156ee20fc759f1900fbe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"phZaSwLVi+EWiSmCwO09Sdhv7A6fQ2pRa2GGgzHthT8=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a6165a\npopulation: 35 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 035f 1fd0 48b8 7ce7 | 126 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n001 5 ff75 e681 eb68 d3e9 | 55 f1ed (0) f305 (0) f2b4 (0) f215 (0)\n002 7 9c8e 9c21 9257 93c0 | 38 9b8e (0) 9959 (0) 9948 (0) 9ec8 (0)\n003 4 ba91 bdc5 bfc7 b3f9 | 14 b5ea (0) b4a1 (0) b78f (0) b6df (0)\n004 6 acee aeb4 aaf0 ab71 | 10 af02 (0) aeb4 (0) acee (0) ab3f (0)\n005 4 a2e6 a330 a1c8 a0c8 | 6 a2a1 (0) a2e6 (0) a327 (0) a330 (0)\n006 2 a5ac a505 | 3 a4ee (0) a5ac (0) a505 (0)\n============ DEPTH: 7 ==========================================\n007 2 a742 a7a8 | 2 a742 (0) a7a8 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 1 a606 | 1 a606 (0)\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","private_key":"f8b37704a0eba9987c7cbd4d718ee3eba88b7d76957c5043be17f16e8408c442","name":"node_a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","services":["bzz","pss"],"enable_msg_events":true,"port":45387},"up":true}},{"node":{"info":{"id":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","name":"node_7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","enode":"enode://ff883ea700704e0d06c059393d1c9c79298f0ff8bd3a806cf777c1b1643539f79b58a73e57a76b7e4631b6f6d224a263b3da5a4029565cd811d1cfba392b16d0@127.0.0.1:0","enr":"0xf88fb84094a7b14977397bf60c09a538d9206bfbb260df1994b06df0a747d58e5b0d17562803bb201f443f5b17d527f875f5c9185455b13bf3aa0789206b83bb9dfb71c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ff883ea700704e0d06c059393d1c9c79298f0ff8bd3a806cf777c1b1643539f7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fOf+yDOi6MdyD8yX+CDyyirKhTiCEPiHw+/niwIHZuc=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7ce7fe\npopulation: 27 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8074 a616 | 130 f645 (0) f6c0 (0) f756 (0) f1ed (0)\n001 4 26ab 138d 1fd0 035f | 65 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n002 5 5538 5bd8 5c37 5c7c | 35 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n003 4 6c01 648a 6795 6790 | 13 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n004 4 70f6 7049 741a 7660 | 4 70f6 (0) 7049 (0) 7660 (0) 741a (0)\n005 4 79e5 7933 7850 7895 | 4 79e5 (0) 7933 (0) 7850 (0) 7895 (0)\n006 1 7e47 | 1 7e47 (0)\n007 1 7d16 | 1 7d16 (0)\n============ DEPTH: 8 ==========================================\n008 2 7c7c 7c46 | 2 7c46 (0) 7c7c (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","private_key":"60cd3f72a03ac58379a8c6ba81e19265da277316a0e01fa3876bc4c92ff49df6","name":"node_7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","services":["bzz","pss"],"enable_msg_events":true,"port":41789},"up":true}},{"node":{"info":{"id":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","name":"node_48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","enode":"enode://707261d403a5192568c194162fd61ffccb0cde756d06d2eb7c117b0160f7ad528446db8695b53393c6b20ec9fa5a555d5a341980d106865e9527566d32b9bb54@127.0.0.1:0","enr":"0xf88fb840bb9ab177f3ef6ff14610eb47e7168572b6f01f94f263f707915fc7ea3d9af0f5468fc44ff2210116cbcf0bfbae738979e4a3cfee6ddecd0e4abac50af13eb92c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102707261d403a5192568c194162fd61ffccb0cde756d06d2eb7c117b0160f7ad52","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SNeaxV+N9RKvjn2GiqQKybYUk/pPGwzgt2v22i6zDng=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48d79a\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a970 8074 93c0 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 3 30fe 26ab 1fd0 | 65 3980 (0) 397a (0) 3938 (0) 3a62 (0)\n002 4 6c01 6790 70f6 7ce7 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 6 5538 50c1 5987 5bd8 | 16 52a8 (0) 50c1 (0) 5144 (0) 56ca (0)\n004 4 402c 4005 46bf 44ad | 9 43d4 (0) 43c9 (0) 435d (0) 402c (0)\n005 2 4cec 4d91 | 3 4cec (0) 4d38 (0) 4d91 (0)\n006 2 4b79 4a95 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 1 48b8 | 1 48b8 (0)\n010 1 48f1 | 1 48f1 (0)\n011 0 | 0\n012 1 48de | 1 48de (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","private_key":"332189f434da38340438c9e98fbf7e82e2cf6bc241b9b8689f12514555c995d7","name":"node_48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","services":["bzz","pss"],"enable_msg_events":true,"port":41935},"up":true}},{"node":{"info":{"id":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","name":"node_48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","enode":"enode://b19c0ae1cb81e68f5f80d6b0ca2e30109c2fd797df00404cd2c70f4b0b22a45a3316d279f68f3d211584bf955fad3326cbf8ccc1c5b4de9f4d34671d033b9aef@127.0.0.1:0","enr":"0xf88fb840cfce87968b891140a7b5398ce7c46c9e55da927db6b676d5150b5d1d5808a0160675b0905f993242da939cc4bd9d3a8ce303209b3442c1a398dbc1c58abe8ede0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b19c0ae1cb81e68f5f80d6b0ca2e30109c2fd797df00404cd2c70f4b0b22a45a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"SLhQl0V1ylejzF+aTPWq/YaIyzK5k/aZg+zmMlj/h24=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 48b850\npopulation: 31 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c2d0 e681 eb68 93c0 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 2 1fd0 1784 | 65 3f31 (0) 3cab (0) 3c5b (0) 3980 (0)\n002 5 6790 7660 741a 70f6 | 26 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n003 5 5538 50c1 5987 5c37 | 16 56ca (0) 5663 (0) 5538 (0) 52a8 (0)\n004 4 44ad 447a 46bf 4005 | 9 43c9 (0) 43d4 (0) 435d (0) 402c (0)\n005 3 4d91 4d38 4cec | 3 4d38 (0) 4d91 (0) 4cec (0)\n006 2 4a95 4b79 | 2 4a95 (0) 4b79 (0)\n============ DEPTH: 7 ==========================================\n007 0 | 0\n008 1 482e | 1 482e (0)\n009 3 48f1 48de 48d7 | 3 48f1 (0) 48de (0) 48d7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","private_key":"dad03259c72bb0ab9ef830e43beb607d0933e8ceab8af57177cdedcccaa94838","name":"node_48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","services":["bzz","pss"],"enable_msg_events":true,"port":34161},"up":true}},{"node":{"info":{"id":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","name":"node_178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","enode":"enode://27897e5bff2021adf7dfc30beeae2d45dee4a331f85ccd2c611ff0df21a46f37373f49a11c7484953162778e229db0f12c587b97e449759086b0d9573e0c1a26@127.0.0.1:0","enr":"0xf88fb840429dfb2ce19f2d10de9df91da52260207acd7bcdb6f38055772e416e732174ee29384cd41078dbe55437ddf28a305fdb26b8fbe9c5f95c36514330d2055b27bf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10227897e5bff2021adf7dfc30beeae2d45dee4a331f85ccd2c611ff0df21a46f37","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F4QB7I0BoKT1UdI+iAqOik64d3NWU2OEPVHPUmYLEhE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 178401\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e681 eb68 9257 a970 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 2 741a 48b8 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 4 3c5b 36b9 3728 26ab | 28 3980 (0) 397a (0) 3938 (0) 3b02 (0)\n003 8 012b 035f 025d 0d1c | 21 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n004 4 1add 1dec 1dc0 1fd0 | 9 194e (0) 19ea (0) 18e0 (0) 1bd5 (0)\n005 3 1049 1070 138d | 3 1049 (0) 1070 (0) 138d (0)\n============ DEPTH: 6 ==========================================\n006 2 140d 1484 | 2 140d (0) 1484 (0)\n007 1 1686 | 1 1686 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","private_key":"354ee66c6897d2e2295d1c694b61628074a9697102dde529318baa2cbc0c698c","name":"node_178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","services":["bzz","pss"],"enable_msg_events":true,"port":34553},"up":true}},{"node":{"info":{"id":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","name":"node_1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","enode":"enode://a6d82f53e41ccd91583fbd89ab6dc5ca9ea1e1c8cf32336f3850d7abd7b67c12d26f485949244e17e996848469b10582ae14d19bba53fa22af1a289e2098fa2f@127.0.0.1:0","enr":"0xf88fb840011b8900371589a6bdc15199784c217ccdb148656c9cf6f7aeaaa2e96dc963a93ee8ad5c8509e66f007be32b90ca078bbc6d9e655df8ce0fa1a1ff258d3599cb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a6d82f53e41ccd91583fbd89ab6dc5ca9ea1e1c8cf32336f3850d7abd7b67c12","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"H9AZLfH78zdxylda+7TifGVBzOSjz/LfwfLAhef6t54=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1fd019\npopulation: 30 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e681 eb68 a616 a970 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 4 741a 7ce7 48b8 48d7 | 61 68cb (0) 6b4e (0) 6e7f (0) 6dd3 (0)\n002 4 36b9 3728 2c85 26ab | 28 3980 (0) 397a (0) 3938 (0) 3b02 (0)\n003 7 012b 025d 035f 0e3b | 21 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n004 4 138d 140d 1484 1784 | 7 1049 (0) 1070 (0) 138d (0) 140d (0)\n005 5 1add 1b1d 18e0 194e | 6 194e (0) 19ea (0) 18e0 (0) 1bd5 (0)\n============ DEPTH: 6 ==========================================\n006 2 1dec 1dc0 | 2 1dec (0) 1dc0 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","private_key":"56799ffc0f8172319a5acee54229b310b2ee9bfcff23054e163d25ebd6b74da6","name":"node_1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","services":["bzz","pss"],"enable_msg_events":true,"port":33911},"up":true}},{"node":{"info":{"id":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","name":"node_26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","enode":"enode://cec920dd405d44d0b1e52e29040cb654a1fe80dc3bf4484ebbc8480cb43d5f0cb060aa4e8ede415db0b1d08a220d5ab4add6b38d42d7aa794db434ff9dda1697@127.0.0.1:0","enr":"0xf88fb840b1a4300c5cadd86b2b219a1044bd3e44834ca1f0053ee7a3e3e45f15100dbe35044cd77a522de4160bbe65b9c8ac4ab26c6a20c7d8a3c037e4e6694d1eb38e6d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103cec920dd405d44d0b1e52e29040cb654a1fe80dc3bf4484ebbc8480cb43d5f0c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JqucgTgi27TxojDNjpnoqygLJCdH3rVf35PRYJBu8zE=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 26ab9c\npopulation: 42 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 c534 ff75 e681 eb68 | 130 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n001 5 7ce7 741a 5bd8 4a95 | 61 6b4e (0) 68cb (0) 6e7f (0) 6dd3 (0)\n002 11 08bd 08f8 0e3b 012b | 37 0cfc (0) 0d1c (0) 0e80 (0) 0e2b (0)\n003 11 3cab 3c5b 3938 3a62 | 17 3f31 (0) 3cab (0) 3c5b (0) 3b02 (0)\n004 6 2a50 298a 2fd2 2e65 | 7 2a50 (0) 298a (0) 2e65 (0) 2fd2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 24f8 244c | 2 24f8 (0) 244c (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 26ac | 1 26ac (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","private_key":"9d39b98cb0569ba31464e7827579e71e40dae5f366d3dfe5cbb197a9f825dbd4","name":"node_26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","services":["bzz","pss"],"enable_msg_events":true,"port":42047},"up":true}},{"node":{"info":{"id":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","name":"node_a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","enode":"enode://a74db2e9fc46ed2ad19743b773f0021b88e21cac389189ca1350aaecaf010fcd452f1991fb38c3d65a3745547b26e6dc0f655d75fd397cfef0fa286823e10b50@127.0.0.1:0","enr":"0xf88fb84002a5006b493d814889934b13a2e3714a6712f571e88ff5139d96e40cc1bcb6d719aba5a3169f334698e6273dfb9e8c3ed5234b18da0cfd2edf656396d0d92fcb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a74db2e9fc46ed2ad19743b773f0021b88e21cac389189ca1350aaecaf010fcd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qXADCFFsAs+a6ogJAApOBZbWtEdT4QvQko34Pi65uec=","hive":"\n=========================================================================\nThu Feb 28 17:51:00 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a97003\npopulation: 28 (255), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 48d7 1784 1fd0 26ab | 126 5663 (0) 56ca (0) 5538 (0) 52a8 (0)\n001 2 eb68 e681 | 55 ddb8 (0) d9cf (0) d959 (0) dbd4 (0)\n002 6 84a9 8402 9c21 9c8e | 38 8b43 (0) 8854 (0) 8862 (0) 8d19 (0)\n003 5 b3f9 ba91 bfc7 bcf8 | 14 b8e1 (0) bbaf (0) ba91 (0) be68 (0)\n004 2 a0c8 a616 | 13 a2e6 (0) a2a1 (0) a327 (0) a330 (0)\n005 3 acee af02 aeb4 | 3 acee (0) af02 (0) aeb4 (0)\n006 3 ab71 ab3f aaf0 | 3 aaf0 (0) ab3f (0) ab71 (0)\n============ DEPTH: 7 ==========================================\n007 3 a8f4 a8ff a8b5 | 3 a8f4 (0) a8ff (0) a8b5 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","private_key":"89ebf8f655338d3ee03b70fce8b3206157e3e198a2c1e6511944e7ba76672303","name":"node_a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","services":["bzz","pss"],"enable_msg_events":true,"port":40557},"up":true}}],"conns":[{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"3f31ecaffaa6311c82c9a575bbc38d6bcb16630ac87e19d1853a64aa96c9dcde","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"031450ec20f353435b429b5fa64f616d07c9d586afabc7a2772e05ad5c88bf50","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","up":true},{"one":"d95965e449dd4069876384cf4b34f986731e255a7948f0a862d229b1dddbc502","other":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"025de1d2ec529d3a7da302eef0f8c54996616d40c940c0956d470ffc2a007f33","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"012ba278d582691241875c4c14ead91fff3983e190df7d9b43ade384e84c11fb","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","up":true},{"one":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"d20931ce3da972fd23ea306e5c604a1fbd9417ba02654c5cdbe278fe259f75d5","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"67f383e5334e9b6701d1dbb20876d4ba9a7e578af0476caed4a7e1b701f2bedb","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","up":true},{"one":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"08bd1e049859b4a7c8078ca9741fe3daa668b9fe478da06d1a435cd5566b3e11","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"51440ab47fc5076c00cad16a542b846c26b3281ecea4dbca795ae9b80183ec90","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","up":true},{"one":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"bea10868d5da506c1801de845c148c2f09761893113ac913fe66674a8f43c178","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"035f15499cdb0f079b3e358ad54a6122681442a5293c3ae2fdf6c527004b36d2","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"56635699bd3bc78193adbdb8e8b7c2c91dab4140fdaa506fea2300ee86c4ba81","up":true},{"one":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","other":"c74d801e85ac0fd8951480d107b41eddc5c92775614c4886b3f732fa3d1a791d","up":true},{"one":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"6e7f1f3d65364399617a4d95fdd04f2ca9b007b2366943e7ba5acd4616a7a425","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f6c028d6a2b6408e90169151f4519b561ed183bd8925ed9a1702806f397666e7","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","up":true},{"one":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"b659418885032905ea20ad47d70470e403e7e407e0e9ebf9277f9a2d81ec121c","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"56ca9dd846a58a0ffa7b49a88aad559a338ba535a6f738468b8f146c97890cb2","up":true},{"one":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"dbd4d90e3342ef837b8ecf5c6e490f7c409f419cf36b77162a87cb2cfb8ae33c","other":"c42e6492879439eeecd9938d17ff283fd8f5f24206906ca512b4daa4803b78b4","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"e6812448728b4bda5962adceb1707b29f661d3d1a6b2ccd5f8183c9a1f4d01b6","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"08e5a268f397385c69a7fec855ae4d889cfa98afef5b7c09fc4841e3f8894ad8","up":true},{"one":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","other":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","up":true},{"one":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"b5eab4869b4cb65bdc1e5cab45c03016d202f9f5b668be50066451cfcf9ef299","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"e8676d17966625c4fdac6bd9437981a0cf869c8b0010812edf0c79805e0e1ff1","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","up":true},{"one":"056152dd9dae85c426378d34acab8d6641da665d2f57359a27a0ff652f3f3d02","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","other":"1addd4a9f01486212e13e43a9650b7f793617d1cb59fb8d941270d7ae55f575f","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","up":true},{"one":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"3a628ef171c1f26fa0966eb89210be0a14305aae8bfed10f4ed9017698f40f4b","up":true},{"one":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","up":true},{"one":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","other":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","up":true},{"one":"fa240411bc4f3e44dfca3faedd112c7743a67b522a910bc99696ef0b31732ee2","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","up":true},{"one":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"31e670638acba3d58f4c67f3ff2f3f25d769e8a5d7a7838927f4d9d169a84404","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","up":true},{"one":"eff2450bea797ff66d93e7c1c1b0977cddf3abba64bfa51bcc509d728569e2fa","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"32ff1969d90aaa5a8ed2260968a8e2bac2d1cae597c906f90495f1dc5de7f8d3","other":"36b93656cab02213fa76124af6251109356abc5e0ae5dd1e203c6a013e014548","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"8862cd85d7039119b984f752a458ac0495ddea98c69fc1d1241db7873a712c11","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","up":true},{"one":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","up":true},{"one":"1070df5e904e3865085b0319a81761e59146494c689e7567efe7465fc819ae8b","other":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"398038811c1c7402fe2e6994c9ce2f15c8166b8e99f379feaaed66ac87702062","other":"3c5b2e125020c80e3674df9cac34de4d8f3a94ee02556fb557921b6d5498b933","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"b78fd21c063006e2e033d1d00fc21e1ad7ad7951bb5621cec9b56639745d65f9","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"a742e8502c619703ce87890110f908bde32b59dc61d77a247759e5d0056e0c94","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"c6a8220726243cceaa6f2cebdac857a05efe721323f0a064c7f85a8340d3da96","other":"c272b12f4020ae5b20e3d29cd09de03fa0088e3eeb5f07aa7728b29a3e90e687","up":true},{"one":"ab719e60a77ba5253f1690c920df9dd9f3a62071e9cce9d62e0001a522b3409e","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"07f5d094a4b22e73cdd6c85452b3d928da9b4b16873824759cb7e8a622417fd5","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"aceee75a260d45252060fe971eabd4bde25f912db4a3c6e47f4a09572fe01697","up":true},{"one":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","up":true},{"one":"5c7c15798e86fe794bb201614d46366ea96dc51091f5b19f149995e0d40df0a6","other":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"4cece9bc134bc2b09400c9f7f8a4df9270d2fe3c077c5e441fffc911fcf6f42e","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"48d79ac55f8df512af8e7d868aa40ac9b61493fa4f1b0ce0b76bf6da2eb30e78","other":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"305162c472c71ddef2320b138102b67d1ce2b8bba79e2e587fc80e085c88e547","up":true},{"one":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"67585dfd87a005bae9bffc2cccb83c69537247c74886b4fa52287f46c796bcb6","other":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","up":true},{"one":"679554b410e415cfcdf1b14ef87759269b2bcaf07f4541122977db3a40091da2","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"3b020c84fb60f59779324d451d9770d683e08133bbaa2d5762f61b8fd4b8d9fd","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"7d162a11662585f8c38d88fb241623e67bacf90703065dae6c092b4b507d6543","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"834f14e9f325482adef62651ddf3685690dd5ebdd18014f2bd266b2143c290ff","other":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","up":true},{"one":"7c464054ea7b6c9ea0c7d4c209769c92f294a9db2ca159b8ef168e310a1eac3a","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"af02c2f471e96ab8defbd229215695b95e64f7c78b145b6793a238961f556fbf","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"9c21cb3e56f8ac66a7917a9ba14e58f77e998ac70c178b88b5053d9ac2777e60","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8e7b96d28edae711e1a4cee0d894e0bd92cdf410ba6f61713f7d9b0bee761d4c","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"3728152c88f1e5e61f6523b09e8f3bb1023b700deccdca5fcc1e6488136b0e57","other":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","up":true},{"one":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6dd3ac0fd9a04a2ce75875c683d135e52eaa1670cb55e78711620712e60fde47","up":true},{"one":"9959385385aade728d3f5763806596222bc1e7b9946c2c92407943d080b32f8d","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"7ce7fec833a2e8c7720fcc97f820f2ca2aca85388210f887c3efe78b020766e7","other":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","up":true},{"one":"b4a1b687fbdb754fd689e26f0870a7dcab5d76190c06f3ea2ea1e198f8aa5ab2","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"34118166845c185d15c286b7e5433539ee98ed634baabd534d57369fd5f7c681","other":"31e129ab3df7e082cc27c649d9ee29a3ea646d6a97d2417875b80e3ff576c047","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"86d6f68ec0b8e1b3406943787f918bee74dd1827998bdb13ece8f690da2d296a","up":true},{"one":"b6dffac4b4eb2974ed0ed241799f97d2e5d9be671e311266826d0dcfecfcc209","other":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8358a74fc8d8e39ccc40b4d3a212b7a69a6a8f6afc25cff2c9c7b44bbaf9ec82","up":true},{"one":"18e00a7e0f826a1aba3f8c0f533ed905f2eee607b697fff056ee7874d374adcd","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","other":"a8ff8d69dcb36462d1116dafa5e3d0c7237bf65dbece482a316862c8d66e35b6","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"bdc5de01276157a0f3fc43a9cc3b41b2cacc8479118b75aec4ba9b2b7fa86d5e","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"5bd8faf93bcad07006e9426b45f5cc599f1963ab791deac4ff63d6739cd62a17","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"e0a0ba7e7e89a7af805e24abde1a5a5b489ba197585051a8755e8c2345c3d57b","other":"e2770cef7c1ad312b70d94ca5570e45f324c798a31a93203f505167aeab122b6","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","other":"a4ee49bb2caabb6b9448bcdff1fc3cc673a2db04eab9f5c62d1787f2c25990a0","up":true},{"one":"feb3bc17ee7369a4fa9889d9250fed3c1257c70916871996e6eabd374dd8dc2e","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"951877b34ee1535b5059c49beb03e8960ff9c12b694ef64708c77c30ff1dc706","up":true},{"one":"7c7ca5a7522a04f62f2bebd6197a03d78f255d0175c3dfceb5d92b684365b2aa","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"aeb45fe10b0dbd0f72ab6a77fbf971a8f46dbcdd96c08f23279d1434b4f38b1d","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"81a5a07f92f813e85b501b0028e1caa6e6a6c7efa5195ecb693cd2d91d5132a0","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"9b8e6bb3a7fe4dc65ac97404e546d8b777d068c94bc2355f4f1a510ad6c11905","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"59876e7ff9e92243856dad23126e1d38d9a5ddae79772ed1b2bdb91f33a4a4b5","other":"5a8b84df651871fce72d11cb1c26c87ae4a0cc6b4c274d37e70532c94f27288e","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4b79e83186f2ab05932eaa99982a2e53373b83780e32d224d15cb2c85462451f","up":true},{"one":"019109311d4888497aa194cce4a89b5ef243421cf0e7e7bb9115d086e1a1f7d7","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","other":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","up":true},{"one":"2ddffddbf452f0c9268058a739f5757fb90281cbfd31bd6f760acc3392fec12a","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"d9cf19895e015cb534d915aed83c0d26bf40a11244027812e17c3bec6e645a8e","other":"da36d1df95a158b0d3f9e7407d663a6b611dde0a77f00a584b97a939ab6a00de","up":true},{"one":"0e3b7722f3f84d83b3d744bea4e893715a01d4df3cf4a1c6a6823a1f5c9ad6b8","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"7049e92a396311fbf2f4a55bb5bd2fe3f7bb3c1a63f41bb88eb800edd45ac6e5","other":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"648a96d61898eb2d336ff7d5a229cfeb7b9f587282e40f9fe640e181ae26bdd3","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"52a8747e4ea35f6f50c72d7c481616f68a5e4396248332b8ff69d3a772de49ac","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"4d381014783980b2f77f0d71160ad9e9d84672b576f4435ccdbae12752350c1c","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"3cabd3a567fc4e6f8da66eb35d938fe1e9a7f2bdd2d36c4dc2d0e0e9149f5e56","other":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","up":true},{"one":"79e5c6c6d78c88c579003cda044882ecb04520fbad1f5feadbe7b6d23fe183c8","other":"7e47a2f82984a600c8583605a91d5cb8f2d9a18961845e9c422edd78e20ac3a3","up":true},{"one":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","other":"a9700308516c02cf9aea8809000a4e0596d6b44753e10bd0928df83e2eb9b9e7","up":true},{"one":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c603138e40fe2f85cc634017956ada6399fca99969e3bf0c1ee8428374e779f1","up":true},{"one":"bbafac5ba5915db3c80e28b249cad260b9b5dad1f728063c48fa8f61d7556e17","other":"ba911175d3aa3fcc266e2a5aa32fb706208b8a9b5021a5f37c0b85f547eb375d","up":true},{"one":"f305273a7d08e72f69b0b153855e822f252cbbf34a18f305134eed9d1eb7b58a","other":"f8ff7440d6f4abb1c89496336843741ed53a544cedeeed71d8ebe0b08698438d","up":true},{"one":"26acc3c373c29150af30bbc9264d0c44c7c606ff7377399ddf844635e97afcfa","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"3938e6b2c095084dc9975a3e8649133557495d34ac6df874c6d929266e3ffe6f","other":"397a0a0e9fadcb571acd8981f5bfe8e059e707e0feae8a9c4c6bfe87bd39e66a","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"6d5ec591af4966ba024c6b2aeb45e0aab8aa1762f9cac30ce3934da529b738e9","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"26ab9c813822dbb4f1a230cd8e99e8ab280b242747deb55fdf93d160906ef331","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"0111e720a84b310f863c2530fbe149e6a221acbad01065c5d052d2b3e1716f54","other":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","up":true},{"one":"b3f95f225e2b6b76e6c7ef7c86caf83e35213f6a22da41e653ca1c190be23c9c","other":"b8e1a8622c256ef29acd52df7b3ace50820fb1a147716165ff862fdc973a48cd","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"1b1dc3f9312df141855c545dd16aee325f9a609230ec6165bdbbb07d0c0862f6","other":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"9464ad8da1a5effdc0351742dfffae941ffd9fab469637b2491caece53c57dc8","other":"97daf2cbe03c80ce6c4dae39cd071dd93cb32ed245aa9aa77285e12296957ca3","up":true},{"one":"955da15edae50a4c68bc8c579b9799d55f41b7c2a6178f645f79d772e0116662","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"95c0a351fb7aa6683280d159a7b808bfa63f63bff91a1c5936e973b2e5d3954f","up":true},{"one":"5ac0d00b8d647dec62d26e1a689fd05b8b7a1a79ab8c43493bd6d7d209816df1","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"0e2b48558ce2af1fbfee38a557d56072e3091cfcaee8d7847c7c9dcf7bef9bfa","other":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","up":true},{"one":"994839e5f3a5b8b23aed84fb029413124af17804b79b0263ec6bfd5aec5dad78","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"094256812084c6052a2604149aa3aba2379c483bf4ec25162f6b43934942775a","other":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","up":true},{"one":"2e65d05648b798fafbc9bb582c05e6f8f891131260e8c90ca725ddcbc823f315","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"e2d36f335d90ad63148db8e353a78a30d8d9c0abe107be2cf8685f6a01ce74b9","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"178401ec8d01a0a4f551d23e880a8e8a4eb87773565363843d51cf52660b1211","other":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"c190f9d08c78ed6dffadaef36e77fe6aa96099e4453753b0cfc8ec542fa96b9d","other":"c2d00c7d960174c0934129fdcec63525bfa728f78fb70b7c52036b772d6297ad","up":true},{"one":"0d1c35c6ea485cb33857b790ee262f974cf0d54cf8ce3003f8308ac2e87c2c25","other":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","up":true},{"one":"93c0e1adf23fdf1623359eb88c517bc521d5a26325554df890cc04c1fa17a5df","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"140dd212f2b193ee6a9d7fc14f7da321c7ef6fd367fb4f194924fd0ad5d135cc","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","up":true},{"one":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","other":"f7561cb6740e17ec7c7d17068251b2c951d954c77804aa5af60464e9c3964e57","up":true},{"one":"16868ec5d8f490ac73ea28b4e8fdda55ac149bb1aafb177545b54b84a5ad5367","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"a8f49e87156fda5510897601689ce968d77032134c523634916b96de16366f9e","up":true},{"one":"046ca54165f0dd4d62fd7d8ee9e97c655db3d35f5452a0ccb0dffc79c047978c","other":"05949ec1a582fa70cab95c59e7c0d315583bf9fc320c60c35268931f21e90853","up":true},{"one":"ddb8be472c3d48dc4d3d112448e6c0c4a826a18af3f3b53fdfef8cd31053c75f","other":"c53417f008e4550e1c4cb9a3e2955b3af6403e059b7b4b4c33869d9ed4a580a5","up":true},{"one":"d408bb6f7af1590e1f162ce02cc016b1b86ede29851caa32434212ffa2a377c8","other":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","up":true},{"one":"a5053958f0cefcff1826bf02525fda98c4dc954cc38690f3c43ecbf0b2ad57af","other":"a7a856a43293aa3004848a86f187e09343bd605e1a93e853a6f6b6b1031bd667","up":true},{"one":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"f215bc09268e60ebbec76f743bebd09d7e72d4cbeedc0b9d3417bb4a2ef42935","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"87a337622455ae65daf3ab2555cee8985e9aa14bac245545d985296060e4a8de","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"bfc711793830779f49aa59bc6f7a205ab4e6eae7abfdafbf3bb5a1163a778ab2","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"807416cc70f02d481a188027f7932b48e8f7b5e8258f7e9623f3f6e2985d8f6a","up":true},{"one":"aaf051a087a92f874a3f6c7923015e4cffb4bb3ef381c977fd902f21e841d0f4","other":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","up":true},{"one":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","other":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","up":true},{"one":"9f7d72b7d9843872904b841e421985082428fba5010db27dd871ed76630a1e1d","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"d3022a46956e75bca85ba89d97b694a3a64f03ccc2d881ed0cd687d43d486925","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"4a95d49f58057b039b55a34f67a348c052f61770065e41243ff055efc570a935","up":true},{"one":"f2b49a2247c9c5e8f6f755834a37fe5c17f208f994878e14b7001e404f52e125","other":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","up":true},{"one":"e471efbcf1def3915b3dda2dc65a86945c607be54a33e31e9625549becac0e34","other":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","up":true},{"one":"c8c8a93779ec4d9ac40925e8208478a00ee27fc220ddd73d8774cf6bfa255c46","other":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","up":true},{"one":"cdb13873ac058861f295ebca5d958bf2bb793e3f9e274cf5a73a633425a9276f","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","other":"ec90a22f41ee659d5759a497946ac2991c916f00fe7caeeeb0908f3af1fe60b6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"ed424d24d702520bf7cb5f6babbdc43a078435fb4a9884ed82a93d642839e127","up":true},{"one":"1fd0192df1fbf33771ca575afbb4e27c6541cce4a3cff2dfc1f2c085e7fab79e","other":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","up":true},{"one":"6c0142984d629ae6995894de9e7e5eb8d3fe45e1641d7ebd63959d2e61548ba3","other":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","up":true},{"one":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","other":"8e282b0f27d4fa56fe14cfeb69fac5a53e3d882c7778eb190653e2eab7c93fd2","up":true},{"one":"0cfc7309afabceeb7d248714e972cf3987205324f5ab8d048d17bea5dc87369d","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"70f68562733da4e3b1c3949fb6e11ac0bdd49ea7e732925f937f87df5af698d6","up":true},{"one":"435d721a568eb906a03c69dbd71337251a550521a4004ab5d4a7deb6f317061a","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"68cbc4a5313080d5dca8ad34e8bf52a6144e0ff8ef3f795d7ae9d5f644fe2042","other":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","up":true},{"one":"48f1ca6d433019f932fa4ae03e0decbcbea3fe635edff4458a669b83f8162b9a","other":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"ab3ff955033c0a2615932faf85fd20090b9121c7edcc8e6f7ce4c4fde0a96b8a","other":"a8b58013ff911871d1aa6c2bbea6c2e6ef9b00b87b80a41dc04724ad0488e2ff","up":true},{"one":"e64d90760cd81e4f112bbf1432e76c82fa4173fd474b988f4096ce187363fd81","other":"e09f98114da64e7547b351637190f6621a1f75568cfa9960980fc77618f8855b","up":true},{"one":"096a8302b6f369c28ed9d47719a507ead8a3cc1ca4fa1e32318b7f97873955fe","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"1dec77c2f4caf053c2d0524ae34a2d970bf4743a0d009d8fc543077ddfdfe3d0","other":"1dc0ef1ce68dc681298177bde808af514efa52a5ad38c9cd2bd61968cdf19cfb","up":true},{"one":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","other":"eb686a686fd70e41659cc69ec0db53d1512dfec238918afd0a515d8ce177d4d9","up":true},{"one":"244c3c954ac612e51d4945ab9b77f0b4a3983285e8add7921777e0c45a1bf338","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"8006b080c78a0ab54fa1be75a939bee2334322fded6c3563de1596b17c36172c","other":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","up":true},{"one":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","other":"8b4318f86ad47976321af97bfbf95cd0a3b0aa22447aeb0611ed1a9bf1e6a4bf","up":true},{"one":"24f80c437be45898e594f821bba0f5c62e0c9a0c720118e362ee6f78410612bd","other":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","up":true},{"one":"f1ed9d45622ff974a1e396cd878b2deb89e31aa5d08da773423f292ae8dbcbb6","other":"f645aab9cb2bd2709998b38e5789c9c5f68d40765e6cbd93b92e6383eb671dba","up":true},{"one":"80735a728720bba0ac08daaccd093370d672a8f9a50845ad78ccd6cf8686c39f","other":"80d7e892bbb26808abb1d1530077fec6b08768c151a9f220881da3c862bae0af","up":true},{"one":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","other":"a32749dc4e134a4fbb038618c58a7c05bbbaa06f1436de3754341af86402581b","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c9c302de4afe7b4dcbb6f3e366ce747083f9dcd7d5c6a01b939da5cdc6ccc874","up":true},{"one":"8ea2c8acc111f38d5b4a5ed60252ee83f312d0f8359265d5b9266d54735052fe","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"bcf85ecf421b871fca0247a7081188a8e2c08778b88ffad16db37ef024fec0fc","other":"be68267d77fb52424227267c665ca1193a010334cac057338aca77b49a4b94da","up":true},{"one":"a3309f8b8bba4d8fbd7c6193d7671cb907b94e71155ef6138e0248682ff00e58","other":"a1c85ee75edb807a01f4ce930086c948918aade324752609b078c28991c04e86","up":true},{"one":"09b3fa30780931e18b92c75d1cdeafa365609c565e4e8c253d393835cb82d98e","other":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","up":true},{"one":"67909bdcaef2330ef120e524c76e1e382b474f3332d86f65282028e051f34c75","other":"60c5647aed152609979366fb33dc8b28fc60736098ff68d232415889b43dfa58","up":true},{"one":"d3e913cf4a7dabfb5699131b65e533a40adb46ea37e0ed4ce9433f99015986ef","other":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","up":true},{"one":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","other":"4d9147e3bf98cb59a7648f616c0d7f713a8cf3b7d25e3115233ff5883128beab","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"43c9e1571c460cb9f599fa8ed79ddd0f9c3a21fd2fa455e0603109c55012f76b","up":true},{"one":"d700d96de1193456dc0bcf492c7c11b0951062974af2f7f47b8c901b17c23165","other":"dad08999cd2edc33cfdc59ea34c8adcd6a34eaa15f2e85b0622e9848b215c1d5","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"c8ea4177420785926e0929701f5e74c744920386f2a43b89d83c8281106cb95e","other":"c96146ee47ec7cd74551cf74f00213bc337d643c4327393f0e6848ecd4a0f8d3","up":true},{"one":"fc3911383f74a982f6af8ab95a63426b56117d45f153b3c1441459d9191daaff","other":"f9ded7b83e473e71be2fc0101d574c44521c96f77f9f84a384785a3af6b1093d","up":true},{"one":"8d192b11538072db750f71204e2e6adf9dc0508d9c5cf1eb457e4e996cd985bc","other":"885427318634c458a3050f2f26eb52454a75cea4a1263b9ed55e6eb899743854","up":true},{"one":"cc3397e9e11f75273d3f81d91f980f4504755f80b27a183212de56cc5085e58d","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"a5ac04d53b569e418ef5007961431155f2c226ee10157b30af71ea4836b08089","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"298ae5d173c5360bc9ad5b492ed35de3b6e0cae868a34bfe6311a8ba5ea9877e","up":true},{"one":"6b4ee1b73942ced78f97c0d0e221209933e63ae7353bb9ab3d37ac4127592e86","other":"6d3c6db15900f2596286f81cc0664d2c8291ead5bad2aa35bad515af088a2e48","up":true},{"one":"5ff09c6859736aad7a82a3bfb3f1a1a8b3c0d58f831863540d9c3013dd35745e","other":"5c373034770e413e700b1cd03b2035f769ecd9ab8eb54d32f7b2645be1991fe5","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"84a9db7645c792dc38c1f2113a8f0590d04e1c94d9a8c464ab0ec8219303d966","up":true},{"one":"9257dc934dfbf17473b70cb85333c6fab67ee9b6228a646576c4f57253f1004e","other":"93ea8ef251fd56b159e080cdf733d33e1fdfb3c7ae5bd9a6a328d0bf5458867b","up":true},{"one":"793322608055d4873776a9a0a6c40b04379bfd2f289a8ad49a7dc456bc65f871","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"14849f811af20ce19fb29417d20c15fc16da1e45aebdf795a2c6ccb671e4bdac","other":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"553824ef701d3cd0191ae3a67de564ed0cf553e74bd60ed9de321f9302732ba6","up":true},{"one":"a606c79a018a6535375d851fcc82c42cc7c952720aa120434cedccf4a4be1f59","other":"a6165a4b02d58be116892982c0ed3d49d86fec0e9f436a516b61868331ed853f","up":true},{"one":"5814be13c8550b9a5a83d08e7af6022002a8fdaa38ba6c2c30be58099a9f7744","other":"5a26ae73eebf27f6dbec2414f1277a249e814a7a06790d7061610e5227b086f6","up":true},{"one":"ef99b6cdc05345a1ee82267890e3ccaeef1f2bd2fe7ae8b02b6b20b9a5ef85bb","other":"eebd48b367cbfe94a37c0deb274a697e628074f9560b909e66229c5c76ce68eb","up":true},{"one":"48de553e15afd3e8a46bfc3a5ba8a298158aa3d60f140d2730230af5cce8084d","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"7660828fb0c8f89201d34e6f4d61cc6ba9a30cead6e4eb8253f6cc92e1845f23","up":true},{"one":"2c8042517dfeaa01586e91e491dd4154fb24c0d84fedb0404b9d5136f60da1d9","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"0e80db9dfa8ce29bedfb2de031622bef8829bee52771322b6a7efb47afe540e7","other":"08f84878e44fed2adb4b2685b9f293dc3c73d5f9bc1c474870d943ec2ae73dbe","up":true},{"one":"1049d321a450726cf39d1d7cea1c108be3bec137a644b62cdc73a853f5a5a22b","other":"138dbc1662c4ce9b2b30ef5035914cc70465666fe18f313318e662d13f099621","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"741a854ae299df49a738725bc58abe614e5e4302ffecd8320bbede8412d160c0","up":true},{"one":"9f0e2bf8a962156c9e0a83c3d42ad3dc5ac5c3e508f24200bfb151aad4e395ff","other":"9ec831d97418916fd9695465e041caf27824dbb51d6ff74d6b70f3bd561e70e6","up":true},{"one":"7850f5ee5048959559b3af0f95689669b250fc3aa58bcc9544dca61ca9c9769c","other":"7895b2cb97b473f8893cc70a4421e0f8be1c033b27cd730fa13438b7a8f3fcb5","up":true},{"one":"a2a163ce2cb092b411c994cc5d5ef555d539d2dcf4e7e1aeb528d2216dc481e5","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"482ec3dc05460579ea9bce87677bd3d9a1930e801fabeba607b8ab6b8729ff15","other":"48b850974575ca57a3cc5f9a4cf5aafd8688cb32b993f69983ece63258ff876e","up":true},{"one":"9ca1fd5d41975acb905f337997922849b4070360e47849bb4fd8cd1b9ddb4d73","other":"9c8e1f23f260c5a46b0001572675b19e5293ca65e7fdfc131c07612e9c4072fa","up":true},{"one":"44adaabf9c46608a374ed816d3c40c63b6645f4f6e033a76431bc8f88713eb41","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"318828fa893a28cc0652d3f81d97c5b8e023e853685f5d3e65fde20689abcc5a","other":"30feca631f06041cb14cead384dfaa5fffa6dc34b0cee54230efbe15e56a5884","up":true},{"one":"5d82a418629cfbe7c57105309319ad695a198626fe3571de213a12ddf62f7308","other":"50c1a8023bfecffb09472fdc50898f4d050a31443d40a6c07b629090beb0df3d","up":true},{"one":"46bfa8bea56b0be1abfa5ad3561bb6bf49ed6695d83ee2b2c192c5a0408347cf","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"2a507f5cb921137a7225c9c4988a8514af0f7e3c442cb8bf2bb612dc522a7daf","other":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","up":true},{"one":"837f0993f6374039a5ad4472d6313e647a4c5db4583bd27ccfa98d3448a17731","other":"8402bd62282811ed236b2fa1f0d41ad4bbe54e420ee34adc6164cfd4baf8658d","up":true},{"one":"cf52b3fc82ec24c3e9b40488d7c5f7ac8af731d159a103619bee932ec74d5e92","other":"cd6c8b42a0b092f41e6925577c9de7d1bea17231bcb3d08f3d3cce9c6fdcf22d","up":true},{"one":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","other":"402cf9d0bffa017ebea34ede11207f3366b3ea450c0428029129a8e8026abbe7","up":true},{"one":"194ea3e14dc5d99f98d15607dc4c405769f5a371acc22d41a62d0537d716be32","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"a2e6c900511768c8c9947ab0fa2e73975cf2a4cec7fd15217abdba25c329317e","other":"a0c88ba70599b0e72c18fa6aedd14d607cca3e9a49a5d50165d084e70328c2dd","up":true},{"one":"8cc3fb39009d0adc26fca1e2ee96822d168d4debc379fd516c15d4b4a1624231","other":"8f9aa2cd33d18e7cb4494d11a7532c97eb4a1cae172b2165c26ae4ed24887c0d","up":true},{"one":"1bd588263274543729d54529ae9e9bf4596db40649a1c2a3f73168d818f34b62","other":"19ea0a685fc4edd298b736dc7a778c9ec4362de378876911105fa9ba2ce90204","up":true},{"one":"447cdbf1ff462aa67d6a46085b1a84fdc495a4142ab174c8e69b271b09732b4d","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"fc514c43c4eb5c62798458da5d622e9248a6e530e4288cd902019aa05c4374d8","other":"ff75b19017c84128f38dec4f63e1f247a5691dc0fae186e667afedb5fe9d2c80","up":true},{"one":"4005fd1fa8fbb318b29a62c368ada579e5122ca0578e6a75c509552be4b63b76","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true},{"one":"2fd2f77d76cca480ac18e9af7a462f297db168c3370b3bc0e2c04aa006c4d037","other":"2c85f5361b2d5abcf799de50fe58b1ed2006ea18f75823748c33eb7e95b1cc39","up":true},{"one":"447a411c80fbd422bfa0c358d3f2a1fe6256c05e35acc6350958dfbe62cd5b9b","other":"43d43e9ebcbceb4830fc1d2d5024650b90698306bbd2c4d0b4841a1a8fd09c93","up":true}]} \ No newline at end of file diff --git a/swarm/pss/testdata/snapshot_3.json b/swarm/pss/testdata/snapshot_3.json deleted file mode 100644 index 15ed45bcfe..0000000000 --- a/swarm/pss/testdata/snapshot_3.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","enode":"enode://6a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f9757875b6b8d02f88fafe3fd7f20f0349a0060ace7c0be1d65470e736a3319431b5c14@127.0.0.1:0","enr":"0xf88fb84096f5dd9030fc74da3701ef7b06dfe4d44068118f8041a728876904d70fa8c88c20df197c343522c76d75d3a12507c567213c13b46a94ed4800f47474643f4ee70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026a7dd306ace8a106c3b86ac6b0cd6eeccde4a9af5090ca4a6d1054787f975787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"/TfkUhDds2+LXs75ydnT+CAbqVI7/WpwKRMzzzuSB+E=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fd37e4\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 1 3594 | 1 3594 (0)\n001 0 | 0\n002 1 cb08 | 1 cb08 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","private_key":"6a02f87b1d13a15ce24bfa58456af8aaabdcf8cb58b9f86c19ab14c721c80f91","name":"node_fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","services":["bzz","pss"],"enable_msg_events":true,"port":39341},"up":true}},{"node":{"info":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","enode":"enode://0972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03397efbad98888f8d740b7cf55c357d1d6d74b5e8cb935f71b19e0e16ceef03f9@127.0.0.1:0","enr":"0xf88fb840d5f39b1ebcd5b616ef67b1c0239ed4501ef45c6a00e5bd8cd3f2ac88870d4c4b6ce4a4af820afab9a714d99a5fef53ec3c042fc3243f403819bcfb3504c2150d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030972df8ba2504ddc155739320ab392e64d000c950e08ce42863449bc4757dd03","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"NZRDinSApcPcBkQOKKFgRMDH0okhnaAvnkHaGBCCeAU=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 359443\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 fd37 cb08 | 2 fd37 (0) cb08 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","private_key":"26266470b7f4e9341cbbbb304b1aed116626cb1bea55d639cdbef1a069c18123","name":"node_3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","services":["bzz","pss"],"enable_msg_events":true,"port":33055},"up":true}},{"node":{"info":{"id":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","name":"node_cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","enode":"enode://046f757c2632f0fbdb74f73ce67be9cf181f85a6d2a8ec0d5e8a329a8ede81fe476bb5a1e5896b9ce49201ec4a32561bbbe91ab46eb9f7d99bb9a0002df3a639@127.0.0.1:0","enr":"0xf88fb84022bde12be56af73a7793d7ffe9f22d205a7540d6cc337815697115edeafcc1d461427c8cdee33e602201d3b2dfac034b567a8270e5f0c8b3fe29e10883f4b1e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103046f757c2632f0fbdb74f73ce67be9cf181f85a6d2a8ec0d5e8a329a8ede81fe","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ywipNV85ulXmoasCQQQCFppjAINUErqkveBJo/oUQ70=","hive":"\n=========================================================================\nThu Feb 28 17:15:44 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cb08a9\npopulation: 2 (2), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 1 3594 | 1 3594 (0)\n001 0 | 0\n002 1 fd37 | 1 fd37 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","private_key":"52fd9e67692ef0963c13052f85f88eac3a527cd50137e4c0a75ebc8ad471b8af","name":"node_cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","services":["bzz","pss"],"enable_msg_events":true,"port":38675},"up":true}}],"conns":[{"one":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","other":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","up":true},{"one":"3594438a7480a5c3dc06440e28a16044c0c7d289219da02f9e41da1810827805","other":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","up":true},{"one":"cb08a9355f39ba55e6a1ab02410402169a6300835412baa4bde049a3fa1443bd","other":"fd37e45210ddb36f8b5ecef9c9d9d3f8201ba9523bfd6a70291333cf3b9207e1","up":true}]} \ No newline at end of file diff --git a/swarm/pss/testdata/snapshot_32.json b/swarm/pss/testdata/snapshot_32.json deleted file mode 100644 index 05a40b2b82..0000000000 --- a/swarm/pss/testdata/snapshot_32.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","name":"node_2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","enode":"enode://6e710e572097f299c352e4e1b8a2980de9e6d2cba35fc6b05623ed829c722148861d96fef1530c41ea27a53be8894dd32b299189b421f1f8f06f6a706b56433a@127.0.0.1:0","enr":"0xf88fb8409bf3f7dd13b162a205ccbe927f310ddf3b8c4c5f89183331a6317408259f970e7cec513e4ee7bafb3ae3378b24837e035bde558630c0e6b7db93527f043dc0de0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026e710e572097f299c352e4e1b8a2980de9e6d2cba35fc6b05623ed829c722148","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"I0Wt0e19mNuIFqrT/aCCnmsMnBZwhwZ6fsOokL7IrVg=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 2345ad\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8ee3 8115 | 13 8115 (0) 8ee3 (0) 9b33 (0) 97b7 (0)\n001 3 7fb9 6e31 4730 | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 3 0518 0d53 0993 | 3 0518 (0) 0d53 (0) 0993 (0)\n============ DEPTH: 3 ==========================================\n003 2 3a42 39fe | 2 39fe (0) 3a42 (0)\n004 0 | 0\n005 1 24cb | 1 24cb (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","private_key":"f020ebea0429ea9f2ed075c50df1841beb61cdb88a0b5a3b864fe27bf214a297","name":"node_2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","services":["bzz","pss"],"enable_msg_events":true,"port":38575},"up":true}},{"node":{"info":{"id":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","name":"node_4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","enode":"enode://e57ffbc9c56f76b56f9005ac74af0db50a8e6f883e392b744080f36b35441ef2031f57e8d5d1899d0343f59545dfdda51cfc3c861bd810e0cb75516e32384676@127.0.0.1:0","enr":"0xf88fb8406472138d3fd8bb33c916d5192587abed17160ddc25b5b725259f95b3b5ab17b92fbb75939667eebdd4a0dab29d5b6a5b0cf3878d40c7c412cd99d22e94ced4e40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e57ffbc9c56f76b56f9005ac74af0db50a8e6f883e392b744080f36b35441ef2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RzA2Bnms9jD8iroUx747vBOVPLHqjXpy9aO1dkFw73Y=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 473036\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8115 f3ed | 13 8115 (0) 8ee3 (0) 9b33 (0) 97b7 (0)\n001 3 0518 39fe 2345 | 7 0518 (0) 0d53 (0) 0993 (0) 39fe (0)\n002 4 7df3 78c7 6a64 6e31 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n============ DEPTH: 3 ==========================================\n003 3 541f 579d 5743 | 3 5743 (0) 579d (0) 541f (0)\n004 0 | 0\n005 0 | 0\n006 1 4464 | 1 4464 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","private_key":"99552bc7c5ce5b7ea569a6d3b46502a171a9ae1a3a6bc88f3fa2da99b1b25ef7","name":"node_4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","services":["bzz","pss"],"enable_msg_events":true,"port":41821},"up":true}},{"node":{"info":{"id":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","name":"node_f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","enode":"enode://0dd06e3e445d2cc141af19d7143f57fdb7fd08688718a628230c9e80ee2e700d12b98585be5c983630faa8061cca9dcee5fa267840ab63c7a177ed32c54abac9@127.0.0.1:0","enr":"0xf88fb8400bc5733ce0c6dab1ea57bf24e37a838bc7bfd4d4fa76002760aba33bf2b102b27f84c60b93282a95881f98a45f91c174957d61630a70e6bb91877a0417b99c970183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030dd06e3e445d2cc141af19d7143f57fdb7fd08688718a628230c9e80ee2e700d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8+0awvoZrhK+qr4ifsAz9JUwDwgwqEAUyDn/LmdsmNM=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f3ed1a\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 39fe 3a42 78c7 541f | 19 0518 (0) 0d53 (0) 0993 (0) 39fe (0)\n001 3 97b7 8115 8ee3 | 7 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n002 2 d735 ceeb | 3 ceeb (0) d735 (0) df92 (0)\n============ DEPTH: 3 ==========================================\n003 2 e17a e25a | 2 e17a (0) e25a (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","private_key":"6cd0d2e5beba190a7a871ae45b3bfa123d3c79b4fd171ef22eceedcfa35dd7d6","name":"node_f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","services":["bzz","pss"],"enable_msg_events":true,"port":46325},"up":true}},{"node":{"info":{"id":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","name":"node_541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","enode":"enode://1cf1ddffc042e967618bacdcf1e4aa0e765d65acc9e75c3ba8ed8b40c5f602eaf1cdb0652219fa04c169441b74ad07b014e7b94c54a54d7aefdb2b9e05d8ed48@127.0.0.1:0","enr":"0xf88fb84017719ad2bdcf75e3de4b6bd1d41115306432abcbd8d0ac6ea95bce768f5b06c12b4f507ff59afcb21724688f254f2f177b300c1f22995c184b3466cad698ff280183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021cf1ddffc042e967618bacdcf1e4aa0e765d65acc9e75c3ba8ed8b40c5f602ea","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VB8Vu+WNnhsr09FYLFz6Yv281DY7z0UZZPjG108XmjQ=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 541f15\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 8ee3 f3ed | 13 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n001 2 0518 24cb | 7 0518 (0) 0d53 (0) 0993 (0) 39fe (0)\n002 2 7fb9 6e31 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n003 2 4730 4464 | 2 4464 (0) 4730 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 5743 579d | 2 5743 (0) 579d (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","private_key":"92852d378cc44e9e13a49fb6eac32c7808f2415bd4882da6076b5c5c57147a52","name":"node_541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","services":["bzz","pss"],"enable_msg_events":true,"port":35339},"up":true}},{"node":{"info":{"id":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","name":"node_24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","enode":"enode://793fc878556c2704dac445d6dd237d8d4a5ffd6a9ccc7b40315790785062fcc9423df4649fdbeed26a47e3220ac6798c43e8111357e37d8a186382805a2d0f7f@127.0.0.1:0","enr":"0xf88fb8405ec36b34d21bc6414e2a974f21a891aa1ba4f896e1787c7e94b253908b8eb9274cf5b6c102479de1aef263c90c09c275ffdc2c8480007c92034d7073ac56b4de0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103793fc878556c2704dac445d6dd237d8d4a5ffd6a9ccc7b40315790785062fcc9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JMs5GxmEpTgK+C8vpiLxoC6wNeyzQB1TjkGCSWXdzFY=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 24cb39\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 e17a 8ee3 bfeb a263 | 13 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n001 2 7fb9 541f | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 3 0993 0d53 0518 | 3 0518 (0) 0d53 (0) 0993 (0)\n============ DEPTH: 3 ==========================================\n003 2 3a42 39fe | 2 39fe (0) 3a42 (0)\n004 0 | 0\n005 1 2345 | 1 2345 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","private_key":"e9e78ca9c5aa6c4d52d7d6f39dc7ef585ac1b3a232beec65a7493e818276c04d","name":"node_24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","services":["bzz","pss"],"enable_msg_events":true,"port":40305},"up":true}},{"node":{"info":{"id":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","name":"node_a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","enode":"enode://0e4cad0aaad50693ff30730b850da74646d6742011b90cbb5ea2e8bd1d5430f553796beed70d373525d4bb7a136a7ff5b3acee77afb21b9c91ba93bab9c1e7c6@127.0.0.1:0","enr":"0xf88fb84093fd09e514cfed721f0cb368859e31ec619cc2d0d8482cd0b216d6d368d761b43c8a0ce93916b46d87f2338a934a1ae706f2070e4cd6599b891ec374c90aa1110183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020e4cad0aaad50693ff30730b850da74646d6742011b90cbb5ea2e8bd1d5430f5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"omOldpzz8ibbfSzZGu6WogbEawziqAeKbThB3D9MXGY=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a263a5\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5743 78b6 24cb 3a42 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 2 e17a d735 | 6 f3ed (0) e17a (0) e25a (0) ceeb (0)\n002 3 8115 8ee3 97b7 | 4 8ee3 (0) 8115 (0) 9b33 (0) 97b7 (0)\n============ DEPTH: 3 ==========================================\n003 1 bfeb | 1 bfeb (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 a3d9 | 1 a3d9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","private_key":"ff1484b5140cd7e811e6ce51bf267644de2b44a4aaac227490a713ed17b998ad","name":"node_a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","services":["bzz","pss"],"enable_msg_events":true,"port":45663},"up":true}},{"node":{"info":{"id":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","name":"node_3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","enode":"enode://6cdb01e6d8e2f2d201ae9593e7234c2f954efe223726481576d9596ecebf45965ce6606620cd8ac5ce8a62dd03ad386319acc6b0b49caef9533b8fb39f928338@127.0.0.1:0","enr":"0xf88fb840d5a5fd5c60a2e5253b01fc73dc69320f4be754df21628a91874bc86ae8e00bc02c432f46859e14dbc35515f1864c6e482e0165490d7a2e9e73a868789e6dc1560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1026cdb01e6d8e2f2d201ae9593e7234c2f954efe223726481576d9596ecebf4596","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OkKYvhPDnd7gRvQjeGNSjAWsHjpsnCzEKWNoZdjuShU=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3a4298\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f3ed a263 | 13 f3ed (0) e17a (0) e25a (0) ceeb (0)\n001 3 4464 753a 78b6 | 12 4464 (0) 4730 (0) 541f (0) 5743 (0)\n002 3 0993 0d53 0518 | 3 0518 (0) 0d53 (0) 0993 (0)\n============ DEPTH: 3 ==========================================\n003 2 24cb 2345 | 2 2345 (0) 24cb (0)\n004 0 | 0\n005 0 | 0\n006 1 39fe | 1 39fe (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","private_key":"c3bd98ec585a2bf57984ea44e3df5862d0ac4036367cf8a71530d6e3da5e19cf","name":"node_3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","services":["bzz","pss"],"enable_msg_events":true,"port":33977},"up":true}},{"node":{"info":{"id":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","name":"node_78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","enode":"enode://0020a4e955476d6774ca840c91a6f298f738eb8bc162cdf0bf919d6ff85430dd080d68b2519e7a8806e30bbedd04d9ca0455e9cfea9a9d1f8316b3e02a7739c5@127.0.0.1:0","enr":"0xf88fb840091444d053b7aaddb31d705918bf78a24089d8db087272558babdf3c35e7e1544ab5f6d6d130c38f71153b590cd6c4a8b0538b39505b3bd53caadb499d7efc350183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030020a4e955476d6774ca840c91a6f298f738eb8bc162cdf0bf919d6ff85430dd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eLai+zQolUhV+9v5mTjhIUuPGfozQUSYQonR+wO7T3w=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 78b6a2\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 a263 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0518 3a42 | 7 0518 (0) 0d53 (0) 0993 (0) 24cb (0)\n002 2 4464 5743 | 5 4464 (0) 4730 (0) 541f (0) 579d (0)\n003 2 6a64 6e31 | 2 6e31 (0) 6a64 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 7fb9 7df3 | 2 7fb9 (0) 7df3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 78c7 | 1 78c7 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","private_key":"5d3e69f521510ed62af7c34c089faa034445e525fae5789a5b2708e3e34a55b7","name":"node_78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","services":["bzz","pss"],"enable_msg_events":true,"port":44923},"up":true}},{"node":{"info":{"id":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","name":"node_5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","enode":"enode://9769d41ff8d1a2220be2c7a9f3f522b197606a2a9b771e70f7115b43e9a3f7f8a2bd1bd4a7eed179a8f5032b122e7a16cc3f38eabf55f2655cb183a12c425f59@127.0.0.1:0","enr":"0xf88fb840406de7323ba3d20449df0acbcba8c0a6104d62495aae6346997f988a71b197a7232ae0db83b24c4b90dc2e9c8192734fd6bae7b1b0d41e80102201920fa864d70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039769d41ff8d1a2220be2c7a9f3f522b197606a2a9b771e70f7115b43e9a3f7f8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V0O8CecT58TVj+8ZUatrYnon5vGjxC24iCehYTvX7z8=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5743bc\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 a263 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0d53 0518 | 7 0518 (0) 0d53 (0) 0993 (0) 24cb (0)\n002 4 6e31 753a 7fb9 78b6 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n003 2 4464 4730 | 2 4464 (0) 4730 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 541f | 1 541f (0)\n007 0 | 0\n008 1 579d | 1 579d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","private_key":"3ec49076ee0972b516c7ac98a7ab569014cf747935fe3dd076c683c1cc7d0509","name":"node_5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","services":["bzz","pss"],"enable_msg_events":true,"port":35273},"up":true}},{"node":{"info":{"id":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","name":"node_579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","enode":"enode://024d47097bb5d264e382a071489167e48e9c4e56ee3d0eb6594603ed7847dbbb141b45523e4b174b7083472630e08dcc15bb2495bb1fccc0506b19d4e14fa297@127.0.0.1:0","enr":"0xf88fb840e1f4b1665503a11d8e8c261ffc24f744272c0d96ebaf17d03c2046f6a0c3161f264ff1c4ddc618cb5da9c35b4dae871aaf7ec77cee48cab46467acc27f7d812b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103024d47097bb5d264e382a071489167e48e9c4e56ee3d0eb6594603ed7847dbbb","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V52hcJAe2RG+NEXUQiZkqZfrFCAVidcC4GiPYUaHKZM=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 579da1\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 d735 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0d53 0518 | 7 0518 (0) 0d53 (0) 0993 (0) 24cb (0)\n002 2 6a64 6e31 | 7 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n003 2 4730 4464 | 2 4464 (0) 4730 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 541f | 1 541f (0)\n007 0 | 0\n008 1 5743 | 1 5743 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","private_key":"6e50f30bce1310aa06e28011d83829b6432b73e09ffaa327bcb09d0a871e56c5","name":"node_579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","services":["bzz","pss"],"enable_msg_events":true,"port":37161},"up":true}},{"node":{"info":{"id":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","name":"node_d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","enode":"enode://e0063bc92893325b6f3aff3a1cdebe170f3a70c3ed8b6aa55607f96ffa9e199f1f37d6b4f5743adeb91e1aea7baea44fca78010706f2615c27840a341d926a4d@127.0.0.1:0","enr":"0xf88fb8407686b23d8d56528be1d859eb241e4228adbebf46b6664fb1a89141257a7552140a602485685a9256944106c9f9f57828d22cd7ce01c64fa504dd7977294b52cf0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e0063bc92893325b6f3aff3a1cdebe170f3a70c3ed8b6aa55607f96ffa9e199f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"1zUeR/DHRu0zxlKw8qov7TVMja2Nh1JaS1EVga/2xvo=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d7351e\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0518 7df3 579d | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 2 a3d9 a263 | 7 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n002 2 e25a f3ed | 3 f3ed (0) e25a (0) e17a (0)\n============ DEPTH: 3 ==========================================\n003 1 ceeb | 1 ceeb (0)\n004 1 df92 | 1 df92 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","private_key":"e6ebe5c66707a0c89243e414155374afcdcd0529b7fb63d17696f685fe9554dc","name":"node_d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","services":["bzz","pss"],"enable_msg_events":true,"port":35925},"up":true}},{"node":{"info":{"id":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","name":"node_7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","enode":"enode://f0b310658f442f5bb853496ee598435dd08bdfdceb62499f0aa1583212529fb831b2d1f6db5a2faadc238f91204b7d5a51d7f9259983008bccba2d35d5bd7114@127.0.0.1:0","enr":"0xf88fb84015bb5fcc3a16b896d129418fd6304c5c4a07d2613278e74c38490a515d97e03074fb145cd653fcf028feb6f005d0ca8c83203df0ec9c042635e41c9a685264810183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0b310658f442f5bb853496ee598435dd08bdfdceb62499f0aa1583212529fb8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ffMHT04RdaIT5XiTmr2cHl/3FUPrXcJO5d7V+ATjuEI=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7df307\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 d735 | 13 a3d9 (0) a263 (0) bfeb (0) 9b33 (0)\n001 2 0993 0d53 | 7 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n002 2 4730 4464 | 5 4464 (0) 4730 (0) 541f (0) 5743 (0)\n003 2 6a64 6e31 | 2 6e31 (0) 6a64 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 78b6 78c7 | 2 78b6 (0) 78c7 (0)\n006 1 7fb9 | 1 7fb9 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","private_key":"2739d262560fd1c32320e01920f26d20fe756d085ea86b3a3c105ee36f6b13c4","name":"node_7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","services":["bzz","pss"],"enable_msg_events":true,"port":34347},"up":true}},{"node":{"info":{"id":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","name":"node_78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","enode":"enode://2852c5c0c2cc4ce9ec1e680b5be7fdc6178bf36e6393d791817042b221a0f787dcb6f00600b95c177940bae3dcad8bb10d7e0601d92d6fee73033dcffe0af98a@127.0.0.1:0","enr":"0xf88fb840250093f9c808805726fa94afee9b1fbe20be7c6bcaf444a93e3073cb2eb4632d1eb840824f9ca949b40b26b9878f7399f4c3c1ee6ac0877c3f52efb88aae18510183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022852c5c0c2cc4ce9ec1e680b5be7fdc6178bf36e6393d791817042b221a0f787","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"eMcNM9/RMbzBxkJnv3Hm/oHpP4kblAoRFMZXyCZnW9c=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 78c70d\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 f3ed a3d9 | 13 f3ed (0) e25a (0) e17a (0) ceeb (0)\n001 2 0993 0d53 | 7 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n002 2 4730 4464 | 5 4464 (0) 4730 (0) 541f (0) 5743 (0)\n003 2 6a64 6e31 | 2 6e31 (0) 6a64 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 7fb9 7df3 | 2 7fb9 (0) 7df3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 1 78b6 | 1 78b6 (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","private_key":"ecb17d33e2878ecc69683c97b16415ef66ea959593d5e15b0a376ab566cccdfb","name":"node_78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","services":["bzz","pss"],"enable_msg_events":true,"port":37163},"up":true}},{"node":{"info":{"id":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","name":"node_a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","enode":"enode://abe44f262b43e0ddcc49d889a93f3f7d43ea44bf504d23937464edf104332b963d3635818c12867c25f4e43c4860e18cbedc28a87dd87ca65bf2b13db23ff93b@127.0.0.1:0","enr":"0xf88fb840c0a357ca865bdcbfbc5f575be6d2ab837c7354069d334c5ab7d618076595a70c5a8a53142161c36f6d759f2f8e196924f722f98635f3fbfbb86fe7a910868ad20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103abe44f262b43e0ddcc49d889a93f3f7d43ea44bf504d23937464edf104332b96","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"o9mHeV4Z+FGOR3D3LJ+AgEuZmjG/ItCc/rBNZEtCm/k=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a3d987\npopulation: 15 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 39fe 579d 5743 753a | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 3 d735 df92 e25a | 6 f3ed (0) e25a (0) e17a (0) ceeb (0)\n002 3 8115 8ee3 9b33 | 4 9b33 (0) 97b7 (0) 8ee3 (0) 8115 (0)\n============ DEPTH: 3 ==========================================\n003 1 bfeb | 1 bfeb (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 1 a263 | 1 a263 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","private_key":"765bfc005ad4dec671a2f1dee108fa60f9760b185dee1d2a2af53a0d56f53902","name":"node_a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","services":["bzz","pss"],"enable_msg_events":true,"port":35675},"up":true}},{"node":{"info":{"id":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","name":"node_39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","enode":"enode://1a9002726d9442faaa087d3f865c4c5d7f2882a87866a710835cbb8d4dc3da7338b868cd888fd898e4016dd20fd21f98891a212f1b17a5427b5476b5b6f6c317@127.0.0.1:0","enr":"0xf88fb840fa5103638887af121c7fe3afedad54432df30561fc796f03459942a3f17f7cc03ea50cfe59d8af29e82b76f1295a8b5697f48525060ed90d804210a80df804bd0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031a9002726d9442faaa087d3f865c4c5d7f2882a87866a710835cbb8d4dc3da73","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Of6nbi5DCRnK20jOKQwRrWay+KZohq4ItZ5Bj6Tq3os=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39fea7\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f3ed e25a a3d9 | 13 f3ed (0) e25a (0) e17a (0) ceeb (0)\n001 3 4730 753a 6a64 | 12 4730 (0) 4464 (0) 541f (0) 5743 (0)\n002 3 0518 0993 0d53 | 3 0d53 (0) 0993 (0) 0518 (0)\n============ DEPTH: 3 ==========================================\n003 2 24cb 2345 | 2 24cb (0) 2345 (0)\n004 0 | 0\n005 0 | 0\n006 1 3a42 | 1 3a42 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","private_key":"bd7dbd51baf88692c24a8d75636af1f00e609fe4eda6444b674b14ab09ecddc5","name":"node_39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","services":["bzz","pss"],"enable_msg_events":true,"port":33437},"up":true}},{"node":{"info":{"id":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","name":"node_6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","enode":"enode://ce647cc2ad911b8cb35aeb74b022bce733ae4cfd609859b6c348e72e4e03cc4284064126b5419e15e7ad1e321469b3fbc3cb30319247c36b0eeba7f5a069a78d@127.0.0.1:0","enr":"0xf88fb840d07202149bb989b7b0bc49a88fab6c8e70082ef55751246005290393cfe8979c72eac475f2a5fe1292b7a48ae288d9fa421806c36447be580061fb5ee11fe5f30183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ce647cc2ad911b8cb35aeb74b022bce733ae4cfd609859b6c348e72e4e03cc42","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"amTXZeQP3hGQ/yKLuGCWuEGC1xnm0bcTcm25qu6kN9o=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6a64d7\npopulation: 14 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ceeb 9b33 | 13 ceeb (0) df92 (0) d735 (0) f3ed (0)\n001 3 0993 0d53 39fe | 7 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n002 3 579d 4464 4730 | 5 4730 (0) 4464 (0) 541f (0) 5743 (0)\n============ DEPTH: 3 ==========================================\n003 5 753a 78c7 78b6 7df3 | 5 753a (0) 7fb9 (0) 7df3 (0) 78b6 (0)\n004 0 | 0\n005 1 6e31 | 1 6e31 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","private_key":"2d1258592260e026c71f0e3d8f9b60ff4264cca8acb232abc3715ed0fa49e8cf","name":"node_6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","services":["bzz","pss"],"enable_msg_events":true,"port":37153},"up":true}},{"node":{"info":{"id":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","name":"node_9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","enode":"enode://ddf82056124d428300b2fbe2318d468707657ce7aed15add51629475f3bf3076eb42fd2da9394bef0c22e2fa4615e39e3cec3073587947862b347e7e30e046e6@127.0.0.1:0","enr":"0xf88fb8403df62e843c1aba232b75f4e1ef741cdcb6a1abc2d70c27548171885786d8cf6262354bc32298a1202bb3a1b484b9840592f11470af89955df5c5cff009f3d5470183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102ddf82056124d428300b2fbe2318d468707657ce7aed15add51629475f3bf3076","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"mzNa62m3+9OWrOUYLT/nkw5dl4ZTFZMxC0ioV8K7dp4=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9b335a\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4464 6a64 | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 2 df92 ceeb | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 bfeb a3d9 | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 8ee3 8115 | 2 8ee3 (0) 8115 (0)\n004 1 97b7 | 1 97b7 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","private_key":"f0dcfc2e5fe5cc19ae0e55c17cea621a344848ba6413de2fa1370d0ef5041cc1","name":"node_9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","services":["bzz","pss"],"enable_msg_events":true,"port":36105},"up":true}},{"node":{"info":{"id":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","name":"node_8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","enode":"enode://519322960c41240dfdf0f6eb33cf4dbcd607f9c71552844f4c88b40535ee8e8edc4f81e969ee6418ecaeb731f6627c7553535db148d6af171aa90d3d4b52de5e@127.0.0.1:0","enr":"0xf88fb840beb59d1ae71c8e13e68f38f5dc4d35fd419423aeb66e9bd02825cd51675e195c59bfe74790a11d3660a429f51c7fa533b03f5de75f9c50bd9deb20aad7bdb3aa0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102519322960c41240dfdf0f6eb33cf4dbcd607f9c71552844f4c88b40535ee8e8e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"gRWrzzl0enrz7s5V8SzJ5JCaduQYU7LhJlIhUNvalQc=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8115ab\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 4730 0d53 2345 | 19 0d53 (0) 0993 (0) 0518 (0) 24cb (0)\n001 2 f3ed ceeb | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 a263 a3d9 | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 97b7 9b33 | 2 97b7 (0) 9b33 (0)\n004 1 8ee3 | 1 8ee3 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","private_key":"0cdcfe48b7096864bb66f2d09b7ef45a27b5f26606f6429a841a266fadc2b8de","name":"node_8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","services":["bzz","pss"],"enable_msg_events":true,"port":37937},"up":true}},{"node":{"info":{"id":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","name":"node_8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","enode":"enode://5eb100e652f1a20369cc22355e5ddbb1f3503d45ab5bc343e42d43c1189ac66d99472efb731fbdb43c086a9867494c340a3b93ec0c248313ed44f017b38f0c97@127.0.0.1:0","enr":"0xf88fb8407e0bff7bd1090185526f52a43ecdda7358286cc0468f0eca9f18958d2a3447361acab4fa03a4a0799aa4e50f8e84c306e840f8249a0308b34f82b76afe046eed0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035eb100e652f1a20369cc22355e5ddbb1f3503d45ab5bc343e42d43c1189ac66d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"juOHQ4urcW87bSD0xaEXvOrsYDz6axvWCx0LhLEatDA=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8ee387\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 24cb 2345 541f 7fb9 | 19 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n001 2 ceeb f3ed | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 a263 a3d9 | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 9b33 97b7 | 2 97b7 (0) 9b33 (0)\n004 1 8115 | 1 8115 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","private_key":"105b799734097e8023441f6939805723ac89fcb4ff9ccac50bd62460e87c247c","name":"node_8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","services":["bzz","pss"],"enable_msg_events":true,"port":40859},"up":true}},{"node":{"info":{"id":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","name":"node_7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","enode":"enode://2fb00f3ef77f231e224d908fcbafa19fcc9384a8636a4f616e2bd1d0aaa901ed6e8af6ae1fe98835650624d7d5cd0d357b6716dfed0096c2a4784a303dacf52a@127.0.0.1:0","enr":"0xf88fb840d2aff8f47839e79ba53089410607c84c3a350f6549787298369c6b4aaee001711772c1ebe313391835a231f69078929006c5bc46a7a7a365339a43019105ee6a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022fb00f3ef77f231e224d908fcbafa19fcc9384a8636a4f616e2bd1d0aaa901ed","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f7lV7jRch+nY48mJvAvMsV5Ejw2ZqI0z+3vmcJL7bxQ=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7fb955\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bfeb 8ee3 | 13 ceeb (0) df92 (0) d735 (0) f3ed (0)\n001 2 2345 24cb | 7 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n002 2 5743 541f | 5 541f (0) 5743 (0) 579d (0) 4730 (0)\n003 2 6a64 6e31 | 2 6a64 (0) 6e31 (0)\n004 1 753a | 1 753a (0)\n============ DEPTH: 5 ==========================================\n005 2 78b6 78c7 | 2 78b6 (0) 78c7 (0)\n006 1 7df3 | 1 7df3 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","private_key":"64333ce54c8da8d7e9c33f7be3b251a5ed1e5aa83a11249a82e29a110b1d5b2b","name":"node_7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","services":["bzz","pss"],"enable_msg_events":true,"port":42481},"up":true}},{"node":{"info":{"id":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","name":"node_bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","enode":"enode://c59989c774f7e074cdf34e86b5606f6413731cb002d6e23fb7048b6abb8d4ab175993ac902afe935830d5aaf2323da442f6001f4efb4f744c8e815d7cbebc210@127.0.0.1:0","enr":"0xf88fb840e0f778f02886637fbd7ea40cc496e93293d426c0339594822cebdd56850aa36f407c7f9a63d251f0a2dff02c8462b150d7c771c2dbb09d6f886529e5a354906c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c59989c774f7e074cdf34e86b5606f6413731cb002d6e23fb7048b6abb8d4ab1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"v+tsaf7RbSm6INEc2LI4neInZbYgm7uPGZQBSiCiBOY=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: bfeb6c\npopulation: 10 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0993 24cb 7fb9 | 19 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n001 3 ceeb df92 e17a | 6 ceeb (0) df92 (0) d735 (0) f3ed (0)\n002 2 9b33 97b7 | 4 97b7 (0) 9b33 (0) 8115 (0) 8ee3 (0)\n============ DEPTH: 3 ==========================================\n003 2 a3d9 a263 | 2 a3d9 (0) a263 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","private_key":"1d29cf23c9755015db0f67b0188c2c19bf24987efa6c1682ccf3cc0ad0ec5a23","name":"node_bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","services":["bzz","pss"],"enable_msg_events":true,"port":46455},"up":true}},{"node":{"info":{"id":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","name":"node_e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","enode":"enode://a2dd668460422389d655b5663deec36cd2881ad83de1e61764a4ac0281dc04de5dfe0a1c77aebf15b1507f62433d08f839fdc45ccde68b1372da5fb05edb2626@127.0.0.1:0","enr":"0xf88fb8402cb1df00b6cd3322b435ed7d378f8f55f11e43f478d15b4c2a5944bc802ae37d5d27186bbb89602d74aba656f45abb719f1f24cbc09221a929fe3b9c49e73e4e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a2dd668460422389d655b5663deec36cd2881ad83de1e61764a4ac0281dc04de","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4XqGI697L+Ioe5Lgs9kXukTY8pcwGXuuKq4gUDVoqzo=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e17a86\npopulation: 8 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 24cb 6e31 | 19 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n001 2 a263 bfeb | 7 97b7 (0) 9b33 (0) 8115 (0) 8ee3 (0)\n002 2 ceeb df92 | 3 df92 (0) d735 (0) ceeb (0)\n============ DEPTH: 3 ==========================================\n003 1 f3ed | 1 f3ed (0)\n004 0 | 0\n005 0 | 0\n006 1 e25a | 1 e25a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","private_key":"77bd5acdbf27ca1f194007ebaae9a384db0ed52cdf49a440fce50fd8986663d1","name":"node_e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","services":["bzz","pss"],"enable_msg_events":true,"port":38823},"up":true}},{"node":{"info":{"id":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","name":"node_6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","enode":"enode://e8f703980df3e25fe82683b6d2a775262e07309814eaaa60c3d22d64d352431ff3fc485e8bea252e646e60acb14b08c53ac0d6c480e468a018c9940cfbb5995a@127.0.0.1:0","enr":"0xf88fb840808b5d498d23de164013220eb74d54a810a0d63485538a9b2e4d05fb854995732e8be73c9c32da53cc2ef4dc9d554295743188a22c08a5ce3731575770cf250f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e8f703980df3e25fe82683b6d2a775262e07309814eaaa60c3d22d64d352431f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"bjFW1QN/r9Tk1v+/tQ/ZV7s0qBza0kxluXFZ9vvKgto=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6e3156\npopulation: 16 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 ceeb e17a | 13 97b7 (0) 9b33 (0) 8115 (0) 8ee3 (0)\n001 4 2345 0d53 0993 0518 | 7 24cb (0) 2345 (0) 3a42 (0) 39fe (0)\n002 4 579d 5743 541f 4730 | 5 5743 (0) 579d (0) 541f (0) 4730 (0)\n============ DEPTH: 3 ==========================================\n003 5 753a 7df3 7fb9 78c7 | 5 7fb9 (0) 7df3 (0) 78b6 (0) 78c7 (0)\n004 0 | 0\n005 1 6a64 | 1 6a64 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","private_key":"a2b5a8fc75c349602ab3f0c732403c34e0dd6d0983bdca9fd6e8e63fa7e625ee","name":"node_6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","services":["bzz","pss"],"enable_msg_events":true,"port":44515},"up":true}},{"node":{"info":{"id":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","name":"node_051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","enode":"enode://f95dcdf6a7b67a12e461b7d620e9e5473ef6630fae5334cc81ee19f7ed5a86af2d898820ee10598f9886270bad22885f33bdd77da3ce1cebc35eab12a851bf29@127.0.0.1:0","enr":"0xf88fb840f83b0db1e290d22c0a001f3850407da61d152aa66b04657db08b30ad9b417d3b20a8c76d1f78787581e182bf5a52a4e4133d916f923ae20b81ea6baccb2500410183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f95dcdf6a7b67a12e461b7d620e9e5473ef6630fae5334cc81ee19f7ed5a86af","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BRhyySYhF5f2JaZ1tQyTSrXynLt9FAtsid7EuSSg/0E=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 051872\npopulation: 15 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d735 df92 | 13 df92 (0) d735 (0) ceeb (0) f3ed (0)\n001 7 541f 5743 579d 4730 | 12 5743 (0) 579d (0) 541f (0) 4730 (0)\n002 4 2345 24cb 39fe 3a42 | 4 3a42 (0) 39fe (0) 24cb (0) 2345 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 2 0d53 0993 | 2 0d53 (0) 0993 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","private_key":"15d5b46039f63072fedea8221981c8ea5e41e2f76fb9f68e11af1dc629514ae9","name":"node_051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","services":["bzz","pss"],"enable_msg_events":true,"port":41645},"up":true}},{"node":{"info":{"id":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","name":"node_4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","enode":"enode://0b5fa0bc32971346e7f724db70c7c2debd42aabad0ae08ddafdd9c2a3089b1e39cb62b34e36b3a4902a20bbd0b86e47b0e660eda5fcd203a2bb7ee411397aebb@127.0.0.1:0","enr":"0xf88fb84042ecaa56acb3a73b05756c24e1d9cb90f3941293a34b7e58d19cf3f3974f801b38ddf5de2c5cc06ab8cddc4f1d39d6429e6bcb5d45b3162cd8efb5e62ab2963a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030b5fa0bc32971346e7f724db70c7c2debd42aabad0ae08ddafdd9c2a3089b1e3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RGTTOqr2BvAMIyVHxk1NDD0LwQCAydLO73jwyaUZjmI=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4464d3\npopulation: 13 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 97b7 9b33 | 13 9b33 (0) 97b7 (0) 8115 (0) 8ee3 (0)\n001 2 3a42 0518 | 7 3a42 (0) 39fe (0) 24cb (0) 2345 (0)\n002 5 6a64 78b6 78c7 7df3 | 7 6a64 (0) 6e31 (0) 7fb9 (0) 7df3 (0)\n============ DEPTH: 3 ==========================================\n003 3 5743 579d 541f | 3 5743 (0) 579d (0) 541f (0)\n004 0 | 0\n005 0 | 0\n006 1 4730 | 1 4730 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","private_key":"2adb4afe6ba823e733df48a3d5d09eb8fa4ed380cb5accf0aae706ef7781f344","name":"node_4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","services":["bzz","pss"],"enable_msg_events":true,"port":42813},"up":true}},{"node":{"info":{"id":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","name":"node_753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","enode":"enode://1352929c4211f4c4cd4a13cbfdce725e4f1bc4ed263b8fb8e5d34ead2f6bf5c0947a7013057d1f5cf04ea9ca1ca19bfe3dcc236e3ce674702dc5e8926b75ba89@127.0.0.1:0","enr":"0xf88fb840b9ab15d6154f9a25168313678352c17719ca962b1c7518185075c93a3f88bf3e224bb5165b657547a61ce6c7d65b28834119ba9de142b3ca096c1bf614cf3ad20183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031352929c4211f4c4cd4a13cbfdce725e4f1bc4ed263b8fb8e5d34ead2f6bf5c0","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"dTqDZ/za+Mrx/myiXtl7I/mYKBFaONYTUkiLw9AqPhc=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 753a83\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a3d9 e25a | 13 a3d9 (0) a263 (0) bfeb (0) 8115 (0)\n001 2 39fe 3a42 | 7 3a42 (0) 39fe (0) 24cb (0) 2345 (0)\n002 2 5743 4464 | 5 5743 (0) 579d (0) 541f (0) 4730 (0)\n003 2 6a64 6e31 | 2 6a64 (0) 6e31 (0)\n============ DEPTH: 4 ==========================================\n004 4 78c7 78b6 7df3 7fb9 | 4 7fb9 (0) 7df3 (0) 78c7 (0) 78b6 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","private_key":"168b73a15e60830a02857df2b0829fd5a8763b349b554523b0159f54eb92e3aa","name":"node_753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","services":["bzz","pss"],"enable_msg_events":true,"port":33315},"up":true}},{"node":{"info":{"id":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","name":"node_e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","enode":"enode://5ac2f47e9c71378005c153f9d63851ec5b6548902f310f0e0d1f70adab24930495a39c6e2f861e4f90a7f6115cdad65b3031270b3a622d53adedf1842c4d5b60@127.0.0.1:0","enr":"0xf88fb840850bea04ffb859769c059b511c2c57509fd3a9169027e68054a4da19741eee99346b08613ccbd87611a1731d116f5eb6e857eb89cd51afd1352d2def6921cc6e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1025ac2f47e9c71378005c153f9d63851ec5b6548902f310f0e0d1f70adab249304","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"4lphH3oGkxQFDo/8oOs4P3KgUFxZQv2fIcDYrE/CJV0=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e25a61\npopulation: 8 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 39fe 753a | 19 39fe (0) 3a42 (0) 24cb (0) 2345 (0)\n001 2 a3d9 97b7 | 7 a3d9 (0) a263 (0) bfeb (0) 8115 (0)\n002 2 d735 df92 | 3 df92 (0) d735 (0) ceeb (0)\n============ DEPTH: 3 ==========================================\n003 1 f3ed | 1 f3ed (0)\n004 0 | 0\n005 0 | 0\n006 1 e17a | 1 e17a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","private_key":"c4c13286dcde737ba9a3fc2e7953732cdab547e3e0b627aa3eb5aa41403370d0","name":"node_e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","services":["bzz","pss"],"enable_msg_events":true,"port":42117},"up":true}},{"node":{"info":{"id":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","name":"node_97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","enode":"enode://2c0df18912e105bbf6f9b8eb475be15fa4b2588774db19e58efa9f9004827b7b7c7ce8c6b85f09ed18d35525894c0fdab9db72bda999b840490a9bf69d4e9483@127.0.0.1:0","enr":"0xf88fb84047867575521a015ed256017d340f51f6b7b89dbf341e7198d2873cdf1643097d57e3353c5b2dedc7ac2f59f228207f23aaf85bd0d5ea22c839cd42093c008c520183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1032c0df18912e105bbf6f9b8eb475be15fa4b2588774db19e58efa9f9004827b7b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"l7cDr+AEiTIc6YBXBOjFCWcasOlG0zlZWjIg28+6F9c=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 97b703\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 4464 0d53 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 2 f3ed e25a | 6 f3ed (0) e17a (0) e25a (0) ceeb (0)\n002 2 a263 bfeb | 3 a3d9 (0) a263 (0) bfeb (0)\n============ DEPTH: 3 ==========================================\n003 2 8ee3 8115 | 2 8115 (0) 8ee3 (0)\n004 1 9b33 | 1 9b33 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","private_key":"459c256ce29dce2b5e51c0ce9519d817687f2ae8d39291bd0bb8c45be3cac239","name":"node_97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","services":["bzz","pss"],"enable_msg_events":true,"port":35847},"up":true}},{"node":{"info":{"id":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","name":"node_0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","enode":"enode://61b38c0b92a4c6ce5d27ea0b6d43d452e1e997c46f8ee202b2e75ea97ced9f4688972acf423e65ef43459bb16e39aebf26088a1f1ff7539524802bc73e3933ae@127.0.0.1:0","enr":"0xf88fb840303205621ea7bf25072f954d0d961007601360547291141945bb0093577673ef019f53965ee35755ee49420db016f5bbeb2033ca540a4697ac74f4a7d44f3f200183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10261b38c0b92a4c6ce5d27ea0b6d43d452e1e997c46f8ee202b2e75ea97ced9f46","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"DVORnD1bCv3DtzjYLLIT+R4F7DsPQqOqRuelBE+MRoQ=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0d5391\npopulation: 15 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 df92 8115 97b7 | 13 f3ed (0) e17a (0) e25a (0) ceeb (0)\n001 6 579d 5743 6a64 6e31 | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 4 2345 24cb 3a42 39fe | 4 39fe (0) 3a42 (0) 24cb (0) 2345 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 0518 | 1 0518 (0)\n005 1 0993 | 1 0993 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","private_key":"c45ad9fcca69152984db9fed40d730632c1298936ade555a8cb20d1a817bd670","name":"node_0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","services":["bzz","pss"],"enable_msg_events":true,"port":38753},"up":true}},{"node":{"info":{"id":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","name":"node_df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","enode":"enode://95f793890df976e2116b50757db31f18f9973a271201d253d5e7eb8045e883b2343ce7c251c3cef5a8a47fb2f7ee194a75fd6da2f6c86edc301d1a1c61967aab@127.0.0.1:0","enr":"0xf88fb840d94e3579279121df14a0951495d39187d19e1eaaf27ea43657c534f73f0478c57461adbb638a01bac20370acce51c6a7336966224889eba1a5c7c71ed0ea14210183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10395f793890df976e2116b50757db31f18f9973a271201d253d5e7eb8045e883b2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"35JqZsJv2fAxTI+ilNeaiPkS7DjEWk8CZ/ZL7qyqG8U=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: df926a\npopulation: 9 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 0518 0d53 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 3 9b33 a3d9 bfeb | 7 bfeb (0) a3d9 (0) a263 (0) 8115 (0)\n002 2 e25a e17a | 3 f3ed (0) e17a (0) e25a (0)\n============ DEPTH: 3 ==========================================\n003 1 ceeb | 1 ceeb (0)\n004 1 d735 | 1 d735 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","private_key":"eeb3903d4463417af9da2ea27fba13fd5093da36946266a277ec581558b2856c","name":"node_df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","services":["bzz","pss"],"enable_msg_events":true,"port":39343},"up":true}},{"node":{"info":{"id":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","name":"node_ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","enode":"enode://b3e2654630b1d6ebbb09ee959e76c7730ae9c6fc480911ff08fcdd24d7ba4b828729f5a4dfc7200e612a8c1fcf86eaeb7cbb8c21397b46c65f32e1aed42147d9@127.0.0.1:0","enr":"0xf88fb84092f5be44e027ba50e860ca40efdd29bbf06481e026e13a4a5ac92a23fbfc4abd14a3e017a8b06df176479a8d5f2917d4c34c2acef2bcf5759a288681f2ea97400183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b3e2654630b1d6ebbb09ee959e76c7730ae9c6fc480911ff08fcdd24d7ba4b82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"zuuCKuMTSaut21Qw6AQz9FM+lClgovUcyEbfldqlqPg=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ceeb82\npopulation: 11 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6a64 6e31 0993 | 19 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n001 4 bfeb 9b33 8ee3 8115 | 7 bfeb (0) a3d9 (0) a263 (0) 8115 (0)\n002 2 e17a f3ed | 3 f3ed (0) e17a (0) e25a (0)\n============ DEPTH: 3 ==========================================\n003 2 d735 df92 | 2 d735 (0) df92 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","private_key":"b6e0764b9a67a61d0b3d28f015fa324dcd1cf91184ffe3e19d09dd4c2e03eba9","name":"node_ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","services":["bzz","pss"],"enable_msg_events":true,"port":33733},"up":true}},{"node":{"info":{"id":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","name":"node_09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","enode":"enode://7865fabc9290d5908d0b0379da577a803da633ce87eca6a230cd485858f79d8732a353fd06bb730a194d4014ac932231ca83337c8523f7134c7d42d4c478d3a2@127.0.0.1:0","enr":"0xf88fb840d2dbe8ecd544c1c014c8f02cd34a100977754a6db7f5e02016625158c1bdd75c53f231aa89315cd6bf3d705704e49986dc7ed17eedc5540e7991a7f69c0df83b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027865fabc9290d5908d0b0379da577a803da633ce87eca6a230cd485858f79d87","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CZN+J8DlJQHatyFXh3+ZSCorctqKNpDlXFF8D8Pzv/w=","hive":"\n=========================================================================\nThu Feb 28 17:37:30 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 09937e\npopulation: 12 (31), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 bfeb ceeb | 13 bfeb (0) a3d9 (0) a263 (0) 8115 (0)\n001 4 78c7 7df3 6a64 6e31 | 12 6e31 (0) 6a64 (0) 753a (0) 7fb9 (0)\n002 4 3a42 39fe 24cb 2345 | 4 39fe (0) 3a42 (0) 24cb (0) 2345 (0)\n============ DEPTH: 3 ==========================================\n003 0 | 0\n004 1 0518 | 1 0518 (0)\n005 1 0d53 | 1 0d53 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","private_key":"e412c080f6539c4ed5ecc3cb66b97b85ee903f61b67fc90fa515775522d067ac","name":"node_09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","services":["bzz","pss"],"enable_msg_events":true,"port":34047},"up":true}}],"conns":[{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","other":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","other":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"bfeb6c69fed16d29ba20d11cd8b2389de22765b6209bbb8f1994014a20a204e6","other":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"df926a66c26fd9f0314c8fa294d79a88f912ec38c45a4f0267f64beeacaa1bc5","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"8115abcf39747a7af3eece55f12cc9e4909a76e41853b2e126522150dbda9507","other":"a263a5769cf3f226db7d2cd91aee96a206c46b0ce2a8078a6d3841dc3f4c5c66","up":true},{"one":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"e17a8623af7b2fe2287b92e0b3d917ba44d8f29730197bae2aae20503568ab3a","other":"ceeb822ae31349abaddb5430e80433f4533e942960a2f51cc846df95daa5a8f8","up":true},{"one":"97b703afe00489321ce9805704e8c509671ab0e946d339595a3220dbcfba17d7","other":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","up":true},{"one":"6e3156d5037fafd4e4d6ffbfb50fd957bb34a81cdad24c65b97159f6fbca82da","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"d7351e47f0c746ed33c652b0f2aa2fed354c8dad8d87525a4b511581aff6c6fa","other":"e25a611f7a069314050e8ffca0eb383f72a0505c5942fd9f21c0d8ac4fc2255d","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","up":true},{"one":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"9b335aeb69b7fbd396ace5182d3fe7930e5d9786531593310b48a857c2bb769e","other":"8ee387438bab716f3b6d20f4c5a117bceaec603cfa6b1bd60b1d0b84b11ab430","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","other":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","up":true},{"one":"541f15bbe58d9e1b2bd3d1582c5cfa62fdbcd4363bcf451964f8c6d74f179a34","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"a3d987795e19f8518e4770f72c9f80804b999a31bf22d09cfeb04d644b429bf9","up":true},{"one":"f3ed1ac2fa19ae12beaabe227ec033f495300f0830a84014c839ff2e676c98d3","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","up":true},{"one":"753a8367fcdaf8caf1fe6ca25ed97b23f99828115a38d61352488bc3d02a3e17","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"39fea76e2e430919cadb48ce290c11ad66b2f8a66886ae08b59e418fa4eade8b","up":true},{"one":"0d53919c3d5b0afdc3b738d82cb213f91e05ec3b0f42a3aa46e7a5044f8c4684","other":"2345add1ed7d98db8816aad3fda0829e6b0c9c167087067a7ec3a890bec8ad58","up":true},{"one":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","other":"051872c926211797f625a675b50c934ab5f29cbb7d140b6c89dec4b924a0ff41","up":true},{"one":"579da170901ed911be3445d4422664a997eb14201589d702e0688f6146872993","other":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"7fb955ee345c87e9d8e3c989bc0bccb15e448f0d99a88d33fb7be67092fb6f14","other":"5743bc09e713e7c4d58fef1951ab6b627a27e6f1a3c42db88827a1613bd7ef3f","up":true},{"one":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","other":"3a4298be13c39ddee046f4237863528c05ac1e3a6c9c2cc429636865d8ee4a15","up":true},{"one":"7df3074f4e1175a213e578939abd9c1e5ff71543eb5dc24ee5ded5f804e3b842","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","other":"4730360679acf630fc8aba14c7be3bbc13953cb1ea8d7a72f5a3b5764170ef76","up":true},{"one":"4464d33aaaf606f00c232547c64d4d0c3d0bc10080c9d2ceef78f0c9a5198e62","other":"78b6a2fb3428954855fbdbf99938e1214b8f19fa334144984289d1fb03bb4f7c","up":true},{"one":"6a64d765e40fde1190ff228bb86096b84182d719e6d1b713726db9aaeea437da","other":"78c70d33dfd131bcc1c64267bf71e6fe81e93f891b940a1114c657c826675bd7","up":true},{"one":"24cb391b1984a5380af82f2fa622f1a02eb035ecb3401d538e41824965ddcc56","other":"09937e27c0e52501dab72157877f99482a2b72da8a3690e55c517c0fc3f3bffc","up":true}]} \ No newline at end of file diff --git a/swarm/pss/testdata/snapshot_4.json b/swarm/pss/testdata/snapshot_4.json deleted file mode 100644 index 9296cad0b9..0000000000 --- a/swarm/pss/testdata/snapshot_4.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","name":"node_39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","enode":"enode://1adbc1635af8ae835d3041edc8a5c633f40a009111b6a74e0cce501181b7ea3b1f26b193294721540ec8970183ff74a9121899af5bc9425f2bd3506e4a164cd5@127.0.0.1:0","enr":"0xf88fb840dc163ce6d8e977e2d01bde715e6b77a6ae29ee68c87cd245047d2f0afc728e847b4674905af3780f2ef7e65dfdcebd5d5a59aa7ba20985ba5edc2edbacc2aa430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031adbc1635af8ae835d3041edc8a5c633f40a009111b6a74e0cce501181b7ea3b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OWN9hua+axvMNCc4qEo298YgLKbh2jeVJPXI2QGK6ZM=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 39637d\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 d9b8 f9ee | 2 d9b8 (0) f9ee (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 1 3eea | 1 3eea (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","private_key":"777c522fea2223bf13c53cc946d4761b29a5f071939160197b8305faff375f5b","name":"node_39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","services":["bzz","pss"],"enable_msg_events":true,"port":45013},"up":true}},{"node":{"info":{"id":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","name":"node_f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","enode":"enode://81d15729673f044e747a296362aceca03a5cec3dbab718bdced562ed52ca46cadcd387403307d69e55793b1bcfd275428d5235492acc0b03d44fc7c320dbb8b8@127.0.0.1:0","enr":"0xf88fb840bcc07b798defeb3fce1c5c15a3a5a1e2ed4f586606b450bf24d63fd0ac43447041869c05e4809d6d7ff1f293d020ef37cd0d9d5ddbbba85db19b26e78cd4276c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10281d15729673f044e747a296362aceca03a5cec3dbab718bdced562ed52ca46ca","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+e53D2+b3csevlmvzABou1NIZNZs5D2H+yVQOMEqT9U=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f9ee77\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 3eea 3963 | 2 3eea (0) 3963 (0)\n001 0 | 0\n002 1 d9b8 | 1 d9b8 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","private_key":"33058348a654e1f7083b1e151159be731dce92dc63fd6a8218d05a0a79556264","name":"node_f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","services":["bzz","pss"],"enable_msg_events":true,"port":42259},"up":true}},{"node":{"info":{"id":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","name":"node_d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","enode":"enode://45ce3a7edb53c1ba49af48932d23cc431c8093e16363be0c164d7a2d91a9b42292fcab0a19f44961c660670ab35585f06671af76660e1879bac551649eeaf383@127.0.0.1:0","enr":"0xf88fb840e84fc1155908a63c768932ac73515e5badc69a4c9870628174f0ada2b2c51b884cd5023d2c99f9ea91f859daec2b6f1861dfbed2a79d64e2ec7d0d5e10b96a670183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10345ce3a7edb53c1ba49af48932d23cc431c8093e16363be0c164d7a2d91a9b422","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2bjt/6M4O2+EZ7ihQyGyRPLrgR/+/oFicF7mHdgxnrg=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d9b8ed\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 3963 3eea | 2 3963 (0) 3eea (0)\n001 0 | 0\n002 1 f9ee | 1 f9ee (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","private_key":"212d7f1311d01b67472c5f08b993f423ae2479ce51b31e223b2d2569b8fe9b2b","name":"node_d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","services":["bzz","pss"],"enable_msg_events":true,"port":42359},"up":true}},{"node":{"info":{"id":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","name":"node_3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","enode":"enode://a858788ee0cfe3e41f87f7f08d6e1f4af3b46aac21c031eb764995c70c13e103dccb92a70cd85004343bd6b52cdfbd448c0692ffb332a328d0655d1e82c67044@127.0.0.1:0","enr":"0xf88fb840e7edbd4abbf61818777dd83a7a33d3ae7965c97845955e1fe850d5826159898f076a7b650aadee767bcf047dbdd7b64e362f458e2dfadc5bf61a70e3bc98e4400183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a858788ee0cfe3e41f87f7f08d6e1f4af3b46aac21c031eb764995c70c13e103","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PuoGR7u2jhDE7X7KZGtlCIJBFE/qQ/OajBtp8CXjqKM=","hive":"\n=========================================================================\nThu Feb 28 17:15:36 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3eea06\npopulation: 3 (3), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 2 f9ee d9b8 | 2 f9ee (0) d9b8 (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 1 3963 | 1 3963 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","private_key":"0e14c45740f36d25300cd008dd1e1c1f98d39c519a1fee65fb30e004f1a992df","name":"node_3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","services":["bzz","pss"],"enable_msg_events":true,"port":42157},"up":true}}],"conns":[{"one":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","other":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","up":true},{"one":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","other":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","up":true},{"one":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","other":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","up":true},{"one":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","other":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","up":true},{"one":"39637d86e6be6b1bcc342738a84a36f7c6202ca6e1da379524f5c8d9018ae993","other":"d9b8edffa3383b6f8467b8a14321b244f2eb811ffefe8162705ee61dd8319eb8","up":true},{"one":"3eea0647bbb68e10c4ed7eca646b65088241144fea43f39a8c1b69f025e3a8a3","other":"f9ee770f6f9bddcb1ebe59afcc0068bb534864d66ce43d87fb255038c12a4fd5","up":true}]} \ No newline at end of file diff --git a/swarm/pss/testdata/snapshot_64.json b/swarm/pss/testdata/snapshot_64.json deleted file mode 100644 index cd3d5593fb..0000000000 --- a/swarm/pss/testdata/snapshot_64.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","name":"node_177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","enode":"enode://b2ecd384df0c1911a363892a8f9f92276afdadbd9766d5367e9426baaf52db54607ef8ed20c6013bcd31216645721a66b33c2afd1f995665b49ef32554fa55c9@127.0.0.1:0","enr":"0xf88fb84084a65eedfefa09006c370680d7af5b4d4600e9775cc2fa0a778a6ca5adf131810dfcdc8b9509da7bbb1a1a865244daf2d32b34b96a9c005080f94eeaf270099f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b2ecd384df0c1911a363892a8f9f92276afdadbd9766d5367e9426baaf52db54","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"F34jK9upcPSwAbIor5QC4/ygqvAGgqEbyZhPfbS3/ro=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 177e23\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b73b be2b | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 3 452b 581a 5602 | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 3 255d 3103 3abf | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 3 0acb 0727 0486 | 5 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 154f 1455 | 2 1455 (0) 154f (0)\n007 0 | 0\n008 0 | 0\n009 1 172b | 1 172b (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","private_key":"1286e8188fe5e907890aef4a270d2307e0937dd38d9340f4e56829fd23413f31","name":"node_177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","services":["bzz","pss"],"enable_msg_events":true,"port":40837},"up":true}},{"node":{"info":{"id":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","name":"node_be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","enode":"enode://7f0ebae8d5040cd874605d9ec6c3a7cb63c1b7cf90d06f7d0b0c7066569ef465f68eb09c19058d1c9cde1d99ae351e95196c1feb2a9ce64ef17076510dd0cd7d@127.0.0.1:0","enr":"0xf88fb840daad2aad3a4d7ff125994a1b8646db6d4bee82774004dd547373a34e6b456b4b34d740e306f79da7c50ae15a5d4dfb60af9dd435898e901986b0570d184a8c2e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1037f0ebae8d5040cd874605d9ec6c3a7cb63c1b7cf90d06f7d0b0c7066569ef465","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"vivLj7SzTuaYHmY0uPMpj7vudW9udlZiBKVruGyOwPA=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: be2bcb\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 7d69 177e | 30 452b (0) 581a (0) 5f83 (0) 5e36 (0)\n001 3 c0c2 d3c1 f6e5 | 17 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n002 5 8673 856e 8926 8802 | 8 8802 (0) 8926 (0) 821a (0) 856e (0)\n003 3 afb1 ae60 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n004 2 b73b b374 | 2 b374 (0) b73b (0)\n============ DEPTH: 5 ==========================================\n005 2 b8f9 b8f3 | 2 b8f9 (0) b8f3 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","private_key":"1bfc88f8747bfe3f0686c0dd06c6994f80bc3109cbce619c87194df9c0af35ec","name":"node_be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","services":["bzz","pss"],"enable_msg_events":true,"port":41679},"up":true}},{"node":{"info":{"id":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","name":"node_7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","enode":"enode://73efd5ce9d1348bb96a73682ab0e0523106c449265974c594f34a445de026e1225f2a1e0cd7d95a391563cdda852cb9ed50a12a5ba174447ac1320743429f15a@127.0.0.1:0","enr":"0xf88fb84027a696cdd03ce902b65824023e0014604a449a0ab2819e417b664ea0f292ea690de64c4fec6dc5b80d5f97fb7c03e0168027a60d77a65ee8845dd7a519d7a7f80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10273efd5ce9d1348bb96a73682ab0e0523106c449265974c594f34a445de026e12","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"fWm1cHpLme3ZATF/FVP/FVhqrDUPOODIExjzXWi4Nag=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7d69b5\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 ebf2 fb7e 8802 be2b | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 3 255d 3103 154f | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 5 452b 581a 5e36 52fc | 8 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 703d 70d0 | 2 70d0 (0) 703d (0)\n005 0 | 0\n006 1 7f80 | 1 7f80 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","private_key":"138b2b1614eba35db1d63a8b4cad155aae9ffe67aeba89da6b77c32d8085978c","name":"node_7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","services":["bzz","pss"],"enable_msg_events":true,"port":37997},"up":true}},{"node":{"info":{"id":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","name":"node_154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","enode":"enode://5383cc445c43a2ed3afe5922fc466e7ad833fadea40c63e1fd3bf6c1beee0db531a26c526994d14249bf854f9b36b49e7416d55407d49a3a70608f02419bc8b9@127.0.0.1:0","enr":"0xf88fb8403a38e49c1e706672d35d764ebcf564cca19c96df63f8777ef17eff0305791fa14a022147e46d186121c4ff0d52488b51e3929b5ba536dffe4e7fb7957f7909940183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035383cc445c43a2ed3afe5922fc466e7ad833fadea40c63e1fd3bf6c1beee0db5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FU/sX6cor5VqFEa9WjXmPXFreagEGXtQ/ZxyWF0ES3c=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 154fec\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 a12b b8f3 f6e5 | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 4 581a 5e36 452b 7d69 | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 2 274f 3c40 | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 4 00ba 0257 0486 0727 | 5 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 177e 172b | 2 172b (0) 177e (0)\n007 1 1455 | 1 1455 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","private_key":"ce1506c16008e68cab421b02e7de0e8bf64bd8061e84336dd3ee4e7382078bb5","name":"node_154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","services":["bzz","pss"],"enable_msg_events":true,"port":41399},"up":true}},{"node":{"info":{"id":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","name":"node_3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","enode":"enode://f98b58ce571bd762921cf62c8001f481eb582bf905c42e8d40eab48cfe6394065721413958fe1a1df85e350f6075bda55b7a8745eb329b11e462282dbc1e7012@127.0.0.1:0","enr":"0xf88fb840193b2d1eaa7d147a52bd4c4a65a9d70c37b92c837f74d8f919a893605560b33c4d5a6df29825a8a430f4e250e5e3a6ec8ce78ec940c759c0b3369cb52ea8e3c90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f98b58ce571bd762921cf62c8001f481eb582bf905c42e8d40eab48cfe639406","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"PECeW3bpd+4xFaChlUDdZ0XmC4h4/cGlwdmW5+R8qWk=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3c409e\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 821a e6cf c3b2 c461 | 34 821a (0) 856e (0) 87aa (0) 87ac (0)\n001 3 70d0 6123 5602 | 13 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n002 3 0727 0486 154f | 9 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n003 3 274f 255d 248a | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n============ DEPTH: 5 ==========================================\n005 3 38f0 3abf 3b4f | 3 3b4f (0) 3abf (0) 38f0 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","private_key":"4e158a7430c532fe0c5fbd4e063cbce5fbd793a516b0d9b2728daac7741a71b9","name":"node_3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","services":["bzz","pss"],"enable_msg_events":true,"port":33099},"up":true}},{"node":{"info":{"id":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","name":"node_c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","enode":"enode://a8deb108b6c33a1abc50c0ce0041d4c5de23f17171fb3558dc0a4aed942dc887bb56c0917ed3032af073d8b2415e0879e264370a800f64d060f8f8e1c096d04d@127.0.0.1:0","enr":"0xf88fb8409107e601aef81da4e1f9a95006f25aeec3f9d59b329245d0475a4a3347ee4f7e69b4c64a5401e0679d1ab092d618b1d678a77ba22e43159d1d46790338e165e00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a8deb108b6c33a1abc50c0ce0041d4c5de23f17171fb3558dc0a4aed942dc887","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"xGHkMMiHiUu7/04ze2HuRJzxLMB9D8X+QXhdWA0Wrpg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c461e4\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 5f83 52fc 452b 6123 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 5 b374 87aa 856e 821a | 17 821a (0) 856e (0) 87aa (0) 87ac (0)\n002 2 f211 e558 | 11 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n003 2 d904 d3c1 | 2 d3c1 (0) d904 (0)\n004 1 cb8d | 1 cb8d (0)\n============ DEPTH: 5 ==========================================\n005 2 c0c2 c3b2 | 2 c3b2 (0) c0c2 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","private_key":"978cfc6313655f0d829dc91a0545aa1369f3b0baafc201c8cbc641c965f85b77","name":"node_c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","services":["bzz","pss"],"enable_msg_events":true,"port":43525},"up":true}},{"node":{"info":{"id":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","name":"node_e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","enode":"enode://26b5014af36030418be4bbab747a56da3f0a0b96e77a5c732cfdf7f61ca71d565f2b43bbbb44d2d047a3c549971b88655d62a889afdbb724e8fefe656dbe2b5d@127.0.0.1:0","enr":"0xf88fb840015e82c76a09041b22bbd93a7ea12ce2f51fbc04bb6629d1f8055d626456b7215bbec219530291b84fb78db61bbd25983f693c69d221fa1155ee0947690be72b0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10326b5014af36030418be4bbab747a56da3f0a0b96e77a5c732cfdf7f61ca71d56","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5VgQXSrrWciW9ftwR1sEbZA070WW6c1fVPFsMWRJJB4=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e55810\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 70d0 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 2 87aa 821a | 17 821a (0) 87aa (0) 87ac (0) 8673 (0)\n002 3 d904 d3c1 c461 | 6 d3c1 (0) d904 (0) cb8d (0) c3b2 (0)\n003 3 fb7e f211 f6e5 | 5 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n004 3 eb30 ebf2 e9fd | 3 ebf2 (0) eb30 (0) e9fd (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e6cf | 1 e6cf (0)\n007 0 | 0\n008 1 e5e1 | 1 e5e1 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","private_key":"62f09d35ddecb1f76c961bd8188912d6ea354de35322e5add87d2eca8154ff74","name":"node_e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","services":["bzz","pss"],"enable_msg_events":true,"port":32823},"up":true}},{"node":{"info":{"id":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","name":"node_e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","enode":"enode://44a78245fbc89e776a8d27b4548fe61dc789a02628d3246a364971e9ebb1497b72d487ce9d7a0745d667c8adba7db2bf35aac7e327a49728bad8184be24dc311@127.0.0.1:0","enr":"0xf88fb840126f89ca6d674b29c05eb8517aa48cc039a7f289bc17d7e1bc24485e90fa504a1ab8b4c6df373aff9c75943533a3b5955016e0ef89824e23c4cb1b06b86d41d60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10344a78245fbc89e776a8d27b4548fe61dc789a02628d3246a364971e9ebb1497b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6f1c1/jSjKFyo9Mx2kAemFPTEhkjyBv4J4f3mJAJ5Do=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e9fd5c\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 70d0 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 2 821a 9629 | 17 9629 (0) 821a (0) 87aa (0) 87ac (0)\n002 2 d3c1 d904 | 6 d3c1 (0) d904 (0) cb8d (0) c3b2 (0)\n003 2 fb7e f0e9 | 5 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n004 3 e6cf e5e1 e558 | 3 e6cf (0) e5e1 (0) e558 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 eb30 ebf2 | 2 ebf2 (0) eb30 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","private_key":"e1866d6c66f9cdff0845058b114b9a15a4967274ad9cda558e102be0a746e9dd","name":"node_e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","services":["bzz","pss"],"enable_msg_events":true,"port":36597},"up":true}},{"node":{"info":{"id":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","name":"node_f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","enode":"enode://39fc37e1b4c1d8d2906469ea880448186e5246e849c0b6f79952d9254173f1d88e5e06d9331f14bd5052073d2c2d28106ca84ae08fab04d3217db4233fd750dd@127.0.0.1:0","enr":"0xf88fb84088c04103f60facca986ee3d5509cb1e58a231d8dc712d3df77c917f1aa9c27df5a9b0797512f9d61477075a6b766f14ea88d4ae2311b8ae23274327c0d9ba93c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10339fc37e1b4c1d8d2906469ea880448186e5246e849c0b6f79952d9254173f1d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8OkA7ze6rWoWharxcA6SkOfpwNXTDjJlIE7JQ0RSSLM=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f0e900\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 70d0 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 3 821a 9629 aabc | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 2 d904 d3c1 | 6 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n003 2 e6cf e9fd | 6 e6cf (0) e5e1 (0) e558 (0) ebf2 (0)\n004 1 fb7e | 1 fb7e (0)\n005 1 f6e5 | 1 f6e5 (0)\n============ DEPTH: 6 ==========================================\n006 2 f211 f35a | 2 f211 (0) f35a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","private_key":"d85d087c4d2770c08517c1b719cd6805713af1046aeba2bd6db5e31402388df2","name":"node_f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","services":["bzz","pss"],"enable_msg_events":true,"port":45551},"up":true}},{"node":{"info":{"id":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","name":"node_aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","enode":"enode://df29ae71bd1cab0ab806f7dea6545ae649dc9e0640e8d1bef8f6b518c4a75e822f1ac2a937b117eed3faf5f9a4e718d31899d4a6466c33fd6ee520daae0650f3@127.0.0.1:0","enr":"0xf88fb84046f68bd288eb808ea2aa0bbf41922e0e52f2bf6dbd65f83ce2d9632d94262fcf2af844233c694aec3e77cb82eb24aff844c4aa24be379900ec5323a3218b8c430183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103df29ae71bd1cab0ab806f7dea6545ae649dc9e0640e8d1bef8f6b518c4a75e82","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"qrxYfdw7fUk86OhJsV02QmXFfTo6UmEwdqWzGATLdT8=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: aabc58\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 172b 6123 7f80 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 3 fb7e f6e5 f0e9 | 17 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n002 3 821a 87aa 9629 | 8 9629 (0) 821a (0) 8673 (0) 87aa (0)\n003 2 b73b b374 | 5 b374 (0) b73b (0) be2b (0) b8f9 (0)\n004 1 a12b | 1 a12b (0)\n============ DEPTH: 5 ==========================================\n005 2 afb1 ae60 | 2 afb1 (0) ae60 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","private_key":"2338394db2f3550707f783ab13a9427021f5e6be8b3431444d735c6506fc2b2d","name":"node_aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","services":["bzz","pss"],"enable_msg_events":true,"port":34323},"up":true}},{"node":{"info":{"id":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","name":"node_f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","enode":"enode://f5975ee0b5c78d6bc4a68b9b35744cec5ac5922b8da008a4b68a8e9ceee9a6d3a817b21d8b51f9fe35123317bc22cbd1dd37d18f93c433a8d82d25774bc84f59@127.0.0.1:0","enr":"0xf88fb8406c21f34341248451d882a4655a586feeb202f8cb7d47b0da9bd8a4f5f915128228efd4998dcfb8d43543463364a2937db016284e0bb78cfec37208079bb910020183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f5975ee0b5c78d6bc4a68b9b35744cec5ac5922b8da008a4b68a8e9ceee9a6d3","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"9uUUjSQhrhHooQmFLJ2ne75Jj55u06o2F1Wh/z/Sm3Q=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f6e514\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 5508 154f 1455 | 30 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n001 8 8926 b73b b8f9 be2b | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 3 cb8d c3b2 c0c2 | 6 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n003 5 eb30 ebf2 e6cf e558 | 6 e6cf (0) e5e1 (0) e558 (0) ebf2 (0)\n004 1 fb7e | 1 fb7e (0)\n============ DEPTH: 5 ==========================================\n005 3 f0e9 f35a f211 | 3 f211 (0) f35a (0) f0e9 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","private_key":"f6740a5cf46069cee8cdfefdd049e563958cbda7e4c59315d0276a92915efe0a","name":"node_f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","services":["bzz","pss"],"enable_msg_events":true,"port":40421},"up":true}},{"node":{"info":{"id":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","name":"node_1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","enode":"enode://b5e652612f7909a70ecaf98ed27cc962687c895a349dcc80a326794a291a3851a3ba447345a30263a39c29f730276e1b1810813d39975649c50537c0febf67f0@127.0.0.1:0","enr":"0xf88fb8405d344eda0bf71d02e1171dbf8e3b0ae13b7091d138dbc1ed3f568b08dea67f526ec263da507139112160bd3260e7f3582b1fe88aa0501cf52d73650bbdb2d6ac0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b5e652612f7909a70ecaf98ed27cc962687c895a349dcc80a326794a291a3851","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"FFXUcTtRNOkVdRe4SwThUpLPGNPgi5XWnxlkj7njgj4=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 1455d4\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 a12b f6e5 | 34 9629 (0) 821a (0) 8673 (0) 87aa (0)\n001 4 5f83 6123 703d 7f80 | 13 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n002 3 3103 3abf 38f0 | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 4 0257 00ba 0727 0486 | 5 0727 (0) 0486 (0) 00ba (0) 0257 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 172b 177e | 2 172b (0) 177e (0)\n007 1 154f | 1 154f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","private_key":"50925145323eadd436d028b14956413b9ce4a6e6e12ee61bc6f39b7bdeb607ce","name":"node_1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","services":["bzz","pss"],"enable_msg_events":true,"port":35787},"up":true}},{"node":{"info":{"id":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","name":"node_38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","enode":"enode://48f1b561316fb88b3f6966b6b77793eb73ade705dffda5b5e889665c61f61eb65fc53b12a893affa1626e2c066c218fbf0cacc47ae235f284b99d1ddb70a1b7b@127.0.0.1:0","enr":"0xf88fb840ac0a5221c7f96140e1c2b39e3ce570681198f21499c4ac2d4cf71f13084d1d463ea56145f4bc0ae39e1bcf6f728c0fb8bcb53b6f59ff82ca0c91761364ae2aeb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10348f1b561316fb88b3f6966b6b77793eb73ade705dffda5b5e889665c61f61eb6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"OPBa9AzQ3Dl06JbiSqdevaHJbwzn2eP/DqhAYVGGMH0=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 38f05a\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9629 821a 856e | 34 9629 (0) 821a (0) 8673 (0) 87aa (0)\n001 2 6123 5508 | 13 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n002 2 0acb 1455 | 9 00ba (0) 0257 (0) 0486 (0) 0727 (0)\n003 3 274f 255d 248a | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n005 1 3c40 | 1 3c40 (0)\n============ DEPTH: 6 ==========================================\n006 2 3b4f 3abf | 2 3b4f (0) 3abf (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","private_key":"72aaff493375ffe3fdf32b207dec2bf4b6947a83b0be8a39d016a620e5d84166","name":"node_38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","services":["bzz","pss"],"enable_msg_events":true,"port":46291},"up":true}},{"node":{"info":{"id":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","name":"node_0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","enode":"enode://f3639f1bd30e3cf2653b9a4f9d20fab2897ba468020ec336c3eff2d6a4b27c4d3f7f01a6e2cbc6496e8ab4b435a53a518f45a78752b9ecce6ff119cd83eae04c@127.0.0.1:0","enr":"0xf88fb84093cbe4a72d6dc31819c9cd24e75d7178f02135c11b41668880b6c4ce743b2602056aa9103ed6fbdaada4c85913a2f4bf90dd092942db61a1df54c4269cc2f46f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f3639f1bd30e3cf2653b9a4f9d20fab2897ba468020ec336c3eff2d6a4b27c4d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"CssXM0JTQIp3MgIEHUpnx4c7DnTpTIbjND+0cL3L7YI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0acb17\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 b8f3 821a 8926 9629 | 34 9629 (0) 821a (0) 8673 (0) 87aa (0)\n001 5 57d9 6123 70d0 703d | 13 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n002 3 274f 3b4f 38f0 | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 2 177e 172b | 4 172b (0) 177e (0) 154f (0) 1455 (0)\n============ DEPTH: 4 ==========================================\n004 4 0727 0486 0257 00ba | 4 00ba (0) 0257 (0) 0486 (0) 0727 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","private_key":"f732331fdd132dd9b4c64ae5c42247591f96dc911fe6a706b14a10ce3a8ed9d6","name":"node_0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","services":["bzz","pss"],"enable_msg_events":true,"port":44253},"up":true}},{"node":{"info":{"id":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","name":"node_f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","enode":"enode://e745eb6d9e95b82f6b4a6fbd9fb578c5ec53de4bf64bf008a25af4595cf01cd932b1070c197157ebeddcf79d4659acc3a6244177421656d601eb1a108f6c8ab8@127.0.0.1:0","enr":"0xf88fb840fd81f60522c3b56a658b661d599993ff0aca7eaadae4a28bff72103db1ffda910194afe2e3799b9f30d6b7c9134a70f7d05f79b082b70dba836d6ae907720f5a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102e745eb6d9e95b82f6b4a6fbd9fb578c5ec53de4bf64bf008a25af4595cf01cd9","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"81pH4dVqbY5cqtUNiOVcg/87lksnm1ilDV5UT/kYeGQ=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f35a47\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 703d 6123 0acb | 30 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n001 3 9629 821a 856e | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 2 d904 d3c1 | 6 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n003 2 ebf2 e5e1 | 6 ebf2 (0) eb30 (0) e9fd (0) e6cf (0)\n004 1 fb7e | 1 fb7e (0)\n005 1 f6e5 | 1 f6e5 (0)\n============ DEPTH: 6 ==========================================\n006 1 f0e9 | 1 f0e9 (0)\n007 1 f211 | 1 f211 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","private_key":"bc31ff1a3354902df6fdba93d648599c420dc962166cd94ba5c9c88781f7b1ac","name":"node_f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","services":["bzz","pss"],"enable_msg_events":true,"port":40235},"up":true}},{"node":{"info":{"id":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","name":"node_e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","enode":"enode://12f560588c3394b54f4be445fbc804457f104c736613aa7516dcdc935bc1004c7489dbd657445bbcfd5d1b4f85571f2805789d680c6e7bdb08950b548093de42@127.0.0.1:0","enr":"0xf88fb840510aeffd2b76786cd66e778ad5f1c6301affb8c7f1a226cd32e3d61f23da281c79562ae15cbd94ce4a39dff5596492b2716cf58c476ce701e22a641d60a8a4af0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10212f560588c3394b54f4be445fbc804457f104c736613aa7516dcdc935bc1004c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5eFm+F6p4mT8JXNFI4adm5FvOIAEy0r5lolWzhSnpSI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5e166\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 703d 7f80 | 30 6123 (0) 703d (0) 70d0 (0) 7d69 (0)\n001 3 8802 856e b8f3 | 17 9629 (0) 821a (0) 8673 (0) 87aa (0)\n002 2 d3c1 d904 | 6 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n003 3 f6e5 f211 f35a | 5 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n004 2 ebf2 e9fd | 3 e9fd (0) ebf2 (0) eb30 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e6cf | 1 e6cf (0)\n007 0 | 0\n008 1 e558 | 1 e558 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","private_key":"25c5ec054b6f8975276f7c37381908b15ba3fdd204996e80188c27a45a120156","name":"node_e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","services":["bzz","pss"],"enable_msg_events":true,"port":42811},"up":true}},{"node":{"info":{"id":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","name":"node_b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","enode":"enode://1eafb72a59e875d1e4c6fcfc48e3b83060dc7edf1745dc4b4d69920b5c498a0aa5028ac463be2a03331b3f50634295010786205311e2dde4214f5375d846be46@127.0.0.1:0","enr":"0xf88fb840f39e6fb0bc59342b1e5379ca1dfe35c07ed85b72975e03d86b5eaacb2845d6013b15e070b59162b9da5f6a9459e9d69522dfd0dd5dc6eab1478e26446d3adf640183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021eafb72a59e875d1e4c6fcfc48e3b83060dc7edf1745dc4b4d69920b5c498a0a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uPNFlAvO2IMbMAef8qJ2q2X77Q3YV1yTo8zYx70byLE=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8f345\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 00ba 0acb 154f | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 2 cb8d e5e1 | 17 d3c1 (0) d904 (0) c461 (0) c3b2 (0)\n002 3 821a 8802 9629 | 8 9629 (0) 821a (0) 8673 (0) 87ac (0)\n003 3 afb1 ae60 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n004 2 b73b b374 | 2 b374 (0) b73b (0)\n============ DEPTH: 5 ==========================================\n005 1 be2b | 1 be2b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 b8f9 | 1 b8f9 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","private_key":"f213075c2bb9ce044c3ea7e245d0e841eeb4448cb914bad8b7cc2aaf223494f5","name":"node_b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","services":["bzz","pss"],"enable_msg_events":true,"port":32901},"up":true}},{"node":{"info":{"id":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","name":"node_cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","enode":"enode://b86efbaace42f2f41e4faeb180734ba7b3bcd88ce25a4b671f0522e50bccc0544084a0f72f57d3183269bc433e8522e008fcf70990130bd428e679cd2ef2301e@127.0.0.1:0","enr":"0xf88fb840fd41041292742e2d87cfac656804056de57d38166539d75aa87d8ea4028c8b905a7395663eced2fb92ca0b03214bb0fd07d36096c4fa09e3b51edc25293577d50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b86efbaace42f2f41e4faeb180734ba7b3bcd88ce25a4b671f0522e50bccc054","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"y43xg+f+pPgI7VadP6CmwmZw9kUbmp9I6GWYccK5qwI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: cb8df1\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 8 274f 0486 0727 452b | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 5 8673 87ac 87aa b374 | 17 9629 (0) 821a (0) 8673 (0) 87ac (0)\n002 3 ebf2 f6e5 fb7e | 11 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n003 2 d904 d3c1 | 2 d904 (0) d3c1 (0)\n============ DEPTH: 4 ==========================================\n004 3 c461 c3b2 c0c2 | 3 c461 (0) c3b2 (0) c0c2 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","private_key":"492d4a83cd01c80cafe080a10aba2708adad9d57c896ddd20c3f1783fb8c8ae2","name":"node_cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","services":["bzz","pss"],"enable_msg_events":true,"port":37973},"up":true}},{"node":{"info":{"id":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","name":"node_c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","enode":"enode://5307ee476b7d4a7cc8fff3c91a49faff9ef919880ec9f6c2bbf3e57f27bd769f5692a37e70531c902a3d1e519fcbfee9cbd946d008e3653287786ead5083cedd@127.0.0.1:0","enr":"0xf88fb8400e91dade29f3fd1bfebe010d282d7b43d12bdf0bcae8e2e549a2e1ed15785ac4504f8048792eba8a6518ad1ae28b39fd2b21dac0adf4e65609f6da91de0b618f0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1035307ee476b7d4a7cc8fff3c91a49faff9ef919880ec9f6c2bbf3e57f27bd769f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"wMLXOr0rarw7oLCYUgxMw+2mG1/J0atC69BOzCXe0iQ=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c0c2d7\npopulation: 12 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0acb 00ba 0486 | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 2 be2b 8926 | 17 be2b (0) b8f9 (0) b8f3 (0) b374 (0)\n002 2 f211 f6e5 | 11 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n003 2 d3c1 d904 | 2 d904 (0) d3c1 (0)\n004 1 cb8d | 1 cb8d (0)\n============ DEPTH: 5 ==========================================\n005 1 c461 | 1 c461 (0)\n006 1 c3b2 | 1 c3b2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","private_key":"2c6df66c8a1843928d4ff1c1f86261392e9ba859e1d50dbc7e47344968446e7d","name":"node_c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","services":["bzz","pss"],"enable_msg_events":true,"port":46541},"up":true}},{"node":{"info":{"id":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","name":"node_892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","enode":"enode://d2b6d26acb63edf3d8f2e7ba86fce1304441bb3a8c9138e4069412e556fe677e49bf669824144f7f2f752c1ba56d21e1d5b2583b7ce06db6f8e466929bb54fa3@127.0.0.1:0","enr":"0xf88fb84030e09ff37ec6e84f56137ccc06cfe91eec3cfba76fd5f655d4220c8984c2bf74694a268165a67c073623dd0c8ef0879ce3f78eddf5ce61832a0f755c5342a26a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d2b6d26acb63edf3d8f2e7ba86fce1304441bb3a8c9138e4069412e556fe677e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iSYD/GT+FprRVRkGDPsdJ3gK3/YNpg+GpiDyv5p8oeE=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 892603\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 00ba 0acb 57d9 | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 3 f6e5 fb7e c0c2 | 17 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n002 5 b73b be2b afb1 ae60 | 9 b8f9 (0) b8f3 (0) be2b (0) b374 (0)\n003 1 9629 | 1 9629 (0)\n============ DEPTH: 4 ==========================================\n004 5 821a 856e 8673 87aa | 5 821a (0) 8673 (0) 87ac (0) 87aa (0)\n005 0 | 0\n006 0 | 0\n007 1 8802 | 1 8802 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","private_key":"44e05a26b9222f67f884d2093377f119349ef6710b86f7b7edc2f0e61793a1ea","name":"node_892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","services":["bzz","pss"],"enable_msg_events":true,"port":33109},"up":true}},{"node":{"info":{"id":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","name":"node_57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","enode":"enode://0527dc36e6d408034587180c2cadb429ac1ea5e4cf5ffaadf60e8af1bbef30368fc234f75f7ede63d70df8d932f3fae54ba14fdbdb033a18ec2e914b85594f0a@127.0.0.1:0","enr":"0xf88fb840783a349f43c192ad36b674821f63954fd4de02eb076100f9dab68b0fe5eafe8051d208f26c93e9ad609307b169dba4ea5236c4cb557365c16b94e96fc85372eb0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1020527dc36e6d408034587180c2cadb429ac1ea5e4cf5ffaadf60e8af1bbef3036","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"V9kR+GS+epDYgHvD/s1ljFaX1wzz3cwd3g3ZvQ/X+2c=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 57d911\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d3c1 eb30 8926 | 34 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n001 4 0acb 0257 00ba 0486 | 17 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n002 2 70d0 6123 | 5 6123 (0) 70d0 (0) 703d (0) 7d69 (0)\n003 1 452b | 1 452b (0)\n004 3 581a 5e36 5f83 | 3 5e36 (0) 5f83 (0) 581a (0)\n005 1 52fc | 1 52fc (0)\n============ DEPTH: 6 ==========================================\n006 1 5508 | 1 5508 (0)\n007 1 5602 | 1 5602 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","private_key":"34c80a58a443bb0e1518a14f812731f34ed2a04d27aad1978a43edfdc46b1219","name":"node_57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","services":["bzz","pss"],"enable_msg_events":true,"port":44125},"up":true}},{"node":{"info":{"id":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","name":"node_eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","enode":"enode://f3a08e5df6a6bcf751846b6ace6f57a31a6d449df1d48df065dea5bfc74586b8933323a5b063ec3e7ae58f7e038d7c218ad2294587029267bb4c092388609234@127.0.0.1:0","enr":"0xf88fb84056d0cb9ccc119c03a9f1d32aedfd19f6e27d6813d9a2ea1813e35ac670286db72f8b2d4481d401b7f7464d2cacd28c10aacbde6fdb7a0b4a83ede973c90042310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f3a08e5df6a6bcf751846b6ace6f57a31a6d449df1d48df065dea5bfc74586b8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6zB6bzM7MOvR47K1G9gJUxHUhwfWyiyBRH0BrUU+JUI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: eb307a\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3abf 57d9 | 30 177e (0) 172b (0) 154f (0) 1455 (0)\n001 3 8802 b73b a12b | 17 b73b (0) b374 (0) b8f9 (0) b8f3 (0)\n002 2 d3c1 d904 | 6 d904 (0) d3c1 (0) c0c2 (0) c3b2 (0)\n003 2 f6e5 fb7e | 5 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n004 2 e558 e6cf | 3 e6cf (0) e558 (0) e5e1 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e9fd | 1 e9fd (0)\n007 0 | 0\n008 1 ebf2 | 1 ebf2 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","private_key":"46e33ba68cfba7f42ff80b2a4e6e42af54661467f574487ae9dd64d58b7f1bff","name":"node_eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","services":["bzz","pss"],"enable_msg_events":true,"port":43461},"up":true}},{"node":{"info":{"id":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","name":"node_3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","enode":"enode://51deaa308d9269c160365fdfcbb25f60a03a82f2efaff308a0eb09a18cf138beda36562ac1c16957da7172ce518f770d922c053efc2c3bce06419cc6e0928014@127.0.0.1:0","enr":"0xf88fb84053019049f1135e4048d6971781321d1f8b972fd8a2a99e110a64833ce5a36834048b662125d1775ff49679add18eb3d76c36c8ec11be8647e6c523b5fe93a8160183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10251deaa308d9269c160365fdfcbb25f60a03a82f2efaff308a0eb09a18cf138be","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Or/p9Pao00tTbQJVH0XAOjWYe5T30zs6DcMK00sV+Co=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3abfe9\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 b73b eb30 | 34 b73b (0) b374 (0) b8f9 (0) b8f3 (0)\n001 2 452b 7f80 | 13 452b (0) 5f83 (0) 5e36 (0) 581a (0)\n002 2 177e 1455 | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 3 255d 248a 274f | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n005 1 3c40 | 1 3c40 (0)\n============ DEPTH: 6 ==========================================\n006 1 38f0 | 1 38f0 (0)\n007 1 3b4f | 1 3b4f (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","private_key":"93982f270ea11ec36ba55e97235856f2ed6fab52aa3d0249bf628e2b9c91d9dd","name":"node_3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","services":["bzz","pss"],"enable_msg_events":true,"port":34193},"up":true}},{"node":{"info":{"id":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","name":"node_7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","enode":"enode://51bcf947a12e8ac505ec8b402224676a504d2c39b71e446006083d741c461c94ab190ab816afaef8a6b24df9b56e6e9f8a30eb2bebd6a7df58e67e31c8c4e405@127.0.0.1:0","enr":"0xf88fb840f65e01347df378f48f5e7ebbb387f2f2cde36dd9aaede48ab5819adf690d1f87361843b84b8b6ab295420b7bf4eb9b12d169c9c53f2ef3d01db492bf9ef0735c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10351bcf947a12e8ac505ec8b402224676a504d2c39b71e446006083d741c461c94","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"f4AOWnlwIw9Sc+SZccfuUh3pfmn1bdVU4w3RLW+1x0k=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 7f800e\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 7 f0e9 e9fd e5e1 e558 | 34 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n001 4 0acb 1455 3103 3abf | 17 154f (0) 1455 (0) 177e (0) 172b (0)\n002 4 452b 5602 5508 581a | 8 452b (0) 5f83 (0) 5e36 (0) 581a (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 703d 70d0 | 2 703d (0) 70d0 (0)\n005 0 | 0\n006 1 7d69 | 1 7d69 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","private_key":"015cba3c04c983b51b26debe83456fc5ce953a720c5d618632a551198845ce87","name":"node_7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","services":["bzz","pss"],"enable_msg_events":true,"port":37409},"up":true}},{"node":{"info":{"id":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","name":"node_ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","enode":"enode://8d29ea4346f1503c80ef55fdb63d33a2d857bbda499bfd296afd75a9ae9badd16b3328fe1ba73b31a2b3cd6600d7fd33d2bfc6dcd1e61dc369f505b16c9df1d5@127.0.0.1:0","enr":"0xf88fb84025b8f01e1b8f2908011afc21980bd9d8b915e89b8851d351a509936bc3202d886b91cb5b9a1c2ba97ae71a5f776d2075237ee89af24379ed746fcf3e3e8eafe60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1038d29ea4346f1503c80ef55fdb63d33a2d857bbda499bfd296afd75a9ae9badd1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"rmAj1BbIe7Qz652NRPl1MXl9KSd0ME2ZaSOj/meIdHg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ae6023\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 248a 7f80 | 30 154f (0) 1455 (0) 177e (0) 172b (0)\n001 4 e6cf fb7e f6e5 f211 | 17 fb7e (0) f6e5 (0) f0e9 (0) f211 (0)\n002 2 8926 9629 | 8 9629 (0) 8926 (0) 8802 (0) 821a (0)\n003 3 be2b b8f3 b8f9 | 5 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n004 1 a12b | 1 a12b (0)\n============ DEPTH: 5 ==========================================\n005 1 aabc | 1 aabc (0)\n006 0 | 0\n007 1 afb1 | 1 afb1 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","private_key":"22c2fb65420237f8b89643102304e7ec4785bd727e32cf8d324a08c0c83bbcc9","name":"node_ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","services":["bzz","pss"],"enable_msg_events":true,"port":45469},"up":true}},{"node":{"info":{"id":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","name":"node_a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","enode":"enode://89914e07e3f818e5857dcf267822b10d9cf455fa7a2fa5b39ec98ad1f931ca0e8b152354d3514f26c9f1414aa10d95d96089819546a41a6f91a6e3c6d3399463@127.0.0.1:0","enr":"0xf88fb8400dc63a9d8ef5bc6b6aeef2fa584f5336ea901d50124c1606f8b2378173ebc2fd66efbc2bdcea10e1ae4587ac22cda0b5d5808a02865c0519648ccce893f76c9a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10389914e07e3f818e5857dcf267822b10d9cf455fa7a2fa5b39ec98ad1f931ca0e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"oSsSCBttSegjeNUjl2W8qMX0MjKzAWO8RpJMw+mOEXc=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: a12b12\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 1455 154f 3103 | 30 154f (0) 1455 (0) 177e (0) 172b (0)\n001 3 e6cf eb30 f6e5 | 17 f6e5 (0) f0e9 (0) f211 (0) f35a (0)\n002 5 9629 8673 821a 8802 | 8 9629 (0) 8926 (0) 8802 (0) 821a (0)\n003 5 b73b b374 b8f3 b8f9 | 5 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n============ DEPTH: 4 ==========================================\n004 3 aabc afb1 ae60 | 3 aabc (0) afb1 (0) ae60 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","private_key":"d7090c3295beb236fb881805333f666cea56d6dea2f42bf3b4ac5b607c63808d","name":"node_a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","services":["bzz","pss"],"enable_msg_events":true,"port":46387},"up":true}},{"node":{"info":{"id":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","name":"node_3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","enode":"enode://2566b869c3ead5eb369d120bdcfb5915162a7ab2b1ad732e88d9d977100c395a12867c8d6d2ce3be2dfed18ce3fc994523093fc48b01e1f7f6c1b9c6d2d2564e@127.0.0.1:0","enr":"0xf88fb84085e944ff27136b601bf818ec370a678631bb4b993981f6f37d4239904fd4c05c7a7bb06485217f380c84013e3ff57efd5f916325ce8929a2429a12af8a95a2bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022566b869c3ead5eb369d120bdcfb5915162a7ab2b1ad732e88d9d977100c395a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"MQPNC3ZU9ZO3Io0XFSCfJ+M5rQFAGalzhBOiDLasY+Q=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3103cd\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 856e a12b | 34 f6e5 (0) f0e9 (0) f35a (0) f211 (0)\n001 3 7f80 7d69 6123 | 13 7f80 (0) 7d69 (0) 703d (0) 70d0 (0)\n002 3 0486 177e 1455 | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 3 274f 255d 248a | 3 274f (0) 255d (0) 248a (0)\n============ DEPTH: 4 ==========================================\n004 4 3b4f 3abf 38f0 3c40 | 4 3c40 (0) 38f0 (0) 3b4f (0) 3abf (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","private_key":"95e6a35c4e714e2f717338757d55e091a179f90a24a9b669a758172f5685ca01","name":"node_3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","services":["bzz","pss"],"enable_msg_events":true,"port":36983},"up":true}},{"node":{"info":{"id":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","name":"node_856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","enode":"enode://bed85f28b7443ca051f8cc01c76cc4b73c1f4d737c273cbb726decbe6e2f3b4b22529e7ae589c40805650784c8d367e53525041825bc8377747743342d1d5ffd@127.0.0.1:0","enr":"0xf88fb84059a5c37cb0e55cbcde717bcf88c22f5c5a45df4aa83358375f04b00efa5e65203ef0371f0755c1afc0d541bf9fab3e7292d4150fbafab8fbb2d627ef6b7605b50183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bed85f28b7443ca051f8cc01c76cc4b73c1f4d737c273cbb726decbe6e2f3b4b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hW4nymiamyr0zT7ZWPIWK5xxB0xyaGisehCsL299Ah0=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 856e27\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 38f0 3103 | 30 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n001 3 c461 e5e1 f35a | 17 eb30 (0) ebf2 (0) e9fd (0) e6cf (0)\n002 2 b8f9 be2b | 9 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8926 (0) 8802 (0)\n005 1 821a | 1 821a (0)\n============ DEPTH: 6 ==========================================\n006 3 8673 87aa 87ac | 3 8673 (0) 87ac (0) 87aa (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","private_key":"35fb992eb3f4de7a3ac9e68c81b4f1e62d1f474eedd1bbd0d6b588d4a123faa3","name":"node_856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","services":["bzz","pss"],"enable_msg_events":true,"port":42951},"up":true}},{"node":{"info":{"id":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","name":"node_88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","enode":"enode://e15ed0ea7080c438ee8f5e359fe828ea27f1cd348449b819cf9ec4df58dbac3a08423e6d525f011d5f41cecc440a49c9b12c6dc8ef3380b5bff38cf6b9ce0e11@127.0.0.1:0","enr":"0xf88fb840617403b8f0d402717d1f39440b4cf23b906c9df7c10b4c846599b0a4787e289b29afdd85207fcfe39147c0467347702bc44ce5da6fe7200a0e57dc2baa99433d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103e15ed0ea7080c438ee8f5e359fe828ea27f1cd348449b819cf9ec4df58dbac3a","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"iAJLn2hDRrd1wcHrbpcJA0E1lXq0GOwAJyXxDviRmDc=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 88024b\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 7f80 7d69 255d | 30 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n001 3 ebf2 eb30 e5e1 | 17 eb30 (0) ebf2 (0) e9fd (0) e6cf (0)\n002 5 a12b b73b b374 b8f3 | 9 b8f9 (0) b8f3 (0) be2b (0) b73b (0)\n003 1 9629 | 1 9629 (0)\n============ DEPTH: 4 ==========================================\n004 5 821a 8673 87aa 87ac | 5 821a (0) 8673 (0) 87ac (0) 87aa (0)\n005 0 | 0\n006 0 | 0\n007 1 8926 | 1 8926 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","private_key":"31dbecd3ca7aa370e3a50aaac4f98bef73f2527b1896da7ed889a43ad771c2e8","name":"node_88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","services":["bzz","pss"],"enable_msg_events":true,"port":40113},"up":true}},{"node":{"info":{"id":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","name":"node_255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","enode":"enode://bb25c5b1634689128e4f6bd8c31f0ac70a9b0dd37e9fbeda681e96ae04a19553f5534314a8e675e517d5ca0013bf79de3893a40c1c2734ef4243d1db4ed08060@127.0.0.1:0","enr":"0xf88fb840a4996422aeb3198fc58ab411a6910daa8a05d960911ef17cc7b14152653cd219771997a20423baa0c51b882a843135d99c31b01eabed91a4818f2cb573ab00660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102bb25c5b1634689128e4f6bd8c31f0ac70a9b0dd37e9fbeda681e96ae04a19553","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JV240xGmanRDsV0ECvoGYm1pGcDSCm/Q9a+jTocoFzI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 255db8\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 d3c1 d904 821a 8802 | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 3 7d69 5e36 581a | 13 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n002 3 0257 177e 172b | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 5 3b4f 3abf 38f0 3c40 | 5 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 274f | 1 274f (0)\n007 1 248a | 1 248a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","private_key":"2ced13cc7febab95479e76339b80139922095bf66b8d47541c9bc22789123a9f","name":"node_255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","services":["bzz","pss"],"enable_msg_events":true,"port":40487},"up":true}},{"node":{"info":{"id":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","name":"node_581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","enode":"enode://9096985dab960112b5511301c88595af2dc0a90852fc6a98c0970cd20b0b11ada5293e4f8b066fbaf3b0a207d51cf0e3d0a50ada11446814054b39e6265cda7e@127.0.0.1:0","enr":"0xf88fb8402f9d16c72c43c1856f7d778c531ea65e02a0450905075f9bdddc9c2938b042941177b8854391706ee69ca82d23eb5654fb434b767fa732ca8167c32c33f5e00a0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029096985dab960112b5511301c88595af2dc0a90852fc6a98c0970cd20b0b11ad","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"WBrZLUNHg0hQwW54GYPAm+NAkXUno13ZZQxaPaH8gis=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 581ad9\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9629 d904 cb8d | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 4 177e 154f 0727 255d | 17 154f (0) 1455 (0) 177e (0) 172b (0)\n002 3 703d 7d69 7f80 | 5 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n003 1 452b | 1 452b (0)\n004 4 52fc 5508 57d9 5602 | 4 52fc (0) 5508 (0) 5602 (0) 57d9 (0)\n============ DEPTH: 5 ==========================================\n005 2 5e36 5f83 | 2 5e36 (0) 5f83 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","private_key":"39aed43a62aad671048b07d25383bb957d88b3bd53c0a52a9b73f132241f47bd","name":"node_581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","services":["bzz","pss"],"enable_msg_events":true,"port":38101},"up":true}},{"node":{"info":{"id":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","name":"node_0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","enode":"enode://90b8c983944e79f3081d0e6e7538f2e6fe78ba7a63412aa32fb3b08b02ed6efad44f45d6e2db83d67a03d0242e3ffd8e62703f0e4e6b74e48331c6b3a8c51db1@127.0.0.1:0","enr":"0xf88fb8409af7b76fd8c8b31f077a6f2fd5be9cd7b6f5f7d1c0dcd1d517334d649fc9f8140f432c4c4641c970093b46b75371213bf7e3e21e3b0e486e4160a092d71f53310183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10390b8c983944e79f3081d0e6e7538f2e6fe78ba7a63412aa32fb3b08b02ed6efa","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ByfX5owxnTpMxaFh3QWyp+cjUME55lwgkMEjLrvtX3g=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0727d7\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 d3c1 d904 cb8d | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 2 6123 581a | 13 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n002 2 3c40 274f | 8 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n003 4 172b 177e 1455 154f | 4 154f (0) 1455 (0) 177e (0) 172b (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0257 00ba | 2 00ba (0) 0257 (0)\n006 1 0486 | 1 0486 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","private_key":"312ee0e8a214abbd131a0e03c9c30710cbea185776d03bc7e6319eb1ce1d8c9d","name":"node_0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","services":["bzz","pss"],"enable_msg_events":true,"port":34603},"up":true}},{"node":{"info":{"id":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","name":"node_6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","enode":"enode://9a0af04a8b33cefc1178e827baadd6211134e17e6d17dda345d9a1af47e657e487d46382b137bd50829a3b49663160237c9c4ae9e5aa57249791029026b71ad8@127.0.0.1:0","enr":"0xf88fb8408d49aa1cfaa238a09955f64747940c56d3e4efcb913e43f3f12bc586038ec8a40405758ebe81aeba159213fe543a4c60c4119097c6eec92157eba0659cd944b60183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029a0af04a8b33cefc1178e827baadd6211134e17e6d17dda345d9a1af47e657e4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"YSO3d33jvCWR4wNqmt66H32OyTPQXuT+ABeRCJaSXRs=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 6123b7\npopulation: 33 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 13 aabc ebf2 e9fd e5e1 | 34 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n001 9 38f0 3b4f 3c40 3103 | 17 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n002 7 452b 5e36 5f83 52fc | 8 452b (0) 5508 (0) 5602 (0) 57d9 (0)\n============ DEPTH: 3 ==========================================\n003 4 703d 70d0 7f80 7d69 | 4 7d69 (0) 7f80 (0) 703d (0) 70d0 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","private_key":"a32ad9e8eb034068af76013c458a289d8bb4faf6000aa63666404d8be13bf5d6","name":"node_6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","services":["bzz","pss"],"enable_msg_events":true,"port":37555},"up":true}},{"node":{"info":{"id":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","name":"node_04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","enode":"enode://0314da640d0324270183587d5ee38b6d7f82082def277f1fa70f2dff054becdaab3c31aa4921f4bdeb7f4c31adc8a70ad09609868642101b3e63eaab91727d69@127.0.0.1:0","enr":"0xf88fb84082ed1045bb3ffd5e7d12ace534321c835e31ed2db07e7eb5bfc3bb200d7e0fb23f55e4975e73ed36e6de025624ddc499148b4d9d8001734be2cd014a9e84cb8d0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1030314da640d0324270183587d5ee38b6d7f82082def277f1fa70f2dff054becda","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"BIYlUO84+DEIXzeOJTOt3CyQQog5RjEgjEnLM2Fa2js=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 048625\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 b374 cb8d c0c2 | 34 be2b (0) b8f9 (0) b8f3 (0) b73b (0)\n001 2 57d9 6123 | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 4 3c40 3103 274f 248a | 8 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n003 4 172b 177e 154f 1455 | 4 154f (0) 1455 (0) 177e (0) 172b (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0257 00ba | 2 00ba (0) 0257 (0)\n006 1 0727 | 1 0727 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","private_key":"dadc2a0436842f90010d95ae0b3d5e1612d72a28854573e679a8a336f5370e21","name":"node_04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","services":["bzz","pss"],"enable_msg_events":true,"port":46049},"up":true}},{"node":{"info":{"id":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","name":"node_248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","enode":"enode://7f0f82c32f25e019be8cba115eba217f82432b010a401a273037351dca0b5c61089825d7b034801b2876318500c566b1991d1efcde1466bdcfee6a128c3bf81a@127.0.0.1:0","enr":"0xf88fb840bfa5193ddceefc65d57437eff8a7a774354003033fd5224a4d2edc41e43b3f5d50f4ea4346ea045e6985ccb53ff48ba17b317e791010248dbfa996b83c429aad0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1027f0f82c32f25e019be8cba115eba217f82432b010a401a273037351dca0b5c61","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"JIouYYCR3urEWPR0FhZAXgvF/9oan5ElMH4yx4FyinU=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 248a2e\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 e6cf ae60 | 34 aabc (0) afb1 (0) ae60 (0) a12b (0)\n001 2 5e36 452b | 13 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n002 4 172b 0257 00ba 0486 | 9 154f (0) 1455 (0) 177e (0) 172b (0)\n003 5 3103 3c40 3b4f 3abf | 5 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 1 274f | 1 274f (0)\n007 1 255d | 1 255d (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","private_key":"5eed72a77466e0457f248c4b926ad580c90bac7ee1e11bca5d5d20a9d2bfab5d","name":"node_248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","services":["bzz","pss"],"enable_msg_events":true,"port":35737},"up":true}},{"node":{"info":{"id":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","name":"node_172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","enode":"enode://a9a9c0be91c80c150ed76c716242763e92cfd34102db458614b97a2fdc1aa9046a873d2e16d6b720a82abef0c3d3afe50c548e82064081f6d3722bfaa8ad5a7a@127.0.0.1:0","enr":"0xf88fb840af989a0c29715008d7c936ddbe8af501a4904339da4b799f99369a5ae9937a805b29f031c54f88d358a298b4ecd360bc06b55108ecaecb17a31f9902f367f44c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a9a9c0be91c80c150ed76c716242763e92cfd34102db458614b97a2fdc1aa904","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"Fyu7yqV8N8JDFKhPvQud5F+DpGAWvSOV3Crbqxu5C1w=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 172bbb\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 afb1 aabc fb7e | 34 aabc (0) afb1 (0) ae60 (0) a12b (0)\n001 2 6123 70d0 | 13 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n002 2 255d 248a | 8 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n003 5 0486 0727 0257 00ba | 5 0acb (0) 00ba (0) 0257 (0) 0727 (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 1455 154f | 2 1455 (0) 154f (0)\n007 0 | 0\n008 0 | 0\n009 1 177e | 1 177e (0)\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","private_key":"2016f3bc79c1f5a91c126a6f548bdd080c149e46cb1165cf1002068c6fcda411","name":"node_172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","services":["bzz","pss"],"enable_msg_events":true,"port":42303},"up":true}},{"node":{"info":{"id":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","name":"node_fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","enode":"enode://f9175ab3d792f133155a959560213cc1c01279ed6e348a68906d8a96a87596baf128933900518e8d6aa1fda56b7139b3dc74dbb690196147ab6480b498c65dd1@127.0.0.1:0","enr":"0xf88fb8400494ee532414babfb684947ef027e954af32abe1255703856100999a37a3b27d4e3e6728f46532dffdb89272cb1948f5bc6df766b40fdd2797bed3c8148074870183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103f9175ab3d792f133155a959560213cc1c01279ed6e348a68906d8a96a87596ba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"+35nFmFKyUG3Thipvz3tY7wAtFMiG0CXb3g2daHAbGM=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: fb7e67\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 5508 7d69 6123 172b | 30 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n001 5 8926 b73b aabc ae60 | 17 aabc (0) afb1 (0) ae60 (0) a12b (0)\n002 3 c3b2 cb8d d904 | 6 d904 (0) d3c1 (0) c461 (0) c3b2 (0)\n003 5 e558 e6cf e9fd eb30 | 6 e6cf (0) e558 (0) e5e1 (0) e9fd (0)\n============ DEPTH: 4 ==========================================\n004 4 f6e5 f0e9 f35a f211 | 4 f6e5 (0) f0e9 (0) f35a (0) f211 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","private_key":"8b2673cf73b2e993026f6a2c87caae15dba45720ad187f9c5f5ddbdc7d1b32a4","name":"node_fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","services":["bzz","pss"],"enable_msg_events":true,"port":40621},"up":true}},{"node":{"info":{"id":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","name":"node_f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","enode":"enode://3595a73fde880c53304b49c39683267c4fa90fa5773dc084a1affc7999314e2dab768ab82091fe068bb824cd54277129cc6f5d0065d9f2dfcf3392c048dcb7c5@127.0.0.1:0","enr":"0xf88fb840e00692e06d4b89b7bdd43adeba6626c5e4bba8988449a048ff3ce2ba802dad3a6f8c07c23a5d3ff37562cec16cff3eae3fb2dfd4e825a8e07ea04a4fa1a054b80183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1033595a73fde880c53304b49c39683267c4fa90fa5773dc084a1affc7999314e2d","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"8hE3bUbm4JZu6YTPWDeAUkCyulPFrHUxXFbb3/uVemU=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: f21137\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 6123 3b4f | 30 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n001 2 b73b ae60 | 17 aabc (0) afb1 (0) ae60 (0) a12b (0)\n002 2 c0c2 c461 | 6 c461 (0) c0c2 (0) c3b2 (0) cb8d (0)\n003 3 e5e1 e558 e6cf | 6 e6cf (0) e558 (0) e5e1 (0) e9fd (0)\n004 1 fb7e | 1 fb7e (0)\n005 1 f6e5 | 1 f6e5 (0)\n============ DEPTH: 6 ==========================================\n006 1 f0e9 | 1 f0e9 (0)\n007 1 f35a | 1 f35a (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","private_key":"cc85dc8007f84a1a4cef3b3f84345cf6212741fe8451882613368b13b8a21170","name":"node_f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","services":["bzz","pss"],"enable_msg_events":true,"port":33599},"up":true}},{"node":{"info":{"id":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","name":"node_3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","enode":"enode://185474977590e399a3bde82710d24deebb17ec414f3fa17d70550ccc7fd742d881f76c5ad58e5854b3cdc16d27789332ba975d840218a363adf9950251006852@127.0.0.1:0","enr":"0xf88fb84041802a5fbc1bf6e457fed3480b3d38fc2bd3d3fa40ca619ef6a09d58e5c1873958cd6cb13ab6d0709a9ee1172496e623f5c6d1ab202915f54b3f3bff6d1923ef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102185474977590e399a3bde82710d24deebb17ec414f3fa17d70550ccc7fd742d8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"O0+n1ykSkGihKB72hJS2HQVSA96MNqX+J68+tWWDIQg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 3b4fa7\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 87aa f211 | 34 aabc (0) afb1 (0) ae60 (0) a12b (0)\n001 2 6123 703d | 13 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n002 2 0acb 00ba | 9 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n003 3 255d 248a 274f | 3 274f (0) 255d (0) 248a (0)\n004 1 3103 | 1 3103 (0)\n005 1 3c40 | 1 3c40 (0)\n============ DEPTH: 6 ==========================================\n006 1 38f0 | 1 38f0 (0)\n007 1 3abf | 1 3abf (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","private_key":"6ad42cf2ce8ec2d947696df2ab9fd0b464376964980f542777118020ce0e5d7b","name":"node_3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","services":["bzz","pss"],"enable_msg_events":true,"port":33419},"up":true}},{"node":{"info":{"id":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","name":"node_87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","enode":"enode://35b27d332ce1f35bec177a8c636960cbfb79cf58bb3f2d1b874231b382a0cdc590c4e8353decd2fe3b1b4f8542b03f2171425bff56edccbbd15272b3cace9a0e@127.0.0.1:0","enr":"0xf88fb8407dbd42f95e5ae03d53a9da07975ce124ffe18be69ad76c445cd2cb001e85da44048d49dca08d4efae5512882c98113f26c2f540eba64a1fd289c35fafa598c040183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10235b27d332ce1f35bec177a8c636960cbfb79cf58bb3f2d1b874231b382a0cdc5","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"h6p33O8ZsMhqPoq2TI8S2acz53p+Eryuw6TNhQTFp3U=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 87aa77\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3b4f 70d0 | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 4 e558 c461 cb8d d904 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 2 afb1 aabc | 9 aabc (0) afb1 (0) ae60 (0) a12b (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8802 (0) 8926 (0)\n005 1 821a | 1 821a (0)\n006 1 856e | 1 856e (0)\n============ DEPTH: 7 ==========================================\n007 1 8673 | 1 8673 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 87ac | 1 87ac (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","private_key":"f61f38cd9320f5d79569492609fbc059d0c28376d87733386c34ed0ee05f9b52","name":"node_87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","services":["bzz","pss"],"enable_msg_events":true,"port":45677},"up":true}},{"node":{"info":{"id":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","name":"node_70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","enode":"enode://75f2fb6caf9b53cf0b82b5c6751b2d06f05decbce5a26d8196d2240fdc8b8cb7cfdac4f123838a8895d81578515dcd5b07ed1ff432667c175ca092bb241e5d81@127.0.0.1:0","enr":"0xf88fb840ca369a7e8bad45d547ba1b43054168da9813f7ebf8143be24488270f9cf1a3373939a5b2c228aa93a6857cc0b50be949c909531bb4269dfce238c9433aca848e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10375f2fb6caf9b53cf0b82b5c6751b2d06f05decbce5a26d8196d2240fdc8b8cb7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cNBxCziU+r8ys0O5tZM594bs45iVx+2l8WLMV1ycglM=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 70d071\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 f0e9 e558 e9fd ebf2 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 4 3c40 0acb 00ba 172b | 17 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n002 2 57d9 52fc | 8 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 7d69 7f80 | 2 7d69 (0) 7f80 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 703d | 1 703d (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","private_key":"c1017fa00e291b4183d30ab17ef32b438afcfd234be6cecbb9897bdb585a9a86","name":"node_70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","services":["bzz","pss"],"enable_msg_events":true,"port":39215},"up":true}},{"node":{"info":{"id":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","name":"node_52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","enode":"enode://b0a77e6fe1c5bc0275bbb7eca27007740ae80fe424fe6acf055bf84789dc99a14280d8c08d2d3a0cc7c2b996c091a5059ed083a8f289704b6e82234b20815447@127.0.0.1:0","enr":"0xf88fb840b35c45f9ad29f754a3318f771140615e64a3fc523df8dc7d6e4aba4bcafa4642422ae39afe0eba129bf9519377d0026bd546255261f4388dc0a7c89d2752e23c0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103b0a77e6fe1c5bc0275bbb7eca27007740ae80fe424fe6acf055bf84789dc99a1","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"UvweIZvFGPuvKJ2jI22Y2xtj3xIn6jJYEilnFHOtw70=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 52fc1e\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 c461 cb8d b374 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 2 00ba 0257 | 17 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n002 3 6123 7d69 70d0 | 5 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n003 1 452b | 1 452b (0)\n004 3 581a 5f83 5e36 | 3 581a (0) 5e36 (0) 5f83 (0)\n============ DEPTH: 5 ==========================================\n005 3 5508 57d9 5602 | 3 57d9 (0) 5602 (0) 5508 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","private_key":"5128d9e0c20a65b00ada80037610ab8459cb99a9bc3cbc467f90e3d94868636e","name":"node_52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","services":["bzz","pss"],"enable_msg_events":true,"port":37815},"up":true}},{"node":{"info":{"id":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","name":"node_b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","enode":"enode://bddef211431764890d0c556f02492d623440dadef8220aa3d14cc5a4a176c0c6a3d9c51db26fa8d00e3b2919ae01708c6ccbcfb89300889f763e88e88f1cf62f@127.0.0.1:0","enr":"0xf88fb840fa92fb538dc1f10b99bd1a5ff04542a013336d8c78c82d02689092893de2558d3be1b76e10a87b2976ab77dba021345e4da01bcf57e968f16179262cbb7f7b610183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103bddef211431764890d0c556f02492d623440dadef8220aa3d14cc5a4a176c0c6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"s3RM9vGAwuuaHe0Obd1gDV95JoOHuXMzBw+1oYOv/Yk=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b3744c\npopulation: 16 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 0486 274f 52fc | 30 0acb (0) 00ba (0) 0257 (0) 0486 (0)\n001 3 cb8d c461 c3b2 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 3 9629 8802 8673 | 8 9629 (0) 8802 (0) 8926 (0) 821a (0)\n003 3 a12b afb1 aabc | 4 a12b (0) aabc (0) ae60 (0) afb1 (0)\n============ DEPTH: 4 ==========================================\n004 3 be2b b8f9 b8f3 | 3 be2b (0) b8f3 (0) b8f9 (0)\n005 1 b73b | 1 b73b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","private_key":"f9b4401c90628262d75ec2b1472b181d0ba586f207e512d8c2bff501f6969006","name":"node_b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","services":["bzz","pss"],"enable_msg_events":true,"port":39313},"up":true}},{"node":{"info":{"id":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","name":"node_274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","enode":"enode://cd29948d6981370c284ab296a55d43dbe7203b54193b763b157977ad2952be300cafaad9cb5d51517a90c64254bc6a0e9b50e40f37487d9a824ff9f6a442d543@127.0.0.1:0","enr":"0xf88fb8400df64191c8bf59e9ac7ad80c636ae992d431ba5d833d277a482b3d374ef08eb8697eef5cbddfdf88bb8e260cb007083c6e9333a667d0cb7e4560630ceeb951820183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103cd29948d6981370c284ab296a55d43dbe7203b54193b763b157977ad2952be30","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"J0+LdS7wyEpcMJgGawtNHAK4obFzD1ntlAZFNe7aR1Y=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 274f8b\npopulation: 20 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 cb8d 87ac 821a b8f9 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 4 703d 5508 5e36 5f83 | 13 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n002 4 154f 0acb 0486 0727 | 9 0acb (0) 0486 (0) 0727 (0) 00ba (0)\n003 5 3103 3c40 38f0 3b4f | 5 3103 (0) 3c40 (0) 38f0 (0) 3abf (0)\n============ DEPTH: 4 ==========================================\n004 0 | 0\n005 0 | 0\n006 2 255d 248a | 2 255d (0) 248a (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","private_key":"7ff83f61deceac3be4f65ab071b30e2906485aa9b9cf9762915bdab24ad3095d","name":"node_274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","services":["bzz","pss"],"enable_msg_events":true,"port":37995},"up":true}},{"node":{"info":{"id":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","name":"node_5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","enode":"enode://a75b279e617f6db28bac0fc33337d87e284116d2e3e069685fe1f42f46fdea15c51124ed699840d171f47d4778553e545475580f510a2ec4f830fedf460df0d6@127.0.0.1:0","enr":"0xf88fb840ef24e78bea8bf572427a95c9bf7cb2faffec0a4a430715acd4aadcdcdb78125e54a5d26f68b4d1be1551eb00e29157acb4b1692b27e80546b20bfd2dd0cd43a70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102a75b279e617f6db28bac0fc33337d87e284116d2e3e069685fe1f42f46fdea15","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"X4MhWM+E4OSKNRiVWHixauJTRn9UZk607BIT/vw/Mnc=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5f8321\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 cb8d c461 c3b2 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 2 1455 274f | 17 1455 (0) 154f (0) 177e (0) 172b (0)\n002 2 6123 703d | 5 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n003 1 452b | 1 452b (0)\n004 4 52fc 5508 5602 57d9 | 4 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n============ DEPTH: 5 ==========================================\n005 1 581a | 1 581a (0)\n006 0 | 0\n007 1 5e36 | 1 5e36 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","private_key":"d19565076e49cecdfa86edf90fdaae204fb957d2aa8d76158101247c371fbecd","name":"node_5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","services":["bzz","pss"],"enable_msg_events":true,"port":45427},"up":true}},{"node":{"info":{"id":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","name":"node_452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","enode":"enode://dea46c610b096ce0543a2ecbed5434bf207a65a42457ddbc6c3132b6809d56a4b3037879121fd53a0c2c0c92fb3736f8373c987c1ba95992e53e2dbf8f35cb79@127.0.0.1:0","enr":"0xf88fb84083953db305d8b6d3f2a3d38e0e8f81c2381c85a3d80ffe54c2a6582a7076e63124e85a302030bc72cf9e748b50ce103fb12c6cd072472f538ff96ccdb08359300183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103dea46c610b096ce0543a2ecbed5434bf207a65a42457ddbc6c3132b6809d56a4","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"RSsH1zQz59bCBaUEQZrhAAGaoZIHIwEScrWWYH22aEo=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 452b07\npopulation: 19 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 c461 cb8d 9629 8673 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 5 3abf 248a 177e 154f | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 7d69 7f80 6123 | 5 6123 (0) 7d69 (0) 7f80 (0) 703d (0)\n============ DEPTH: 3 ==========================================\n003 7 52fc 5508 57d9 5602 | 7 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","private_key":"92e76eb57823fd78556776b404da0b21c27ef8c4824adef769ea1c5f49ae3db9","name":"node_452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","services":["bzz","pss"],"enable_msg_events":true,"port":33293},"up":true}},{"node":{"info":{"id":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","name":"node_86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","enode":"enode://2733db14205f39cf4a5f52580a937dccc7220e36a80b7c541c95e9f5f1ab651bd96f451fecc2e2cdab225fc0e37fc63b70f3a4e84d99ceb7c2d7f1bf0a0f39f6@127.0.0.1:0","enr":"0xf88fb84044d30c7582fe27aa3b8c55da3f032e7cb56b288e44baf86177cfde6ed4c9149015288e5ba011d1c31348e0f182578ce8e67d5005e9643a93d79062b0b49214570183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1022733db14205f39cf4a5f52580a937dccc7220e36a80b7c541c95e9f5f1ab651b","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hnNaRtp2sxMvcpspO02FAuk57Lp3a42Fs65z76IYS18=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 86735a\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 452b 5e36 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 2 cb8d c3b2 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 4 a12b afb1 be2b b374 | 9 b73b (0) b374 (0) be2b (0) b8f3 (0)\n003 1 9629 | 1 9629 (0)\n004 2 8802 8926 | 2 8926 (0) 8802 (0)\n005 1 821a | 1 821a (0)\n006 1 856e | 1 856e (0)\n============ DEPTH: 7 ==========================================\n007 2 87aa 87ac | 2 87aa (0) 87ac (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","private_key":"b24570a9ec33187bd0150552ac01cdd88eec842a46287b6ac1b2deb18f33e085","name":"node_86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","services":["bzz","pss"],"enable_msg_events":true,"port":40543},"up":true}},{"node":{"info":{"id":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","name":"node_5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","enode":"enode://6828133036c9b44a750ebe723643ebb654f1e58df2ceeebc03acfb272369884cb2d2d655af0643f45967522375b8ffead57932e55b3b7dcfb52c9f7d82f137b9@127.0.0.1:0","enr":"0xf88fb84028bf1f9f6157f4c3f2d4ef7e1ea62299c768b52e33444503387ea891297151581142a59adab791688ddb3eac52f9b5edfedc501289011d1b817c4cbe2bada5770183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036828133036c9b44a750ebe723643ebb654f1e58df2ceeebc03acfb272369884c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"XjZUK7vA1wIxydAHQssw/M8/IG7s8QoPNDMqKYbIb/s=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 5e3654\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 9629 87ac 8673 | 34 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n001 4 154f 274f 255d 248a | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 6123 7d69 703d | 5 6123 (0) 7f80 (0) 7d69 (0) 703d (0)\n003 1 452b | 1 452b (0)\n004 4 52fc 5508 57d9 5602 | 4 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n============ DEPTH: 5 ==========================================\n005 1 581a | 1 581a (0)\n006 0 | 0\n007 1 5f83 | 1 5f83 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","private_key":"89f0ff7aa444ba31932f2d98ccf6dfd9c65ff023efd774671320ecaf9a928885","name":"node_5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","services":["bzz","pss"],"enable_msg_events":true,"port":45057},"up":true}},{"node":{"info":{"id":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","name":"node_87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","enode":"enode://fd65f331dd55b301498b1fd8690370c2150ce0c0cb0eba8fafb9401b873683998d605be7cbf6b1e4653a44decd3ce45eb6666582fb64a1549b8d6f6ea5136ccc@127.0.0.1:0","enr":"0xf88fb84067a97cfc4b4ead1783d6733994223dd4f8e0a4b58e380a6b43e24efb3992b7d765533669304855d20d5c0b1970f6756f7294840f8d7caf98d1292c63a1ae46860183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102fd65f331dd55b301498b1fd8690370c2150ce0c0cb0eba8fafb9401b87368399","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"h6z2SyLFeXUXGNwJPADIKzn+twI/5TxkhrKIlgrZ4UY=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 87acf6\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 274f 5e36 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 2 cb8d ebf2 | 17 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n002 2 b73b b8f9 | 9 b73b (0) b374 (0) be2b (0) b8f3 (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8802 (0) 8926 (0)\n005 1 821a | 1 821a (0)\n006 1 856e | 1 856e (0)\n============ DEPTH: 7 ==========================================\n007 1 8673 | 1 8673 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 1 87aa | 1 87aa (0)\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","private_key":"9037526f177112177c3d058d3b13b501be3a83fdd3c1e99b947fc4282b4ea6ec","name":"node_87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","services":["bzz","pss"],"enable_msg_events":true,"port":39033},"up":true}},{"node":{"info":{"id":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","name":"node_ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","enode":"enode://6e0b7fe07cf0a0ef6aff0adebd4fa523361aa0a557c6d363f9e618c229187bba266e046891e4d574f089cb9a13f952a3be1d3484b2917e7a07d8f0504f24e32d@127.0.0.1:0","enr":"0xf88fb840ea01ea00dc23b440bab5e4b3afbb32e20216d4bb47fda6ac71084c371a93e32e5fa1f8064f95b4756488093c95804591ca4cf7045cae8e2d84a75c6f998a6ee10183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036e0b7fe07cf0a0ef6aff0adebd4fa523361aa0a557c6d363f9e618c229187bba","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"6/Jc5CeQUQa3BiXACE3LEXlkpNS5lR9Zd0V9pXQbcWw=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: ebf25c\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 6123 7d69 70d0 | 30 6123 (0) 7d69 (0) 7f80 (0) 70d0 (0)\n001 2 8802 87ac | 17 b73b (0) b374 (0) be2b (0) b8f3 (0)\n002 2 cb8d d3c1 | 6 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n003 3 f35a f6e5 fb7e | 5 fb7e (0) f6e5 (0) f0e9 (0) f35a (0)\n004 2 e558 e5e1 | 3 e5e1 (0) e558 (0) e6cf (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 1 e9fd | 1 e9fd (0)\n007 0 | 0\n008 1 eb30 | 1 eb30 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","private_key":"a5091bd57fcc7b35a7f062cffd9498b8ca19657267318836a47b545deb40052a","name":"node_ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","services":["bzz","pss"],"enable_msg_events":true,"port":34261},"up":true}},{"node":{"info":{"id":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","name":"node_d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","enode":"enode://9dbd240d54a8ec88749a933200a7985b59dad0875db66a334b61ddf1a0475851fe15d0a2c521bb9b9c8dd762f98d16fb1606e18aaa7e9be9635a70684f792ce1@127.0.0.1:0","enr":"0xf88fb84081bae7fd011c17a28aec0c170fcf86fce22719550c958b1b76570e8ff83a371f434558ff6b1c828ee71f3809adc8e7e3ff1b17ab1c6a2ea47fa94ffcb9a2f6c00183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039dbd240d54a8ec88749a933200a7985b59dad0875db66a334b61ddf1a0475851","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"08Ga1MGrya8Dv/wavJcX9Odl1f/3rndiA0OLrJTQGAY=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d3c19a\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 6123 5602 57d9 255d | 30 57d9 (0) 5602 (0) 5508 (0) 52fc (0)\n001 2 b8f9 be2b | 17 b374 (0) b73b (0) be2b (0) b8f3 (0)\n002 8 f35a f0e9 e6cf e558 | 11 fb7e (0) f6e5 (0) f0e9 (0) f35a (0)\n============ DEPTH: 3 ==========================================\n003 4 cb8d c461 c0c2 c3b2 | 4 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n004 1 d904 | 1 d904 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","private_key":"9e4ad8ba562de45511544b4f652f51689e2ad6dcfe4324845b41cab2a1cdb499","name":"node_d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","services":["bzz","pss"],"enable_msg_events":true,"port":42733},"up":true}},{"node":{"info":{"id":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","name":"node_0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","enode":"enode://9a31745dfa11805bdde500a1cfb7d3c0df78681ccd7705384e39e7c6b90278255f7273815bae322e633c7a7e7267f6c310d98ae8b849c34c87f94c40528e54f5@127.0.0.1:0","enr":"0xf88fb840a1f769829999e7af043cecab4b6b39ce1d53fdaf5a02a960165c8eda587bfd0378ad69db24c3f47258aaad5a06acf5dfd842cf65ba503e4cd72580a85176d6290183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1039a31745dfa11805bdde500a1cfb7d3c0df78681ccd7705384e39e7c6b9027825","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"AlftRr1JJxMG/tAScBn9VNtHIoTQAJnxDK3X6DWIpjo=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 0257ed\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d904 d3c1 | 34 9629 (0) 8802 (0) 8926 (0) 821a (0)\n001 3 5602 57d9 52fc | 13 52fc (0) 57d9 (0) 5602 (0) 5508 (0)\n002 2 255d 248a | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 3 172b 1455 154f | 4 154f (0) 1455 (0) 172b (0) 177e (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0727 0486 | 2 0486 (0) 0727 (0)\n006 1 00ba | 1 00ba (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","private_key":"93e56d43d2445522babc78fe39d069e01dced5497755d2a0a5690b1b3bc7f5aa","name":"node_0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","services":["bzz","pss"],"enable_msg_events":true,"port":39565},"up":true}},{"node":{"info":{"id":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","name":"node_d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","enode":"enode://a7d3655360abbdb952e9fdf7575d8fb2930309cf2d41bb6a7c8e33f0fb424c1e39c847da1cb0ec0bef9f7569e687f3d71ff62764ed431c2e149f839e060a8d61@127.0.0.1:0","enr":"0xf88fb8404ea64b440fd4d8c1d58f6d37ea7fa76455fb2e1df09a99d151cd5837622939a442f0b9e20b90df55a6c93c013fa1a6e2b6df5ed709823b48d4485e34a03687f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103a7d3655360abbdb952e9fdf7575d8fb2930309cf2d41bb6a7c8e33f0fb424c1e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"2QT22HkMwjUGP1RmFSHDoZfj6c3Z27zWdl7GzaXY97Q=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d904f6\npopulation: 21 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 581a 6123 703d 255d | 30 581a (0) 5e36 (0) 5f83 (0) 52fc (0)\n001 2 87aa 821a | 17 8802 (0) 8926 (0) 821a (0) 856e (0)\n002 8 f35a f0e9 fb7e e9fd | 11 fb7e (0) f6e5 (0) f0e9 (0) f35a (0)\n============ DEPTH: 3 ==========================================\n003 4 cb8d c461 c3b2 c0c2 | 4 cb8d (0) c461 (0) c0c2 (0) c3b2 (0)\n004 1 d3c1 | 1 d3c1 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","private_key":"b53f894c8449d42e7dfbb557649b7fd8816b55d7fd57c3ed65a65c5fdc643478","name":"node_d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","services":["bzz","pss"],"enable_msg_events":true,"port":39481},"up":true}},{"node":{"info":{"id":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","name":"node_703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","enode":"enode://123c89683b99e7d2cb71f5e7d6d6fad3200c8c9129dd11844158320310a15d658bdf8af970f938bbe2e97f72f08405e8c323d49f1c84a7b8cbc8c94bdb1ac762@127.0.0.1:0","enr":"0xf88fb8404488d9cd1ca1b9bdb277610eac83b22a38260188c4604d95f5d9b673feb11b6e262970fefd02bb8685d3be492dd5950f2d3db07395f949562dbcc9c154cc77bc0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102123c89683b99e7d2cb71f5e7d6d6fad3200c8c9129dd11844158320310a15d65","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"cD3HasckRXyAWrzB7S4/MhghQJ+0zwGF4vB+vEwYFE8=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 703dc7\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 4 afb1 e5e1 f35a d904 | 34 8802 (0) 8926 (0) 856e (0) 8673 (0)\n001 4 0acb 1455 274f 3b4f | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 581a 5f83 5e36 | 8 581a (0) 5e36 (0) 5f83 (0) 52fc (0)\n003 1 6123 | 1 6123 (0)\n============ DEPTH: 4 ==========================================\n004 2 7d69 7f80 | 2 7f80 (0) 7d69 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 1 70d0 | 1 70d0 (0)\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","private_key":"e16c1c8c92402bfd9f8fe2a57e37c01f1898f2f128430398ac33ae7482108ebc","name":"node_703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","services":["bzz","pss"],"enable_msg_events":true,"port":36893},"up":true}},{"node":{"info":{"id":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","name":"node_afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","enode":"enode://50e65aecad41df245ddc2f29869d81db24b988a216918b80b305904ed62647ce8c03cc7fdcee80bbe864ca008714bce3d055bbfb50bec1214ae67ba54b9126bb@127.0.0.1:0","enr":"0xf88fb8401f728d3897ecb9512cf5eb7a662998136041c670409700a9f59b5e9b8a04a81e395e1d3f21b92032fb70f5ab6ffc3b648f6b884268426117ba50407330ee9eef0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10350e65aecad41df245ddc2f29869d81db24b988a216918b80b305904ed62647ce","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"r7HQuNGx9qNBOEwfCBj2souF/v5qRaiSVS3k3lN59qU=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: afb1d0\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 172b 00ba 703d | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 3 e6cf fb7e f6e5 | 17 fb7e (0) f6e5 (0) f35a (0) f211 (0)\n002 3 8926 87aa 8673 | 8 8926 (0) 8802 (0) 856e (0) 8673 (0)\n003 5 b73b b374 be2b b8f3 | 5 b374 (0) b73b (0) be2b (0) b8f3 (0)\n004 1 a12b | 1 a12b (0)\n============ DEPTH: 5 ==========================================\n005 1 aabc | 1 aabc (0)\n006 0 | 0\n007 1 ae60 | 1 ae60 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","private_key":"4354e176e57a83691528c333e221af5d016371701e1d7f08607a0a04f5fca409","name":"node_afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","services":["bzz","pss"],"enable_msg_events":true,"port":33425},"up":true}},{"node":{"info":{"id":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","name":"node_00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","enode":"enode://d2088cb0561220a69e8efa4945b89411db2f73bd1432a997f9cf0f4316eda2a7f5962c0b0d5b314fea4cb73dc4df7fedcccc2027eb9d4cedf7fbe996d7f5e0bf@127.0.0.1:0","enr":"0xf88fb84063cbdaf9b29653c80c1532a4963d23258dc89555d21522053f86d7a73b54520d64eee9fa218232119ae212b2c9b0d27e5b8cacf6f3c727bf3dc4cbbf690dd51e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103d2088cb0561220a69e8efa4945b89411db2f73bd1432a997f9cf0f4316eda2a7","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ALpsYbLWSA9T9Iw97zrIVYfZt6kmWNIcI1/Q/dwkaFA=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 00ba6c\npopulation: 18 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 c0c2 8926 9629 b8f3 | 34 fb7e (0) f6e5 (0) f35a (0) f211 (0)\n001 4 70d0 452b 57d9 52fc | 13 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n002 2 248a 3b4f | 8 274f (0) 255d (0) 248a (0) 3103 (0)\n003 3 1455 154f 172b | 4 154f (0) 1455 (0) 172b (0) 177e (0)\n004 1 0acb | 1 0acb (0)\n============ DEPTH: 5 ==========================================\n005 2 0727 0486 | 2 0486 (0) 0727 (0)\n006 1 0257 | 1 0257 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","private_key":"5a24ca759ff05fd20635c180866850474c9548f77adb55e3dd1b4745a871f0b7","name":"node_00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","services":["bzz","pss"],"enable_msg_events":true,"port":43657},"up":true}},{"node":{"info":{"id":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","name":"node_9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","enode":"enode://28248a4e3b947a840d138ec02d99874ec310f8a569c25dc8a34c5e334dc69bbd196f0769f32afad244552e8f321e4ab1b498e10ba875cb6e008146607b4b1748@127.0.0.1:0","enr":"0xf88fb840410401b0463d1535e6372c265c06ccac3b6116261f346d31b2c4da7487baa40b0d04f506d7a30412b7ca365e1283a8c1f6298c2a0fd14448a8b7b9d3d0e6f9f70183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10228248a4e3b947a840d138ec02d99874ec310f8a569c25dc8a34c5e334dc69bbd","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"likyDWSP2jg07drHJjzGyIZR3GB0IGzuABRJGNInYok=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 962932\npopulation: 24 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 6 5e36 581a 452b 38f0 | 30 452b (0) 581a (0) 5e36 (0) 5f83 (0)\n001 5 f35a f0e9 e9fd c461 | 17 fb7e (0) f6e5 (0) f35a (0) f211 (0)\n002 6 a12b ae60 aabc b374 | 9 b73b (0) b374 (0) be2b (0) b8f3 (0)\n============ DEPTH: 3 ==========================================\n003 7 821a 856e 8673 87aa | 7 8926 (0) 8802 (0) 856e (0) 8673 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","private_key":"37f4999bea53d1c97ec6a575c20dd5a83d19dbf990fe54e165401484f46a0ad5","name":"node_9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","services":["bzz","pss"],"enable_msg_events":true,"port":41351},"up":true}},{"node":{"info":{"id":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","name":"node_c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","enode":"enode://6d97076d32b9b9f4b5283863a9e98ae3565c5b76c4d79066a19dcea55b59368e7608ba4756a6ad7c2abcfa2cd8a35687b72abc688594d2e75acf7c06224f070f@127.0.0.1:0","enr":"0xf88fb84051fb637bffdf225590478fd9c8d1191799580989e08e24be868d06fc5bcc1d331b83c265df3b5914dd08cb298f5c664aed93b478f82c2b79044d18b9e6e8e05e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036d97076d32b9b9f4b5283863a9e98ae3565c5b76c4d79066a19dcea55b59368e","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"w7LS8McnU+2J/ExYDIH1DGbLAsH5AFRlDhkaAQXEDR0=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: c3b2d2\npopulation: 13 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 3c40 5f83 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 3 b374 8673 9629 | 17 a12b (0) afb1 (0) ae60 (0) aabc (0)\n002 3 f6e5 fb7e e6cf | 11 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n003 2 d904 d3c1 | 2 d3c1 (0) d904 (0)\n004 1 cb8d | 1 cb8d (0)\n============ DEPTH: 5 ==========================================\n005 1 c461 | 1 c461 (0)\n006 1 c0c2 | 1 c0c2 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","private_key":"3e87a7f0724932c97ccea342e08f9cbab0a16398baa4d83cf262cab27e823a00","name":"node_c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","services":["bzz","pss"],"enable_msg_events":true,"port":33597},"up":true}},{"node":{"info":{"id":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","name":"node_e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","enode":"enode://66956dc6f44f5a14fbd8cacccb4a0392af57212942e8ab9a389056d9577bf347a38cfdd762902a5edcb4eecf9651e855e67968089887e622490e8b69b548f496@127.0.0.1:0","enr":"0xf88fb840736618f919fc2c358b6f142a11f97cfe9676c53077ffac8dc2e6f386275e20054d088ed925aeddf27038b97725b58eb517ada94564ace17c71b2e679b3a0712e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10266956dc6f44f5a14fbd8cacccb4a0392af57212942e8ab9a389056d9577bf347","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5s8zfQ5pXoYeo2hk4qzh9AKdWzJG970Vzk3MIgv+Pkg=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e6cf33\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 248a 3c40 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 4 ae60 afb1 a12b 821a | 17 a12b (0) afb1 (0) ae60 (0) aabc (0)\n002 3 d904 d3c1 c3b2 | 6 d3c1 (0) d904 (0) cb8d (0) c461 (0)\n003 4 f6e5 f0e9 f211 fb7e | 5 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n004 2 eb30 e9fd | 3 e9fd (0) eb30 (0) ebf2 (0)\n============ DEPTH: 5 ==========================================\n005 0 | 0\n006 2 e5e1 e558 | 2 e5e1 (0) e558 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","private_key":"17299832d5703762960e077579ea9a6ffc090a4e52d4b7da5ac8f0a93fe3dc58","name":"node_e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","services":["bzz","pss"],"enable_msg_events":true,"port":42449},"up":true}},{"node":{"info":{"id":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","name":"node_821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","enode":"enode://9076c5a898a4ed3432a2f812f4c221429a92437f6e27430d6606d7e0d8d01467f860d0949c1bf61d8630a2f1cdcac9b59dff894910bb4d5f11793e03ca4812bc@127.0.0.1:0","enr":"0xf88fb840c4b0861f6a4c06646188be8b72ed472c5dce5473d4568b7bbfc15409a2b575fd1ffe9c6597915b5a0d3225f043bc7c42438fc6786f38fa60c9372592fbf0b3720183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1029076c5a898a4ed3432a2f812f4c221429a92437f6e27430d6606d7e0d8d01467","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"ghryXmNmI3zKJWgexjPrqI20ik/4i1kgzckuFGFhQOQ=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 821af2\npopulation: 23 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 5 0acb 255d 274f 38f0 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 7 c461 d904 f35a f0e9 | 17 d3c1 (0) d904 (0) cb8d (0) c461 (0)\n002 4 a12b aabc b8f3 b8f9 | 9 a12b (0) afb1 (0) ae60 (0) aabc (0)\n003 1 9629 | 1 9629 (0)\n004 2 8926 8802 | 2 8802 (0) 8926 (0)\n============ DEPTH: 5 ==========================================\n005 4 8673 87aa 87ac 856e | 4 856e (0) 8673 (0) 87aa (0) 87ac (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","private_key":"7a3f8c7619489d91c82cd5712ea79f4a09bda58899b9c47305cecaaf474446e9","name":"node_821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","services":["bzz","pss"],"enable_msg_events":true,"port":37855},"up":true}},{"node":{"info":{"id":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","name":"node_b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","enode":"enode://4d06d30c93bb00f7ea04113fb7db1f44cf2d64fa6fa84136844915317a078a5f515d67f2c9531726774eff1e1c55e794444413207a7a33f8efe69c3b9a1ce809@127.0.0.1:0","enr":"0xf88fb840da80dce04c535f4a03e572241364ebfcc260ac172c2f4f8613c30690c319e6916a57ccbc2ba5996f0eb97daa72b5f179ddc8c8402cbf34e3d4e25b6d5de65d560183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1034d06d30c93bb00f7ea04113fb7db1f44cf2d64fa6fa84136844915317a078a5f","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"uPmUaxfOpdu6S6HDfNTQCjVxfGn7DjkfJK+SlPkDDC4=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b8f994\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 274f 5508 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 2 d3c1 f6e5 | 17 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n002 3 856e 87ac 821a | 8 9629 (0) 8802 (0) 8926 (0) 856e (0)\n003 3 ae60 afb1 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n004 2 b374 b73b | 2 b73b (0) b374 (0)\n============ DEPTH: 5 ==========================================\n005 1 be2b | 1 be2b (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 1 b8f3 | 1 b8f3 (0)\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","private_key":"ba7822a917d871b0db8d2f35c273e03d2611d6b1ec22afa5f3904d5912715fe6","name":"node_b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","services":["bzz","pss"],"enable_msg_events":true,"port":46635},"up":true}},{"node":{"info":{"id":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","name":"node_550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","enode":"enode://674d26ce4cfc8f488a5582293dcb0b48dbafe55633179a515be743fd8df0115312862eb9890c52caa8a448b0643237fa1cb52630bbb037f10a4b51c9bb03547c@127.0.0.1:0","enr":"0xf88fb840f50fd3df45a62d984c9335d268586911f8ca0e81aa4bcb0d91ba62cd4c9d788739972464e7736c25bafc230322b8cd066b8336706c3829ba54844c18cc2d1e510183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102674d26ce4cfc8f488a5582293dcb0b48dbafe55633179a515be743fd8df01153","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VQhXusIHh8p/ZJN67boLo9K1hQUtboJP3oQDg4osKtw=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 550857\npopulation: 14 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 f6e5 fb7e b8f9 | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 2 274f 38f0 | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 2 7f80 6123 | 5 6123 (0) 7f80 (0) 7d69 (0) 70d0 (0)\n003 1 452b | 1 452b (0)\n004 3 5f83 5e36 581a | 3 581a (0) 5e36 (0) 5f83 (0)\n005 1 52fc | 1 52fc (0)\n============ DEPTH: 6 ==========================================\n006 2 57d9 5602 | 2 57d9 (0) 5602 (0)\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","private_key":"71212a2c0cc74c7f5acae0d49389517fb9f8125452e5ff53a87d9f94d1cdb656","name":"node_550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","services":["bzz","pss"],"enable_msg_events":true,"port":38047},"up":true}},{"node":{"info":{"id":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","name":"node_56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","enode":"enode://6e7531fa1aad96956cb94991feb1de42184d663cf91edeec3ec9c44a40b74669a30ca1b149de068ad02287f4749aaa00baba98cfaf078c9616119971af4d8e41@127.0.0.1:0","enr":"0xf88fb840e9d8fe4011fb432017522b9895b5df21af7f12f9f032d6fe91afd6674259563329ec357a908efcdf03bf0ce90552bec005f8d8e48d4ff8501f5d4a78f5e140a90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1036e7531fa1aad96956cb94991feb1de42184d663cf91edeec3ec9c44a40b74669","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"VgKekTxY+aEKUcJfvzIq7lToREdssXI8MS8Pi7nCTjk=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 56029e\npopulation: 15 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 2 d3c1 b73b | 34 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n001 3 3c40 0257 177e | 17 274f (0) 255d (0) 248a (0) 3103 (0)\n002 3 6123 7f80 7d69 | 5 6123 (0) 7f80 (0) 7d69 (0) 70d0 (0)\n003 1 452b | 1 452b (0)\n004 3 581a 5f83 5e36 | 3 581a (0) 5e36 (0) 5f83 (0)\n005 1 52fc | 1 52fc (0)\n============ DEPTH: 6 ==========================================\n006 1 5508 | 1 5508 (0)\n007 1 57d9 | 1 57d9 (0)\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","private_key":"4e9222727f6b16c6bf0ed7a54aa1b7469e124eba3236c02cdbcc687cd60b72bc","name":"node_56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","services":["bzz","pss"],"enable_msg_events":true,"port":38635},"up":true}},{"node":{"info":{"id":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","name":"node_b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","enode":"enode://ab3e384377a188409c644d5b90e2c6ef1f2684a6f706d706a4648f7de14c6636e1879b40b73c0ae2f50e0a5b310fae9d87dec78077f765ea86d1d1692e7f30e9@127.0.0.1:0","enr":"0xf88fb8402367c86e536923173d2217bd08333ff411134bf6cfd0e621b7979b3e8e5858f46c7490fafa705e3e2039990a49492e9061617d5dc27a275fbb87b2b5af9a1b020183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a103ab3e384377a188409c644d5b90e2c6ef1f2684a6f706d706a4648f7de14c6636","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"tzuapaYmTJoBipiKgTuRJ9m/lwc2R4zw3D7dHCAj9vI=","hive":"\n=========================================================================\nThu Feb 28 17:44:10 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b73b9a\npopulation: 17 (63), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 3 3abf 177e 5602 | 30 274f (0) 255d (0) 248a (0) 3103 (0)\n001 4 eb30 fb7e f211 f6e5 | 17 fb7e (0) f6e5 (0) f211 (0) f35a (0)\n002 3 87ac 8802 8926 | 8 8802 (0) 8926 (0) 821a (0) 856e (0)\n003 3 aabc afb1 a12b | 4 a12b (0) afb1 (0) ae60 (0) aabc (0)\n============ DEPTH: 4 ==========================================\n004 3 be2b b8f3 b8f9 | 3 b8f9 (0) b8f3 (0) be2b (0)\n005 1 b374 | 1 b374 (0)\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","private_key":"7b8ef93d2a057f4d4cd38111d6f670c9ea7480d10fb335de23e95b1e66c6c445","name":"node_b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","services":["bzz","pss"],"enable_msg_events":true,"port":33079},"up":true}}],"conns":[{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","other":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","up":true},{"one":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","up":true},{"one":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"248a2e618091deeac458f4741616405e0bc5ffda1a9f9125307e32c781728a75","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"856e27ca689a9b2af4cd3ed958f2162b9c71074c726868ac7a10ac2f6f7d021d","other":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"ae6023d416c87bb433eb9d8d44f97531797d292774304d996923a3fe67887478","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"eb307a6f333b30ebd1e3b2b51bd8095311d48707d6ca2c81447d01ad453e2542","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"3103cd0b7654f593b7228d1715209f27e339ad014019a9738413a20cb6ac63e4","up":true},{"one":"87aa77dcef19b0c86a3e8ab64c8f12d9a733e77a7e12bcaec3a4cd8504c5a775","other":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"3b4fa7d729129068a1281ef68494b61d055203de8c36a5fe27af3eb565832108","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","up":true},{"one":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","up":true},{"one":"0257ed46bd49271306fed0127019fd54db472284d00099f10cadd7e83588a63a","other":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","up":true},{"one":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"b8f9946b17cea5dbba4ba1c37cd4d00a35717c69fb0e391f24af9294f9030c2e","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","up":true},{"one":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"38f05af40cd0dc3974e896e24aa75ebda1c96f0ce7d9e3ff0ea840615186307d","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","other":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"7f800e5a7970230f5273e49971c7ee521de97e69f56dd554e30dd12d6fb5c749","other":"56029e913c58f9a10a51c25fbf322aee54e844476cb1723c312f0f8bb9c24e39","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"177e232bdba970f4b001b228af9402e3fca0aaf00682a11bc9984f7db4b7feba","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","other":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","other":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f211376d46e6e0966ee984cf5837805240b2ba53c5ac75315c56dbdffb957a65","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"aabc587ddc3b7d493ce8e849b15d364265c57d3a3a52613076a5b31804cb753f","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","up":true},{"one":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","other":"0727d7e68c319d3a4cc5a161dd05b2a7e72350c139e65c2090c1232ebbed5f78","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"c3b2d2f0c72753ed89fc4c580c81f50c66cb02c1f90054650e191a0105c40d1d","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"452b07d73433e7d6c205a504419ae100019aa1920723011272b596607db6684a","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"b3744cf6f180c2eb9a1ded0e6ddd600d5f79268387b97333070fb5a183affd89","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"7d69b5707a4b99edd901317f1553ff15586aac350f38e0c81318f35d68b835a8","other":"52fc1e219bc518fbaf289da3236d98db1b63df1227ea32581229671473adc3bd","up":true},{"one":"afb1d0b8d1b1f6a341384c1f0818f6b28b85fefe6a45a892552de4de5379f6a5","other":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","up":true},{"one":"a12b12081b6d49e82378d5239765bca8c5f43232b30163bc46924cc3e98e1177","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","other":"c461e430c887894bbbff4e337b61ee449cf12cc07d0fc5fe41785d580d16ae98","up":true},{"one":"703dc76ac724457c805abcc1ed2e3f321821409fb4cf0185e2f07ebc4c18144f","other":"e5e166f85ea9e264fc25734523869d9b916f388004cb4af9968956ce14a7a522","up":true},{"one":"3c409e5b76e977ee3115a0a19540dd6745e60b8878fdc1a5c1d996e7e47ca969","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"5e36542bbbc0d70231c9d00742cb30fccf3f206eecf10a0f34332a2986c86ffb","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"70d0710b3894fabf32b343b9b59339f786ece39895c7eda5f162cc575c9c8253","other":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","up":true},{"one":"1455d4713b5134e9157517b84b04e15292cf18d3e08b95d69f19648fb9e3823e","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"57d911f864be7a90d8807bc3fecd658c5697d70cf3ddcc1dde0dd9bd0fd7fb67","other":"581ad92d4347834850c16e781983c09be340917527a35dd9650c5a3da1fc822b","up":true},{"one":"0acb17334253408a773202041d4a67c7873b0e74e94c86e3343fb470bdcbed82","other":"6123b7777de3bc2591e3036a9adeba1f7d8ec933d05ee4fe0017910896925d1b","up":true},{"one":"be2bcb8fb4b34ee6981e6634b8f3298fbbee756f6e76566204a56bb86c8ec0f0","other":"c0c2d73abd2b6abc3ba0b098520c4cc3eda61b5fc9d1ab42ebd04ecc25ded224","up":true},{"one":"b8f345940bced8831b30079ff2a276ab65fbed0dd8575c93a3ccd8c7bd1bc8b1","other":"00ba6c61b2d6480f53f48c3def3ac85587d9b7a92658d21c235fd0fddc246850","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"9629320d648fda3834eddac7263cc6c88651dc6074206cee00144918d2276289","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"154fec5fa728af956a1446bd5a35e63d716b79a804197b50fd9c72585d044b77","other":"274f8b752ef0c84a5c3098066b0b4d1c02b8a1b1730f59ed94064535eeda4756","up":true},{"one":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"04862550ef38f831085f378e2533addc2c904288394631208c49cb33615ada3b","other":"172bbbcaa57c37c24314a84fbd0b9de45f83a46016bd2395dc2adbab1bb90b5c","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"d3c19ad4c1abc9af03bffc1abc9717f4e765d5fff7ae776203438bac94d01806","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"821af25e6366237cca25681ec633eba88db48a4ff88b5920cdc92e14616140e4","up":true},{"one":"892603fc64fe169ad15519060cfb1d27780adff60da60f86a620f2bf9a7ca1e1","other":"f6e5148d2421ae11e8a109852c9da77bbe498f9e6ed3aa361755a1ff3fd29b74","up":true},{"one":"3abfe9f4f6a8d34b536d02551f45c03a35987b94f7d33b3a0dc30ad34b15f82a","other":"255db8d311a66a7443b15d040afa06626d6919c0d20a6fd0f5afa34e87281732","up":true},{"one":"e558105d2aeb59c896f5fb70475b046d9034ef4596e9cd5f54f16c316449241e","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","other":"d904f6d8790cc235063f54661521c3a197e3e9cdd9dbbcd6765ec6cda5d8f7b4","up":true},{"one":"86735a46da76b3132f729b293b4d8502e939ecba776b8d85b3ae73efa2184b5f","other":"88024b9f684346b775c1c1eb6e9709034135957ab418ec002725f10ef8919837","up":true},{"one":"f0e900ef37baad6a1685aaf1700e9290e7e9c0d5d30e3265204ec943445248b3","other":"e6cf337d0e695e861ea36864e2ace1f4029d5b3246f7bd15ce4dcc220bfe3e48","up":true},{"one":"550857bac20787ca7f64937aedba0ba3d2b585052d6e824fde8403838a2c2adc","other":"5f832158cf84e0e48a3518955878b16ae253467f54664eb4ec1213fefc3f3277","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"cb8df183e7fea4f808ed569d3fa0a6c26670f6451b9a9f48e8659871c2b9ab02","up":true},{"one":"e9fd5cd7f8d28ca172a3d331da401e9853d3121923c81bf82787f7989009e43a","other":"fb7e6716614ac941b74e18a9bf3ded63bc00b453221b40976f783675a1c06c63","up":true},{"one":"f35a47e1d56a6d8e5caad50d88e55c83ff3b964b279b58a50d5e544ff9187864","other":"ebf25ce427905106b70625c0084dcb117964a4d4b9951f5977457da5741b716c","up":true},{"one":"87acf64b22c579751718dc093c00c82b39feb7023fe53c6486b288960ad9e146","other":"b73b9aa5a6264c9a018a988a813b9127d9bf970736478cf0dc3edd1c2023f6f2","up":true}]} \ No newline at end of file diff --git a/swarm/pss/testdata/snapshot_8.json b/swarm/pss/testdata/snapshot_8.json deleted file mode 100644 index 53fe4f96b9..0000000000 --- a/swarm/pss/testdata/snapshot_8.json +++ /dev/null @@ -1 +0,0 @@ -{"nodes":[{"node":{"info":{"id":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","name":"node_b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","enode":"enode://1fdd80e21167da20c5b50282fff16b9d9ba26b1ba66f4b485f2a280c97d135d2650a0aec63b0c4f05ebc1fd1e26dd701c78c3d26660ae55b1ec443d0858d5fae@127.0.0.1:0","enr":"0xf88fb84089ca9b4322a861dc171283da9cf5f01c2f522abc20fea004cdc9e021133e69a63c392de428728d12dae699dc4db983978a7d49e9f842a2a97e608411c26b0f380183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1021fdd80e21167da20c5b50282fff16b9d9ba26b1ba66f4b485f2a280c97d135d2","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"sMKCtIQZcFFyJ1Ur32MDhVUaj9cYhM5kyoZbqVGSldI=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: b0c282\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 e5c3 d20e | 2 e5c3 (0) d20e (0)\n============ DEPTH: 2 ==========================================\n002 3 9d65 8d78 857f | 3 9d65 (0) 8d78 (0) 857f (0)\n003 1 af5a | 1 af5a (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","private_key":"4abb6d72d23ab230f5903ce4eade3e17621c344793b5b4478adc885ea16ccd5e","name":"node_b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","services":["bzz","pss"],"enable_msg_events":true,"port":38939},"up":true}},{"node":{"info":{"id":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","name":"node_857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","enode":"enode://1253be1d17f585c64b93f4521a8c9a6fc2219941cbd4c0a0f4f9c505ff25faf880745e2fbb7d85bdd43510ef61222a11730770d75060eeb8d2449198ca9d99d9@127.0.0.1:0","enr":"0xf88fb8401ff2d62982fa003d6d8138eddc966e3bb01f0418be800a888246409230f7331b2ae72c81e74b250219b1b53c54eb658716fae5653e2154f8e489d8fd9c556ac90183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a1031253be1d17f585c64b93f4521a8c9a6fc2219941cbd4c0a0f4f9c505ff25faf8","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"hX/d+AgXh7TdgwRZd44e4oFrIrtq+61imwRUfOgw1MQ=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 857fdd\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 d20e e5c3 | 2 e5c3 (0) d20e (0)\n002 2 af5a b0c2 | 2 af5a (0) b0c2 (0)\n============ DEPTH: 3 ==========================================\n003 1 9d65 | 1 9d65 (0)\n004 1 8d78 | 1 8d78 (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","private_key":"9ec93c440894afdab5919df0886cf410fed4c31a7a2a859ca39f7f702c0c68a7","name":"node_857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","services":["bzz","pss"],"enable_msg_events":true,"port":37411},"up":true}},{"node":{"info":{"id":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","name":"node_9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","enode":"enode://f0854e632647b0c6194987efc857de2018a55c3e41fa83d66c1bc7a6b41b6410667343be112125a56d00813a2217a9c7f9de6294f90d1062868195b0209febee@127.0.0.1:0","enr":"0xf88fb84092a5952a80b7c2970b3026cba7242670edc3bfeb88145f517586537cf3c723cf0f843d8e4fd79b03865506c72c4e359828e844d734a156e9433ea8005a84e86e0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102f0854e632647b0c6194987efc857de2018a55c3e41fa83d66c1bc7a6b41b6410","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"nWVoU2sk38S+r/qiRApWkBntiFVpU27zrzZtT9fkFVw=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 9d6568\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 d20e e5c3 | 2 d20e (0) e5c3 (0)\n002 2 af5a b0c2 | 2 b0c2 (0) af5a (0)\n============ DEPTH: 3 ==========================================\n003 2 8d78 857f | 2 8d78 (0) 857f (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","private_key":"78c3cbec4b5203c57cb07bec48b1f6b483333254270f8c78369f663a67332275","name":"node_9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","services":["bzz","pss"],"enable_msg_events":true,"port":35167},"up":true}},{"node":{"info":{"id":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","name":"node_e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","enode":"enode://b942a7abe4d7bb812c4dd793e10b90bd0a052d02c8fd30a51d4fc7f2c0ba00a69f28d80b694d467a8e0dd3a91d8c002d7cc4b559c0814a3465c88c848ee67c78@127.0.0.1:0","enr":"0xf88fb840e652351f98a74786fc3ef30d88e198485e1d1d2dbcee24527737d3e7ed9f7e1c327b5e0e5222fad7b1b8849a7cf930a11d784b8b5df0a4e83f96bed207be80fe0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102b942a7abe4d7bb812c4dd793e10b90bd0a052d02c8fd30a51d4fc7f2c0ba00a6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"5cP6M2xt64ESi9Y8+/Fstk1Kg8bmp6ZdGvUe4B5LiuE=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: e5c3fa\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n============ DEPTH: 1 ==========================================\n001 5 af5a b0c2 8d78 857f | 5 b0c2 (0) af5a (0) 8d78 (0) 857f (0)\n002 1 d20e | 1 d20e (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","private_key":"e47c725966b157b8d5f82a845e7972a8f46f4afdd7e6936924b091f6903f206a","name":"node_e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","services":["bzz","pss"],"enable_msg_events":true,"port":40723},"up":true}},{"node":{"info":{"id":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","name":"node_4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","enode":"enode://07926b76c1525c50780e9665d8eece3669309dbe11901ecce0fdd4b58cb674d6492eb005708df46901b05fb100b3e0e7d5fa68063b264ece3b89dab0387f75eb@127.0.0.1:0","enr":"0xf88fb8409b7e55bf546e10ed700d31d91c0da7485440884d8765e8690b5a6d36622a9b1d3e701b927e7ec276477e7c249a7c6ed5a3d723e5c2b5343eda892e3b510e7f760183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10307926b76c1525c50780e9665d8eece3669309dbe11901ecce0fdd4b58cb674d6","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"TygdoL/x+v48VU0NTqGumi06FP+7hC3CUaRbHwAWMcU=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 4f281d\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 7 9d65 8d78 857f b0c2 | 7 b0c2 (0) af5a (0) 8d78 (0) 857f (0)\n001 0 | 0\n002 0 | 0\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","private_key":"314da8f87c03fe3bea0fc585c33443cd627cf93a51f609e88d0251a248cc8a2b","name":"node_4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","services":["bzz","pss"],"enable_msg_events":true,"port":40771},"up":true}},{"node":{"info":{"id":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","name":"node_af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","enode":"enode://86e63eb120fa323784aab76c4586fc5f96764473b5e5181e5101d05f99b6a2ae42b40d2ada4ff77338a6189c68745b96d1a7535fa1a81211aaf719b7918344f0@127.0.0.1:0","enr":"0xf88fb840ef88957469c48aed8ea2da3a5d910b199f8506a13703fbfc55f28d26199820175dd29361863b9cd50ce0d032412687302fb1b12ad7ca026dab30c5c600e541ba0183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10286e63eb120fa323784aab76c4586fc5f96764473b5e5181e5101d05f99b6a2ae","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"r1pDikcZaqKWKUeWZNRU54EEzDyPAENfoU2jB1XrGbg=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: af5a43\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 e5c3 d20e | 2 d20e (0) e5c3 (0)\n============ DEPTH: 2 ==========================================\n002 3 9d65 857f 8d78 | 3 9d65 (0) 857f (0) 8d78 (0)\n003 1 b0c2 | 1 b0c2 (0)\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","private_key":"ca50145cbbcbb65bb54caae3f33b2253f05203a2825ad5e77aebe7513ac1f2f6","name":"node_af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","services":["bzz","pss"],"enable_msg_events":true,"port":33411},"up":true}},{"node":{"info":{"id":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","name":"node_8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","enode":"enode://c0fbc89e69cc5371b97f530380e78cac1cd7e3ad87a6bc1597e714ba892d53da030438cfdc1d7f3f1a50f1328733feb1afaabe1bdfdb731d7c134f42637bc570@127.0.0.1:0","enr":"0xf88fb8402e0b00cc0ddeb598d3dd71f1538b77e52afb8b6ee456a56a15d73b850f88480d686962bb60c059abf4080bb090dd6960e00ccc3992a79682f4d0b32d7f1182f40183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a102c0fbc89e69cc5371b97f530380e78cac1cd7e3ad87a6bc1597e714ba892d53da","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"jXiz9/uGRNeQrUQ058JzVYR1r6O9KQdIBXyKuozLGMI=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: 8d78b3\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n001 2 e5c3 d20e | 2 e5c3 (0) d20e (0)\n002 2 b0c2 af5a | 2 b0c2 (0) af5a (0)\n============ DEPTH: 3 ==========================================\n003 1 9d65 | 1 9d65 (0)\n004 1 857f | 1 857f (0)\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","private_key":"3610f2b1d9031bcf4dd8e44f17d7262c53c302d49aae7068bf58bf63593b168c","name":"node_8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","services":["bzz","pss"],"enable_msg_events":true,"port":46461},"up":true}},{"node":{"info":{"id":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","name":"node_d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","enode":"enode://59a306fa22d2124205f53d5eb905896f7fe818569fc14221c50a3b0ce032b67c275381f7b3ccbc88fb679a42d19dc9b24f699f2f44cc34a9e92c4087f3df3224@127.0.0.1:0","enr":"0xf88fb84010c45aa3fc72b92b0a6c1999ec487c845993f1fe4210e415c1995ec007cf990b62cbe15723436c2b6324564678c3dcf711ec0dd6fea5cd02f59758e5ec8caf660183636170cdc583627a7a08c6846869766508826964827634826970847f00000189736563703235366b31a10259a306fa22d2124205f53d5eb905896f7fe818569fc14221c50a3b0ce032b67c","ip":"127.0.0.1","ports":{"discovery":0,"listener":0},"listenAddr":"","protocols":{"bzz":"0g6deWEImIWbj251Q96WEZtzj1WNhzej53b0IfguhtA=","hive":"\n=========================================================================\nThu Feb 28 17:15:23 UTC 2019 KΛÐΞMLIΛ hive: queen's address: d20e9d\npopulation: 7 (7), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n000 1 4f28 | 1 4f28 (0)\n============ DEPTH: 1 ==========================================\n001 5 af5a b0c2 9d65 857f | 5 af5a (0) b0c2 (0) 9d65 (0) 857f (0)\n002 1 e5c3 | 1 e5c3 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n008 0 | 0\n009 0 | 0\n010 0 | 0\n011 0 | 0\n012 0 | 0\n013 0 | 0\n014 0 | 0\n015 0 | 0\n========================================================================="}},"config":{"id":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","private_key":"4f08d74f4aae2cc502689afad5bb760072c6f1931f7872c3d4ca210972736b74","name":"node_d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","services":["bzz","pss"],"enable_msg_events":true,"port":36035},"up":true}}],"conns":[{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true},{"one":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","other":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","up":true},{"one":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","other":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","up":true},{"one":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","other":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","up":true},{"one":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"4f281da0bff1fafe3c554d0d4ea1ae9a2d3a14ffbb842dc251a45b1f001631c5","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"b0c282b4841970517227552bdf630385551a8fd71884ce64ca865ba9519295d2","up":true},{"one":"e5c3fa336c6deb81128bd63cfbf16cb64d4a83c6e6a7a65d1af51ee01e4b8ae1","other":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","up":true},{"one":"8d78b3f7fb8644d790ad4434e7c273558475afa3bd290748057c8aba8ccb18c2","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"9d6568536b24dfc4beaffaa2440a569019ed885569536ef3af366d4fd7e4155c","up":true},{"one":"d20e9d79610898859b8f6e7543de96119b738f558d8737a3e776f421f82e86d0","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true},{"one":"af5a438a47196aa29629479664d454e78104cc3c8f00435fa14da30755eb19b8","other":"857fddf8081787b4dd830459778e1ee2816b22bb6afbad629b04547ce830d4c4","up":true}]} \ No newline at end of file diff --git a/swarm/pss/types.go b/swarm/pss/types.go deleted file mode 100644 index 2ce1f5cfb0..0000000000 --- a/swarm/pss/types.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package pss - -import ( - "encoding/json" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/swarm/storage" - whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" -) - -const ( - defaultWhisperTTL = 6000 -) - -const ( - pssControlSym = 1 - pssControlRaw = 1 << 1 -) - -var ( - topicHashMutex = sync.Mutex{} - topicHashFunc = storage.MakeHashFunc("SHA256")() - rawTopic = Topic{} -) - -// Topic is the PSS encapsulation of the Whisper topic type -type Topic whisper.TopicType - -func (t *Topic) String() string { - return hexutil.Encode(t[:]) -} - -// MarshalJSON implements the json.Marshaler interface -func (t Topic) MarshalJSON() (b []byte, err error) { - return json.Marshal(t.String()) -} - -// MarshalJSON implements the json.Marshaler interface -func (t *Topic) UnmarshalJSON(input []byte) error { - topicbytes, err := hexutil.Decode(string(input[1 : len(input)-1])) - if err != nil { - return err - } - copy(t[:], topicbytes) - return nil -} - -// PssAddress is an alias for []byte. It represents a variable length address -type PssAddress []byte - -// MarshalJSON implements the json.Marshaler interface -func (a PssAddress) MarshalJSON() ([]byte, error) { - return json.Marshal(hexutil.Encode(a[:])) -} - -// UnmarshalJSON implements the json.Marshaler interface -func (a *PssAddress) UnmarshalJSON(input []byte) error { - b, err := hexutil.Decode(string(input[1 : len(input)-1])) - if err != nil { - return err - } - for _, bb := range b { - *a = append(*a, bb) - } - return nil -} - -// holds the digest of a message used for caching -type pssDigest [digestLength]byte - -// conceals bitwise operations on the control flags byte -type msgParams struct { - raw bool - sym bool -} - -func newMsgParamsFromBytes(paramBytes []byte) *msgParams { - if len(paramBytes) != 1 { - return nil - } - return &msgParams{ - raw: paramBytes[0]&pssControlRaw > 0, - sym: paramBytes[0]&pssControlSym > 0, - } -} - -func (m *msgParams) Bytes() (paramBytes []byte) { - var b byte - if m.raw { - b |= pssControlRaw - } - if m.sym { - b |= pssControlSym - } - paramBytes = append(paramBytes, b) - return paramBytes -} - -// PssMsg encapsulates messages transported over pss. -type PssMsg struct { - To []byte - Control []byte - Expire uint32 - Payload *whisper.Envelope -} - -func newPssMsg(param *msgParams) *PssMsg { - return &PssMsg{ - Control: param.Bytes(), - } -} - -// message is flagged as raw / external encryption -func (msg *PssMsg) isRaw() bool { - return msg.Control[0]&pssControlRaw > 0 -} - -// message is flagged as symmetrically encrypted -func (msg *PssMsg) isSym() bool { - return msg.Control[0]&pssControlSym > 0 -} - -// serializes the message for use in cache -func (msg *PssMsg) serialize() []byte { - rlpdata, _ := rlp.EncodeToBytes(struct { - To []byte - Payload *whisper.Envelope - }{ - To: msg.To, - Payload: msg.Payload, - }) - return rlpdata -} - -// String representation of PssMsg -func (msg *PssMsg) String() string { - return fmt.Sprintf("PssMsg: Recipient: %x", common.ToHex(msg.To)) -} - -// Signature for a message handler function for a PssMsg -// Implementations of this type are passed to Pss.Register together with a topic, -type HandlerFunc func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error - -type handlerCaps struct { - raw bool - prox bool -} - -// Handler defines code to be executed upon reception of content. -type handler struct { - f HandlerFunc - caps *handlerCaps -} - -// NewHandler returns a new message handler -func NewHandler(f HandlerFunc) *handler { - return &handler{ - f: f, - caps: &handlerCaps{}, - } -} - -// WithRaw is a chainable method that allows raw messages to be handled. -func (h *handler) WithRaw() *handler { - h.caps.raw = true - return h -} - -// WithProxBin is a chainable method that allows sending messages with full addresses to neighbourhoods using the kademlia depth as reference -func (h *handler) WithProxBin() *handler { - h.caps.prox = true - return h -} - -// the stateStore handles saving and loading PSS peers and their corresponding keys -// it is currently unimplemented -type stateStore struct { - values map[string][]byte -} - -func (store *stateStore) Load(key string) ([]byte, error) { - return nil, nil -} - -func (store *stateStore) Save(key string, v []byte) error { - return nil -} - -// BytesToTopic hashes an arbitrary length byte slice and truncates it to the length of a topic, using only the first bytes of the digest -func BytesToTopic(b []byte) Topic { - topicHashMutex.Lock() - defer topicHashMutex.Unlock() - topicHashFunc.Reset() - topicHashFunc.Write(b) - return Topic(whisper.BytesToTopic(topicHashFunc.Sum(nil))) -} diff --git a/swarm/pss/writeup.md b/swarm/pss/writeup.md deleted file mode 100644 index af731fe7fd..0000000000 --- a/swarm/pss/writeup.md +++ /dev/null @@ -1,125 +0,0 @@ -## PSS tests failures explanation - -This document aims to explain the changes in https://github.com/ethersphere/go-ethereum/pull/126 and how those changes affect the pss_test.go TestNetwork tests. - -### Problem - -When running the TestNetwork test, execution sometimes: - -* deadlocks -* panics -* failures with wrong result, such as: - -``` -$ go test -v ./swarm/pss -cpu 4 -run TestNetwork -``` - -``` ---- FAIL: TestNetwork (68.13s) - --- FAIL: TestNetwork/3/10/4/sim (68.13s) - pss_test.go:697: 7 of 10 messages received - pss_test.go:700: 3 messages were not received -FAIL -``` - -Moreover execution almost always deadlocks with `sim` adapter, and `sock` adapter (when buffer is low), but is mostly stable with `exec` and `tcp` adapters. - -### Findings and Fixes - -#### 1. Addressing panics - -Panics were caused due to concurrent map read/writes and unsynchronised access to shared memory by multiple goroutines. This is visible when running the test with the `-race` flag. - -``` -go test -race -v ./swarm/pss -cpu 4 -run TestNetwork - - 1 ================== - 2 WARNING: DATA RACE - 3 Read at 0x00c424d456a0 by goroutine 1089: - 4 github.com/ethereum/go-ethereum/swarm/pss.(*Pss).forward.func1() - 5 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/pss/pss.go:654 +0x44f - 6 github.com/ethereum/go-ethereum/swarm/network.(*Kademlia).eachConn.func1() - 7 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/network/kademlia.go:350 +0xc9 - 8 github.com/ethereum/go-ethereum/pot.(*Pot).eachNeighbour.func1() - 9 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/pot/pot.go:599 +0x59 - ... - - 28 - 29 Previous write at 0x00c424d456a0 by goroutine 829: - 30 github.com/ethereum/go-ethereum/swarm/pss.(*Pss).Run() - 31 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/pss/pss.go:192 +0x16a - 32 github.com/ethereum/go-ethereum/swarm/pss.(*Pss).Run-fm() - 33 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/swarm/pss/pss.go:185 +0x63 - 34 github.com/ethereum/go-ethereum/p2p.(*Peer).startProtocols.func1() - 35 /Users/nonsense/code/src/github.com/ethereum/go-ethereum/p2p/peer.go:347 +0x8b - ... -``` - -##### Current solution - -Adding a mutex around all shared data. - -#### 2. Failures with wrong result - -The validation phase of the TestNetwork test is done using an RPC subscription: - -``` - ... - triggerChecks := func(trigger chan enode.ID, id enode.ID, rpcclient *rpc.Client) error { - msgC := make(chan APIMsg) - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", hextopic) - ... -``` - -By design the RPC uses a subscription buffer with a max length. When this length is reached, the subscription is dropped. The current config value is not suitable for stress tests. - -##### Current solution - -Increase the max length of the RPC subscription buffer. - -``` -const ( - // Subscriptions are removed when the subscriber cannot keep up. - // - // This can be worked around by supplying a channel with sufficiently sized buffer, - // but this can be inconvenient and hard to explain in the docs. Another issue with - // buffered channels is that the buffer is static even though it might not be needed - // most of the time. - // - // The approach taken here is to maintain a per-subscription linked list buffer - // shrinks on demand. If the buffer reaches the size below, the subscription is - // dropped. - maxClientSubscriptionBuffer = 20000 -) -``` - -#### 3. Deadlocks - -Deadlocks are triggered when using: -* `sim` adapter - synchronous, unbuffered channel -* `sock` adapter - asynchronous, buffered channel (when using a 1K buffer) - -No deadlocks were triggered when using: -* `tcp` adapter - asynchronous, buffered channel -* `exec` adapter - asynchronous, buffered channel - -Ultimately the deadlocks happen due to blocking `pp.Send()` call at: - - // attempt to send the message - err := pp.Send(msg) - if err != nil { - log.Debug(fmt.Sprintf("%v: failed forwarding: %v", sendMsg, err)) - return true - } - - `p2p` request handling is synchronous (as discussed at https://github.com/ethersphere/go-ethereum/issues/130), `pss` is also synchronous, therefore if two nodes happen to be processing a request, while at the same time waiting for response on `pp.Send(msg)`, deadlock occurs. - - `pp.Send(msg)` is only blocking when the underlying adapter is blocking (read `sim` or `sock`) or the buffer of the connection is full. - -##### Current solution - -Make no assumption on the undelying connection, and call `pp.Send` asynchronously in a go-routine. - -Alternatively, get rid of the `sim` and `sock` adapters, and use `tcp` adapter for testing. diff --git a/swarm/sctx/sctx.go b/swarm/sctx/sctx.go deleted file mode 100644 index adc8c7dab2..0000000000 --- a/swarm/sctx/sctx.go +++ /dev/null @@ -1,37 +0,0 @@ -package sctx - -import "context" - -type ( - HTTPRequestIDKey struct{} - requestHostKey struct{} - tagKey struct{} -) - -// SetHost sets the http request host in the context -func SetHost(ctx context.Context, domain string) context.Context { - return context.WithValue(ctx, requestHostKey{}, domain) -} - -// GetHost gets the request host from the context -func GetHost(ctx context.Context) string { - v, ok := ctx.Value(requestHostKey{}).(string) - if ok { - return v - } - return "" -} - -// SetTag sets the tag unique identifier in the context -func SetTag(ctx context.Context, tagId uint32) context.Context { - return context.WithValue(ctx, tagKey{}, tagId) -} - -// GetTag gets the tag unique identifier from the context -func GetTag(ctx context.Context) uint32 { - v, ok := ctx.Value(tagKey{}).(uint32) - if ok { - return v - } - return 0 -} diff --git a/swarm/services/swap/swap.go b/swarm/services/swap/swap.go deleted file mode 100644 index 91fa54fcf0..0000000000 --- a/swarm/services/swap/swap.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swap - -import ( - "context" - "crypto/ecdsa" - "errors" - "fmt" - "math/big" - "os" - "path/filepath" - "sync" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/chequebook" - "github.com/ethereum/go-ethereum/contracts/chequebook/contract" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/services/swap/swap" -) - -// SwAP Swarm Accounting Protocol with -// SWAP^2 Strategies of Withholding Automatic Payments -// SWAP^3 Accreditation: payment via credit SWAP -// using chequebook pkg for delayed payments -// default parameters - -var ( - autoCashInterval = 300 * time.Second // default interval for autocash - autoCashThreshold = big.NewInt(50000000000000) // threshold that triggers autocash (wei) - autoDepositInterval = 300 * time.Second // default interval for autocash - autoDepositThreshold = big.NewInt(50000000000000) // threshold that triggers autodeposit (wei) - autoDepositBuffer = big.NewInt(100000000000000) // buffer that is surplus for fork protection etc (wei) - buyAt = big.NewInt(20000000000) // maximum chunk price host is willing to pay (wei) - sellAt = big.NewInt(20000000000) // minimum chunk price host requires (wei) - payAt = 100 // threshold that triggers payment {request} (units) - dropAt = 10000 // threshold that triggers disconnect (units) -) - -const ( - chequebookDeployRetries = 5 - chequebookDeployDelay = 1 * time.Second // delay between retries -) - -// LocalProfile combines a PayProfile with *swap.Params -type LocalProfile struct { - *swap.Params - *PayProfile -} - -// RemoteProfile combines a PayProfile with *swap.Profile -type RemoteProfile struct { - *swap.Profile - *PayProfile -} - -// PayProfile is a container for relevant chequebook and beneficiary options -type PayProfile struct { - PublicKey string // check against signature of promise - Contract common.Address // address of chequebook contract - Beneficiary common.Address // recipient address for swarm sales revenue - privateKey *ecdsa.PrivateKey - publicKey *ecdsa.PublicKey - owner common.Address - chbook *chequebook.Chequebook - lock sync.RWMutex -} - -// NewDefaultSwapParams create params with default values -func NewDefaultSwapParams() *LocalProfile { - return &LocalProfile{ - PayProfile: &PayProfile{}, - Params: &swap.Params{ - Profile: &swap.Profile{ - BuyAt: buyAt, - SellAt: sellAt, - PayAt: uint(payAt), - DropAt: uint(dropAt), - }, - Strategy: &swap.Strategy{ - AutoCashInterval: autoCashInterval, - AutoCashThreshold: autoCashThreshold, - AutoDepositInterval: autoDepositInterval, - AutoDepositThreshold: autoDepositThreshold, - AutoDepositBuffer: autoDepositBuffer, - }, - }, - } -} - -// Init this can only finally be set after all config options (file, cmd line, env vars) -// have been evaluated -func (lp *LocalProfile) Init(contract common.Address, prvkey *ecdsa.PrivateKey) { - pubkey := &prvkey.PublicKey - - lp.PayProfile = &PayProfile{ - PublicKey: common.ToHex(crypto.FromECDSAPub(pubkey)), - Contract: contract, - Beneficiary: crypto.PubkeyToAddress(*pubkey), - privateKey: prvkey, - publicKey: pubkey, - owner: crypto.PubkeyToAddress(*pubkey), - } -} - -// NewSwap constructor, parameters -// * global chequebook, assume deployed service and -// * the balance is at buffer. -// swap.Add(n) called in netstore -// n > 0 called when sending chunks = receiving retrieve requests -// OR sending cheques. -// n < 0 called when receiving chunks = receiving delivery responses -// OR receiving cheques. -func NewSwap(localProfile *LocalProfile, remoteProfile *RemoteProfile, backend chequebook.Backend, proto swap.Protocol) (swapInstance *swap.Swap, err error) { - var ( - ctx = context.TODO() - ok bool - in *chequebook.Inbox - out *chequebook.Outbox - ) - - remotekey, err := crypto.UnmarshalPubkey(common.FromHex(remoteProfile.PublicKey)) - if err != nil { - return nil, errors.New("invalid remote public key") - } - - // check if remoteProfile chequebook is valid - // insolvent chequebooks suicide so will signal as invalid - // TODO: monitoring a chequebooks events - ok, err = chequebook.ValidateCode(ctx, backend, remoteProfile.Contract) - if !ok { - log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remoteProfile.Contract.Hex()[:8], proto, err)) - } else { - // remoteProfile contract valid, create inbox - in, err = chequebook.NewInbox(localProfile.privateKey, remoteProfile.Contract, localProfile.Beneficiary, remotekey, backend) - if err != nil { - log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remoteProfile.Contract.Hex()[:8], proto, err)) - } - } - - // check if localProfile chequebook contract is valid - ok, err = chequebook.ValidateCode(ctx, backend, localProfile.Contract) - if !ok { - log.Warn(fmt.Sprintf("unable to set up outbox for peer %v: chequebook contract (owner: %v): %v)", proto, localProfile.owner.Hex(), err)) - } else { - out = chequebook.NewOutbox(localProfile.Chequebook(), remoteProfile.Beneficiary) - } - - pm := swap.Payment{ - In: in, - Out: out, - Buys: out != nil, - Sells: in != nil, - } - swapInstance, err = swap.New(localProfile.Params, pm, proto) - if err != nil { - return - } - // remoteProfile profile given (first) in handshake - swapInstance.SetRemote(remoteProfile.Profile) - var buy, sell string - if swapInstance.Buys { - buy = "purchase from peer enabled at " + remoteProfile.SellAt.String() + " wei/chunk" - } else { - buy = "purchase from peer disabled" - } - if swapInstance.Sells { - sell = "selling to peer enabled at " + localProfile.SellAt.String() + " wei/chunk" - } else { - sell = "selling to peer disabled" - } - log.Warn(fmt.Sprintf("SWAP arrangement with <%v>: %v; %v)", proto, buy, sell)) - - return -} - -// Chequebook get's chequebook from the localProfile -func (lp *LocalProfile) Chequebook() *chequebook.Chequebook { - defer lp.lock.Unlock() - lp.lock.Lock() - return lp.chbook -} - -// PrivateKey accessor -func (lp *LocalProfile) PrivateKey() *ecdsa.PrivateKey { - return lp.privateKey -} - -// func (self *LocalProfile) PublicKey() *ecdsa.PublicKey { -// return self.publicKey -// } - -// SetKey set's private and public key on localProfile -func (lp *LocalProfile) SetKey(prvkey *ecdsa.PrivateKey) { - lp.privateKey = prvkey - lp.publicKey = &prvkey.PublicKey -} - -// SetChequebook wraps the chequebook initialiser and sets up autoDeposit to cover spending. -func (lp *LocalProfile) SetChequebook(ctx context.Context, backend chequebook.Backend, path string) error { - lp.lock.Lock() - swapContract := lp.Contract - lp.lock.Unlock() - - valid, err := chequebook.ValidateCode(ctx, backend, swapContract) - if err != nil { - return err - } else if valid { - return lp.newChequebookFromContract(path, backend) - } - return lp.deployChequebook(ctx, backend, path) -} - -// deployChequebook deploys the localProfile Chequebook -func (lp *LocalProfile) deployChequebook(ctx context.Context, backend chequebook.Backend, path string) error { - opts := bind.NewKeyedTransactor(lp.privateKey) - opts.Value = lp.AutoDepositBuffer - opts.Context = ctx - - log.Info(fmt.Sprintf("Deploying new chequebook (owner: %v)", opts.From.Hex())) - address, err := deployChequebookLoop(opts, backend) - if err != nil { - log.Error(fmt.Sprintf("unable to deploy new chequebook: %v", err)) - return err - } - log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", address.Hex(), opts.From.Hex())) - - // need to save config at this point - lp.lock.Lock() - lp.Contract = address - err = lp.newChequebookFromContract(path, backend) - lp.lock.Unlock() - if err != nil { - log.Warn(fmt.Sprintf("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err)) - } - return err -} - -// deployChequebookLoop repeatedly tries to deploy a chequebook. -func deployChequebookLoop(opts *bind.TransactOpts, backend chequebook.Backend) (addr common.Address, err error) { - var tx *types.Transaction - for try := 0; try < chequebookDeployRetries; try++ { - if try > 0 { - time.Sleep(chequebookDeployDelay) - } - if _, tx, _, err = contract.DeployChequebook(opts, backend); err != nil { - log.Warn(fmt.Sprintf("can't send chequebook deploy tx (try %d): %v", try, err)) - continue - } - if addr, err = bind.WaitDeployed(opts.Context, backend, tx); err != nil { - log.Warn(fmt.Sprintf("chequebook deploy error (try %d): %v", try, err)) - continue - } - return addr, nil - } - return addr, err -} - -// newChequebookFromContract - initialise the chequebook from a persisted json file or create a new one -// caller holds the lock -func (lp *LocalProfile) newChequebookFromContract(path string, backend chequebook.Backend) error { - hexkey := common.Bytes2Hex(lp.Contract.Bytes()) - err := os.MkdirAll(filepath.Join(path, "chequebooks"), os.ModePerm) - if err != nil { - return fmt.Errorf("unable to create directory for chequebooks: %v", err) - } - - chbookpath := filepath.Join(path, "chequebooks", hexkey+".json") - lp.chbook, err = chequebook.LoadChequebook(chbookpath, lp.privateKey, backend, true) - - if err != nil { - lp.chbook, err = chequebook.NewChequebook(chbookpath, lp.Contract, lp.privateKey, backend) - if err != nil { - log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", lp.owner.Hex(), err)) - return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", lp.owner.Hex(), err) - } - } - - lp.chbook.AutoDeposit(lp.AutoDepositInterval, lp.AutoDepositThreshold, lp.AutoDepositBuffer) - log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(lp.publicKey)).Hex()[:8], lp.Contract.Hex()[:8], lp.AutoDepositInterval, lp.AutoDepositThreshold, lp.AutoDepositBuffer)) - - return nil -} diff --git a/swarm/services/swap/swap/swap.go b/swarm/services/swap/swap/swap.go deleted file mode 100644 index 0afca9ab30..0000000000 --- a/swarm/services/swap/swap/swap.go +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swap - -import ( - "fmt" - "math/big" - "sync" - "time" - - "github.com/ethereum/go-ethereum/swarm/log" -) - -// SwAP Swarm Accounting Protocol with -// Swift Automatic Payments -// a peer to peer micropayment system - -// Profile - public swap profile -// public parameters for SWAP, serializable config struct passed in handshake -type Profile struct { - BuyAt *big.Int // accepted max price for chunk - SellAt *big.Int // offered sale price for chunk - PayAt uint // threshold that triggers payment request - DropAt uint // threshold that triggers disconnect -} - -// Strategy encapsulates parameters relating to -// automatic deposit and automatic cashing -type Strategy struct { - AutoCashInterval time.Duration // default interval for autocash - AutoCashThreshold *big.Int // threshold that triggers autocash (wei) - AutoDepositInterval time.Duration // default interval for autocash - AutoDepositThreshold *big.Int // threshold that triggers autodeposit (wei) - AutoDepositBuffer *big.Int // buffer that is surplus for fork protection etc (wei) -} - -// Params extends the public profile with private parameters relating to -// automatic deposit and automatic cashing -type Params struct { - *Profile - *Strategy -} - -// Promise - 3rd party Provable Promise of Payment -// issued by outPayment -// serializable to send with Protocol -type Promise interface{} - -// Protocol interface for the peer protocol for testing or external alternative payment -type Protocol interface { - Pay(int, Promise) // units, payment proof - Drop() - String() string -} - -// OutPayment interface for the (delayed) outgoing payment system with auto-deposit -type OutPayment interface { - Issue(amount *big.Int) (promise Promise, err error) - AutoDeposit(interval time.Duration, threshold, buffer *big.Int) - Stop() -} - -// InPayment interface for the (delayed) incoming payment system with autocash -type InPayment interface { - Receive(promise Promise) (*big.Int, error) - AutoCash(cashInterval time.Duration, maxUncashed *big.Int) - Stop() -} - -// Swap is the swarm accounting protocol instance -// * pairwise accounting and payments -type Swap struct { - lock sync.Mutex // mutex for balance access - balance int // units of chunk/retrieval request - local *Params // local peer's swap parameters - remote *Profile // remote peer's swap profile - proto Protocol // peer communication protocol - Payment -} - -// Payment handlers -type Payment struct { - Out OutPayment // outgoing payment handler - In InPayment // incoming payment handler - Buys, Sells bool -} - -// New - swap constructor -func New(local *Params, pm Payment, proto Protocol) (swap *Swap, err error) { - - swap = &Swap{ - local: local, - Payment: pm, - proto: proto, - } - - swap.SetParams(local) - - return -} - -// SetRemote - entry point for setting remote swap profile (e.g from handshake or other message) -func (swap *Swap) SetRemote(remote *Profile) { - defer swap.lock.Unlock() - swap.lock.Lock() - - swap.remote = remote - if swap.Sells && (remote.BuyAt.Sign() <= 0 || swap.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(swap.local.SellAt) < 0) { - swap.Out.Stop() - swap.Sells = false - } - if swap.Buys && (remote.SellAt.Sign() <= 0 || swap.local.BuyAt.Sign() <= 0 || swap.local.BuyAt.Cmp(swap.remote.SellAt) < 0) { - swap.In.Stop() - swap.Buys = false - } - - log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", swap.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt)) - -} - -// SetParams - to set strategy dynamically -func (swap *Swap) SetParams(local *Params) { - defer swap.lock.Unlock() - swap.lock.Lock() - swap.local = local - swap.setParams(local) -} - -// setParams - caller holds the lock -func (swap *Swap) setParams(local *Params) { - - if swap.Sells { - swap.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold) - log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", swap.proto, local.AutoCashInterval, local.AutoCashThreshold)) - } else { - log.Info(fmt.Sprintf("<%v> autocash off (not selling)", swap.proto)) - } - if swap.Buys { - swap.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer) - log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", swap.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)) - } else { - log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", swap.proto)) - } -} - -// Add (n) -// n > 0 called when promised/provided n units of service -// n < 0 called when used/requested n units of service -func (swap *Swap) Add(n int) error { - defer swap.lock.Unlock() - swap.lock.Lock() - swap.balance += n - if !swap.Sells && swap.balance > 0 { - log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", swap.proto, swap.balance)) - swap.proto.Drop() - return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", swap.proto, swap.balance) - } - if !swap.Buys && swap.balance < 0 { - log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", swap.proto, swap.balance)) - return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", swap.proto, swap.balance) - } - if swap.balance >= int(swap.local.DropAt) { - log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", swap.proto, swap.balance, swap.local.DropAt)) - swap.proto.Drop() - return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", swap.proto, swap.balance, swap.local.DropAt) - } else if swap.balance <= -int(swap.remote.PayAt) { - swap.send() - } - return nil -} - -// Balance accessor -func (swap *Swap) Balance() int { - defer swap.lock.Unlock() - swap.lock.Lock() - return swap.balance -} - -// send (units) is called when payment is due -// In case of insolvency no promise is issued and sent, safe against fraud -// No return value: no error = payment is opportunistic = hang in till dropped -func (swap *Swap) send() { - if swap.local.BuyAt != nil && swap.balance < 0 { - amount := big.NewInt(int64(-swap.balance)) - amount.Mul(amount, swap.remote.SellAt) - promise, err := swap.Out.Issue(amount) - if err != nil { - log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", swap.proto, amount, swap.Out, err)) - } else { - log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", swap.proto, amount, swap.Out)) - swap.proto.Pay(-swap.balance, promise) - swap.balance = 0 - } - } -} - -// Receive (units, promise) is called by the protocol when a payment msg is received -// returns error if promise is invalid. -func (swap *Swap) Receive(units int, promise Promise) error { - if units <= 0 { - return fmt.Errorf("invalid units: %v <= 0", units) - } - - price := new(big.Int).SetInt64(int64(units)) - price.Mul(price, swap.local.SellAt) - - amount, err := swap.In.Receive(promise) - - if err != nil { - err = fmt.Errorf("invalid promise: %v", err) - } else if price.Cmp(amount) != 0 { - // verify amount = units * unit sale price - return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, swap.local.SellAt, amount) - } - if err != nil { - log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", swap.proto, amount, swap.In, err)) - return err - } - - // credit remote peer with units - swap.Add(-units) - log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", swap.proto, amount, swap.In, promise)) - - return nil -} - -// Stop causes autocash loop to terminate. -// Called after protocol handle loop terminates. -func (swap *Swap) Stop() { - defer swap.lock.Unlock() - swap.lock.Lock() - if swap.Buys { - swap.Out.Stop() - } - if swap.Sells { - swap.In.Stop() - } -} diff --git a/swarm/services/swap/swap/swap_test.go b/swarm/services/swap/swap/swap_test.go deleted file mode 100644 index d0e34f8a54..0000000000 --- a/swarm/services/swap/swap/swap_test.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swap - -import ( - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" -) - -type testInPayment struct { - received []*testPromise - autocashInterval time.Duration - autocashLimit *big.Int -} - -type testPromise struct { - amount *big.Int -} - -func (test *testInPayment) Receive(promise Promise) (*big.Int, error) { - p := promise.(*testPromise) - test.received = append(test.received, p) - return p.amount, nil -} - -func (test *testInPayment) AutoCash(interval time.Duration, limit *big.Int) { - test.autocashInterval = interval - test.autocashLimit = limit -} - -func (test *testInPayment) Cash() (string, error) { return "", nil } - -func (test *testInPayment) Stop() {} - -type testOutPayment struct { - deposits []*big.Int - autodepositInterval time.Duration - autodepositThreshold *big.Int - autodepositBuffer *big.Int -} - -func (test *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) { - return &testPromise{amount}, nil -} - -func (test *testOutPayment) Deposit(amount *big.Int) (string, error) { - test.deposits = append(test.deposits, amount) - return "", nil -} - -func (test *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - test.autodepositInterval = interval - test.autodepositThreshold = threshold - test.autodepositBuffer = buffer -} - -func (test *testOutPayment) Stop() {} - -type testProtocol struct { - drop bool - amounts []int - promises []*testPromise -} - -func (test *testProtocol) Drop() { - test.drop = true -} - -func (test *testProtocol) String() string { - return "" -} - -func (test *testProtocol) Pay(amount int, promise Promise) { - p := promise.(*testPromise) - test.promises = append(test.promises, p) - test.amounts = append(test.amounts, amount) -} - -func TestSwap(t *testing.T) { - - strategy := &Strategy{ - AutoCashInterval: 1 * time.Second, - AutoCashThreshold: big.NewInt(20), - AutoDepositInterval: 1 * time.Second, - AutoDepositThreshold: big.NewInt(20), - AutoDepositBuffer: big.NewInt(40), - } - - local := &Params{ - Profile: &Profile{ - PayAt: 5, - DropAt: 10, - BuyAt: common.Big3, - SellAt: common.Big2, - }, - Strategy: strategy, - } - - in := &testInPayment{} - out := &testOutPayment{} - proto := &testProtocol{} - - swap, _ := New(local, Payment{In: in, Out: out, Buys: true, Sells: true}, proto) - - if in.autocashInterval != strategy.AutoCashInterval { - t.Fatalf("autocash interval not properly set, expect %v, got %v", strategy.AutoCashInterval, in.autocashInterval) - } - if out.autodepositInterval != strategy.AutoDepositInterval { - t.Fatalf("autodeposit interval not properly set, expect %v, got %v", strategy.AutoDepositInterval, out.autodepositInterval) - } - - remote := &Profile{ - PayAt: 3, - DropAt: 10, - BuyAt: common.Big2, - SellAt: common.Big3, - } - swap.SetRemote(remote) - - swap.Add(9) - if proto.drop { - t.Fatalf("not expected peer to be dropped") - } - swap.Add(1) - if !proto.drop { - t.Fatalf("expected peer to be dropped") - } - if !proto.drop { - t.Fatalf("expected peer to be dropped") - } - proto.drop = false - - swap.Receive(10, &testPromise{big.NewInt(20)}) - if swap.balance != 0 { - t.Fatalf("expected zero balance, got %v", swap.balance) - } - - if len(proto.amounts) != 0 { - t.Fatalf("expected zero balance, got %v", swap.balance) - } - - swap.Add(-2) - if len(proto.amounts) > 0 { - t.Fatalf("expected no payments yet, got %v", proto.amounts) - } - - swap.Add(-1) - if len(proto.amounts) != 1 { - t.Fatalf("expected one payment, got %v", len(proto.amounts)) - } - - if proto.amounts[0] != 3 { - t.Fatalf("expected payment for %v units, got %v", proto.amounts[0], 3) - } - - exp := new(big.Int).Mul(big.NewInt(int64(proto.amounts[0])), remote.SellAt) - if proto.promises[0].amount.Cmp(exp) != 0 { - t.Fatalf("expected payment amount %v, got %v", exp, proto.promises[0].amount) - } - - swap.SetParams(&Params{ - Profile: &Profile{ - PayAt: 5, - DropAt: 10, - BuyAt: common.Big3, - SellAt: common.Big2, - }, - Strategy: &Strategy{ - AutoCashInterval: 2 * time.Second, - AutoCashThreshold: big.NewInt(40), - AutoDepositInterval: 2 * time.Second, - AutoDepositThreshold: big.NewInt(40), - AutoDepositBuffer: big.NewInt(60), - }, - }) - -} diff --git a/swarm/shed/db.go b/swarm/shed/db.go deleted file mode 100644 index 6fc5208669..0000000000 --- a/swarm/shed/db.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package shed provides a simple abstraction components to compose -// more complex operations on storage data organized in fields and indexes. -// -// Only type which holds logical information about swarm storage chunks data -// and metadata is Item. This part is not generalized mostly for -// performance reasons. -package shed - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/iterator" - "github.com/syndtr/goleveldb/leveldb/opt" -) - -const ( - openFileLimit = 128 // The limit for LevelDB OpenFilesCacheCapacity. - writePauseWarningThrottler = 1 * time.Minute -) - -// DB provides abstractions over LevelDB in order to -// implement complex structures using fields and ordered indexes. -// It provides a schema functionality to store fields and indexes -// information about naming and types. -type DB struct { - ldb *leveldb.DB - quit chan struct{} // Quit channel to stop the metrics collection before closing the database -} - -// NewDB constructs a new DB and validates the schema -// if it exists in database on the given path. -// metricsPrefix is used for metrics collection for the given DB. -func NewDB(path string, metricsPrefix string) (db *DB, err error) { - ldb, err := leveldb.OpenFile(path, &opt.Options{ - OpenFilesCacheCapacity: openFileLimit, - }) - if err != nil { - return nil, err - } - db = &DB{ - ldb: ldb, - } - - if _, err = db.getSchema(); err != nil { - if err == leveldb.ErrNotFound { - // save schema with initialized default fields - if err = db.putSchema(schema{ - Fields: make(map[string]fieldSpec), - Indexes: make(map[byte]indexSpec), - }); err != nil { - return nil, err - } - } else { - return nil, err - } - } - - // Create a quit channel for the periodic metrics collector and run it - db.quit = make(chan struct{}) - - go db.meter(metricsPrefix, 10*time.Second) - - return db, nil -} - -// Put wraps LevelDB Put method to increment metrics counter. -func (db *DB) Put(key []byte, value []byte) (err error) { - err = db.ldb.Put(key, value, nil) - if err != nil { - metrics.GetOrRegisterCounter("DB.putFail", nil).Inc(1) - return err - } - metrics.GetOrRegisterCounter("DB.put", nil).Inc(1) - return nil -} - -// Get wraps LevelDB Get method to increment metrics counter. -func (db *DB) Get(key []byte) (value []byte, err error) { - value, err = db.ldb.Get(key, nil) - if err != nil { - if err == leveldb.ErrNotFound { - metrics.GetOrRegisterCounter("DB.getNotFound", nil).Inc(1) - } else { - metrics.GetOrRegisterCounter("DB.getFail", nil).Inc(1) - } - return nil, err - } - metrics.GetOrRegisterCounter("DB.get", nil).Inc(1) - return value, nil -} - -// Has wraps LevelDB Has method to increment metrics counter. -func (db *DB) Has(key []byte) (yes bool, err error) { - yes, err = db.ldb.Has(key, nil) - if err != nil { - metrics.GetOrRegisterCounter("DB.hasFail", nil).Inc(1) - return false, err - } - metrics.GetOrRegisterCounter("DB.has", nil).Inc(1) - return yes, nil -} - -// Delete wraps LevelDB Delete method to increment metrics counter. -func (db *DB) Delete(key []byte) (err error) { - err = db.ldb.Delete(key, nil) - if err != nil { - metrics.GetOrRegisterCounter("DB.deleteFail", nil).Inc(1) - return err - } - metrics.GetOrRegisterCounter("DB.delete", nil).Inc(1) - return nil -} - -// NewIterator wraps LevelDB NewIterator method to increment metrics counter. -func (db *DB) NewIterator() iterator.Iterator { - metrics.GetOrRegisterCounter("DB.newiterator", nil).Inc(1) - - return db.ldb.NewIterator(nil, nil) -} - -// WriteBatch wraps LevelDB Write method to increment metrics counter. -func (db *DB) WriteBatch(batch *leveldb.Batch) (err error) { - err = db.ldb.Write(batch, nil) - if err != nil { - metrics.GetOrRegisterCounter("DB.writebatchFail", nil).Inc(1) - return err - } - metrics.GetOrRegisterCounter("DB.writebatch", nil).Inc(1) - return nil -} - -// Close closes LevelDB database. -func (db *DB) Close() (err error) { - close(db.quit) - return db.ldb.Close() -} - -func (db *DB) meter(prefix string, refresh time.Duration) { - // Meter for measuring the total time spent in database compaction - compTimeMeter := metrics.NewRegisteredMeter(prefix+"compact/time", nil) - // Meter for measuring the data read during compaction - compReadMeter := metrics.NewRegisteredMeter(prefix+"compact/input", nil) - // Meter for measuring the data written during compaction - compWriteMeter := metrics.NewRegisteredMeter(prefix+"compact/output", nil) - // Meter for measuring the write delay number due to database compaction - writeDelayMeter := metrics.NewRegisteredMeter(prefix+"compact/writedelay/duration", nil) - // Meter for measuring the write delay duration due to database compaction - writeDelayNMeter := metrics.NewRegisteredMeter(prefix+"compact/writedelay/counter", nil) - // Meter for measuring the effective amount of data read - diskReadMeter := metrics.NewRegisteredMeter(prefix+"disk/read", nil) - // Meter for measuring the effective amount of data written - diskWriteMeter := metrics.NewRegisteredMeter(prefix+"disk/write", nil) - - // Create the counters to store current and previous compaction values - compactions := make([][]float64, 2) - for i := 0; i < 2; i++ { - compactions[i] = make([]float64, 3) - } - // Create storage for iostats. - var iostats [2]float64 - - // Create storage and warning log tracer for write delay. - var ( - delaystats [2]int64 - lastWritePaused time.Time - ) - - // Iterate ad infinitum and collect the stats - for i := 1; true; i++ { - // Retrieve the database stats - stats, err := db.ldb.GetProperty("leveldb.stats") - if err != nil { - log.Error("Failed to read database stats", "err", err) - continue - } - // Find the compaction table, skip the header - lines := strings.Split(stats, "\n") - for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" { - lines = lines[1:] - } - if len(lines) <= 3 { - log.Error("Compaction table not found") - continue - } - lines = lines[3:] - - // Iterate over all the table rows, and accumulate the entries - for j := 0; j < len(compactions[i%2]); j++ { - compactions[i%2][j] = 0 - } - for _, line := range lines { - parts := strings.Split(line, "|") - if len(parts) != 6 { - break - } - for idx, counter := range parts[3:] { - value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64) - if err != nil { - log.Error("Compaction entry parsing failed", "err", err) - continue - } - compactions[i%2][idx] += value - } - } - // Update all the requested meters - if compTimeMeter != nil { - compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000)) - } - if compReadMeter != nil { - compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024)) - } - if compWriteMeter != nil { - compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024)) - } - - // Retrieve the write delay statistic - writedelay, err := db.ldb.GetProperty("leveldb.writedelay") - if err != nil { - log.Error("Failed to read database write delay statistic", "err", err) - continue - } - var ( - delayN int64 - delayDuration string - duration time.Duration - paused bool - ) - if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil { - log.Error("Write delay statistic not found") - continue - } - duration, err = time.ParseDuration(delayDuration) - if err != nil { - log.Error("Failed to parse delay duration", "err", err) - continue - } - if writeDelayNMeter != nil { - writeDelayNMeter.Mark(delayN - delaystats[0]) - } - if writeDelayMeter != nil { - writeDelayMeter.Mark(duration.Nanoseconds() - delaystats[1]) - } - // If a warning that db is performing compaction has been displayed, any subsequent - // warnings will be withheld for one minute not to overwhelm the user. - if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 && - time.Now().After(lastWritePaused.Add(writePauseWarningThrottler)) { - log.Warn("Database compacting, degraded performance") - lastWritePaused = time.Now() - } - delaystats[0], delaystats[1] = delayN, duration.Nanoseconds() - - // Retrieve the database iostats. - ioStats, err := db.ldb.GetProperty("leveldb.iostats") - if err != nil { - log.Error("Failed to read database iostats", "err", err) - continue - } - var nRead, nWrite float64 - parts := strings.Split(ioStats, " ") - if len(parts) < 2 { - log.Error("Bad syntax of ioStats", "ioStats", ioStats) - continue - } - if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil { - log.Error("Bad syntax of read entry", "entry", parts[0]) - continue - } - if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil { - log.Error("Bad syntax of write entry", "entry", parts[1]) - continue - } - if diskReadMeter != nil { - diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024)) - } - if diskWriteMeter != nil { - diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024)) - } - iostats[0], iostats[1] = nRead, nWrite - - // Sleep a bit, then repeat the stats collection - select { - case <-db.quit: - // Quit requesting, stop hammering the database - return - case <-time.After(refresh): - // Timeout, gather a new set of stats - } - } -} diff --git a/swarm/shed/db_test.go b/swarm/shed/db_test.go deleted file mode 100644 index 4e8276f746..0000000000 --- a/swarm/shed/db_test.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "io/ioutil" - "os" - "testing" -) - -// TestNewDB constructs a new DB -// and validates if the schema is initialized properly. -func TestNewDB(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - s, err := db.getSchema() - if err != nil { - t.Fatal(err) - } - if s.Fields == nil { - t.Error("schema fields are empty") - } - if len(s.Fields) != 0 { - t.Errorf("got schema fields length %v, want %v", len(s.Fields), 0) - } - if s.Indexes == nil { - t.Error("schema indexes are empty") - } - if len(s.Indexes) != 0 { - t.Errorf("got schema indexes length %v, want %v", len(s.Indexes), 0) - } -} - -// TestDB_persistence creates one DB, saves a field and closes that DB. -// Then, it constructs another DB and trues to retrieve the saved value. -func TestDB_persistence(t *testing.T) { - dir, err := ioutil.TempDir("", "shed-test-persistence") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - db, err := NewDB(dir, "") - if err != nil { - t.Fatal(err) - } - stringField, err := db.NewStringField("preserve-me") - if err != nil { - t.Fatal(err) - } - want := "persistent value" - err = stringField.Put(want) - if err != nil { - t.Fatal(err) - } - err = db.Close() - if err != nil { - t.Fatal(err) - } - - db2, err := NewDB(dir, "") - if err != nil { - t.Fatal(err) - } - stringField2, err := db2.NewStringField("preserve-me") - if err != nil { - t.Fatal(err) - } - got, err := stringField2.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got string %q, want %q", got, want) - } -} - -// newTestDB is a helper function that constructs a -// temporary database and returns a cleanup function that must -// be called to remove the data. -func newTestDB(t *testing.T) (db *DB, cleanupFunc func()) { - t.Helper() - - dir, err := ioutil.TempDir("", "shed-test") - if err != nil { - t.Fatal(err) - } - db, err = NewDB(dir, "") - if err != nil { - os.RemoveAll(dir) - t.Fatal(err) - } - return db, func() { - db.Close() - os.RemoveAll(dir) - } -} diff --git a/swarm/shed/example_store_test.go b/swarm/shed/example_store_test.go deleted file mode 100644 index 9a83855e70..0000000000 --- a/swarm/shed/example_store_test.go +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed_test - -import ( - "bytes" - "context" - "encoding/binary" - "fmt" - "io/ioutil" - "log" - "os" - "time" - - "github.com/ethereum/go-ethereum/swarm/shed" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/syndtr/goleveldb/leveldb" -) - -// Store holds fields and indexes (including their encoding functions) -// and defines operations on them by composing data from them. -// It implements storage.ChunkStore interface. -// It is just an example without any support for parallel operations -// or real world implementation. -type Store struct { - db *shed.DB - - // fields and indexes - schemaName shed.StringField - sizeCounter shed.Uint64Field - accessCounter shed.Uint64Field - retrievalIndex shed.Index - accessIndex shed.Index - gcIndex shed.Index -} - -// New returns new Store. All fields and indexes are initialized -// and possible conflicts with schema from existing database is checked -// automatically. -func New(path string) (s *Store, err error) { - db, err := shed.NewDB(path, "") - if err != nil { - return nil, err - } - s = &Store{ - db: db, - } - // Identify current storage schema by arbitrary name. - s.schemaName, err = db.NewStringField("schema-name") - if err != nil { - return nil, err - } - // Global ever incrementing index of chunk accesses. - s.accessCounter, err = db.NewUint64Field("access-counter") - if err != nil { - return nil, err - } - // Index storing actual chunk address, data and store timestamp. - s.retrievalIndex, err = db.NewIndex("Address->StoreTimestamp|Data", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - return fields.Address, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.Address = key - return e, nil - }, - EncodeValue: func(fields shed.Item) (value []byte, err error) { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(fields.StoreTimestamp)) - value = append(b, fields.Data...) - return value, nil - }, - DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[:8])) - e.Data = value[8:] - return e, nil - }, - }) - if err != nil { - return nil, err - } - // Index storing access timestamp for a particular address. - // It is needed in order to update gc index keys for iteration order. - s.accessIndex, err = db.NewIndex("Address->AccessTimestamp", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - return fields.Address, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.Address = key - return e, nil - }, - EncodeValue: func(fields shed.Item) (value []byte, err error) { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(fields.AccessTimestamp)) - return b, nil - }, - DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - e.AccessTimestamp = int64(binary.BigEndian.Uint64(value)) - return e, nil - }, - }) - if err != nil { - return nil, err - } - // Index with keys ordered by access timestamp for garbage collection prioritization. - s.gcIndex, err = db.NewIndex("AccessTimestamp|StoredTimestamp|Address->nil", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - b := make([]byte, 16, 16+len(fields.Address)) - binary.BigEndian.PutUint64(b[:8], uint64(fields.AccessTimestamp)) - binary.BigEndian.PutUint64(b[8:16], uint64(fields.StoreTimestamp)) - key = append(b, fields.Address...) - return key, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.AccessTimestamp = int64(binary.BigEndian.Uint64(key[:8])) - e.StoreTimestamp = int64(binary.BigEndian.Uint64(key[8:16])) - e.Address = key[16:] - return e, nil - }, - EncodeValue: func(fields shed.Item) (value []byte, err error) { - return nil, nil - }, - DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - return e, nil - }, - }) - if err != nil { - return nil, err - } - return s, nil -} - -// Put stores the chunk and sets it store timestamp. -func (s *Store) Put(_ context.Context, ch storage.Chunk) (err error) { - return s.retrievalIndex.Put(shed.Item{ - Address: ch.Address(), - Data: ch.Data(), - StoreTimestamp: time.Now().UTC().UnixNano(), - }) -} - -// Get retrieves a chunk with the provided address. -// It updates access and gc indexes by removing the previous -// items from them and adding new items as keys of index entries -// are changed. -func (s *Store) Get(_ context.Context, addr storage.Address) (c storage.Chunk, err error) { - batch := new(leveldb.Batch) - - // Get the chunk data and storage timestamp. - item, err := s.retrievalIndex.Get(shed.Item{ - Address: addr, - }) - if err != nil { - if err == leveldb.ErrNotFound { - return nil, storage.ErrChunkNotFound - } - return nil, err - } - - // Get the chunk access timestamp. - accessItem, err := s.accessIndex.Get(shed.Item{ - Address: addr, - }) - switch err { - case nil: - // Remove gc index entry if access timestamp is found. - err = s.gcIndex.DeleteInBatch(batch, shed.Item{ - Address: item.Address, - StoreTimestamp: accessItem.AccessTimestamp, - AccessTimestamp: item.StoreTimestamp, - }) - if err != nil { - return nil, err - } - case leveldb.ErrNotFound: - // Access timestamp is not found. Do not do anything. - // This is the firs get request. - default: - return nil, err - } - - // Specify new access timestamp - accessTimestamp := time.Now().UTC().UnixNano() - - // Put new access timestamp in access index. - err = s.accessIndex.PutInBatch(batch, shed.Item{ - Address: addr, - AccessTimestamp: accessTimestamp, - }) - if err != nil { - return nil, err - } - - // Put new access timestamp in gc index. - err = s.gcIndex.PutInBatch(batch, shed.Item{ - Address: item.Address, - AccessTimestamp: accessTimestamp, - StoreTimestamp: item.StoreTimestamp, - }) - if err != nil { - return nil, err - } - - // Increment access counter. - // Currently this information is not used anywhere. - _, err = s.accessCounter.IncInBatch(batch) - if err != nil { - return nil, err - } - - // Write the batch. - err = s.db.WriteBatch(batch) - if err != nil { - return nil, err - } - - // Return the chunk. - return storage.NewChunk(item.Address, item.Data), nil -} - -// CollectGarbage is an example of index iteration. -// It provides no reliable garbage collection functionality. -func (s *Store) CollectGarbage() (err error) { - const maxTrashSize = 100 - maxRounds := 10 // arbitrary number, needs to be calculated - - // Run a few gc rounds. - for roundCount := 0; roundCount < maxRounds; roundCount++ { - var garbageCount int - // New batch for a new cg round. - trash := new(leveldb.Batch) - // Iterate through all index items and break when needed. - err = s.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { - // Remove the chunk. - err = s.retrievalIndex.DeleteInBatch(trash, item) - if err != nil { - return false, err - } - // Remove the element in gc index. - err = s.gcIndex.DeleteInBatch(trash, item) - if err != nil { - return false, err - } - // Remove the relation in access index. - err = s.accessIndex.DeleteInBatch(trash, item) - if err != nil { - return false, err - } - garbageCount++ - if garbageCount >= maxTrashSize { - return true, nil - } - return false, nil - }, nil) - if err != nil { - return err - } - if garbageCount == 0 { - return nil - } - err = s.db.WriteBatch(trash) - if err != nil { - return err - } - } - return nil -} - -// GetSchema is an example of retrieveing the most simple -// string from a database field. -func (s *Store) GetSchema() (name string, err error) { - name, err = s.schemaName.Get() - if err == leveldb.ErrNotFound { - return "", nil - } - return name, err -} - -// GetSchema is an example of storing the most simple -// string in a database field. -func (s *Store) PutSchema(name string) (err error) { - return s.schemaName.Put(name) -} - -// Close closes the underlying database. -func (s *Store) Close() error { - return s.db.Close() -} - -// Example_store constructs a simple storage implementation using shed package. -func Example_store() { - dir, err := ioutil.TempDir("", "ephemeral") - if err != nil { - log.Fatal(err) - } - defer os.RemoveAll(dir) - - s, err := New(dir) - if err != nil { - log.Fatal(err) - } - defer s.Close() - - ch := storage.GenerateRandomChunk(1024) - err = s.Put(context.Background(), ch) - if err != nil { - log.Fatal(err) - } - - got, err := s.Get(context.Background(), ch.Address()) - if err != nil { - log.Fatal(err) - } - - fmt.Println(bytes.Equal(got.Data(), ch.Data())) - - //Output: true -} diff --git a/swarm/shed/field_string.go b/swarm/shed/field_string.go deleted file mode 100644 index a7e8f0c754..0000000000 --- a/swarm/shed/field_string.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "github.com/syndtr/goleveldb/leveldb" -) - -// StringField is the most simple field implementation -// that stores an arbitrary string under a specific LevelDB key. -type StringField struct { - db *DB - key []byte -} - -// NewStringField retruns a new Instance of StringField. -// It validates its name and type against the database schema. -func (db *DB) NewStringField(name string) (f StringField, err error) { - key, err := db.schemaFieldKey(name, "string") - if err != nil { - return f, err - } - return StringField{ - db: db, - key: key, - }, nil -} - -// Get returns a string value from database. -// If the value is not found, an empty string is returned -// an no error. -func (f StringField) Get() (val string, err error) { - b, err := f.db.Get(f.key) - if err != nil { - if err == leveldb.ErrNotFound { - return "", nil - } - return "", err - } - return string(b), nil -} - -// Put stores a string in the database. -func (f StringField) Put(val string) (err error) { - return f.db.Put(f.key, []byte(val)) -} - -// PutInBatch stores a string in a batch that can be -// saved later in database. -func (f StringField) PutInBatch(batch *leveldb.Batch, val string) { - batch.Put(f.key, []byte(val)) -} diff --git a/swarm/shed/field_string_test.go b/swarm/shed/field_string_test.go deleted file mode 100644 index 4215075bca..0000000000 --- a/swarm/shed/field_string_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "testing" - - "github.com/syndtr/goleveldb/leveldb" -) - -// TestStringField validates put and get operations -// of the StringField. -func TestStringField(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - simpleString, err := db.NewStringField("simple-string") - if err != nil { - t.Fatal(err) - } - - t.Run("get empty", func(t *testing.T) { - got, err := simpleString.Get() - if err != nil { - t.Fatal(err) - } - want := "" - if got != want { - t.Errorf("got string %q, want %q", got, want) - } - }) - - t.Run("put", func(t *testing.T) { - want := "simple string value" - err = simpleString.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := simpleString.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got string %q, want %q", got, want) - } - - t.Run("overwrite", func(t *testing.T) { - want := "overwritten string value" - err = simpleString.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := simpleString.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got string %q, want %q", got, want) - } - }) - }) - - t.Run("put in batch", func(t *testing.T) { - batch := new(leveldb.Batch) - want := "simple string batch value" - simpleString.PutInBatch(batch, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := simpleString.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got string %q, want %q", got, want) - } - - t.Run("overwrite", func(t *testing.T) { - batch := new(leveldb.Batch) - want := "overwritten string batch value" - simpleString.PutInBatch(batch, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := simpleString.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got string %q, want %q", got, want) - } - }) - }) -} diff --git a/swarm/shed/field_struct.go b/swarm/shed/field_struct.go deleted file mode 100644 index 90daee7fc4..0000000000 --- a/swarm/shed/field_struct.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "github.com/ethereum/go-ethereum/rlp" - "github.com/syndtr/goleveldb/leveldb" -) - -// StructField is a helper to store complex structure by -// encoding it in RLP format. -type StructField struct { - db *DB - key []byte -} - -// NewStructField returns a new StructField. -// It validates its name and type against the database schema. -func (db *DB) NewStructField(name string) (f StructField, err error) { - key, err := db.schemaFieldKey(name, "struct-rlp") - if err != nil { - return f, err - } - return StructField{ - db: db, - key: key, - }, nil -} - -// Get unmarshals data from the database to a provided val. -// If the data is not found leveldb.ErrNotFound is returned. -func (f StructField) Get(val interface{}) (err error) { - b, err := f.db.Get(f.key) - if err != nil { - return err - } - return rlp.DecodeBytes(b, val) -} - -// Put marshals provided val and saves it to the database. -func (f StructField) Put(val interface{}) (err error) { - b, err := rlp.EncodeToBytes(val) - if err != nil { - return err - } - return f.db.Put(f.key, b) -} - -// PutInBatch marshals provided val and puts it into the batch. -func (f StructField) PutInBatch(batch *leveldb.Batch, val interface{}) (err error) { - b, err := rlp.EncodeToBytes(val) - if err != nil { - return err - } - batch.Put(f.key, b) - return nil -} diff --git a/swarm/shed/field_struct_test.go b/swarm/shed/field_struct_test.go deleted file mode 100644 index cc0be01863..0000000000 --- a/swarm/shed/field_struct_test.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "testing" - - "github.com/syndtr/goleveldb/leveldb" -) - -// TestStructField validates put and get operations -// of the StructField. -func TestStructField(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - complexField, err := db.NewStructField("complex-field") - if err != nil { - t.Fatal(err) - } - - type complexStructure struct { - A string - } - - t.Run("get empty", func(t *testing.T) { - var s complexStructure - err := complexField.Get(&s) - if err != leveldb.ErrNotFound { - t.Fatalf("got error %v, want %v", err, leveldb.ErrNotFound) - } - want := "" - if s.A != want { - t.Errorf("got string %q, want %q", s.A, want) - } - }) - - t.Run("put", func(t *testing.T) { - want := complexStructure{ - A: "simple string value", - } - err = complexField.Put(want) - if err != nil { - t.Fatal(err) - } - var got complexStructure - err = complexField.Get(&got) - if err != nil { - t.Fatal(err) - } - if got.A != want.A { - t.Errorf("got string %q, want %q", got.A, want.A) - } - - t.Run("overwrite", func(t *testing.T) { - want := complexStructure{ - A: "overwritten string value", - } - err = complexField.Put(want) - if err != nil { - t.Fatal(err) - } - var got complexStructure - err = complexField.Get(&got) - if err != nil { - t.Fatal(err) - } - if got.A != want.A { - t.Errorf("got string %q, want %q", got.A, want.A) - } - }) - }) - - t.Run("put in batch", func(t *testing.T) { - batch := new(leveldb.Batch) - want := complexStructure{ - A: "simple string batch value", - } - complexField.PutInBatch(batch, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - var got complexStructure - err := complexField.Get(&got) - if err != nil { - t.Fatal(err) - } - if got.A != want.A { - t.Errorf("got string %q, want %q", got, want) - } - - t.Run("overwrite", func(t *testing.T) { - batch := new(leveldb.Batch) - want := complexStructure{ - A: "overwritten string batch value", - } - complexField.PutInBatch(batch, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - var got complexStructure - err := complexField.Get(&got) - if err != nil { - t.Fatal(err) - } - if got.A != want.A { - t.Errorf("got string %q, want %q", got, want) - } - }) - }) -} diff --git a/swarm/shed/field_uint64.go b/swarm/shed/field_uint64.go deleted file mode 100644 index 0417583ac3..0000000000 --- a/swarm/shed/field_uint64.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "encoding/binary" - - "github.com/syndtr/goleveldb/leveldb" -) - -// Uint64Field provides a way to have a simple counter in the database. -// It transparently encodes uint64 type value to bytes. -type Uint64Field struct { - db *DB - key []byte -} - -// NewUint64Field returns a new Uint64Field. -// It validates its name and type against the database schema. -func (db *DB) NewUint64Field(name string) (f Uint64Field, err error) { - key, err := db.schemaFieldKey(name, "uint64") - if err != nil { - return f, err - } - return Uint64Field{ - db: db, - key: key, - }, nil -} - -// Get retrieves a uint64 value from the database. -// If the value is not found in the database a 0 value -// is returned and no error. -func (f Uint64Field) Get() (val uint64, err error) { - b, err := f.db.Get(f.key) - if err != nil { - if err == leveldb.ErrNotFound { - return 0, nil - } - return 0, err - } - return binary.BigEndian.Uint64(b), nil -} - -// Put encodes uin64 value and stores it in the database. -func (f Uint64Field) Put(val uint64) (err error) { - return f.db.Put(f.key, encodeUint64(val)) -} - -// PutInBatch stores a uint64 value in a batch -// that can be saved later in the database. -func (f Uint64Field) PutInBatch(batch *leveldb.Batch, val uint64) { - batch.Put(f.key, encodeUint64(val)) -} - -// Inc increments a uint64 value in the database. -// This operation is not goroutine save. -func (f Uint64Field) Inc() (val uint64, err error) { - val, err = f.Get() - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - val++ - return val, f.Put(val) -} - -// IncInBatch increments a uint64 value in the batch -// by retreiving a value from the database, not the same batch. -// This operation is not goroutine save. -func (f Uint64Field) IncInBatch(batch *leveldb.Batch) (val uint64, err error) { - val, err = f.Get() - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - val++ - f.PutInBatch(batch, val) - return val, nil -} - -// Dec decrements a uint64 value in the database. -// This operation is not goroutine save. -// The field is protected from overflow to a negative value. -func (f Uint64Field) Dec() (val uint64, err error) { - val, err = f.Get() - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - if val != 0 { - val-- - } - return val, f.Put(val) -} - -// DecInBatch decrements a uint64 value in the batch -// by retreiving a value from the database, not the same batch. -// This operation is not goroutine save. -// The field is protected from overflow to a negative value. -func (f Uint64Field) DecInBatch(batch *leveldb.Batch) (val uint64, err error) { - val, err = f.Get() - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - if val != 0 { - val-- - } - f.PutInBatch(batch, val) - return val, nil -} - -// encode transforms uint64 to 8 byte long -// slice in big endian encoding. -func encodeUint64(val uint64) (b []byte) { - b = make([]byte, 8) - binary.BigEndian.PutUint64(b, val) - return b -} diff --git a/swarm/shed/field_uint64_test.go b/swarm/shed/field_uint64_test.go deleted file mode 100644 index 9462b56dd1..0000000000 --- a/swarm/shed/field_uint64_test.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "testing" - - "github.com/syndtr/goleveldb/leveldb" -) - -// TestUint64Field validates put and get operations -// of the Uint64Field. -func TestUint64Field(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - counter, err := db.NewUint64Field("counter") - if err != nil { - t.Fatal(err) - } - - t.Run("get empty", func(t *testing.T) { - got, err := counter.Get() - if err != nil { - t.Fatal(err) - } - var want uint64 - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - }) - - t.Run("put", func(t *testing.T) { - var want uint64 = 42 - err = counter.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - - t.Run("overwrite", func(t *testing.T) { - var want uint64 = 84 - err = counter.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - }) - }) - - t.Run("put in batch", func(t *testing.T) { - batch := new(leveldb.Batch) - var want uint64 = 42 - counter.PutInBatch(batch, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - - t.Run("overwrite", func(t *testing.T) { - batch := new(leveldb.Batch) - var want uint64 = 84 - counter.PutInBatch(batch, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - }) - }) -} - -// TestUint64Field_Inc validates Inc operation -// of the Uint64Field. -func TestUint64Field_Inc(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - counter, err := db.NewUint64Field("counter") - if err != nil { - t.Fatal(err) - } - - var want uint64 = 1 - got, err := counter.Inc() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - - want = 2 - got, err = counter.Inc() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } -} - -// TestUint64Field_IncInBatch validates IncInBatch operation -// of the Uint64Field. -func TestUint64Field_IncInBatch(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - counter, err := db.NewUint64Field("counter") - if err != nil { - t.Fatal(err) - } - - batch := new(leveldb.Batch) - var want uint64 = 1 - got, err := counter.IncInBatch(batch) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err = counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - - batch2 := new(leveldb.Batch) - want = 2 - got, err = counter.IncInBatch(batch2) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - err = db.WriteBatch(batch2) - if err != nil { - t.Fatal(err) - } - got, err = counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } -} - -// TestUint64Field_Dec validates Dec operation -// of the Uint64Field. -func TestUint64Field_Dec(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - counter, err := db.NewUint64Field("counter") - if err != nil { - t.Fatal(err) - } - - // test overflow protection - var want uint64 - got, err := counter.Dec() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - - want = 32 - err = counter.Put(want) - if err != nil { - t.Fatal(err) - } - - want = 31 - got, err = counter.Dec() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } -} - -// TestUint64Field_DecInBatch validates DecInBatch operation -// of the Uint64Field. -func TestUint64Field_DecInBatch(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - counter, err := db.NewUint64Field("counter") - if err != nil { - t.Fatal(err) - } - - batch := new(leveldb.Batch) - var want uint64 - got, err := counter.DecInBatch(batch) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err = counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - - batch2 := new(leveldb.Batch) - want = 42 - counter.PutInBatch(batch2, want) - err = db.WriteBatch(batch2) - if err != nil { - t.Fatal(err) - } - got, err = counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - - batch3 := new(leveldb.Batch) - want = 41 - got, err = counter.DecInBatch(batch3) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - err = db.WriteBatch(batch3) - if err != nil { - t.Fatal(err) - } - got, err = counter.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } -} diff --git a/swarm/shed/index.go b/swarm/shed/index.go deleted file mode 100644 index 38afbce4ca..0000000000 --- a/swarm/shed/index.go +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "bytes" - - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/iterator" -) - -// Item holds fields relevant to Swarm Chunk data and metadata. -// All information required for swarm storage and operations -// on that storage must be defined here. -// This structure is logically connected to swarm storage, -// the only part of this package that is not generalized, -// mostly for performance reasons. -// -// Item is a type that is used for retrieving, storing and encoding -// chunk data and metadata. It is passed as an argument to Index encoding -// functions, get function and put function. -// But it is also returned with additional data from get function call -// and as the argument in iterator function definition. -type Item struct { - Address []byte - Data []byte - AccessTimestamp int64 - StoreTimestamp int64 - BinID uint64 -} - -// Merge is a helper method to construct a new -// Item by filling up fields with default values -// of a particular Item with values from another one. -func (i Item) Merge(i2 Item) (new Item) { - if i.Address == nil { - i.Address = i2.Address - } - if i.Data == nil { - i.Data = i2.Data - } - if i.AccessTimestamp == 0 { - i.AccessTimestamp = i2.AccessTimestamp - } - if i.StoreTimestamp == 0 { - i.StoreTimestamp = i2.StoreTimestamp - } - if i.BinID == 0 { - i.BinID = i2.BinID - } - return i -} - -// Index represents a set of LevelDB key value pairs that have common -// prefix. It holds functions for encoding and decoding keys and values -// to provide transparent actions on saved data which inclide: -// - getting a particular Item -// - saving a particular Item -// - iterating over a sorted LevelDB keys -// It implements IndexIteratorInterface interface. -type Index struct { - db *DB - prefix []byte - encodeKeyFunc func(fields Item) (key []byte, err error) - decodeKeyFunc func(key []byte) (e Item, err error) - encodeValueFunc func(fields Item) (value []byte, err error) - decodeValueFunc func(keyFields Item, value []byte) (e Item, err error) -} - -// IndexFuncs structure defines functions for encoding and decoding -// LevelDB keys and values for a specific index. -type IndexFuncs struct { - EncodeKey func(fields Item) (key []byte, err error) - DecodeKey func(key []byte) (e Item, err error) - EncodeValue func(fields Item) (value []byte, err error) - DecodeValue func(keyFields Item, value []byte) (e Item, err error) -} - -// NewIndex returns a new Index instance with defined name and -// encoding functions. The name must be unique and will be validated -// on database schema for a key prefix byte. -func (db *DB) NewIndex(name string, funcs IndexFuncs) (f Index, err error) { - id, err := db.schemaIndexPrefix(name) - if err != nil { - return f, err - } - prefix := []byte{id} - return Index{ - db: db, - prefix: prefix, - // This function adjusts Index LevelDB key - // by appending the provided index id byte. - // This is needed to avoid collisions between keys of different - // indexes as all index ids are unique. - encodeKeyFunc: func(e Item) (key []byte, err error) { - key, err = funcs.EncodeKey(e) - if err != nil { - return nil, err - } - return append(append(make([]byte, 0, len(key)+1), prefix...), key...), nil - }, - // This function reverses the encodeKeyFunc constructed key - // to transparently work with index keys without their index ids. - // It assumes that index keys are prefixed with only one byte. - decodeKeyFunc: func(key []byte) (e Item, err error) { - return funcs.DecodeKey(key[1:]) - }, - encodeValueFunc: funcs.EncodeValue, - decodeValueFunc: funcs.DecodeValue, - }, nil -} - -// Get accepts key fields represented as Item to retrieve a -// value from the index and return maximum available information -// from the index represented as another Item. -func (f Index) Get(keyFields Item) (out Item, err error) { - key, err := f.encodeKeyFunc(keyFields) - if err != nil { - return out, err - } - value, err := f.db.Get(key) - if err != nil { - return out, err - } - out, err = f.decodeValueFunc(keyFields, value) - if err != nil { - return out, err - } - return out.Merge(keyFields), nil -} - -// Has accepts key fields represented as Item to check -// if there this Item's encoded key is stored in -// the index. -func (f Index) Has(keyFields Item) (bool, error) { - key, err := f.encodeKeyFunc(keyFields) - if err != nil { - return false, err - } - return f.db.Has(key) -} - -// Put accepts Item to encode information from it -// and save it to the database. -func (f Index) Put(i Item) (err error) { - key, err := f.encodeKeyFunc(i) - if err != nil { - return err - } - value, err := f.encodeValueFunc(i) - if err != nil { - return err - } - return f.db.Put(key, value) -} - -// PutInBatch is the same as Put method, but it just -// saves the key/value pair to the batch instead -// directly to the database. -func (f Index) PutInBatch(batch *leveldb.Batch, i Item) (err error) { - key, err := f.encodeKeyFunc(i) - if err != nil { - return err - } - value, err := f.encodeValueFunc(i) - if err != nil { - return err - } - batch.Put(key, value) - return nil -} - -// Delete accepts Item to remove a key/value pair -// from the database based on its fields. -func (f Index) Delete(keyFields Item) (err error) { - key, err := f.encodeKeyFunc(keyFields) - if err != nil { - return err - } - return f.db.Delete(key) -} - -// DeleteInBatch is the same as Delete just the operation -// is performed on the batch instead on the database. -func (f Index) DeleteInBatch(batch *leveldb.Batch, keyFields Item) (err error) { - key, err := f.encodeKeyFunc(keyFields) - if err != nil { - return err - } - batch.Delete(key) - return nil -} - -// IndexIterFunc is a callback on every Item that is decoded -// by iterating on an Index keys. -// By returning a true for stop variable, iteration will -// stop, and by returning the error, that error will be -// propagated to the called iterator method on Index. -type IndexIterFunc func(item Item) (stop bool, err error) - -// IterateOptions defines optional parameters for Iterate function. -type IterateOptions struct { - // StartFrom is the Item to start the iteration from. - StartFrom *Item - // If SkipStartFromItem is true, StartFrom item will not - // be iterated on. - SkipStartFromItem bool - // Iterate over items which keys have a common prefix. - Prefix []byte -} - -// Iterate function iterates over keys of the Index. -// If IterateOptions is nil, the iterations is over all keys. -func (f Index) Iterate(fn IndexIterFunc, options *IterateOptions) (err error) { - if options == nil { - options = new(IterateOptions) - } - // construct a prefix with Index prefix and optional common key prefix - prefix := append(f.prefix, options.Prefix...) - // start from the prefix - startKey := prefix - if options.StartFrom != nil { - // start from the provided StartFrom Item key value - startKey, err = f.encodeKeyFunc(*options.StartFrom) - if err != nil { - return err - } - } - it := f.db.NewIterator() - defer it.Release() - - // move the cursor to the start key - ok := it.Seek(startKey) - if !ok { - // stop iterator if seek has failed - return it.Error() - } - if options.SkipStartFromItem && bytes.Equal(startKey, it.Key()) { - // skip the start from Item if it is the first key - // and it is explicitly configured to skip it - ok = it.Next() - } - for ; ok; ok = it.Next() { - item, err := f.itemFromIterator(it, prefix) - if err != nil { - if err == leveldb.ErrNotFound { - break - } - return err - } - stop, err := fn(item) - if err != nil { - return err - } - if stop { - break - } - } - return it.Error() -} - -// First returns the first item in the Index which encoded key starts with a prefix. -// If the prefix is nil, the first element of the whole index is returned. -// If Index has no elements, a leveldb.ErrNotFound error is returned. -func (f Index) First(prefix []byte) (i Item, err error) { - it := f.db.NewIterator() - defer it.Release() - - totalPrefix := append(f.prefix, prefix...) - it.Seek(totalPrefix) - - return f.itemFromIterator(it, totalPrefix) -} - -// itemFromIterator returns the Item from the current iterator position. -// If the complete encoded key does not start with totalPrefix, -// leveldb.ErrNotFound is returned. Value for totalPrefix must start with -// Index prefix. -func (f Index) itemFromIterator(it iterator.Iterator, totalPrefix []byte) (i Item, err error) { - key := it.Key() - if !bytes.HasPrefix(key, totalPrefix) { - return i, leveldb.ErrNotFound - } - // create a copy of key byte slice not to share leveldb underlaying slice array - keyItem, err := f.decodeKeyFunc(append([]byte(nil), key...)) - if err != nil { - return i, err - } - // create a copy of value byte slice not to share leveldb underlaying slice array - valueItem, err := f.decodeValueFunc(keyItem, append([]byte(nil), it.Value()...)) - if err != nil { - return i, err - } - return keyItem.Merge(valueItem), it.Error() -} - -// Last returns the last item in the Index which encoded key starts with a prefix. -// If the prefix is nil, the last element of the whole index is returned. -// If Index has no elements, a leveldb.ErrNotFound error is returned. -func (f Index) Last(prefix []byte) (i Item, err error) { - it := f.db.NewIterator() - defer it.Release() - - // get the next prefix in line - // since leveldb iterator Seek seeks to the - // next key if the key that it seeks to is not found - // and by getting the previous key, the last one for the - // actual prefix is found - nextPrefix := incByteSlice(prefix) - l := len(prefix) - - if l > 0 && nextPrefix != nil { - it.Seek(append(f.prefix, nextPrefix...)) - it.Prev() - } else { - it.Last() - } - - totalPrefix := append(f.prefix, prefix...) - return f.itemFromIterator(it, totalPrefix) -} - -// incByteSlice returns the byte slice of the same size -// of the provided one that is by one incremented in its -// total value. If all bytes in provided slice are equal -// to 255 a nil slice would be returned indicating that -// increment can not happen for the same length. -func incByteSlice(b []byte) (next []byte) { - l := len(b) - next = make([]byte, l) - copy(next, b) - for i := l - 1; i >= 0; i-- { - if b[i] == 255 { - next[i] = 0 - } else { - next[i] = b[i] + 1 - return next - } - } - return nil -} - -// Count returns the number of items in index. -func (f Index) Count() (count int, err error) { - it := f.db.NewIterator() - defer it.Release() - - for ok := it.Seek(f.prefix); ok; ok = it.Next() { - key := it.Key() - if key[0] != f.prefix[0] { - break - } - count++ - } - return count, it.Error() -} - -// CountFrom returns the number of items in index keys -// starting from the key encoded from the provided Item. -func (f Index) CountFrom(start Item) (count int, err error) { - startKey, err := f.encodeKeyFunc(start) - if err != nil { - return 0, err - } - it := f.db.NewIterator() - defer it.Release() - - for ok := it.Seek(startKey); ok; ok = it.Next() { - key := it.Key() - if key[0] != f.prefix[0] { - break - } - count++ - } - return count, it.Error() -} diff --git a/swarm/shed/index_test.go b/swarm/shed/index_test.go deleted file mode 100644 index de181fa41a..0000000000 --- a/swarm/shed/index_test.go +++ /dev/null @@ -1,962 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "bytes" - "encoding/binary" - "fmt" - "sort" - "testing" - "time" - - "github.com/syndtr/goleveldb/leveldb" -) - -// Index functions for the index that is used in tests in this file. -var retrievalIndexFuncs = IndexFuncs{ - EncodeKey: func(fields Item) (key []byte, err error) { - return fields.Address, nil - }, - DecodeKey: func(key []byte) (e Item, err error) { - e.Address = key - return e, nil - }, - EncodeValue: func(fields Item) (value []byte, err error) { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(fields.StoreTimestamp)) - value = append(b, fields.Data...) - return value, nil - }, - DecodeValue: func(keyItem Item, value []byte) (e Item, err error) { - e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[:8])) - e.Data = value[8:] - return e, nil - }, -} - -// TestIndex validates put, get, has and delete functions of the Index implementation. -func TestIndex(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - index, err := db.NewIndex("retrieval", retrievalIndexFuncs) - if err != nil { - t.Fatal(err) - } - - t.Run("put", func(t *testing.T) { - want := Item{ - Address: []byte("put-hash"), - Data: []byte("DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - err := index.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := index.Get(Item{ - Address: want.Address, - }) - if err != nil { - t.Fatal(err) - } - checkItem(t, got, want) - - t.Run("overwrite", func(t *testing.T) { - want := Item{ - Address: []byte("put-hash"), - Data: []byte("New DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - err = index.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := index.Get(Item{ - Address: want.Address, - }) - if err != nil { - t.Fatal(err) - } - checkItem(t, got, want) - }) - }) - - t.Run("put in batch", func(t *testing.T) { - want := Item{ - Address: []byte("put-in-batch-hash"), - Data: []byte("DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - batch := new(leveldb.Batch) - index.PutInBatch(batch, want) - err := db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := index.Get(Item{ - Address: want.Address, - }) - if err != nil { - t.Fatal(err) - } - checkItem(t, got, want) - - t.Run("overwrite", func(t *testing.T) { - want := Item{ - Address: []byte("put-in-batch-hash"), - Data: []byte("New DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - batch := new(leveldb.Batch) - index.PutInBatch(batch, want) - db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := index.Get(Item{ - Address: want.Address, - }) - if err != nil { - t.Fatal(err) - } - checkItem(t, got, want) - }) - }) - - t.Run("put in batch twice", func(t *testing.T) { - // ensure that the last item of items with the same db keys - // is actually saved - batch := new(leveldb.Batch) - address := []byte("put-in-batch-twice-hash") - - // put the first item - index.PutInBatch(batch, Item{ - Address: address, - Data: []byte("DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - }) - - want := Item{ - Address: address, - Data: []byte("New DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - // then put the item that will produce the same key - // but different value in the database - index.PutInBatch(batch, want) - db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := index.Get(Item{ - Address: address, - }) - if err != nil { - t.Fatal(err) - } - checkItem(t, got, want) - }) - - t.Run("has", func(t *testing.T) { - want := Item{ - Address: []byte("has-hash"), - Data: []byte("DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - dontWant := Item{ - Address: []byte("do-not-has-hash"), - Data: []byte("DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - err := index.Put(want) - if err != nil { - t.Fatal(err) - } - - has, err := index.Has(want) - if err != nil { - t.Fatal(err) - } - if !has { - t.Error("item is not found") - } - - has, err = index.Has(dontWant) - if err != nil { - t.Fatal(err) - } - if has { - t.Error("unwanted item is found") - } - }) - - t.Run("delete", func(t *testing.T) { - want := Item{ - Address: []byte("delete-hash"), - Data: []byte("DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - err := index.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := index.Get(Item{ - Address: want.Address, - }) - if err != nil { - t.Fatal(err) - } - checkItem(t, got, want) - - err = index.Delete(Item{ - Address: want.Address, - }) - if err != nil { - t.Fatal(err) - } - - wantErr := leveldb.ErrNotFound - got, err = index.Get(Item{ - Address: want.Address, - }) - if err != wantErr { - t.Fatalf("got error %v, want %v", err, wantErr) - } - }) - - t.Run("delete in batch", func(t *testing.T) { - want := Item{ - Address: []byte("delete-in-batch-hash"), - Data: []byte("DATA"), - StoreTimestamp: time.Now().UTC().UnixNano(), - } - - err := index.Put(want) - if err != nil { - t.Fatal(err) - } - got, err := index.Get(Item{ - Address: want.Address, - }) - if err != nil { - t.Fatal(err) - } - checkItem(t, got, want) - - batch := new(leveldb.Batch) - index.DeleteInBatch(batch, Item{ - Address: want.Address, - }) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - - wantErr := leveldb.ErrNotFound - got, err = index.Get(Item{ - Address: want.Address, - }) - if err != wantErr { - t.Fatalf("got error %v, want %v", err, wantErr) - } - }) -} - -// TestIndex_Iterate validates index Iterate -// functions for correctness. -func TestIndex_Iterate(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - index, err := db.NewIndex("retrieval", retrievalIndexFuncs) - if err != nil { - t.Fatal(err) - } - - items := []Item{ - { - Address: []byte("iterate-hash-01"), - Data: []byte("data80"), - }, - { - Address: []byte("iterate-hash-03"), - Data: []byte("data22"), - }, - { - Address: []byte("iterate-hash-05"), - Data: []byte("data41"), - }, - { - Address: []byte("iterate-hash-02"), - Data: []byte("data84"), - }, - { - Address: []byte("iterate-hash-06"), - Data: []byte("data1"), - }, - } - batch := new(leveldb.Batch) - for _, i := range items { - index.PutInBatch(batch, i) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - item04 := Item{ - Address: []byte("iterate-hash-04"), - Data: []byte("data0"), - } - err = index.Put(item04) - if err != nil { - t.Fatal(err) - } - items = append(items, item04) - - sort.SliceStable(items, func(i, j int) bool { - return bytes.Compare(items[i].Address, items[j].Address) < 0 - }) - - t.Run("all", func(t *testing.T) { - var i int - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - return false, nil - }, nil) - if err != nil { - t.Fatal(err) - } - }) - - t.Run("start from", func(t *testing.T) { - startIndex := 2 - i := startIndex - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - return false, nil - }, &IterateOptions{ - StartFrom: &items[startIndex], - }) - if err != nil { - t.Fatal(err) - } - }) - - t.Run("skip start from", func(t *testing.T) { - startIndex := 2 - i := startIndex + 1 - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - return false, nil - }, &IterateOptions{ - StartFrom: &items[startIndex], - SkipStartFromItem: true, - }) - if err != nil { - t.Fatal(err) - } - }) - - t.Run("stop", func(t *testing.T) { - var i int - stopIndex := 3 - var count int - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - count++ - if i == stopIndex { - return true, nil - } - i++ - return false, nil - }, nil) - if err != nil { - t.Fatal(err) - } - wantItemsCount := stopIndex + 1 - if count != wantItemsCount { - t.Errorf("got %v items, expected %v", count, wantItemsCount) - } - }) - - t.Run("no overflow", func(t *testing.T) { - secondIndex, err := db.NewIndex("second-index", retrievalIndexFuncs) - if err != nil { - t.Fatal(err) - } - - secondItem := Item{ - Address: []byte("iterate-hash-10"), - Data: []byte("data-second"), - } - err = secondIndex.Put(secondItem) - if err != nil { - t.Fatal(err) - } - - var i int - err = index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - return false, nil - }, nil) - if err != nil { - t.Fatal(err) - } - - i = 0 - err = secondIndex.Iterate(func(item Item) (stop bool, err error) { - if i > 1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - checkItem(t, item, secondItem) - i++ - return false, nil - }, nil) - if err != nil { - t.Fatal(err) - } - }) -} - -// TestIndex_Iterate_withPrefix validates index Iterate -// function for correctness. -func TestIndex_Iterate_withPrefix(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - index, err := db.NewIndex("retrieval", retrievalIndexFuncs) - if err != nil { - t.Fatal(err) - } - - allItems := []Item{ - {Address: []byte("want-hash-00"), Data: []byte("data80")}, - {Address: []byte("skip-hash-01"), Data: []byte("data81")}, - {Address: []byte("skip-hash-02"), Data: []byte("data82")}, - {Address: []byte("skip-hash-03"), Data: []byte("data83")}, - {Address: []byte("want-hash-04"), Data: []byte("data84")}, - {Address: []byte("want-hash-05"), Data: []byte("data85")}, - {Address: []byte("want-hash-06"), Data: []byte("data86")}, - {Address: []byte("want-hash-07"), Data: []byte("data87")}, - {Address: []byte("want-hash-08"), Data: []byte("data88")}, - {Address: []byte("want-hash-09"), Data: []byte("data89")}, - {Address: []byte("skip-hash-10"), Data: []byte("data90")}, - } - batch := new(leveldb.Batch) - for _, i := range allItems { - index.PutInBatch(batch, i) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - - prefix := []byte("want") - - items := make([]Item, 0) - for _, item := range allItems { - if bytes.HasPrefix(item.Address, prefix) { - items = append(items, item) - } - } - sort.SliceStable(items, func(i, j int) bool { - return bytes.Compare(items[i].Address, items[j].Address) < 0 - }) - - t.Run("with prefix", func(t *testing.T) { - var i int - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - return false, nil - }, &IterateOptions{ - Prefix: prefix, - }) - if err != nil { - t.Fatal(err) - } - if i != len(items) { - t.Errorf("got %v items, want %v", i, len(items)) - } - }) - - t.Run("with prefix and start from", func(t *testing.T) { - startIndex := 2 - var count int - i := startIndex - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - count++ - return false, nil - }, &IterateOptions{ - StartFrom: &items[startIndex], - Prefix: prefix, - }) - if err != nil { - t.Fatal(err) - } - wantCount := len(items) - startIndex - if count != wantCount { - t.Errorf("got %v items, want %v", count, wantCount) - } - }) - - t.Run("with prefix and skip start from", func(t *testing.T) { - startIndex := 2 - var count int - i := startIndex + 1 - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - count++ - return false, nil - }, &IterateOptions{ - StartFrom: &items[startIndex], - SkipStartFromItem: true, - Prefix: prefix, - }) - if err != nil { - t.Fatal(err) - } - wantCount := len(items) - startIndex - 1 - if count != wantCount { - t.Errorf("got %v items, want %v", count, wantCount) - } - }) - - t.Run("stop", func(t *testing.T) { - var i int - stopIndex := 3 - var count int - err := index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - count++ - if i == stopIndex { - return true, nil - } - i++ - return false, nil - }, &IterateOptions{ - Prefix: prefix, - }) - if err != nil { - t.Fatal(err) - } - wantItemsCount := stopIndex + 1 - if count != wantItemsCount { - t.Errorf("got %v items, expected %v", count, wantItemsCount) - } - }) - - t.Run("no overflow", func(t *testing.T) { - secondIndex, err := db.NewIndex("second-index", retrievalIndexFuncs) - if err != nil { - t.Fatal(err) - } - - secondItem := Item{ - Address: []byte("iterate-hash-10"), - Data: []byte("data-second"), - } - err = secondIndex.Put(secondItem) - if err != nil { - t.Fatal(err) - } - - var i int - err = index.Iterate(func(item Item) (stop bool, err error) { - if i > len(items)-1 { - return true, fmt.Errorf("got unexpected index item: %#v", item) - } - want := items[i] - checkItem(t, item, want) - i++ - return false, nil - }, &IterateOptions{ - Prefix: prefix, - }) - if err != nil { - t.Fatal(err) - } - if i != len(items) { - t.Errorf("got %v items, want %v", i, len(items)) - } - }) -} - -// TestIndex_count tests if Index.Count and Index.CountFrom -// returns the correct number of items. -func TestIndex_count(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - index, err := db.NewIndex("retrieval", retrievalIndexFuncs) - if err != nil { - t.Fatal(err) - } - - items := []Item{ - { - Address: []byte("iterate-hash-01"), - Data: []byte("data80"), - }, - { - Address: []byte("iterate-hash-02"), - Data: []byte("data84"), - }, - { - Address: []byte("iterate-hash-03"), - Data: []byte("data22"), - }, - { - Address: []byte("iterate-hash-04"), - Data: []byte("data41"), - }, - { - Address: []byte("iterate-hash-05"), - Data: []byte("data1"), - }, - } - batch := new(leveldb.Batch) - for _, i := range items { - index.PutInBatch(batch, i) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - - t.Run("Count", func(t *testing.T) { - got, err := index.Count() - if err != nil { - t.Fatal(err) - } - - want := len(items) - if got != want { - t.Errorf("got %v items count, want %v", got, want) - } - }) - - t.Run("CountFrom", func(t *testing.T) { - got, err := index.CountFrom(Item{ - Address: items[1].Address, - }) - if err != nil { - t.Fatal(err) - } - - want := len(items) - 1 - if got != want { - t.Errorf("got %v items count, want %v", got, want) - } - }) - - // update the index with another item - t.Run("add item", func(t *testing.T) { - item04 := Item{ - Address: []byte("iterate-hash-06"), - Data: []byte("data0"), - } - err = index.Put(item04) - if err != nil { - t.Fatal(err) - } - - count := len(items) + 1 - - t.Run("Count", func(t *testing.T) { - got, err := index.Count() - if err != nil { - t.Fatal(err) - } - - want := count - if got != want { - t.Errorf("got %v items count, want %v", got, want) - } - }) - - t.Run("CountFrom", func(t *testing.T) { - got, err := index.CountFrom(Item{ - Address: items[1].Address, - }) - if err != nil { - t.Fatal(err) - } - - want := count - 1 - if got != want { - t.Errorf("got %v items count, want %v", got, want) - } - }) - }) - - // delete some items - t.Run("delete items", func(t *testing.T) { - deleteCount := 3 - - for _, item := range items[:deleteCount] { - err := index.Delete(item) - if err != nil { - t.Fatal(err) - } - } - - count := len(items) + 1 - deleteCount - - t.Run("Count", func(t *testing.T) { - got, err := index.Count() - if err != nil { - t.Fatal(err) - } - - want := count - if got != want { - t.Errorf("got %v items count, want %v", got, want) - } - }) - - t.Run("CountFrom", func(t *testing.T) { - got, err := index.CountFrom(Item{ - Address: items[deleteCount+1].Address, - }) - if err != nil { - t.Fatal(err) - } - - want := count - 1 - if got != want { - t.Errorf("got %v items count, want %v", got, want) - } - }) - }) -} - -// checkItem is a test helper function that compares if two Index items are the same. -func checkItem(t *testing.T, got, want Item) { - t.Helper() - - if !bytes.Equal(got.Address, want.Address) { - t.Errorf("got hash %q, expected %q", string(got.Address), string(want.Address)) - } - if !bytes.Equal(got.Data, want.Data) { - t.Errorf("got data %q, expected %q", string(got.Data), string(want.Data)) - } - if got.StoreTimestamp != want.StoreTimestamp { - t.Errorf("got store timestamp %v, expected %v", got.StoreTimestamp, want.StoreTimestamp) - } - if got.AccessTimestamp != want.AccessTimestamp { - t.Errorf("got access timestamp %v, expected %v", got.AccessTimestamp, want.AccessTimestamp) - } -} - -// TestIndex_firstAndLast validates that index First and Last methods -// are returning expected results based on the provided prefix. -func TestIndex_firstAndLast(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - index, err := db.NewIndex("retrieval", retrievalIndexFuncs) - if err != nil { - t.Fatal(err) - } - - addrs := [][]byte{ - {0, 0, 0, 0, 0}, - {0, 1}, - {0, 1, 0, 0, 0}, - {0, 1, 0, 0, 1}, - {0, 1, 0, 0, 2}, - {0, 2, 0, 0, 1}, - {0, 4, 0, 0, 0}, - {0, 10, 0, 0, 10}, - {0, 10, 0, 0, 11}, - {0, 10, 0, 0, 20}, - {1, 32, 255, 0, 1}, - {1, 32, 255, 0, 2}, - {1, 32, 255, 0, 3}, - {255, 255, 255, 255, 32}, - {255, 255, 255, 255, 64}, - {255, 255, 255, 255, 255}, - } - - // ensure that the addresses are sorted for - // validation of nil prefix - sort.Slice(addrs, func(i, j int) (less bool) { - return bytes.Compare(addrs[i], addrs[j]) == -1 - }) - - batch := new(leveldb.Batch) - for _, addr := range addrs { - index.PutInBatch(batch, Item{ - Address: addr, - }) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - - for _, tc := range []struct { - prefix []byte - first []byte - last []byte - err error - }{ - { - prefix: nil, - first: addrs[0], - last: addrs[len(addrs)-1], - }, - { - prefix: []byte{0, 0}, - first: []byte{0, 0, 0, 0, 0}, - last: []byte{0, 0, 0, 0, 0}, - }, - { - prefix: []byte{0}, - first: []byte{0, 0, 0, 0, 0}, - last: []byte{0, 10, 0, 0, 20}, - }, - { - prefix: []byte{0, 1}, - first: []byte{0, 1}, - last: []byte{0, 1, 0, 0, 2}, - }, - { - prefix: []byte{0, 10}, - first: []byte{0, 10, 0, 0, 10}, - last: []byte{0, 10, 0, 0, 20}, - }, - { - prefix: []byte{1, 32, 255}, - first: []byte{1, 32, 255, 0, 1}, - last: []byte{1, 32, 255, 0, 3}, - }, - { - prefix: []byte{255}, - first: []byte{255, 255, 255, 255, 32}, - last: []byte{255, 255, 255, 255, 255}, - }, - { - prefix: []byte{255, 255, 255, 255, 255}, - first: []byte{255, 255, 255, 255, 255}, - last: []byte{255, 255, 255, 255, 255}, - }, - { - prefix: []byte{0, 3}, - err: leveldb.ErrNotFound, - }, - { - prefix: []byte{222}, - err: leveldb.ErrNotFound, - }, - } { - got, err := index.Last(tc.prefix) - if tc.err != err { - t.Errorf("got error %v for Last with prefix %v, want %v", err, tc.prefix, tc.err) - } else { - if !bytes.Equal(got.Address, tc.last) { - t.Errorf("got %v for Last with prefix %v, want %v", got.Address, tc.prefix, tc.last) - } - } - - got, err = index.First(tc.prefix) - if tc.err != err { - t.Errorf("got error %v for First with prefix %v, want %v", err, tc.prefix, tc.err) - } else { - if !bytes.Equal(got.Address, tc.first) { - t.Errorf("got %v for First with prefix %v, want %v", got.Address, tc.prefix, tc.first) - } - } - } -} - -// TestIncByteSlice validates returned values of incByteSlice function. -func TestIncByteSlice(t *testing.T) { - for _, tc := range []struct { - b []byte - want []byte - }{ - {b: nil, want: nil}, - {b: []byte{}, want: nil}, - {b: []byte{0}, want: []byte{1}}, - {b: []byte{42}, want: []byte{43}}, - {b: []byte{255}, want: nil}, - {b: []byte{0, 0}, want: []byte{0, 1}}, - {b: []byte{1, 0}, want: []byte{1, 1}}, - {b: []byte{1, 255}, want: []byte{2, 0}}, - {b: []byte{255, 255}, want: nil}, - {b: []byte{32, 0, 255}, want: []byte{32, 1, 0}}, - } { - got := incByteSlice(tc.b) - if !bytes.Equal(got, tc.want) { - t.Errorf("got %v, want %v", got, tc.want) - } - } -} diff --git a/swarm/shed/schema.go b/swarm/shed/schema.go deleted file mode 100644 index 557d951fbb..0000000000 --- a/swarm/shed/schema.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "encoding/json" - "errors" - "fmt" -) - -var ( - // LevelDB key value for storing the schema. - keySchema = []byte{0} - // LevelDB key prefix for all field type. - // LevelDB keys will be constructed by appending name values to this prefix. - keyPrefixFields byte = 1 - // LevelDB key prefix from which indexing keys start. - // Every index has its own key prefix and this value defines the first one. - keyPrefixIndexStart byte = 2 // Q: or maybe a higher number like 7, to have more space for potential specific perfixes -) - -// schema is used to serialize known database structure information. -type schema struct { - Fields map[string]fieldSpec `json:"fields"` // keys are field names - Indexes map[byte]indexSpec `json:"indexes"` // keys are index prefix bytes -} - -// fieldSpec holds information about a particular field. -// It does not need Name field as it is contained in the -// schema.Field map key. -type fieldSpec struct { - Type string `json:"type"` -} - -// indxSpec holds information about a particular index. -// It does not contain index type, as indexes do not have type. -type indexSpec struct { - Name string `json:"name"` -} - -// schemaFieldKey retrieves the complete LevelDB key for -// a particular field form the schema definition. -func (db *DB) schemaFieldKey(name, fieldType string) (key []byte, err error) { - if name == "" { - return nil, errors.New("field name can not be blank") - } - if fieldType == "" { - return nil, errors.New("field type can not be blank") - } - s, err := db.getSchema() - if err != nil { - return nil, err - } - var found bool - for n, f := range s.Fields { - if n == name { - if f.Type != fieldType { - return nil, fmt.Errorf("field %q of type %q stored as %q in db", name, fieldType, f.Type) - } - break - } - } - if !found { - s.Fields[name] = fieldSpec{ - Type: fieldType, - } - err := db.putSchema(s) - if err != nil { - return nil, err - } - } - return append([]byte{keyPrefixFields}, []byte(name)...), nil -} - -// schemaIndexID retrieves the complete LevelDB prefix for -// a particular index. -func (db *DB) schemaIndexPrefix(name string) (id byte, err error) { - if name == "" { - return 0, errors.New("index name can not be blank") - } - s, err := db.getSchema() - if err != nil { - return 0, err - } - nextID := keyPrefixIndexStart - for i, f := range s.Indexes { - if i >= nextID { - nextID = i + 1 - } - if f.Name == name { - return i, nil - } - } - id = nextID - s.Indexes[id] = indexSpec{ - Name: name, - } - return id, db.putSchema(s) -} - -// getSchema retrieves the complete schema from -// the database. -func (db *DB) getSchema() (s schema, err error) { - b, err := db.Get(keySchema) - if err != nil { - return s, err - } - err = json.Unmarshal(b, &s) - return s, err -} - -// putSchema stores the complete schema to -// the database. -func (db *DB) putSchema(s schema) (err error) { - b, err := json.Marshal(s) - if err != nil { - return err - } - return db.Put(keySchema, b) -} diff --git a/swarm/shed/schema_test.go b/swarm/shed/schema_test.go deleted file mode 100644 index a0c1838c8b..0000000000 --- a/swarm/shed/schema_test.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "bytes" - "testing" -) - -// TestDB_schemaFieldKey validates correctness of schemaFieldKey. -func TestDB_schemaFieldKey(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - t.Run("empty name or type", func(t *testing.T) { - _, err := db.schemaFieldKey("", "") - if err == nil { - t.Errorf("error not returned, but expected") - } - _, err = db.schemaFieldKey("", "type") - if err == nil { - t.Errorf("error not returned, but expected") - } - - _, err = db.schemaFieldKey("test", "") - if err == nil { - t.Errorf("error not returned, but expected") - } - }) - - t.Run("same field", func(t *testing.T) { - key1, err := db.schemaFieldKey("test", "undefined") - if err != nil { - t.Fatal(err) - } - - key2, err := db.schemaFieldKey("test", "undefined") - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(key1, key2) { - t.Errorf("schema keys for the same field name are not the same: %q, %q", string(key1), string(key2)) - } - }) - - t.Run("different fields", func(t *testing.T) { - key1, err := db.schemaFieldKey("test1", "undefined") - if err != nil { - t.Fatal(err) - } - - key2, err := db.schemaFieldKey("test2", "undefined") - if err != nil { - t.Fatal(err) - } - - if bytes.Equal(key1, key2) { - t.Error("schema keys for the same field name are the same, but must not be") - } - }) - - t.Run("same field name different types", func(t *testing.T) { - _, err := db.schemaFieldKey("the-field", "one-type") - if err != nil { - t.Fatal(err) - } - - _, err = db.schemaFieldKey("the-field", "another-type") - if err == nil { - t.Errorf("error not returned, but expected") - } - }) -} - -// TestDB_schemaIndexPrefix validates correctness of schemaIndexPrefix. -func TestDB_schemaIndexPrefix(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - t.Run("same name", func(t *testing.T) { - id1, err := db.schemaIndexPrefix("test") - if err != nil { - t.Fatal(err) - } - - id2, err := db.schemaIndexPrefix("test") - if err != nil { - t.Fatal(err) - } - - if id1 != id2 { - t.Errorf("schema keys for the same field name are not the same: %v, %v", id1, id2) - } - }) - - t.Run("different names", func(t *testing.T) { - id1, err := db.schemaIndexPrefix("test1") - if err != nil { - t.Fatal(err) - } - - id2, err := db.schemaIndexPrefix("test2") - if err != nil { - t.Fatal(err) - } - - if id1 == id2 { - t.Error("schema ids for the same index name are the same, but must not be") - } - }) -} diff --git a/swarm/shed/vector_uint64.go b/swarm/shed/vector_uint64.go deleted file mode 100644 index 0926e64f80..0000000000 --- a/swarm/shed/vector_uint64.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "encoding/binary" - - "github.com/syndtr/goleveldb/leveldb" -) - -// Uint64Vector provides a way to have multiple counters in the database. -// It transparently encodes uint64 type value to bytes. -type Uint64Vector struct { - db *DB - key []byte -} - -// NewUint64Vector returns a new Uint64Vector. -// It validates its name and type against the database schema. -func (db *DB) NewUint64Vector(name string) (f Uint64Vector, err error) { - key, err := db.schemaFieldKey(name, "vector-uint64") - if err != nil { - return f, err - } - return Uint64Vector{ - db: db, - key: key, - }, nil -} - -// Get retrieves a uint64 value at index i from the database. -// If the value is not found in the database a 0 value -// is returned and no error. -func (f Uint64Vector) Get(i uint64) (val uint64, err error) { - b, err := f.db.Get(f.indexKey(i)) - if err != nil { - if err == leveldb.ErrNotFound { - return 0, nil - } - return 0, err - } - return binary.BigEndian.Uint64(b), nil -} - -// Put encodes uin64 value and stores it in the database. -func (f Uint64Vector) Put(i, val uint64) (err error) { - return f.db.Put(f.indexKey(i), encodeUint64(val)) -} - -// PutInBatch stores a uint64 value at index i in a batch -// that can be saved later in the database. -func (f Uint64Vector) PutInBatch(batch *leveldb.Batch, i, val uint64) { - batch.Put(f.indexKey(i), encodeUint64(val)) -} - -// Inc increments a uint64 value in the database. -// This operation is not goroutine safe. -func (f Uint64Vector) Inc(i uint64) (val uint64, err error) { - val, err = f.Get(i) - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - val++ - return val, f.Put(i, val) -} - -// IncInBatch increments a uint64 value at index i in the batch -// by retreiving a value from the database, not the same batch. -// This operation is not goroutine safe. -func (f Uint64Vector) IncInBatch(batch *leveldb.Batch, i uint64) (val uint64, err error) { - val, err = f.Get(i) - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - val++ - f.PutInBatch(batch, i, val) - return val, nil -} - -// Dec decrements a uint64 value at index i in the database. -// This operation is not goroutine safe. -// The field is protected from overflow to a negative value. -func (f Uint64Vector) Dec(i uint64) (val uint64, err error) { - val, err = f.Get(i) - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - if val != 0 { - val-- - } - return val, f.Put(i, val) -} - -// DecInBatch decrements a uint64 value at index i in the batch -// by retreiving a value from the database, not the same batch. -// This operation is not goroutine safe. -// The field is protected from overflow to a negative value. -func (f Uint64Vector) DecInBatch(batch *leveldb.Batch, i uint64) (val uint64, err error) { - val, err = f.Get(i) - if err != nil { - if err == leveldb.ErrNotFound { - val = 0 - } else { - return 0, err - } - } - if val != 0 { - val-- - } - f.PutInBatch(batch, i, val) - return val, nil -} - -// indexKey concatenates field prefix and vector index -// returning a unique database key for a specific vector element. -func (f Uint64Vector) indexKey(i uint64) (key []byte) { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, i) - return append(f.key, b...) -} diff --git a/swarm/shed/vector_uint64_test.go b/swarm/shed/vector_uint64_test.go deleted file mode 100644 index 75aed7d1c3..0000000000 --- a/swarm/shed/vector_uint64_test.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package shed - -import ( - "testing" - - "github.com/syndtr/goleveldb/leveldb" -) - -// TestUint64Vector validates put and get operations -// of the Uint64Vector. -func TestUint64Vector(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - bins, err := db.NewUint64Vector("bins") - if err != nil { - t.Fatal(err) - } - - t.Run("get empty", func(t *testing.T) { - got, err := bins.Get(0) - if err != nil { - t.Fatal(err) - } - var want uint64 - if got != want { - t.Errorf("got uint64 %v, want %v", got, want) - } - }) - - t.Run("put", func(t *testing.T) { - for _, index := range []uint64{0, 1, 2, 5, 100} { - var want uint64 = 42 + index - err = bins.Put(index, want) - if err != nil { - t.Fatal(err) - } - got, err := bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - - t.Run("overwrite", func(t *testing.T) { - var want uint64 = 84 + index - err = bins.Put(index, want) - if err != nil { - t.Fatal(err) - } - got, err := bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - }) - } - }) - - t.Run("put in batch", func(t *testing.T) { - for _, index := range []uint64{0, 1, 2, 3, 5, 10} { - batch := new(leveldb.Batch) - var want uint64 = 43 + index - bins.PutInBatch(batch, index, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - - t.Run("overwrite", func(t *testing.T) { - batch := new(leveldb.Batch) - var want uint64 = 85 + index - bins.PutInBatch(batch, index, want) - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err := bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - }) - } - }) -} - -// TestUint64Vector_Inc validates Inc operation -// of the Uint64Vector. -func TestUint64Vector_Inc(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - bins, err := db.NewUint64Vector("bins") - if err != nil { - t.Fatal(err) - } - - for _, index := range []uint64{0, 1, 2, 3, 5, 10} { - var want uint64 = 1 - got, err := bins.Inc(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - - want = 2 - got, err = bins.Inc(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - } -} - -// TestUint64Vector_IncInBatch validates IncInBatch operation -// of the Uint64Vector. -func TestUint64Vector_IncInBatch(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - bins, err := db.NewUint64Vector("bins") - if err != nil { - t.Fatal(err) - } - - for _, index := range []uint64{0, 1, 2, 3, 5, 10} { - batch := new(leveldb.Batch) - var want uint64 = 1 - got, err := bins.IncInBatch(batch, index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err = bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - - batch2 := new(leveldb.Batch) - want = 2 - got, err = bins.IncInBatch(batch2, index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - err = db.WriteBatch(batch2) - if err != nil { - t.Fatal(err) - } - got, err = bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - } -} - -// TestUint64Vector_Dec validates Dec operation -// of the Uint64Vector. -func TestUint64Vector_Dec(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - bins, err := db.NewUint64Vector("bins") - if err != nil { - t.Fatal(err) - } - - for _, index := range []uint64{0, 1, 2, 3, 5, 10} { - // test overflow protection - var want uint64 - got, err := bins.Dec(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - - want = 32 + index - err = bins.Put(index, want) - if err != nil { - t.Fatal(err) - } - - want = 31 + index - got, err = bins.Dec(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - } -} - -// TestUint64Vector_DecInBatch validates DecInBatch operation -// of the Uint64Vector. -func TestUint64Vector_DecInBatch(t *testing.T) { - db, cleanupFunc := newTestDB(t) - defer cleanupFunc() - - bins, err := db.NewUint64Vector("bins") - if err != nil { - t.Fatal(err) - } - - for _, index := range []uint64{0, 1, 2, 3, 5, 10} { - batch := new(leveldb.Batch) - var want uint64 - got, err := bins.DecInBatch(batch, index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - err = db.WriteBatch(batch) - if err != nil { - t.Fatal(err) - } - got, err = bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - - batch2 := new(leveldb.Batch) - want = 42 + index - bins.PutInBatch(batch2, index, want) - err = db.WriteBatch(batch2) - if err != nil { - t.Fatal(err) - } - got, err = bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - - batch3 := new(leveldb.Batch) - want = 41 + index - got, err = bins.DecInBatch(batch3, index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - err = db.WriteBatch(batch3) - if err != nil { - t.Fatal(err) - } - got, err = bins.Get(index) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got %v uint64 %v, want %v", index, got, want) - } - } -} diff --git a/swarm/spancontext/spancontext.go b/swarm/spancontext/spancontext.go deleted file mode 100644 index 2cb9f82f7c..0000000000 --- a/swarm/spancontext/spancontext.go +++ /dev/null @@ -1,49 +0,0 @@ -package spancontext - -import ( - "context" - - opentracing "github.com/opentracing/opentracing-go" -) - -func WithContext(ctx context.Context, sctx opentracing.SpanContext) context.Context { - return context.WithValue(ctx, "span_context", sctx) -} - -func FromContext(ctx context.Context) opentracing.SpanContext { - sctx, ok := ctx.Value("span_context").(opentracing.SpanContext) - if ok { - return sctx - } - - return nil -} - -func StartSpan(ctx context.Context, name string) (context.Context, opentracing.Span) { - tracer := opentracing.GlobalTracer() - - sctx := FromContext(ctx) - - var sp opentracing.Span - if sctx != nil { - sp = tracer.StartSpan( - name, - opentracing.ChildOf(sctx)) - } else { - sp = tracer.StartSpan(name) - } - - nctx := context.WithValue(ctx, "span_context", sp.Context()) - - return nctx, sp -} - -func StartSpanFrom(name string, sctx opentracing.SpanContext) opentracing.Span { - tracer := opentracing.GlobalTracer() - - sp := tracer.StartSpan( - name, - opentracing.ChildOf(sctx)) - - return sp -} diff --git a/swarm/state/dbstore.go b/swarm/state/dbstore.go deleted file mode 100644 index 1b541e7854..0000000000 --- a/swarm/state/dbstore.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package state - -import ( - "encoding" - "encoding/json" - "errors" - - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/storage" -) - -// ErrNotFound is returned when no results are returned from the database -var ErrNotFound = errors.New("ErrorNotFound") - -// Store defines methods required to get, set, delete values for different keys -// and close the underlying resources. -type Store interface { - Get(key string, i interface{}) (err error) - Put(key string, i interface{}) (err error) - Delete(key string) (err error) - Close() error -} - -// DBStore uses LevelDB to store values. -type DBStore struct { - db *leveldb.DB -} - -// NewDBStore creates a new instance of DBStore. -func NewDBStore(path string) (s *DBStore, err error) { - db, err := leveldb.OpenFile(path, nil) - if err != nil { - return nil, err - } - return &DBStore{ - db: db, - }, nil -} - -// NewInmemoryStore returns a new instance of DBStore. To be used only in tests and simulations. -func NewInmemoryStore() *DBStore { - db, err := leveldb.Open(storage.NewMemStorage(), nil) - if err != nil { - panic(err) - } - return &DBStore{ - db: db, - } -} - -// Get retrieves a persisted value for a specific key. If there is no results -// ErrNotFound is returned. The provided parameter should be either a byte slice or -// a struct that implements the encoding.BinaryUnmarshaler interface -func (s *DBStore) Get(key string, i interface{}) (err error) { - has, err := s.db.Has([]byte(key), nil) - if err != nil || !has { - return ErrNotFound - } - - data, err := s.db.Get([]byte(key), nil) - if err == leveldb.ErrNotFound { - return ErrNotFound - } - - unmarshaler, ok := i.(encoding.BinaryUnmarshaler) - if !ok { - return json.Unmarshal(data, i) - } - return unmarshaler.UnmarshalBinary(data) -} - -// Put stores an object that implements Binary for a specific key. -func (s *DBStore) Put(key string, i interface{}) (err error) { - var bytes []byte - if marshaler, ok := i.(encoding.BinaryMarshaler); ok { - if bytes, err = marshaler.MarshalBinary(); err != nil { - return err - } - } else { - if bytes, err = json.Marshal(i); err != nil { - return err - } - } - return s.db.Put([]byte(key), bytes, nil) -} - -// Delete removes entries stored under a specific key. -func (s *DBStore) Delete(key string) (err error) { - return s.db.Delete([]byte(key), nil) -} - -// Close releases the resources used by the underlying LevelDB. -func (s *DBStore) Close() error { - return s.db.Close() -} diff --git a/swarm/state/dbstore_test.go b/swarm/state/dbstore_test.go deleted file mode 100644 index f7098956d0..0000000000 --- a/swarm/state/dbstore_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package state - -import ( - "bytes" - "errors" - "io/ioutil" - "os" - "strings" - "testing" -) - -var ErrInvalidArraySize = errors.New("invalid byte array size") -var ErrInvalidValuePersisted = errors.New("invalid value was persisted to the db") - -type SerializingType struct { - key string - value string -} - -func (st *SerializingType) MarshalBinary() (data []byte, err error) { - d := []byte(strings.Join([]string{st.key, st.value}, ";")) - - return d, nil -} - -func (st *SerializingType) UnmarshalBinary(data []byte) (err error) { - d := bytes.Split(data, []byte(";")) - l := len(d) - if l == 0 { - return ErrInvalidArraySize - } - if l == 2 { - keyLen := len(d[0]) - st.key = string(d[0][:keyLen]) - - valLen := len(d[1]) - st.value = string(d[1][:valLen]) - } - - return nil -} - -// TestDBStore tests basic functionality of DBStore. -func TestDBStore(t *testing.T) { - dir, err := ioutil.TempDir("", "db_store_test") - if err != nil { - panic(err) - } - defer os.RemoveAll(dir) - - store, err := NewDBStore(dir) - if err != nil { - t.Fatal(err) - } - - testStore(t, store) - - store.Close() - - persistedStore, err := NewDBStore(dir) - if err != nil { - t.Fatal(err) - } - defer persistedStore.Close() - - testPersistedStore(t, persistedStore) -} - -func testStore(t *testing.T, store Store) { - ser := &SerializingType{key: "key1", value: "value1"} - jsonify := []string{"a", "b", "c"} - - err := store.Put(ser.key, ser) - if err != nil { - t.Fatal(err) - } - - err = store.Put("key2", jsonify) - if err != nil { - t.Fatal(err) - } - -} - -func testPersistedStore(t *testing.T, store Store) { - ser := &SerializingType{} - - err := store.Get("key1", ser) - if err != nil { - t.Fatal(err) - } - - if ser.key != "key1" || ser.value != "value1" { - t.Fatal(ErrInvalidValuePersisted) - } - - as := []string{} - err = store.Get("key2", &as) - if err != nil { - t.Fatal(err) - } - - if len(as) != 3 { - t.Fatalf("serialized array did not match expectation") - } - if as[0] != "a" || as[1] != "b" || as[2] != "c" { - t.Fatalf("elements serialized did not match expected values") - } -} diff --git a/swarm/storage/chunker.go b/swarm/storage/chunker.go deleted file mode 100644 index b2f0f5633c..0000000000 --- a/swarm/storage/chunker.go +++ /dev/null @@ -1,612 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package storage - -import ( - "context" - "encoding/binary" - "errors" - "fmt" - "io" - "sync" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/spancontext" - opentracing "github.com/opentracing/opentracing-go" - olog "github.com/opentracing/opentracing-go/log" -) - -/* -The distributed storage implemented in this package requires fix sized chunks of content. - -Chunker is the interface to a component that is responsible for disassembling and assembling larger data. - -TreeChunker implements a Chunker based on a tree structure defined as follows: - -1 each node in the tree including the root and other branching nodes are stored as a chunk. - -2 branching nodes encode data contents that includes the size of the dataslice covered by its entire subtree under the node as well as the hash keys of all its children : -data_{i} := size(subtree_{i}) || key_{j} || key_{j+1} .... || key_{j+n-1} - -3 Leaf nodes encode an actual subslice of the input data. - -4 if data size is not more than maximum chunksize, the data is stored in a single chunk - key = hash(int64(size) + data) - -5 if data size is more than chunksize*branches^l, but no more than chunksize* - branches^(l+1), the data vector is split into slices of chunksize* - branches^l length (except the last one). - key = hash(int64(size) + key(slice0) + key(slice1) + ...) - - The underlying hash function is configurable -*/ - -/* -Tree chunker is a concrete implementation of data chunking. -This chunker works in a simple way, it builds a tree out of the document so that each node either represents a chunk of real data or a chunk of data representing an branching non-leaf node of the tree. In particular each such non-leaf chunk will represent is a concatenation of the hash of its respective children. This scheme simultaneously guarantees data integrity as well as self addressing. Abstract nodes are transparent since their represented size component is strictly greater than their maximum data size, since they encode a subtree. - -If all is well it is possible to implement this by simply composing readers so that no extra allocation or buffering is necessary for the data splitting and joining. This means that in principle there can be direct IO between : memory, file system, network socket (bzz peers storage request is read from the socket). In practice there may be need for several stages of internal buffering. -The hashing itself does use extra copies and allocation though, since it does need it. -*/ - -type ChunkerParams struct { - chunkSize int64 - hashSize int64 -} - -type SplitterParams struct { - ChunkerParams - reader io.Reader - putter Putter - addr Address -} - -type TreeSplitterParams struct { - SplitterParams - size int64 -} - -type JoinerParams struct { - ChunkerParams - addr Address - getter Getter - // TODO: there is a bug, so depth can only be 0 today, see: https://github.com/ethersphere/go-ethereum/issues/344 - depth int - ctx context.Context -} - -type TreeChunker struct { - ctx context.Context - - branches int64 - dataSize int64 - data io.Reader - // calculated - addr Address - depth int - hashSize int64 // self.hashFunc.New().Size() - chunkSize int64 // hashSize* branches - workerCount int64 // the number of worker routines used - workerLock sync.RWMutex // lock for the worker count - jobC chan *hashJob - wg *sync.WaitGroup - putter Putter - getter Getter - errC chan error - quitC chan bool -} - -/* - Join reconstructs original content based on a root key. - When joining, the caller gets returned a Lazy SectionReader, which is - seekable and implements on-demand fetching of chunks as and where it is read. - New chunks to retrieve are coming from the getter, which the caller provides. - If an error is encountered during joining, it appears as a reader error. - The SectionReader. - As a result, partial reads from a document are possible even if other parts - are corrupt or lost. - The chunks are not meant to be validated by the chunker when joining. This - is because it is left to the DPA to decide which sources are trusted. -*/ -func TreeJoin(ctx context.Context, addr Address, getter Getter, depth int) *LazyChunkReader { - jp := &JoinerParams{ - ChunkerParams: ChunkerParams{ - chunkSize: chunk.DefaultSize, - hashSize: int64(len(addr)), - }, - addr: addr, - getter: getter, - depth: depth, - ctx: ctx, - } - - return NewTreeJoiner(jp).Join(ctx) -} - -/* - When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Key), the root hash of the entire content will fill this once processing finishes. - New chunks to store are store using the putter which the caller provides. -*/ -func TreeSplit(ctx context.Context, data io.Reader, size int64, putter Putter) (k Address, wait func(context.Context) error, err error) { - tsp := &TreeSplitterParams{ - SplitterParams: SplitterParams{ - ChunkerParams: ChunkerParams{ - chunkSize: chunk.DefaultSize, - hashSize: putter.RefSize(), - }, - reader: data, - putter: putter, - }, - size: size, - } - return NewTreeSplitter(tsp).Split(ctx) -} - -func NewTreeJoiner(params *JoinerParams) *TreeChunker { - tc := &TreeChunker{} - tc.hashSize = params.hashSize - tc.branches = params.chunkSize / params.hashSize - tc.addr = params.addr - tc.getter = params.getter - tc.depth = params.depth - tc.chunkSize = params.chunkSize - tc.workerCount = 0 - tc.jobC = make(chan *hashJob, 2*ChunkProcessors) - tc.wg = &sync.WaitGroup{} - tc.errC = make(chan error) - tc.quitC = make(chan bool) - - tc.ctx = params.ctx - - return tc -} - -func NewTreeSplitter(params *TreeSplitterParams) *TreeChunker { - tc := &TreeChunker{} - tc.data = params.reader - tc.dataSize = params.size - tc.hashSize = params.hashSize - tc.branches = params.chunkSize / params.hashSize - tc.addr = params.addr - tc.chunkSize = params.chunkSize - tc.putter = params.putter - tc.workerCount = 0 - tc.jobC = make(chan *hashJob, 2*ChunkProcessors) - tc.wg = &sync.WaitGroup{} - tc.errC = make(chan error) - tc.quitC = make(chan bool) - - return tc -} - -type hashJob struct { - key Address - chunk []byte - size int64 - parentWg *sync.WaitGroup -} - -func (tc *TreeChunker) incrementWorkerCount() { - tc.workerLock.Lock() - defer tc.workerLock.Unlock() - tc.workerCount += 1 -} - -func (tc *TreeChunker) getWorkerCount() int64 { - tc.workerLock.RLock() - defer tc.workerLock.RUnlock() - return tc.workerCount -} - -func (tc *TreeChunker) decrementWorkerCount() { - tc.workerLock.Lock() - defer tc.workerLock.Unlock() - tc.workerCount -= 1 -} - -func (tc *TreeChunker) Split(ctx context.Context) (k Address, wait func(context.Context) error, err error) { - if tc.chunkSize <= 0 { - panic("chunker must be initialised") - } - - tc.runWorker(ctx) - - depth := 0 - treeSize := tc.chunkSize - - // takes lowest depth such that chunksize*HashCount^(depth+1) > size - // power series, will find the order of magnitude of the data size in base hashCount or numbers of levels of branching in the resulting tree. - for ; treeSize < tc.dataSize; treeSize *= tc.branches { - depth++ - } - - key := make([]byte, tc.hashSize) - // this waitgroup member is released after the root hash is calculated - tc.wg.Add(1) - //launch actual recursive function passing the waitgroups - go tc.split(ctx, depth, treeSize/tc.branches, key, tc.dataSize, tc.wg) - - // closes internal error channel if all subprocesses in the workgroup finished - go func() { - // waiting for all threads to finish - tc.wg.Wait() - close(tc.errC) - }() - - defer close(tc.quitC) - defer tc.putter.Close() - select { - case err := <-tc.errC: - if err != nil { - return nil, nil, err - } - case <-ctx.Done(): - return nil, nil, ctx.Err() - } - - return key, tc.putter.Wait, nil -} - -func (tc *TreeChunker) split(ctx context.Context, depth int, treeSize int64, addr Address, size int64, parentWg *sync.WaitGroup) { - - // - - for depth > 0 && size < treeSize { - treeSize /= tc.branches - depth-- - } - - if depth == 0 { - // leaf nodes -> content chunks - chunkData := make([]byte, size+8) - binary.LittleEndian.PutUint64(chunkData[0:8], uint64(size)) - var readBytes int64 - for readBytes < size { - n, err := tc.data.Read(chunkData[8+readBytes:]) - readBytes += int64(n) - if err != nil && !(err == io.EOF && readBytes == size) { - tc.errC <- err - return - } - } - select { - case tc.jobC <- &hashJob{addr, chunkData, size, parentWg}: - case <-tc.quitC: - } - return - } - // dept > 0 - // intermediate chunk containing child nodes hashes - branchCnt := (size + treeSize - 1) / treeSize - - var chunk = make([]byte, branchCnt*tc.hashSize+8) - var pos, i int64 - - binary.LittleEndian.PutUint64(chunk[0:8], uint64(size)) - - childrenWg := &sync.WaitGroup{} - var secSize int64 - for i < branchCnt { - // the last item can have shorter data - if size-pos < treeSize { - secSize = size - pos - } else { - secSize = treeSize - } - // the hash of that data - subTreeAddress := chunk[8+i*tc.hashSize : 8+(i+1)*tc.hashSize] - - childrenWg.Add(1) - tc.split(ctx, depth-1, treeSize/tc.branches, subTreeAddress, secSize, childrenWg) - - i++ - pos += treeSize - } - // wait for all the children to complete calculating their hashes and copying them onto sections of the chunk - // parentWg.Add(1) - // go func() { - childrenWg.Wait() - - worker := tc.getWorkerCount() - if int64(len(tc.jobC)) > worker && worker < ChunkProcessors { - tc.runWorker(ctx) - - } - select { - case tc.jobC <- &hashJob{addr, chunk, size, parentWg}: - case <-tc.quitC: - } -} - -func (tc *TreeChunker) runWorker(ctx context.Context) { - tc.incrementWorkerCount() - go func() { - defer tc.decrementWorkerCount() - for { - select { - - case job, ok := <-tc.jobC: - if !ok { - return - } - - h, err := tc.putter.Put(ctx, job.chunk) - if err != nil { - tc.errC <- err - return - } - copy(job.key, h) - job.parentWg.Done() - case <-tc.quitC: - return - } - } - }() -} - -// LazyChunkReader implements LazySectionReader -type LazyChunkReader struct { - ctx context.Context - addr Address // root address - chunkData ChunkData - off int64 // offset - chunkSize int64 // inherit from chunker - branches int64 // inherit from chunker - hashSize int64 // inherit from chunker - depth int - getter Getter -} - -func (tc *TreeChunker) Join(ctx context.Context) *LazyChunkReader { - return &LazyChunkReader{ - addr: tc.addr, - chunkSize: tc.chunkSize, - branches: tc.branches, - hashSize: tc.hashSize, - depth: tc.depth, - getter: tc.getter, - ctx: tc.ctx, - } -} - -func (r *LazyChunkReader) Context() context.Context { - return r.ctx -} - -// Size is meant to be called on the LazySectionReader -func (r *LazyChunkReader) Size(ctx context.Context, quitC chan bool) (n int64, err error) { - metrics.GetOrRegisterCounter("lazychunkreader.size", nil).Inc(1) - - var sp opentracing.Span - var cctx context.Context - cctx, sp = spancontext.StartSpan( - ctx, - "lcr.size") - defer sp.Finish() - - log.Debug("lazychunkreader.size", "addr", r.addr) - if r.chunkData == nil { - startTime := time.Now() - chunkData, err := r.getter.Get(cctx, Reference(r.addr)) - if err != nil { - metrics.GetOrRegisterResettingTimer("lcr.getter.get.err", nil).UpdateSince(startTime) - return 0, err - } - metrics.GetOrRegisterResettingTimer("lcr.getter.get", nil).UpdateSince(startTime) - r.chunkData = chunkData - } - - s := r.chunkData.Size() - log.Debug("lazychunkreader.size", "key", r.addr, "size", s) - - return int64(s), nil -} - -// read at can be called numerous times -// concurrent reads are allowed -// Size() needs to be called synchronously on the LazyChunkReader first -func (r *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) { - metrics.GetOrRegisterCounter("lazychunkreader.readat", nil).Inc(1) - - var sp opentracing.Span - var cctx context.Context - cctx, sp = spancontext.StartSpan( - r.ctx, - "lcr.read") - defer sp.Finish() - - defer func() { - sp.LogFields( - olog.Int("off", int(off)), - olog.Int("read", read)) - }() - - // this is correct, a swarm doc cannot be zero length, so no EOF is expected - if len(b) == 0 { - return 0, nil - } - quitC := make(chan bool) - size, err := r.Size(cctx, quitC) - if err != nil { - log.Debug("lazychunkreader.readat.size", "size", size, "err", err) - return 0, err - } - - errC := make(chan error) - - // } - var treeSize int64 - var depth int - // calculate depth and max treeSize - treeSize = r.chunkSize - for ; treeSize < size; treeSize *= r.branches { - depth++ - } - wg := sync.WaitGroup{} - length := int64(len(b)) - for d := 0; d < r.depth; d++ { - off *= r.chunkSize - length *= r.chunkSize - } - wg.Add(1) - go r.join(cctx, b, off, off+length, depth, treeSize/r.branches, r.chunkData, &wg, errC, quitC) - go func() { - wg.Wait() - close(errC) - }() - - err = <-errC - if err != nil { - log.Debug("lazychunkreader.readat.errc", "err", err) - close(quitC) - return 0, err - } - if off+int64(len(b)) >= size { - log.Debug("lazychunkreader.readat.return at end", "size", size, "off", off) - return int(size - off), io.EOF - } - log.Debug("lazychunkreader.readat.errc", "buff", len(b)) - return len(b), nil -} - -func (r *LazyChunkReader) join(ctx context.Context, b []byte, off int64, eoff int64, depth int, treeSize int64, chunkData ChunkData, parentWg *sync.WaitGroup, errC chan error, quitC chan bool) { - defer parentWg.Done() - // find appropriate block level - for chunkData.Size() < uint64(treeSize) && depth > r.depth { - treeSize /= r.branches - depth-- - } - - // leaf chunk found - if depth == r.depth { - extra := 8 + eoff - int64(len(chunkData)) - if extra > 0 { - eoff -= extra - } - copy(b, chunkData[8+off:8+eoff]) - return // simply give back the chunks reader for content chunks - } - - // subtree - start := off / treeSize - end := (eoff + treeSize - 1) / treeSize - - // last non-leaf chunk can be shorter than default chunk size, let's not read it further then its end - currentBranches := int64(len(chunkData)-8) / r.hashSize - if end > currentBranches { - end = currentBranches - } - - wg := &sync.WaitGroup{} - defer wg.Wait() - for i := start; i < end; i++ { - soff := i * treeSize - roff := soff - seoff := soff + treeSize - - if soff < off { - soff = off - } - if seoff > eoff { - seoff = eoff - } - if depth > 1 { - wg.Wait() - } - wg.Add(1) - go func(j int64) { - childAddress := chunkData[8+j*r.hashSize : 8+(j+1)*r.hashSize] - startTime := time.Now() - chunkData, err := r.getter.Get(ctx, Reference(childAddress)) - if err != nil { - metrics.GetOrRegisterResettingTimer("lcr.getter.get.err", nil).UpdateSince(startTime) - select { - case errC <- fmt.Errorf("chunk %v-%v not found; key: %s", off, off+treeSize, fmt.Sprintf("%x", childAddress)): - case <-quitC: - } - return - } - metrics.GetOrRegisterResettingTimer("lcr.getter.get", nil).UpdateSince(startTime) - if l := len(chunkData); l < 9 { - select { - case errC <- fmt.Errorf("chunk %v-%v incomplete; key: %s, data length %v", off, off+treeSize, fmt.Sprintf("%x", childAddress), l): - case <-quitC: - } - return - } - if soff < off { - soff = off - } - r.join(ctx, b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/r.branches, chunkData, wg, errC, quitC) - }(i) - } //for -} - -// Read keeps a cursor so cannot be called simulateously, see ReadAt -func (r *LazyChunkReader) Read(b []byte) (read int, err error) { - log.Trace("lazychunkreader.read", "key", r.addr) - metrics.GetOrRegisterCounter("lazychunkreader.read", nil).Inc(1) - - read, err = r.ReadAt(b, r.off) - if err != nil && err != io.EOF { - log.Trace("lazychunkreader.readat", "read", read, "err", err) - metrics.GetOrRegisterCounter("lazychunkreader.read.err", nil).Inc(1) - } - - metrics.GetOrRegisterCounter("lazychunkreader.read.bytes", nil).Inc(int64(read)) - - r.off += int64(read) - return read, err -} - -// completely analogous to standard SectionReader implementation -var errWhence = errors.New("Seek: invalid whence") -var errOffset = errors.New("Seek: invalid offset") - -func (r *LazyChunkReader) Seek(offset int64, whence int) (int64, error) { - cctx, sp := spancontext.StartSpan( - r.ctx, - "lcr.seek") - defer sp.Finish() - - log.Debug("lazychunkreader.seek", "key", r.addr, "offset", offset) - switch whence { - default: - return 0, errWhence - case 0: - offset += 0 - case 1: - offset += r.off - case 2: - - if r.chunkData == nil { //seek from the end requires rootchunk for size. call Size first - _, err := r.Size(cctx, nil) - if err != nil { - return 0, fmt.Errorf("can't get size: %v", err) - } - } - offset += int64(r.chunkData.Size()) - } - - if offset < 0 { - return 0, errOffset - } - r.off = offset - return offset, nil -} diff --git a/swarm/storage/chunker_test.go b/swarm/storage/chunker_test.go deleted file mode 100644 index a0fe2e7697..0000000000 --- a/swarm/storage/chunker_test.go +++ /dev/null @@ -1,470 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "bytes" - "context" - "encoding/binary" - "fmt" - "io" - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/testutil" - "golang.org/x/crypto/sha3" -) - -/* -Tests TreeChunker by splitting and joining a random byte slice -*/ - -type test interface { - Fatalf(string, ...interface{}) - Logf(string, ...interface{}) -} - -type chunkerTester struct { - inputs map[uint64][]byte - t test -} - -var mockTag = chunk.NewTag(0, "mock-tag", 0) - -func newTestHasherStore(store ChunkStore, hash string) *hasherStore { - return NewHasherStore(store, MakeHashFunc(hash), false, chunk.NewTag(0, "test-tag", 0)) -} - -func testRandomBrokenData(n int, tester *chunkerTester) { - data := testutil.RandomReader(1, n) - brokendata := brokenLimitReader(data, n, n/2) - - buf := make([]byte, n) - _, err := brokendata.Read(buf) - if err == nil || err.Error() != "Broken reader" { - tester.t.Fatalf("Broken reader is not broken, hence broken. Returns: %v", err) - } - - data = testutil.RandomReader(2, n) - brokendata = brokenLimitReader(data, n, n/2) - - putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) - - expectedError := fmt.Errorf("Broken reader") - ctx := context.Background() - key, _, err := TreeSplit(ctx, brokendata, int64(n), putGetter) - if err == nil || err.Error() != expectedError.Error() { - tester.t.Fatalf("Not receiving the correct error! Expected %v, received %v", expectedError, err) - } - tester.t.Logf(" Address = %v\n", key) -} - -func testRandomData(usePyramid bool, hash string, n int, tester *chunkerTester) Address { - if tester.inputs == nil { - tester.inputs = make(map[uint64][]byte) - } - input, found := tester.inputs[uint64(n)] - var data io.Reader - if !found { - input = testutil.RandomBytes(1, n) - data = bytes.NewReader(input) - tester.inputs[uint64(n)] = input - } else { - data = io.LimitReader(bytes.NewReader(input), int64(n)) - } - - putGetter := newTestHasherStore(NewMapChunkStore(), hash) - - var addr Address - var wait func(context.Context) error - var err error - ctx := context.TODO() - if usePyramid { - addr, wait, err = PyramidSplit(ctx, data, putGetter, putGetter, mockTag) - } else { - addr, wait, err = TreeSplit(ctx, data, int64(n), putGetter) - } - if err != nil { - tester.t.Fatalf(err.Error()) - } - tester.t.Logf(" Address = %v\n", addr) - err = wait(ctx) - if err != nil { - tester.t.Fatalf(err.Error()) - } - - reader := TreeJoin(ctx, addr, putGetter, 0) - output := make([]byte, n) - r, err := reader.Read(output) - if r != n || err != io.EOF { - tester.t.Fatalf("read error read: %v n = %v err = %v\n", r, n, err) - } - if input != nil { - if !bytes.Equal(output, input) { - tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", input, output) - } - } - - // testing partial read - for i := 1; i < n; i += 10000 { - readableLength := n - i - r, err := reader.ReadAt(output, int64(i)) - if r != readableLength || err != io.EOF { - tester.t.Fatalf("readAt error with offset %v read: %v n = %v err = %v\n", i, r, readableLength, err) - } - if input != nil { - if !bytes.Equal(output[:readableLength], input[i:]) { - tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", input[i:], output[:readableLength]) - } - } - } - - return addr -} - -func TestSha3ForCorrectness(t *testing.T) { - tester := &chunkerTester{t: t} - - size := 4096 - input := make([]byte, size+8) - binary.LittleEndian.PutUint64(input[:8], uint64(size)) - - io.LimitReader(bytes.NewReader(input[8:]), int64(size)) - - rawSha3 := sha3.NewLegacyKeccak256() - rawSha3.Reset() - rawSha3.Write(input) - rawSha3Output := rawSha3.Sum(nil) - - sha3FromMakeFunc := MakeHashFunc(SHA3Hash)() - sha3FromMakeFunc.ResetWithLength(input[:8]) - sha3FromMakeFunc.Write(input[8:]) - sha3FromMakeFuncOutput := sha3FromMakeFunc.Sum(nil) - - if len(rawSha3Output) != len(sha3FromMakeFuncOutput) { - tester.t.Fatalf("Original SHA3 and abstracted Sha3 has different length %v:%v\n", len(rawSha3Output), len(sha3FromMakeFuncOutput)) - } - - if !bytes.Equal(rawSha3Output, sha3FromMakeFuncOutput) { - tester.t.Fatalf("Original SHA3 and abstracted Sha3 mismatch %v:%v\n", rawSha3Output, sha3FromMakeFuncOutput) - } - -} - -func TestDataAppend(t *testing.T) { - sizes := []int{1, 1, 1, 4095, 4096, 4097, 1, 1, 1, 123456, 2345678, 2345678} - appendSizes := []int{4095, 4096, 4097, 1, 1, 1, 8191, 8192, 8193, 9000, 3000, 5000} - - tester := &chunkerTester{t: t} - for i := range sizes { - n := sizes[i] - m := appendSizes[i] - - if tester.inputs == nil { - tester.inputs = make(map[uint64][]byte) - } - input, found := tester.inputs[uint64(n)] - var data io.Reader - if !found { - input = testutil.RandomBytes(i, n) - data = bytes.NewReader(input) - tester.inputs[uint64(n)] = input - } else { - data = io.LimitReader(bytes.NewReader(input), int64(n)) - } - - store := NewMapChunkStore() - putGetter := newTestHasherStore(store, SHA3Hash) - - ctx := context.TODO() - addr, wait, err := PyramidSplit(ctx, data, putGetter, putGetter, mockTag) - if err != nil { - tester.t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - tester.t.Fatalf(err.Error()) - } - //create a append data stream - appendInput, found := tester.inputs[uint64(m)] - var appendData io.Reader - if !found { - appendInput = testutil.RandomBytes(i, m) - appendData = bytes.NewReader(appendInput) - tester.inputs[uint64(m)] = appendInput - } else { - appendData = io.LimitReader(bytes.NewReader(appendInput), int64(m)) - } - - putGetter = newTestHasherStore(store, SHA3Hash) - newAddr, wait, err := PyramidAppend(ctx, addr, appendData, putGetter, putGetter, mockTag) - if err != nil { - tester.t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - tester.t.Fatalf(err.Error()) - } - - reader := TreeJoin(ctx, newAddr, putGetter, 0) - newOutput := make([]byte, n+m) - r, err := reader.Read(newOutput) - if r != (n + m) { - tester.t.Fatalf("read error read: %v n = %v m = %v err = %v\n", r, n, m, err) - } - - newInput := append(input, appendInput...) - if !bytes.Equal(newOutput, newInput) { - tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", newInput, newOutput) - } - } -} - -func TestRandomData(t *testing.T) { - // This test can validate files up to a relatively short length, as tree chunker slows down drastically. - // Validation of longer files is done by TestLocalStoreAndRetrieve in swarm package. - //sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4096, 4097, 8191, 8192, 8193, 12287, 12288, 12289, 524288, 524288 + 1, 524288 + 4097, 7 * 524288, 7*524288 + 1, 7*524288 + 4097} - sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4097, 8191, 8192, 12288, 12289, 524288} - tester := &chunkerTester{t: t} - - for _, s := range sizes { - treeChunkerAddress := testRandomData(false, SHA3Hash, s, tester) - pyramidChunkerAddress := testRandomData(true, SHA3Hash, s, tester) - if treeChunkerAddress.String() != pyramidChunkerAddress.String() { - tester.t.Fatalf("tree chunker and pyramid chunker key mismatch for size %v\n TC: %v\n PC: %v\n", s, treeChunkerAddress.String(), pyramidChunkerAddress.String()) - } - } - - for _, s := range sizes { - treeChunkerAddress := testRandomData(false, BMTHash, s, tester) - pyramidChunkerAddress := testRandomData(true, BMTHash, s, tester) - if treeChunkerAddress.String() != pyramidChunkerAddress.String() { - tester.t.Fatalf("tree chunker and pyramid chunker key mismatch for size %v\n TC: %v\n PC: %v\n", s, treeChunkerAddress.String(), pyramidChunkerAddress.String()) - } - } -} - -func TestRandomBrokenData(t *testing.T) { - sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4096, 4097, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678} - tester := &chunkerTester{t: t} - for _, s := range sizes { - testRandomBrokenData(s, tester) - } -} - -func benchReadAll(reader LazySectionReader) { - size, _ := reader.Size(context.TODO(), nil) - output := make([]byte, 1000) - for pos := int64(0); pos < size; pos += 1000 { - reader.ReadAt(output, pos) - } -} - -func benchmarkSplitJoin(n int, t *testing.B) { - t.ReportAllocs() - for i := 0; i < t.N; i++ { - data := testutil.RandomReader(i, n) - - putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) - ctx := context.TODO() - key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter, mockTag) - if err != nil { - t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - t.Fatalf(err.Error()) - } - reader := TreeJoin(ctx, key, putGetter, 0) - benchReadAll(reader) - } -} - -func benchmarkSplitTreeSHA3(n int, t *testing.B) { - t.ReportAllocs() - for i := 0; i < t.N; i++ { - data := testutil.RandomReader(i, n) - putGetter := newTestHasherStore(&FakeChunkStore{}, SHA3Hash) - - ctx := context.Background() - _, wait, err := TreeSplit(ctx, data, int64(n), putGetter) - if err != nil { - t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - t.Fatalf(err.Error()) - } - - } -} - -func benchmarkSplitTreeBMT(n int, t *testing.B) { - t.ReportAllocs() - for i := 0; i < t.N; i++ { - data := testutil.RandomReader(i, n) - putGetter := newTestHasherStore(&FakeChunkStore{}, BMTHash) - - ctx := context.Background() - _, wait, err := TreeSplit(ctx, data, int64(n), putGetter) - if err != nil { - t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - t.Fatalf(err.Error()) - } - } -} - -func benchmarkSplitPyramidBMT(n int, t *testing.B) { - t.ReportAllocs() - for i := 0; i < t.N; i++ { - data := testutil.RandomReader(i, n) - putGetter := newTestHasherStore(&FakeChunkStore{}, BMTHash) - - ctx := context.Background() - _, wait, err := PyramidSplit(ctx, data, putGetter, putGetter, mockTag) - if err != nil { - t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - t.Fatalf(err.Error()) - } - } -} - -func benchmarkSplitPyramidSHA3(n int, t *testing.B) { - t.ReportAllocs() - for i := 0; i < t.N; i++ { - data := testutil.RandomReader(i, n) - putGetter := newTestHasherStore(&FakeChunkStore{}, SHA3Hash) - - ctx := context.Background() - _, wait, err := PyramidSplit(ctx, data, putGetter, putGetter, mockTag) - if err != nil { - t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - t.Fatalf(err.Error()) - } - } -} - -func benchmarkSplitAppendPyramid(n, m int, t *testing.B) { - t.ReportAllocs() - for i := 0; i < t.N; i++ { - data := testutil.RandomReader(i, n) - data1 := testutil.RandomReader(t.N+i, m) - - store := NewMapChunkStore() - putGetter := newTestHasherStore(store, SHA3Hash) - - ctx := context.Background() - key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter, mockTag) - if err != nil { - t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - t.Fatalf(err.Error()) - } - - putGetter = newTestHasherStore(store, SHA3Hash) - _, wait, err = PyramidAppend(ctx, key, data1, putGetter, putGetter, mockTag) - if err != nil { - t.Fatalf(err.Error()) - } - err = wait(ctx) - if err != nil { - t.Fatalf(err.Error()) - } - } -} - -func BenchmarkSplitJoin_2(t *testing.B) { benchmarkSplitJoin(100, t) } -func BenchmarkSplitJoin_3(t *testing.B) { benchmarkSplitJoin(1000, t) } -func BenchmarkSplitJoin_4(t *testing.B) { benchmarkSplitJoin(10000, t) } -func BenchmarkSplitJoin_5(t *testing.B) { benchmarkSplitJoin(100000, t) } -func BenchmarkSplitJoin_6(t *testing.B) { benchmarkSplitJoin(1000000, t) } -func BenchmarkSplitJoin_7(t *testing.B) { benchmarkSplitJoin(10000000, t) } - -// func BenchmarkSplitJoin_8(t *testing.B) { benchmarkJoin(100000000, t) } - -func BenchmarkSplitTreeSHA3_2(t *testing.B) { benchmarkSplitTreeSHA3(100, t) } -func BenchmarkSplitTreeSHA3_2h(t *testing.B) { benchmarkSplitTreeSHA3(500, t) } -func BenchmarkSplitTreeSHA3_3(t *testing.B) { benchmarkSplitTreeSHA3(1000, t) } -func BenchmarkSplitTreeSHA3_3h(t *testing.B) { benchmarkSplitTreeSHA3(5000, t) } -func BenchmarkSplitTreeSHA3_4(t *testing.B) { benchmarkSplitTreeSHA3(10000, t) } -func BenchmarkSplitTreeSHA3_4h(t *testing.B) { benchmarkSplitTreeSHA3(50000, t) } -func BenchmarkSplitTreeSHA3_5(t *testing.B) { benchmarkSplitTreeSHA3(100000, t) } -func BenchmarkSplitTreeSHA3_6(t *testing.B) { benchmarkSplitTreeSHA3(1000000, t) } -func BenchmarkSplitTreeSHA3_7(t *testing.B) { benchmarkSplitTreeSHA3(10000000, t) } - -// func BenchmarkSplitTreeSHA3_8(t *testing.B) { benchmarkSplitTreeSHA3(100000000, t) } - -func BenchmarkSplitTreeBMT_2(t *testing.B) { benchmarkSplitTreeBMT(100, t) } -func BenchmarkSplitTreeBMT_2h(t *testing.B) { benchmarkSplitTreeBMT(500, t) } -func BenchmarkSplitTreeBMT_3(t *testing.B) { benchmarkSplitTreeBMT(1000, t) } -func BenchmarkSplitTreeBMT_3h(t *testing.B) { benchmarkSplitTreeBMT(5000, t) } -func BenchmarkSplitTreeBMT_4(t *testing.B) { benchmarkSplitTreeBMT(10000, t) } -func BenchmarkSplitTreeBMT_4h(t *testing.B) { benchmarkSplitTreeBMT(50000, t) } -func BenchmarkSplitTreeBMT_5(t *testing.B) { benchmarkSplitTreeBMT(100000, t) } -func BenchmarkSplitTreeBMT_6(t *testing.B) { benchmarkSplitTreeBMT(1000000, t) } -func BenchmarkSplitTreeBMT_7(t *testing.B) { benchmarkSplitTreeBMT(10000000, t) } - -// func BenchmarkSplitTreeBMT_8(t *testing.B) { benchmarkSplitTreeBMT(100000000, t) } - -func BenchmarkSplitPyramidSHA3_2(t *testing.B) { benchmarkSplitPyramidSHA3(100, t) } -func BenchmarkSplitPyramidSHA3_2h(t *testing.B) { benchmarkSplitPyramidSHA3(500, t) } -func BenchmarkSplitPyramidSHA3_3(t *testing.B) { benchmarkSplitPyramidSHA3(1000, t) } -func BenchmarkSplitPyramidSHA3_3h(t *testing.B) { benchmarkSplitPyramidSHA3(5000, t) } -func BenchmarkSplitPyramidSHA3_4(t *testing.B) { benchmarkSplitPyramidSHA3(10000, t) } -func BenchmarkSplitPyramidSHA3_4h(t *testing.B) { benchmarkSplitPyramidSHA3(50000, t) } -func BenchmarkSplitPyramidSHA3_5(t *testing.B) { benchmarkSplitPyramidSHA3(100000, t) } -func BenchmarkSplitPyramidSHA3_6(t *testing.B) { benchmarkSplitPyramidSHA3(1000000, t) } -func BenchmarkSplitPyramidSHA3_7(t *testing.B) { benchmarkSplitPyramidSHA3(10000000, t) } - -// func BenchmarkSplitPyramidSHA3_8(t *testing.B) { benchmarkSplitPyramidSHA3(100000000, t) } - -func BenchmarkSplitPyramidBMT_2(t *testing.B) { benchmarkSplitPyramidBMT(100, t) } -func BenchmarkSplitPyramidBMT_2h(t *testing.B) { benchmarkSplitPyramidBMT(500, t) } -func BenchmarkSplitPyramidBMT_3(t *testing.B) { benchmarkSplitPyramidBMT(1000, t) } -func BenchmarkSplitPyramidBMT_3h(t *testing.B) { benchmarkSplitPyramidBMT(5000, t) } -func BenchmarkSplitPyramidBMT_4(t *testing.B) { benchmarkSplitPyramidBMT(10000, t) } -func BenchmarkSplitPyramidBMT_4h(t *testing.B) { benchmarkSplitPyramidBMT(50000, t) } -func BenchmarkSplitPyramidBMT_5(t *testing.B) { benchmarkSplitPyramidBMT(100000, t) } -func BenchmarkSplitPyramidBMT_6(t *testing.B) { benchmarkSplitPyramidBMT(1000000, t) } -func BenchmarkSplitPyramidBMT_7(t *testing.B) { benchmarkSplitPyramidBMT(10000000, t) } - -// func BenchmarkSplitPyramidBMT_8(t *testing.B) { benchmarkSplitPyramidBMT(100000000, t) } - -func BenchmarkSplitAppendPyramid_2(t *testing.B) { benchmarkSplitAppendPyramid(100, 1000, t) } -func BenchmarkSplitAppendPyramid_2h(t *testing.B) { benchmarkSplitAppendPyramid(500, 1000, t) } -func BenchmarkSplitAppendPyramid_3(t *testing.B) { benchmarkSplitAppendPyramid(1000, 1000, t) } -func BenchmarkSplitAppendPyramid_4(t *testing.B) { benchmarkSplitAppendPyramid(10000, 1000, t) } -func BenchmarkSplitAppendPyramid_4h(t *testing.B) { benchmarkSplitAppendPyramid(50000, 1000, t) } -func BenchmarkSplitAppendPyramid_5(t *testing.B) { benchmarkSplitAppendPyramid(1000000, 1000, t) } -func BenchmarkSplitAppendPyramid_6(t *testing.B) { benchmarkSplitAppendPyramid(1000000, 1000, t) } -func BenchmarkSplitAppendPyramid_7(t *testing.B) { benchmarkSplitAppendPyramid(10000000, 1000, t) } - -// func BenchmarkAppendPyramid_8(t *testing.B) { benchmarkAppendPyramid(100000000, 1000, t) } - -// go test -timeout 20m -cpu 4 -bench=./swarm/storage -run no -// If you dont add the timeout argument above .. the benchmark will timeout and dump diff --git a/swarm/storage/common_test.go b/swarm/storage/common_test.go deleted file mode 100644 index 100e778a39..0000000000 --- a/swarm/storage/common_test.go +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "bytes" - "context" - "flag" - "fmt" - "io" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/mattn/go-colorable" -) - -var ( - loglevel = flag.Int("loglevel", 3, "verbosity of logs") - getTimeout = 30 * time.Second -) - -func init() { - flag.Parse() - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) -} - -type brokenLimitedReader struct { - lr io.Reader - errAt int - off int - size int -} - -func brokenLimitReader(data io.Reader, size int, errAt int) *brokenLimitedReader { - return &brokenLimitedReader{ - lr: data, - errAt: errAt, - size: size, - } -} - -func mputRandomChunks(store ChunkStore, n int) ([]Chunk, error) { - return mput(store, n, GenerateRandomChunk) -} - -func mput(store ChunkStore, n int, f func(i int64) Chunk) (hs []Chunk, err error) { - // put to localstore and wait for stored channel - // does not check delivery error state - errc := make(chan error) - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) - defer cancel() - for i := int64(0); i < int64(n); i++ { - ch := f(chunk.DefaultSize) - go func() { - _, err := store.Put(ctx, chunk.ModePutUpload, ch) - select { - case errc <- err: - case <-ctx.Done(): - } - }() - hs = append(hs, ch) - } - - // wait for all chunks to be stored - for i := 0; i < n; i++ { - err := <-errc - if err != nil { - return nil, err - } - } - return hs, nil -} - -func mget(store ChunkStore, hs []Address, f func(h Address, chunk Chunk) error) error { - wg := sync.WaitGroup{} - wg.Add(len(hs)) - errc := make(chan error) - - for _, k := range hs { - go func(h Address) { - defer wg.Done() - // TODO: write timeout with context - ch, err := store.Get(context.TODO(), chunk.ModeGetRequest, h) - if err != nil { - errc <- err - return - } - if f != nil { - err = f(h, ch) - if err != nil { - errc <- err - return - } - } - }(k) - } - go func() { - wg.Wait() - close(errc) - }() - var err error - timeout := 20 * time.Second - select { - case err = <-errc: - case <-time.NewTimer(timeout).C: - err = fmt.Errorf("timed out after %v", timeout) - } - return err -} - -func (r *brokenLimitedReader) Read(buf []byte) (int, error) { - if r.off+len(buf) > r.errAt { - return 0, fmt.Errorf("Broken reader") - } - r.off += len(buf) - return r.lr.Read(buf) -} - -func testStoreRandom(m ChunkStore, n int, t *testing.T) { - chunks, err := mputRandomChunks(m, n) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - err = mget(m, chunkAddresses(chunks), nil) - if err != nil { - t.Fatalf("testStore failed: %v", err) - } -} - -func testStoreCorrect(m ChunkStore, n int, t *testing.T) { - chunks, err := mputRandomChunks(m, n) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - f := func(h Address, chunk Chunk) error { - if !bytes.Equal(h, chunk.Address()) { - return fmt.Errorf("key does not match retrieved chunk Address") - } - hasher := MakeHashFunc(DefaultHash)() - data := chunk.Data() - hasher.ResetWithLength(data[:8]) - hasher.Write(data[8:]) - exp := hasher.Sum(nil) - if !bytes.Equal(h, exp) { - return fmt.Errorf("key is not hash of chunk data") - } - return nil - } - err = mget(m, chunkAddresses(chunks), f) - if err != nil { - t.Fatalf("testStore failed: %v", err) - } -} - -func benchmarkStorePut(store ChunkStore, n int, b *testing.B) { - chunks := make([]Chunk, n) - i := 0 - f := func(dataSize int64) Chunk { - chunk := GenerateRandomChunk(dataSize) - chunks[i] = chunk - i++ - return chunk - } - - mput(store, n, f) - - f = func(dataSize int64) Chunk { - chunk := chunks[i] - i++ - return chunk - } - - b.ReportAllocs() - b.ResetTimer() - - for j := 0; j < b.N; j++ { - i = 0 - mput(store, n, f) - } -} - -func benchmarkStoreGet(store ChunkStore, n int, b *testing.B) { - chunks, err := mputRandomChunks(store, n) - if err != nil { - b.Fatalf("expected no error, got %v", err) - } - b.ReportAllocs() - b.ResetTimer() - addrs := chunkAddresses(chunks) - for i := 0; i < b.N; i++ { - err := mget(store, addrs, nil) - if err != nil { - b.Fatalf("mget failed: %v", err) - } - } -} - -// MapChunkStore is a very simple ChunkStore implementation to store chunks in a map in memory. -type MapChunkStore struct { - chunks map[string]Chunk - mu sync.RWMutex -} - -func NewMapChunkStore() *MapChunkStore { - return &MapChunkStore{ - chunks: make(map[string]Chunk), - } -} - -func (m *MapChunkStore) Put(_ context.Context, _ chunk.ModePut, ch Chunk) (bool, error) { - m.mu.Lock() - defer m.mu.Unlock() - _, exists := m.chunks[ch.Address().Hex()] - m.chunks[ch.Address().Hex()] = ch - return exists, nil -} - -func (m *MapChunkStore) Get(_ context.Context, _ chunk.ModeGet, ref Address) (Chunk, error) { - m.mu.RLock() - defer m.mu.RUnlock() - chunk := m.chunks[ref.Hex()] - if chunk == nil { - return nil, ErrChunkNotFound - } - return chunk, nil -} - -// Need to implement Has from SyncChunkStore -func (m *MapChunkStore) Has(ctx context.Context, ref Address) (has bool, err error) { - m.mu.RLock() - defer m.mu.RUnlock() - - _, has = m.chunks[ref.Hex()] - return has, nil -} - -func (m *MapChunkStore) Set(ctx context.Context, mode chunk.ModeSet, addr chunk.Address) (err error) { - return nil -} - -func (m *MapChunkStore) LastPullSubscriptionBinID(bin uint8) (id uint64, err error) { - return 0, nil -} - -func (m *MapChunkStore) SubscribePull(ctx context.Context, bin uint8, since, until uint64) (c <-chan chunk.Descriptor, stop func()) { - return nil, nil -} - -func (m *MapChunkStore) Close() error { - return nil -} - -func chunkAddresses(chunks []Chunk) []Address { - addrs := make([]Address, len(chunks)) - for i, ch := range chunks { - addrs[i] = ch.Address() - } - return addrs -} diff --git a/swarm/storage/encryption/encryption.go b/swarm/storage/encryption/encryption.go deleted file mode 100644 index 6fbdab062b..0000000000 --- a/swarm/storage/encryption/encryption.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package encryption - -import ( - "crypto/rand" - "encoding/binary" - "fmt" - "hash" - "sync" -) - -const KeyLength = 32 - -type Key []byte - -type Encryption interface { - Encrypt(data []byte) ([]byte, error) - Decrypt(data []byte) ([]byte, error) -} - -type encryption struct { - key Key // the encryption key (hashSize bytes long) - keyLen int // length of the key = length of blockcipher block - padding int // encryption will pad the data upto this if > 0 - initCtr uint32 // initial counter used for counter mode blockcipher - hashFunc func() hash.Hash // hasher constructor function -} - -// New constructs a new encryptor/decryptor -func New(key Key, padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption { - return &encryption{ - key: key, - keyLen: len(key), - padding: padding, - initCtr: initCtr, - hashFunc: hashFunc, - } -} - -// Encrypt encrypts the data and does padding if specified -func (e *encryption) Encrypt(data []byte) ([]byte, error) { - length := len(data) - outLength := length - isFixedPadding := e.padding > 0 - if isFixedPadding { - if length > e.padding { - return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding) - } - outLength = e.padding - } - out := make([]byte, outLength) - e.transform(data, out) - return out, nil -} - -// Decrypt decrypts the data, if padding was used caller must know original length and truncate -func (e *encryption) Decrypt(data []byte) ([]byte, error) { - length := len(data) - if e.padding > 0 && length != e.padding { - return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding) - } - out := make([]byte, length) - e.transform(data, out) - return out, nil -} - -// -func (e *encryption) transform(in, out []byte) { - inLength := len(in) - wg := sync.WaitGroup{} - wg.Add((inLength-1)/e.keyLen + 1) - for i := 0; i < inLength; i += e.keyLen { - l := min(e.keyLen, inLength-i) - // call transformations per segment (asyncronously) - go func(i int, x, y []byte) { - defer wg.Done() - e.Transcrypt(i, x, y) - }(i/e.keyLen, in[i:i+l], out[i:i+l]) - } - // pad the rest if out is longer - pad(out[inLength:]) - wg.Wait() -} - -// used for segmentwise transformation -// if in is shorter than out, padding is used -func (e *encryption) Transcrypt(i int, in []byte, out []byte) { - // first hash key with counter (initial counter + i) - hasher := e.hashFunc() - hasher.Write(e.key) - - ctrBytes := make([]byte, 4) - binary.LittleEndian.PutUint32(ctrBytes, uint32(i)+e.initCtr) - hasher.Write(ctrBytes) - - ctrHash := hasher.Sum(nil) - hasher.Reset() - - // second round of hashing for selective disclosure - hasher.Write(ctrHash) - segmentKey := hasher.Sum(nil) - hasher.Reset() - - // XOR bytes uptil length of in (out must be at least as long) - inLength := len(in) - for j := 0; j < inLength; j++ { - out[j] = in[j] ^ segmentKey[j] - } - // insert padding if out is longer - pad(out[inLength:]) -} - -func pad(b []byte) { - l := len(b) - for total := 0; total < l; { - read, _ := rand.Read(b[total:]) - total += read - } -} - -// GenerateRandomKey generates a random key of length l -func GenerateRandomKey(l int) Key { - key := make([]byte, l) - var total int - for total < l { - read, _ := rand.Read(key[total:]) - total += read - } - return key -} - -func min(x, y int) int { - if x < y { - return x - } - return y -} diff --git a/swarm/storage/encryption/encryption_test.go b/swarm/storage/encryption/encryption_test.go deleted file mode 100644 index 3b4f8a4e36..0000000000 --- a/swarm/storage/encryption/encryption_test.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package encryption - -import ( - "bytes" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/swarm/testutil" - "golang.org/x/crypto/sha3" -) - -var expectedTransformedHex = "352187af3a843decc63ceca6cb01ea39dbcf77caf0a8f705f5c30d557044ceec9392b94a79376f1e5c10cd0c0f2a98e5353bf22b3ea4fdac6677ee553dec192e3db64e179d0474e96088fb4abd2babd67de123fb398bdf84d818f7bda2c1ab60b3ea0e0569ae54aa969658eb4844e6960d2ff44d7c087ee3aaffa1c0ee5df7e50b615f7ad90190f022934ad5300c7d1809bfe71a11cc04cece5274eb97a5f20350630522c1dbb7cebaf4f97f84e03f5cfd88f2b48880b25d12f4d5e75c150f704ef6b46c72e07db2b705ac3644569dccd22fd8f964f6ef787fda63c46759af334e6f665f70eac775a7017acea49f3c7696151cb1b9434fa4ac27fb803921ffb5ec58dafa168098d7d5b97e384be3384cf5bc235c3d887fef89fe76c0065f9b8d6ad837b442340d9e797b46ef5709ea3358bc415df11e4830de986ef0f1c418ffdcc80e9a3cda9bea0ab5676c0d4240465c43ba527e3b4ea50b4f6255b510e5d25774a75449b0bd71e56c537ade4fcf0f4d63c99ae1dbb5a844971e2c19941b8facfcfc8ee3056e7cb3c7114c5357e845b52f7103cb6e00d2308c37b12baa5b769e1cc7b00fc06f2d16e70cc27a82cb9c1a4e40cb0d43907f73df2c9db44f1b51a6b0bc6d09f77ac3be14041fae3f9df2da42df43ae110904f9ecee278030185254d7c6e918a5512024d047f77a992088cb3190a6587aa54d0c7231c1cd2e455e0d4c07f74bece68e29cd8ba0190c0bcfb26d24634af5d91a81ef5d4dd3d614836ce942ddbf7bb1399317f4c03faa675f325f18324bf9433844bfe5c4cc04130c8d5c329562b7cd66e72f7355de8f5375a72202971613c32bd7f3fcdcd51080758cd1d0a46dbe8f0374381dbc359f5864250c63dde8131cbd7c98ae2b0147d6ea4bf65d1443d511b18e6d608bbb46ac036353b4c51df306a10a6f6939c38629a5c18aaf89cac04bd3ad5156e6b92011c88341cb08551bab0a89e6a46538f5af33b86121dba17e3a434c273f385cd2e8cb90bdd32747d8425d929ccbd9b0815c73325988855549a8489dfd047daf777aaa3099e54cf997175a5d9e1edfe363e3b68c70e02f6bf4fcde6a0f3f7d0e7e98bde1a72ae8b6cd27b32990680cc4a04fc467f41c5adcaddabfc71928a3f6872c360c1d765260690dd28b269864c8e380d9c92ef6b89b0094c8f9bb22608b4156381b19b920e9583c9616ce5693b4d2a6c689f02e6a91584a8e501e107403d2689dd0045269dd9946c0e969fb656a3b39d84a798831f5f9290f163eb2f97d3ae25071324e95e2256d9c1e56eb83c26397855323edc202d56ad05894333b7f0ed3c1e4734782eb8bd5477242fd80d7a89b12866f85cfae476322f032465d6b1253993033fccd4723530630ab97a1566460af9c90c9da843c229406e65f3fa578bd6bf04dee9b6153807ddadb8ceefc5c601a8ab26023c67b1ab1e8e0f29ce94c78c308005a781853e7a2e0e51738939a657c987b5e611f32f47b5ff461c52e63e0ea390515a8e1f5393dae54ea526934b5f310b76e3fa050e40718cb4c8a20e58946d6ee1879f08c52764422fe542b3240e75eccb7aa75b1f8a651e37a3bc56b0932cdae0e985948468db1f98eb4b77b82081ea25d8a762db00f7898864984bd80e2f3f35f236bf57291dec28f550769943bcfb6f884b7687589b673642ef7fe5d7d5a87d3eca5017f83ccb9a3310520474479464cb3f433440e7e2f1e28c0aef700a45848573409e7ab66e0cfd4fe5d2147ace81bc65fd8891f6245cd69246bbf5c27830e5ab882dd1d02aba34ff6ca9af88df00fd602892f02fedbdc65dedec203faf3f8ff4a97314e0ddb58b9ab756a61a562597f4088b445fcc3b28a708ca7b1485dcd791b779fbf2b3ef1ec5c6205f595fbe45a02105034147e5a146089c200a49dae33ae051a08ea5f974a21540aaeffa7f9d9e3d35478016fb27b871036eb27217a5b834b461f535752fb5f1c8dded3ae14ce3a2ef6639e2fe41939e3509e46e347a95d50b2080f1ba42c804b290ddc912c952d1cec3f2661369f738feacc0dbf1ea27429c644e45f9e26f30c341acd34c7519b2a1663e334621691e810767e9918c2c547b2e23cce915f97d26aac8d0d2fcd3edb7986ad4e2b8a852edebad534cb6c0e9f0797d3563e5409d7e068e48356c67ce519246cd9c560e881453df97cbba562018811e6cf8c327f399d1d1253ab47a19f4a0ccc7c6d86a9603e0551da310ea595d71305c4aad96819120a92cdbaf1f77ec8df9cc7c838c0d4de1e8692dd81da38268d1d71324bcffdafbe5122e4b81828e021e936d83ae8021eac592aa52cd296b5ce392c7173d622f8e07d18f59bb1b08ba15211af6703463b09b593af3c37735296816d9f2e7a369354a5374ea3955e14ca8ac56d5bfe4aef7a21bd825d6ae85530bee5d2aaaa4914981b3dfdb2e92ec2a27c83d74b59e84ff5c056f7d8945745f2efc3dcf28f288c6cd8383700fb2312f7001f24dd40015e436ae23e052fe9070ea9535b9c989898a9bda3d5382cf10e432fae6ccf0c825b3e6436edd3a9f8846e5606f8563931b5f29ba407c5236e5730225dda211a8504ec1817bc935e1fd9a532b648c502df302ed2063aed008fd5676131ac9e95998e9447b02bd29d77e38fcfd2959f2de929b31970335eb2a74348cc6918bc35b9bf749eab0fe304c946cd9e1ca284e6853c42646e60b6b39e0d3fb3c260abfc5c1b4ca3c3770f344118ca7c7f5c1ad1f123f8f369cd60afc3cdb3e9e81968c5c9fa7c8b014ffe0508dd4f0a2a976d5d1ca8fc9ad7a237d92cfe7b41413d934d6e142824b252699397e48e4bac4e91ebc10602720684bd0863773c548f9a2f9724245e47b129ecf65afd7252aac48c8a8d6fd3d888af592a01fb02dc71ed7538a700d3d16243e4621e0fcf9f8ed2b4e11c9fa9a95338bb1dac74a7d9bc4eb8cbf900b634a2a56469c00f5994e4f0934bdb947640e6d67e47d0b621aacd632bfd3c800bd7d93bd329f494a90e06ed51535831bd6e07ac1b4b11434ef3918fa9511813a002913f33f836454798b8d1787fea9a4c4743ba091ed192ed92f4d33e43a226bf9503e1a83a16dd340b3cbbf38af6db0d99201da8de529b4225f3d2fa2aad6621afc6c79ef3537720591edfc681ae6d00ede53ed724fc71b23b90d2e9b7158aaee98d626a4fe029107df2cb5f90147e07ebe423b1519d848af18af365c71bfd0665db46be493bbe99b79a188de0cf3594aef2299f0324075bdce9eb0b87bc29d62401ba4fd6ae48b1ba33261b5b845279becf38ee03e3dc5c45303321c5fac96fd02a3ad8c9e3b02127b320501333c9e6360440d1ad5e64a6239501502dde1a49c9abe33b66098458eee3d611bb06ffcd234a1b9aef4af5021cd61f0de6789f822ee116b5078aae8c129e8391d8987500d322b58edd1595dc570b57341f2df221b94a96ab7fbcf32a8ca9684196455694024623d7ed49f7d66e8dd453c0bae50e0d8b34377b22d0ece059e2c385dfc70b9089fcd27577c51f4d870b5738ee2b68c361a67809c105c7848b68860a829f29930857a9f9d40b14fd2384ac43bafdf43c0661103794c4bd07d1cfdd4681b6aeaefad53d4c1473359bcc5a83b09189352e5bb9a7498dd0effb89c35aad26954551f8b0621374b449bf515630bd3974dca982279733470fdd059aa9c3df403d8f22b38c4709c82d8f12b888e22990350490e16179caf406293cc9e65f116bafcbe96af132f679877061107a2f690a82a8cb46eea57a90abd23798c5937c6fe6b17be3f9bfa01ce117d2c268181b9095bf49f395fea07ca03838de0588c5e2db633e836d64488c1421e653ea52d810d096048c092d0da6e02fa6613890219f51a76148c8588c2487b171a28f17b7a299204874af0131725d793481333be5f08e86ca837a226850b0c1060891603bfecf9e55cddd22c0dbb28d495342d9cc3de8409f72e52a0115141cffe755c74f061c1a770428ccb0ae59536ee6fc074fbfc6cacb51a549d327527e20f8407477e60355863f1153f9ce95641198663c968874e7fdb29407bd771d94fdda8180cbb0358f5874738db705924b8cbe0cd5e1484aeb64542fe8f38667b7c34baf818c63b1e18440e9fba575254d063fd49f24ef26432f4eb323f3836972dca87473e3e9bb26dc3be236c3aae6bc8a6da567442309da0e8450e242fc9db836e2964f2c76a3b80a2c677979882dda7d7ebf62c93664018bcf4ec431fe6b403d49b3b36618b9c07c2d0d4569cb8d52223903debc72ec113955b206c34f1ae5300990ccfc0180f47d91afdb542b6312d12aeff7e19c645dc0b9fe6e3288e9539f6d5870f99882df187bfa6d24d179dfd1dac22212c8b5339f7171a3efc15b760fed8f68538bc5cbd845c2d1ab41f3a6c692820653eaef7930c02fbe6061d93805d73decdbb945572a7c44ed0241982a6e4d2d730898f82b3d9877cb7bca41cc6dcee67aa0c3d6db76f0b0a708ace0031113e48429de5d886c10e9200f68f32263a2fbf44a5992c2459fda7b8796ba796e3a0804fc25992ed2c9a5fe0580a6b809200ecde6caa0364b58be11564dcb9a616766dd7906db5636ee708b0204f38d309466d8d4a162965dd727e29f5a6c133e9b4ed5bafe803e479f9b2a7640c942c4a40b14ac7dc9828546052761a070f6404008f1ec3605836339c3da95a00b4fd81b2cabf88b51d2087d5b83e8c5b69bf96d8c72cbd278dad3bbb42b404b436f84ad688a22948adf60a81090f1e904291503c16e9f54b05fc76c881a5f95f0e732949e95d3f1bae2d3652a14fe0dda2d68879604657171856ef72637def2a96ac47d7b3fe86eb3198f5e0e626f06be86232305f2ae79ffcd2725e48208f9d8d63523f81915acc957563ab627cd6bc68c2a37d59fb0ed77a90aa9d085d6914a8ebada22a2c2d471b5163aeddd799d90fbb10ed6851ace2c4af504b7d572686700a59d6db46d5e42bb83f8e0c0ffe1dfa6582cc0b34c921ff6e85e83188d24906d5c08bb90069639e713051b3102b53e6f703e8210017878add5df68e6f2b108de279c5490e9eef5590185c4a1c744d4e00d244e1245a8805bd30407b1bc488db44870ccfd75a8af104df78efa2fb7ba31f048a263efdb3b63271fff4922bece9a71187108f65744a24f4947dc556b7440cb4fa45d296bb7f724588d1f245125b21ea063500029bd49650237f53899daf1312809552c81c5827341263cc807a29fe84746170cdfa1ff3838399a5645319bcaff674bb70efccdd88b3d3bb2f2d98111413585dc5d5bd5168f43b3f55e58972a5b2b9b3733febf02f931bd436648cb617c3794841aab961fe41277ab07812e1d3bc4ff6f4350a3e615bfba08c3b9480ef57904d3a16f7e916345202e3f93d11f7a7305170cb8c4eb9ac88ace8bbd1f377bdd5855d3162d6723d4435e84ce529b8f276a8927915ac759a0d04e5ca4a9d3da6291f0333b475df527e99fe38f7a4082662e8125936640c26dd1d17cf284ce6e2b17777a05aa0574f7793a6a062cc6f7263f7ab126b4528a17becfdec49ac0f7d8705aa1704af97fb861faa8a466161b2b5c08a5bacc79fe8500b913d65c8d3c52d1fd52d2ab2c9f52196e712455619c1cd3e0f391b274487944240e2ed8858dd0823c801094310024ae3fe4dd1cf5a2b6487b42cc5937bbafb193ee331d87e378258963d49b9da90899bbb4b88e79f78e866b0213f4719f67da7bcc2fce073c01e87c62ea3cdbcd589cfc41281f2f4c757c742d6d1e" - -var hashFunc = sha3.NewLegacyKeccak256 -var testKey Key - -func init() { - var err error - testKey, err = hexutil.Decode("0x8abf1502f557f15026716030fb6384792583daf39608a3cd02ff2f47e9bc6e49") - if err != nil { - panic(err.Error()) - } -} - -func TestEncryptDataLongerThanPadding(t *testing.T) { - enc := New(testKey, 4095, uint32(0), hashFunc) - - data := make([]byte, 4096) - - expectedError := "Data length longer than padding, data length 4096 padding 4095" - - _, err := enc.Encrypt(data) - if err == nil || err.Error() != expectedError { - t.Fatalf("Expected error \"%v\" got \"%v\"", expectedError, err) - } -} - -func TestEncryptDataZeroPadding(t *testing.T) { - enc := New(testKey, 0, uint32(0), hashFunc) - - data := make([]byte, 2048) - - encrypted, err := enc.Encrypt(data) - if err != nil { - t.Fatalf("Expected no error got %v", err) - } - if len(encrypted) != 2048 { - t.Fatalf("Encrypted data length expected \"%v\" got %v", 2048, len(encrypted)) - } -} - -func TestEncryptDataLengthEqualsPadding(t *testing.T) { - enc := New(testKey, 4096, uint32(0), hashFunc) - - data := make([]byte, 4096) - - encrypted, err := enc.Encrypt(data) - if err != nil { - t.Fatalf("Expected no error got %v", err) - } - encryptedHex := common.Bytes2Hex(encrypted) - expectedTransformed := common.Hex2Bytes(expectedTransformedHex) - - if !bytes.Equal(encrypted, expectedTransformed) { - t.Fatalf("Expected %v got %v", expectedTransformedHex, encryptedHex) - } -} - -func TestEncryptDataLengthSmallerThanPadding(t *testing.T) { - enc := New(testKey, 4096, uint32(0), hashFunc) - - data := make([]byte, 4080) - - encrypted, err := enc.Encrypt(data) - if err != nil { - t.Fatalf("Expected no error got %v", err) - } - if len(encrypted) != 4096 { - t.Fatalf("Encrypted data length expected %v got %v", 4096, len(encrypted)) - } -} - -func TestEncryptDataCounterNonZero(t *testing.T) { - // TODO -} - -func TestDecryptDataLengthNotEqualsPadding(t *testing.T) { - enc := New(testKey, 4096, uint32(0), hashFunc) - - data := make([]byte, 4097) - - expectedError := "Data length different than padding, data length 4097 padding 4096" - - _, err := enc.Decrypt(data) - if err == nil || err.Error() != expectedError { - t.Fatalf("Expected error \"%v\" got \"%v\"", expectedError, err) - } -} - -func TestEncryptDecryptIsIdentity(t *testing.T) { - testEncryptDecryptIsIdentity(t, 2048, 0, 2048, 32) - testEncryptDecryptIsIdentity(t, 4096, 0, 4096, 32) - testEncryptDecryptIsIdentity(t, 4096, 0, 1000, 32) - testEncryptDecryptIsIdentity(t, 32, 10, 32, 32) -} - -func testEncryptDecryptIsIdentity(t *testing.T, padding int, initCtr uint32, dataLength int, keyLength int) { - key := GenerateRandomKey(keyLength) - enc := New(key, padding, initCtr, hashFunc) - - data := testutil.RandomBytes(1, dataLength) - - encrypted, err := enc.Encrypt(data) - if err != nil { - t.Fatalf("Expected no error got %v", err) - } - - decrypted, err := enc.Decrypt(encrypted) - if err != nil { - t.Fatalf("Expected no error got %v", err) - } - if len(decrypted) != padding { - t.Fatalf("Expected decrypted data length %v got %v", padding, len(decrypted)) - } - - // we have to remove the extra bytes which were randomly added to fill until padding - if len(data) < padding { - decrypted = decrypted[:len(data)] - } - - if !bytes.Equal(data, decrypted) { - t.Fatalf("Expected decrypted %v got %v", common.Bytes2Hex(data), common.Bytes2Hex(decrypted)) - } -} diff --git a/swarm/storage/error.go b/swarm/storage/error.go deleted file mode 100644 index 1e412e55ce..0000000000 --- a/swarm/storage/error.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import "github.com/ethereum/go-ethereum/swarm/chunk" - -const ( - ErrInit = iota - ErrNotFound - ErrUnauthorized - ErrInvalidValue - ErrDataOverflow - ErrNothingToReturn - ErrInvalidSignature - ErrNotSynced -) - -// Errors are the same as the ones in chunk package for backward compatibility. -var ( - ErrChunkNotFound = chunk.ErrChunkNotFound - ErrChunkInvalid = chunk.ErrChunkNotFound -) diff --git a/swarm/storage/feed/binaryserializer.go b/swarm/storage/feed/binaryserializer.go deleted file mode 100644 index 4e4f67a094..0000000000 --- a/swarm/storage/feed/binaryserializer.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import "github.com/ethereum/go-ethereum/common/hexutil" - -type binarySerializer interface { - binaryPut(serializedData []byte) error - binaryLength() int - binaryGet(serializedData []byte) error -} - -// Values interface represents a string key-value store -// useful for building query strings -type Values interface { - Get(key string) string - Set(key, value string) -} - -type valueSerializer interface { - FromValues(values Values) error - AppendValues(values Values) -} - -// Hex serializes the structure and converts it to a hex string -func Hex(bin binarySerializer) string { - b := make([]byte, bin.binaryLength()) - bin.binaryPut(b) - return hexutil.Encode(b) -} diff --git a/swarm/storage/feed/binaryserializer_test.go b/swarm/storage/feed/binaryserializer_test.go deleted file mode 100644 index 37828d1c94..0000000000 --- a/swarm/storage/feed/binaryserializer_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "encoding/json" - "reflect" - "testing" - - "github.com/ethereum/go-ethereum/common/hexutil" -) - -// KV mocks a key value store -type KV map[string]string - -func (kv KV) Get(key string) string { - return kv[key] -} -func (kv KV) Set(key, value string) { - kv[key] = value -} - -func compareByteSliceToExpectedHex(t *testing.T, variableName string, actualValue []byte, expectedHex string) { - if hexutil.Encode(actualValue) != expectedHex { - t.Fatalf("%s: Expected %s to be %s, got %s", t.Name(), variableName, expectedHex, hexutil.Encode(actualValue)) - } -} - -func testBinarySerializerRecovery(t *testing.T, bin binarySerializer, expectedHex string) { - name := reflect.TypeOf(bin).Elem().Name() - serialized := make([]byte, bin.binaryLength()) - if err := bin.binaryPut(serialized); err != nil { - t.Fatalf("%s.binaryPut error when trying to serialize structure: %s", name, err) - } - - compareByteSliceToExpectedHex(t, name, serialized, expectedHex) - - recovered := reflect.New(reflect.TypeOf(bin).Elem()).Interface().(binarySerializer) - if err := recovered.binaryGet(serialized); err != nil { - t.Fatalf("%s.binaryGet error when trying to deserialize structure: %s", name, err) - } - - if !reflect.DeepEqual(bin, recovered) { - t.Fatalf("Expected that the recovered %s equals the marshalled %s", name, name) - } - - serializedWrongLength := make([]byte, 1) - copy(serializedWrongLength[:], serialized) - if err := recovered.binaryGet(serializedWrongLength); err == nil { - t.Fatalf("Expected %s.binaryGet to fail since data is too small", name) - } -} - -func testBinarySerializerLengthCheck(t *testing.T, bin binarySerializer) { - name := reflect.TypeOf(bin).Elem().Name() - // make a slice that is too small to contain the metadata - serialized := make([]byte, bin.binaryLength()-1) - - if err := bin.binaryPut(serialized); err == nil { - t.Fatalf("Expected %s.binaryPut to fail, since target slice is too small", name) - } -} - -func testValueSerializer(t *testing.T, v valueSerializer, expected KV) { - name := reflect.TypeOf(v).Elem().Name() - kv := make(KV) - - v.AppendValues(kv) - if !reflect.DeepEqual(expected, kv) { - expj, _ := json.Marshal(expected) - gotj, _ := json.Marshal(kv) - t.Fatalf("Expected %s.AppendValues to return %s, got %s", name, string(expj), string(gotj)) - } - - recovered := reflect.New(reflect.TypeOf(v).Elem()).Interface().(valueSerializer) - err := recovered.FromValues(kv) - if err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(recovered, v) { - t.Fatalf("Expected recovered %s to be the same", name) - } -} diff --git a/swarm/storage/feed/cacheentry.go b/swarm/storage/feed/cacheentry.go deleted file mode 100644 index 1c7e226198..0000000000 --- a/swarm/storage/feed/cacheentry.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "bytes" - "context" - "time" - - "github.com/ethereum/go-ethereum/swarm/storage" -) - -const ( - hasherCount = 8 - feedsHashAlgorithm = storage.SHA3Hash - defaultRetrieveTimeout = 1000 * time.Millisecond -) - -// cacheEntry caches the last known update of a specific Swarm feed. -type cacheEntry struct { - Update - *bytes.Reader - lastKey storage.Address -} - -// implements storage.LazySectionReader -func (r *cacheEntry) Size(ctx context.Context, _ chan bool) (int64, error) { - return int64(len(r.Update.data)), nil -} - -//returns the feed's topic -func (r *cacheEntry) Topic() Topic { - return r.Feed.Topic -} diff --git a/swarm/storage/feed/doc.go b/swarm/storage/feed/doc.go deleted file mode 100644 index 1f07948f21..0000000000 --- a/swarm/storage/feed/doc.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -Package feeds defines Swarm Feeds. - -Swarm Feeds allows a user to build an update feed about a particular topic -without resorting to ENS on each update. -The update scheme is built on swarm chunks with chunk keys following -a predictable, versionable pattern. - -A Feed is tied to a unique identifier that is deterministically generated out of -the chosen topic. - -A Feed is defined as the series of updates of a specific user about a particular topic - -Actual data updates are also made in the form of swarm chunks. The keys -of the updates are the hash of a concatenation of properties as follows: - -updateAddr = H(Feed, Epoch ID) -where H is the SHA3 hash function -Feed is the combination of Topic and the user address -Epoch ID is a time slot. See the lookup package for more information. - -A user looking up a the latest update in a Feed only needs to know the Topic -and the other user's address. - -The Feed Update data is: -updatedata = Feed|Epoch|data - -The full update data that goes in the chunk payload is: -updatedata|sign(updatedata) - -Structure Summary: - -Request: Feed Update with signature - Update: headers + data - Header: Protocol version and reserved for future use placeholders - ID: Information about how to locate a specific update - Feed: Represents a user's series of publications about a specific Topic - Topic: Item that the updates are about - User: User who updates the Feed - Epoch: time slot where the update is stored - -*/ -package feed diff --git a/swarm/storage/feed/error.go b/swarm/storage/feed/error.go deleted file mode 100644 index 206ba3316f..0000000000 --- a/swarm/storage/feed/error.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "fmt" -) - -const ( - ErrInit = iota - ErrNotFound - ErrIO - ErrUnauthorized - ErrInvalidValue - ErrDataOverflow - ErrNothingToReturn - ErrCorruptData - ErrInvalidSignature - ErrNotSynced - ErrPeriodDepth - ErrCnt -) - -// Error is a the typed error object used for Swarm feeds -type Error struct { - code int - err string -} - -// Error implements the error interface -func (e *Error) Error() string { - return e.err -} - -// Code returns the error code -// Error codes are enumerated in the error.go file within the feeds package -func (e *Error) Code() int { - return e.code -} - -// NewError creates a new Swarm feeds Error object with the specified code and custom error message -func NewError(code int, s string) error { - if code < 0 || code >= ErrCnt { - panic("no such error code!") - } - r := &Error{ - err: s, - } - switch code { - case ErrNotFound, ErrIO, ErrUnauthorized, ErrInvalidValue, ErrDataOverflow, ErrNothingToReturn, ErrInvalidSignature, ErrNotSynced, ErrPeriodDepth, ErrCorruptData: - r.code = code - } - return r -} - -// NewErrorf is a convenience version of NewError that incorporates printf-style formatting -func NewErrorf(code int, format string, args ...interface{}) error { - return NewError(code, fmt.Sprintf(format, args...)) -} diff --git a/swarm/storage/feed/feed.go b/swarm/storage/feed/feed.go deleted file mode 100644 index b6ea665a6f..0000000000 --- a/swarm/storage/feed/feed.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "hash" - "unsafe" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -// Feed represents a particular user's stream of updates on a topic -type Feed struct { - Topic Topic `json:"topic"` - User common.Address `json:"user"` -} - -// Feed layout: -// TopicLength bytes -// userAddr common.AddressLength bytes -const feedLength = TopicLength + common.AddressLength - -// mapKey calculates a unique id for this feed. Used by the cache map in `Handler` -func (f *Feed) mapKey() uint64 { - serializedData := make([]byte, feedLength) - f.binaryPut(serializedData) - hasher := hashPool.Get().(hash.Hash) - defer hashPool.Put(hasher) - hasher.Reset() - hasher.Write(serializedData) - hash := hasher.Sum(nil) - return *(*uint64)(unsafe.Pointer(&hash[0])) -} - -// binaryPut serializes this feed instance into the provided slice -func (f *Feed) binaryPut(serializedData []byte) error { - if len(serializedData) != feedLength { - return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize feed. Expected %d, got %d", feedLength, len(serializedData)) - } - var cursor int - copy(serializedData[cursor:cursor+TopicLength], f.Topic[:TopicLength]) - cursor += TopicLength - - copy(serializedData[cursor:cursor+common.AddressLength], f.User[:]) - cursor += common.AddressLength - - return nil -} - -// binaryLength returns the expected size of this structure when serialized -func (f *Feed) binaryLength() int { - return feedLength -} - -// binaryGet restores the current instance from the information contained in the passed slice -func (f *Feed) binaryGet(serializedData []byte) error { - if len(serializedData) != feedLength { - return NewErrorf(ErrInvalidValue, "Incorrect slice size to read feed. Expected %d, got %d", feedLength, len(serializedData)) - } - - var cursor int - copy(f.Topic[:], serializedData[cursor:cursor+TopicLength]) - cursor += TopicLength - - copy(f.User[:], serializedData[cursor:cursor+common.AddressLength]) - cursor += common.AddressLength - - return nil -} - -// Hex serializes the feed to a hex string -func (f *Feed) Hex() string { - serializedData := make([]byte, feedLength) - f.binaryPut(serializedData) - return hexutil.Encode(serializedData) -} - -// FromValues deserializes this instance from a string key-value store -// useful to parse query strings -func (f *Feed) FromValues(values Values) (err error) { - topic := values.Get("topic") - if topic != "" { - if err := f.Topic.FromHex(values.Get("topic")); err != nil { - return err - } - } else { // see if the user set name and relatedcontent - name := values.Get("name") - relatedContent, _ := hexutil.Decode(values.Get("relatedcontent")) - if len(relatedContent) > 0 { - if len(relatedContent) < storage.AddressLength { - return NewErrorf(ErrInvalidValue, "relatedcontent field must be a hex-encoded byte array exactly %d bytes long", storage.AddressLength) - } - relatedContent = relatedContent[:storage.AddressLength] - } - f.Topic, err = NewTopic(name, relatedContent) - if err != nil { - return err - } - } - f.User = common.HexToAddress(values.Get("user")) - return nil -} - -// AppendValues serializes this structure into the provided string key-value store -// useful to build query strings -func (f *Feed) AppendValues(values Values) { - values.Set("topic", f.Topic.Hex()) - values.Set("user", f.User.Hex()) -} diff --git a/swarm/storage/feed/feed_test.go b/swarm/storage/feed/feed_test.go deleted file mode 100644 index 6a575594f4..0000000000 --- a/swarm/storage/feed/feed_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . -package feed - -import ( - "testing" -) - -func getTestFeed() *Feed { - topic, _ := NewTopic("world news report, every hour", nil) - return &Feed{ - Topic: topic, - User: newCharlieSigner().Address(), - } -} - -func TestFeedSerializerDeserializer(t *testing.T) { - testBinarySerializerRecovery(t, getTestFeed(), "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781c") -} - -func TestFeedSerializerLengthCheck(t *testing.T) { - testBinarySerializerLengthCheck(t, getTestFeed()) -} diff --git a/swarm/storage/feed/handler.go b/swarm/storage/feed/handler.go deleted file mode 100644 index 98ed7fa991..0000000000 --- a/swarm/storage/feed/handler.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Handler is the API for feeds -// It enables creating, updating, syncing and retrieving feed updates and their data -package feed - -import ( - "bytes" - "context" - "fmt" - "sync" - "sync/atomic" - - "github.com/ethereum/go-ethereum/swarm/chunk" - - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" - - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -type Handler struct { - chunkStore *storage.NetStore - HashSize int - cache map[uint64]*cacheEntry - cacheLock sync.RWMutex -} - -// HandlerParams pass parameters to the Handler constructor NewHandler -// Signer and TimestampProvider are mandatory parameters -type HandlerParams struct { -} - -// hashPool contains a pool of ready hashers -var hashPool sync.Pool - -// init initializes the package and hashPool -func init() { - hashPool = sync.Pool{ - New: func() interface{} { - return storage.MakeHashFunc(feedsHashAlgorithm)() - }, - } -} - -// NewHandler creates a new Swarm feeds API -func NewHandler(params *HandlerParams) *Handler { - fh := &Handler{ - cache: make(map[uint64]*cacheEntry), - } - - for i := 0; i < hasherCount; i++ { - hashfunc := storage.MakeHashFunc(feedsHashAlgorithm)() - if fh.HashSize == 0 { - fh.HashSize = hashfunc.Size() - } - hashPool.Put(hashfunc) - } - - return fh -} - -// SetStore sets the store backend for the Swarm feeds API -func (h *Handler) SetStore(store *storage.NetStore) { - h.chunkStore = store -} - -// Validate is a chunk validation method -// If it looks like a feed update, the chunk address is checked against the userAddr of the update's signature -// It implements the storage.ChunkValidator interface -func (h *Handler) Validate(chunk storage.Chunk) bool { - if len(chunk.Data()) < minimumSignedUpdateLength { - return false - } - - // check if it is a properly formatted update chunk with - // valid signature and proof of ownership of the feed it is trying - // to update - - // First, deserialize the chunk - var r Request - if err := r.fromChunk(chunk); err != nil { - log.Debug("Invalid feed update chunk", "addr", chunk.Address(), "err", err) - return false - } - - // Verify signatures and that the signer actually owns the feed - // If it fails, it means either the signature is not valid, data is corrupted - // or someone is trying to update someone else's feed. - if err := r.Verify(); err != nil { - log.Debug("Invalid feed update signature", "err", err) - return false - } - - return true -} - -// GetContent retrieves the data payload of the last synced update of the feed -func (h *Handler) GetContent(feed *Feed) (storage.Address, []byte, error) { - if feed == nil { - return nil, nil, NewError(ErrInvalidValue, "feed is nil") - } - feedUpdate := h.get(feed) - if feedUpdate == nil { - return nil, nil, NewError(ErrNotFound, "feed update not cached") - } - return feedUpdate.lastKey, feedUpdate.data, nil -} - -// NewRequest prepares a Request structure with all the necessary information to -// just add the desired data and sign it. -// The resulting structure can then be signed and passed to Handler.Update to be verified and sent -func (h *Handler) NewRequest(ctx context.Context, feed *Feed) (request *Request, err error) { - if feed == nil { - return nil, NewError(ErrInvalidValue, "feed cannot be nil") - } - - now := TimestampProvider.Now().Time - request = new(Request) - request.Header.Version = ProtocolVersion - - query := NewQueryLatest(feed, lookup.NoClue) - - feedUpdate, err := h.Lookup(ctx, query) - if err != nil { - if err.(*Error).code != ErrNotFound { - return nil, err - } - // not finding updates means that there is a network error - // or that the feed really does not have updates - } - - request.Feed = *feed - - // if we already have an update, then find next epoch - if feedUpdate != nil { - request.Epoch = lookup.GetNextEpoch(feedUpdate.Epoch, now) - } else { - request.Epoch = lookup.GetFirstEpoch(now) - } - - return request, nil -} - -// Lookup retrieves a specific or latest feed update -// Lookup works differently depending on the configuration of `query` -// See the `query` documentation and helper functions: -// `NewQueryLatest` and `NewQuery` -func (h *Handler) Lookup(ctx context.Context, query *Query) (*cacheEntry, error) { - - timeLimit := query.TimeLimit - if timeLimit == 0 { // if time limit is set to zero, the user wants to get the latest update - timeLimit = TimestampProvider.Now().Time - } - - if query.Hint == lookup.NoClue { // try to use our cache - entry := h.get(&query.Feed) - if entry != nil && entry.Epoch.Time <= timeLimit { // avoid bad hints - query.Hint = entry.Epoch - } - } - - // we can't look for anything without a store - if h.chunkStore == nil { - return nil, NewError(ErrInit, "Call Handler.SetStore() before performing lookups") - } - - var readCount int32 - - // Invoke the lookup engine. - // The callback will be called every time the lookup algorithm needs to guess - requestPtr, err := lookup.Lookup(ctx, timeLimit, query.Hint, func(ctx context.Context, epoch lookup.Epoch, now uint64) (interface{}, error) { - atomic.AddInt32(&readCount, 1) - id := ID{ - Feed: query.Feed, - Epoch: epoch, - } - ctx, cancel := context.WithTimeout(ctx, defaultRetrieveTimeout) - defer cancel() - - ch, err := h.chunkStore.Get(ctx, chunk.ModeGetLookup, id.Addr()) - if err != nil { - if err == context.DeadlineExceeded { // chunk not found - return nil, nil - } - return nil, err //something else happened or context was cancelled. - } - - var request Request - if err := request.fromChunk(ch); err != nil { - return nil, nil - } - if request.Time <= timeLimit { - return &request, nil - } - return nil, nil - }) - if err != nil { - return nil, err - } - - log.Info(fmt.Sprintf("Feed lookup finished in %d lookups", readCount)) - - request, _ := requestPtr.(*Request) - if request == nil { - return nil, NewError(ErrNotFound, "no feed updates found") - } - return h.updateCache(request) - -} - -// update feed updates cache with specified content -func (h *Handler) updateCache(request *Request) (*cacheEntry, error) { - - updateAddr := request.Addr() - log.Trace("feed cache update", "topic", request.Topic.Hex(), "updateaddr", updateAddr, "epoch time", request.Epoch.Time, "epoch level", request.Epoch.Level) - - entry := h.get(&request.Feed) - if entry == nil { - entry = &cacheEntry{} - h.set(&request.Feed, entry) - } - - // update our rsrcs entry map - entry.lastKey = updateAddr - entry.Update = request.Update - entry.Reader = bytes.NewReader(entry.data) - return entry, nil -} - -// Update publishes a feed update -// Note that a feed update cannot span chunks, and thus has a MAX NET LENGTH 4096, INCLUDING update header data and signature. -// This results in a max payload of `maxUpdateDataLength` (check update.go for more details) -// An error will be returned if the total length of the chunk payload will exceed this limit. -// Update can only check if the caller is trying to overwrite the very last known version, otherwise it just puts the update -// on the network. -func (h *Handler) Update(ctx context.Context, r *Request) (updateAddr storage.Address, err error) { - - // we can't update anything without a store - if h.chunkStore == nil { - return nil, NewError(ErrInit, "Call Handler.SetStore() before updating") - } - - feedUpdate := h.get(&r.Feed) - if feedUpdate != nil && feedUpdate.Epoch.Equals(r.Epoch) { // This is the only cheap check we can do for sure - return nil, NewError(ErrInvalidValue, "A former update in this epoch is already known to exist") - } - - ch, err := r.toChunk() // Serialize the update into a chunk. Fails if data is too big - if err != nil { - return nil, err - } - - // send the chunk - h.chunkStore.Put(ctx, chunk.ModePutUpload, ch) - log.Trace("feed update", "updateAddr", r.idAddr, "epoch time", r.Epoch.Time, "epoch level", r.Epoch.Level, "data", ch.Data()) - // update our feed updates map cache entry if the new update is older than the one we have, if we have it. - if feedUpdate != nil && r.Epoch.After(feedUpdate.Epoch) { - feedUpdate.Epoch = r.Epoch - feedUpdate.data = make([]byte, len(r.data)) - feedUpdate.lastKey = r.idAddr - copy(feedUpdate.data, r.data) - feedUpdate.Reader = bytes.NewReader(feedUpdate.data) - } - - return r.idAddr, nil -} - -// Retrieves the feed update cache value for the given nameHash -func (h *Handler) get(feed *Feed) *cacheEntry { - mapKey := feed.mapKey() - h.cacheLock.RLock() - defer h.cacheLock.RUnlock() - feedUpdate := h.cache[mapKey] - return feedUpdate -} - -// Sets the feed update cache value for the given feed -func (h *Handler) set(feed *Feed, feedUpdate *cacheEntry) { - mapKey := feed.mapKey() - h.cacheLock.Lock() - defer h.cacheLock.Unlock() - h.cache[mapKey] = feedUpdate -} diff --git a/swarm/storage/feed/handler_test.go b/swarm/storage/feed/handler_test.go deleted file mode 100644 index 3d8213e60b..0000000000 --- a/swarm/storage/feed/handler_test.go +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "bytes" - "context" - "flag" - "fmt" - "io/ioutil" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" -) - -var ( - loglevel = flag.Int("loglevel", 3, "loglevel") - startTime = Timestamp{ - Time: uint64(4200), - } - cleanF func() - subtopicName = "føø.bar" -) - -func init() { - flag.Parse() - log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) -} - -// simulated timeProvider -type fakeTimeProvider struct { - currentTime uint64 -} - -func (f *fakeTimeProvider) Tick() { - f.currentTime++ -} - -func (f *fakeTimeProvider) Set(time uint64) { - f.currentTime = time -} - -func (f *fakeTimeProvider) FastForward(offset uint64) { - f.currentTime += offset -} - -func (f *fakeTimeProvider) Now() Timestamp { - return Timestamp{ - Time: f.currentTime, - } -} - -// make updates and retrieve them based on periods and versions -func TestFeedsHandler(t *testing.T) { - - // make fake timeProvider - clock := &fakeTimeProvider{ - currentTime: startTime.Time, // clock starts at t=4200 - } - - // signer containing private key - signer := newAliceSigner() - - feedsHandler, datadir, teardownTest, err := setupTest(clock, signer) - if err != nil { - t.Fatal(err) - } - defer teardownTest() - - // create a new feed - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - topic, _ := NewTopic("Mess with Swarm feeds code and see what ghost catches you", nil) - fd := Feed{ - Topic: topic, - User: signer.Address(), - } - - // data for updates: - updates := []string{ - "blinky", // t=4200 - "pinky", // t=4242 - "inky", // t=4284 - "clyde", // t=4285 - } - - request := NewFirstRequest(fd.Topic) // this timestamps the update at t = 4200 (start time) - chunkAddress := make(map[string]storage.Address) - data := []byte(updates[0]) - request.SetData(data) - if err := request.Sign(signer); err != nil { - t.Fatal(err) - } - chunkAddress[updates[0]], err = feedsHandler.Update(ctx, request) - if err != nil { - t.Fatal(err) - } - - // move the clock ahead 21 seconds - clock.FastForward(21) // t=4221 - - request, err = feedsHandler.NewRequest(ctx, &request.Feed) // this timestamps the update at t = 4221 - if err != nil { - t.Fatal(err) - } - if request.Epoch.Base() != 0 || request.Epoch.Level != lookup.HighestLevel-1 { - t.Fatalf("Suggested epoch BaseTime should be 0 and Epoch level should be %d", lookup.HighestLevel-1) - } - - request.Epoch.Level = lookup.HighestLevel // force level 25 instead of 24 to make it fail - data = []byte(updates[1]) - request.SetData(data) - if err := request.Sign(signer); err != nil { - t.Fatal(err) - } - chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request) - if err == nil { - t.Fatal("Expected update to fail since an update in this epoch already exists") - } - - // move the clock ahead 21 seconds - clock.FastForward(21) // t=4242 - request, err = feedsHandler.NewRequest(ctx, &request.Feed) - if err != nil { - t.Fatal(err) - } - request.SetData(data) - if err := request.Sign(signer); err != nil { - t.Fatal(err) - } - chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request) - if err != nil { - t.Fatal(err) - } - - // move the clock ahead 42 seconds - clock.FastForward(42) // t=4284 - request, err = feedsHandler.NewRequest(ctx, &request.Feed) - if err != nil { - t.Fatal(err) - } - data = []byte(updates[2]) - request.SetData(data) - if err := request.Sign(signer); err != nil { - t.Fatal(err) - } - chunkAddress[updates[2]], err = feedsHandler.Update(ctx, request) - if err != nil { - t.Fatal(err) - } - - // move the clock ahead 1 second - clock.FastForward(1) // t=4285 - request, err = feedsHandler.NewRequest(ctx, &request.Feed) - if err != nil { - t.Fatal(err) - } - if request.Epoch.Base() != 0 || request.Epoch.Level != 28 { - t.Fatalf("Expected epoch base time to be %d, got %d. Expected epoch level to be %d, got %d", 0, request.Epoch.Base(), 28, request.Epoch.Level) - } - data = []byte(updates[3]) - request.SetData(data) - - if err := request.Sign(signer); err != nil { - t.Fatal(err) - } - chunkAddress[updates[3]], err = feedsHandler.Update(ctx, request) - if err != nil { - t.Fatal(err) - } - - time.Sleep(time.Second) - feedsHandler.Close() - - // check we can retrieve the updates after close - clock.FastForward(2000) // t=6285 - - feedParams := &HandlerParams{} - - feedsHandler2, err := NewTestHandler(datadir, feedParams) - if err != nil { - t.Fatal(err) - } - - update2, err := feedsHandler2.Lookup(ctx, NewQueryLatest(&request.Feed, lookup.NoClue)) - if err != nil { - t.Fatal(err) - } - - // last update should be "clyde" - if !bytes.Equal(update2.data, []byte(updates[len(updates)-1])) { - t.Fatalf("feed update data was %v, expected %v", string(update2.data), updates[len(updates)-1]) - } - if update2.Level != 28 { - t.Fatalf("feed update epoch level was %d, expected 28", update2.Level) - } - if update2.Base() != 0 { - t.Fatalf("feed update epoch base time was %d, expected 0", update2.Base()) - } - log.Debug("Latest lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data) - - // specific point in time - update, err := feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, 4284, lookup.NoClue)) - if err != nil { - t.Fatal(err) - } - // check data - if !bytes.Equal(update.data, []byte(updates[2])) { - t.Fatalf("feed update data (historical) was %v, expected %v", string(update2.data), updates[2]) - } - log.Debug("Historical lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data) - - // beyond the first should yield an error - update, err = feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, startTime.Time-1, lookup.NoClue)) - if err == nil { - t.Fatalf("expected previous to fail, returned epoch %s data %v", update.Epoch.String(), update.data) - } - -} - -const Day = 60 * 60 * 24 -const Year = Day * 365 -const Month = Day * 30 - -func generateData(x uint64) []byte { - return []byte(fmt.Sprintf("%d", x)) -} - -func TestSparseUpdates(t *testing.T) { - - // make fake timeProvider - timeProvider := &fakeTimeProvider{ - currentTime: startTime.Time, - } - - // signer containing private key - signer := newAliceSigner() - - rh, datadir, teardownTest, err := setupTest(timeProvider, signer) - if err != nil { - t.Fatal(err) - } - defer teardownTest() - defer os.RemoveAll(datadir) - - // create a new feed - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - topic, _ := NewTopic("Very slow updates", nil) - fd := Feed{ - Topic: topic, - User: signer.Address(), - } - - // publish one update every 5 years since Unix 0 until today - today := uint64(1533799046) - var epoch lookup.Epoch - var lastUpdateTime uint64 - for T := uint64(0); T < today; T += 5 * Year { - request := NewFirstRequest(fd.Topic) - request.Epoch = lookup.GetNextEpoch(epoch, T) - request.data = generateData(T) // this generates some data that depends on T, so we can check later - request.Sign(signer) - if err != nil { - t.Fatal(err) - } - - if _, err := rh.Update(ctx, request); err != nil { - t.Fatal(err) - } - epoch = request.Epoch - lastUpdateTime = T - } - - query := NewQuery(&fd, today, lookup.NoClue) - - _, err = rh.Lookup(ctx, query) - if err != nil { - t.Fatal(err) - } - - _, content, err := rh.GetContent(&fd) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(generateData(lastUpdateTime), content) { - t.Fatalf("Expected to recover last written value %d, got %s", lastUpdateTime, string(content)) - } - - // lookup the closest update to 35*Year + 6* Month (~ June 2005): - // it should find the update we put on 35*Year, since we were updating every 5 years. - - query.TimeLimit = 35*Year + 6*Month - - _, err = rh.Lookup(ctx, query) - if err != nil { - t.Fatal(err) - } - - _, content, err = rh.GetContent(&fd) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(generateData(35*Year), content) { - t.Fatalf("Expected to recover %d, got %s", 35*Year, string(content)) - } -} - -func TestValidator(t *testing.T) { - - // make fake timeProvider - timeProvider := &fakeTimeProvider{ - currentTime: startTime.Time, - } - - // signer containing private key. Alice will be the good girl - signer := newAliceSigner() - - // set up sim timeProvider - rh, _, teardownTest, err := setupTest(timeProvider, signer) - if err != nil { - t.Fatal(err) - } - defer teardownTest() - - // create new feed - topic, _ := NewTopic(subtopicName, nil) - fd := Feed{ - Topic: topic, - User: signer.Address(), - } - mr := NewFirstRequest(fd.Topic) - - // chunk with address - data := []byte("foo") - mr.SetData(data) - if err := mr.Sign(signer); err != nil { - t.Fatalf("sign fail: %v", err) - } - - chunk, err := mr.toChunk() - if err != nil { - t.Fatal(err) - } - if !rh.Validate(chunk) { - t.Fatal("Chunk validator fail on update chunk") - } - - address := chunk.Address() - // mess with the address - address[0] = 11 - address[15] = 99 - - if rh.Validate(storage.NewChunk(address, chunk.Data())) { - t.Fatal("Expected Validate to fail with false chunk address") - } -} - -// tests that the content address validator correctly checks the data -// tests that feed update chunks are passed through content address validator -// there is some redundancy in this test as it also tests content addressed chunks, -// which should be evaluated as invalid chunks by this validator -func TestValidatorInStore(t *testing.T) { - - // make fake timeProvider - TimestampProvider = &fakeTimeProvider{ - currentTime: startTime.Time, - } - - // signer containing private key - signer := newAliceSigner() - - // set up localstore - datadir, err := ioutil.TempDir("", "storage-testfeedsvalidator") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(datadir) - - localstore, err := localstore.New(datadir, make([]byte, 32), nil) - if err != nil { - t.Fatal(err) - } - - // set up Swarm feeds handler and add is as a validator to the localstore - fhParams := &HandlerParams{} - fh := NewHandler(fhParams) - store := chunk.NewValidatorStore(localstore, fh) - - // create content addressed chunks, one good, one faulty - chunks := storage.GenerateRandomChunks(chunk.DefaultSize, 2) - goodChunk := chunks[0] - badChunk := storage.NewChunk(chunks[1].Address(), goodChunk.Data()) - - topic, _ := NewTopic("xyzzy", nil) - fd := Feed{ - Topic: topic, - User: signer.Address(), - } - - // create a feed update chunk with correct publickey - id := ID{ - Epoch: lookup.Epoch{Time: 42, - Level: 1, - }, - Feed: fd, - } - - updateAddr := id.Addr() - data := []byte("bar") - - r := new(Request) - r.idAddr = updateAddr - r.Update.ID = id - r.data = data - - r.Sign(signer) - - uglyChunk, err := r.toChunk() - if err != nil { - t.Fatal(err) - } - - // put the chunks in the store and check their error status - _, err = store.Put(context.Background(), chunk.ModePutUpload, goodChunk) - if err == nil { - t.Fatal("expected error on good content address chunk with feed update validator only, but got nil") - } - _, err = store.Put(context.Background(), chunk.ModePutUpload, badChunk) - if err == nil { - t.Fatal("expected error on bad content address chunk with feed update validator only, but got nil") - } - _, err = store.Put(context.Background(), chunk.ModePutUpload, uglyChunk) - if err != nil { - t.Fatalf("expected no error on feed update chunk with feed update validator only, but got: %s", err) - } -} - -// create rpc and feeds Handler -func setupTest(timeProvider timestampProvider, signer Signer) (fh *TestHandler, datadir string, teardown func(), err error) { - - var fsClean func() - var rpcClean func() - cleanF = func() { - if fsClean != nil { - fsClean() - } - if rpcClean != nil { - rpcClean() - } - } - - // temp datadir - datadir, err = ioutil.TempDir("", "fh") - if err != nil { - return nil, "", nil, err - } - fsClean = func() { - os.RemoveAll(datadir) - } - - TimestampProvider = timeProvider - fhParams := &HandlerParams{} - fh, err = NewTestHandler(datadir, fhParams) - return fh, datadir, cleanF, err -} - -func newAliceSigner() *GenericSigner { - privKey, _ := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") - return NewGenericSigner(privKey) -} - -func newBobSigner() *GenericSigner { - privKey, _ := crypto.HexToECDSA("accedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedecaca") - return NewGenericSigner(privKey) -} - -func newCharlieSigner() *GenericSigner { - privKey, _ := crypto.HexToECDSA("facadefacadefacadefacadefacadefacadefacadefacadefacadefacadefaca") - return NewGenericSigner(privKey) -} diff --git a/swarm/storage/feed/id.go b/swarm/storage/feed/id.go deleted file mode 100644 index 7e17743c11..0000000000 --- a/swarm/storage/feed/id.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "fmt" - "hash" - "strconv" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" - - "github.com/ethereum/go-ethereum/swarm/storage" -) - -// ID uniquely identifies an update on the network. -type ID struct { - Feed `json:"feed"` - lookup.Epoch `json:"epoch"` -} - -// ID layout: -// Feed feedLength bytes -// Epoch EpochLength -const idLength = feedLength + lookup.EpochLength - -// Addr calculates the feed update chunk address corresponding to this ID -func (u *ID) Addr() (updateAddr storage.Address) { - serializedData := make([]byte, idLength) - var cursor int - u.Feed.binaryPut(serializedData[cursor : cursor+feedLength]) - cursor += feedLength - - eid := u.Epoch.ID() - copy(serializedData[cursor:cursor+lookup.EpochLength], eid[:]) - - hasher := hashPool.Get().(hash.Hash) - defer hashPool.Put(hasher) - hasher.Reset() - hasher.Write(serializedData) - return hasher.Sum(nil) -} - -// binaryPut serializes this instance into the provided slice -func (u *ID) binaryPut(serializedData []byte) error { - if len(serializedData) != idLength { - return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize ID. Expected %d, got %d", idLength, len(serializedData)) - } - var cursor int - if err := u.Feed.binaryPut(serializedData[cursor : cursor+feedLength]); err != nil { - return err - } - cursor += feedLength - - epochBytes, err := u.Epoch.MarshalBinary() - if err != nil { - return err - } - copy(serializedData[cursor:cursor+lookup.EpochLength], epochBytes[:]) - cursor += lookup.EpochLength - - return nil -} - -// binaryLength returns the expected size of this structure when serialized -func (u *ID) binaryLength() int { - return idLength -} - -// binaryGet restores the current instance from the information contained in the passed slice -func (u *ID) binaryGet(serializedData []byte) error { - if len(serializedData) != idLength { - return NewErrorf(ErrInvalidValue, "Incorrect slice size to read ID. Expected %d, got %d", idLength, len(serializedData)) - } - - var cursor int - if err := u.Feed.binaryGet(serializedData[cursor : cursor+feedLength]); err != nil { - return err - } - cursor += feedLength - - if err := u.Epoch.UnmarshalBinary(serializedData[cursor : cursor+lookup.EpochLength]); err != nil { - return err - } - cursor += lookup.EpochLength - - return nil -} - -// FromValues deserializes this instance from a string key-value store -// useful to parse query strings -func (u *ID) FromValues(values Values) error { - level, _ := strconv.ParseUint(values.Get("level"), 10, 32) - u.Epoch.Level = uint8(level) - u.Epoch.Time, _ = strconv.ParseUint(values.Get("time"), 10, 64) - - if u.Feed.User == (common.Address{}) { - return u.Feed.FromValues(values) - } - return nil -} - -// AppendValues serializes this structure into the provided string key-value store -// useful to build query strings -func (u *ID) AppendValues(values Values) { - values.Set("level", fmt.Sprintf("%d", u.Epoch.Level)) - values.Set("time", fmt.Sprintf("%d", u.Epoch.Time)) - u.Feed.AppendValues(values) -} diff --git a/swarm/storage/feed/id_test.go b/swarm/storage/feed/id_test.go deleted file mode 100644 index 8a820abfed..0000000000 --- a/swarm/storage/feed/id_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package feed - -import ( - "testing" - - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" -) - -func getTestID() *ID { - return &ID{ - Feed: *getTestFeed(), - Epoch: lookup.GetFirstEpoch(1000), - } -} - -func TestIDAddr(t *testing.T) { - id := getTestID() - updateAddr := id.Addr() - compareByteSliceToExpectedHex(t, "updateAddr", updateAddr, "0x842d0a81987b9755dfeaa5558f5c134c1c0af48b6545005cac7b533d9411453a") -} - -func TestIDSerializer(t *testing.T) { - testBinarySerializerRecovery(t, getTestID(), "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce80300000000001f") -} - -func TestIDLengthCheck(t *testing.T) { - testBinarySerializerLengthCheck(t, getTestID()) -} diff --git a/swarm/storage/feed/lookup/algorithm_fluzcapacitor.go b/swarm/storage/feed/lookup/algorithm_fluzcapacitor.go deleted file mode 100644 index 3840bd0fd6..0000000000 --- a/swarm/storage/feed/lookup/algorithm_fluzcapacitor.go +++ /dev/null @@ -1,63 +0,0 @@ -package lookup - -import "context" - -// FluzCapacitorAlgorithm works by narrowing the epoch search area if an update is found -// going back and forth in time -// First, it will attempt to find an update where it should be now if the hint was -// really the last update. If that lookup fails, then the last update must be either the hint itself -// or the epochs right below. If however, that lookup succeeds, then the update must be -// that one or within the epochs right below. -// see the guide for a more graphical representation -func FluzCapacitorAlgorithm(ctx context.Context, now uint64, hint Epoch, read ReadFunc) (value interface{}, err error) { - var lastFound interface{} - var epoch Epoch - if hint == NoClue { - hint = worstHint - } - - t := now - - for { - epoch = GetNextEpoch(hint, t) - value, err = read(ctx, epoch, now) - if err != nil { - return nil, err - } - if value != nil { - lastFound = value - if epoch.Level == LowestLevel || epoch.Equals(hint) { - return value, nil - } - hint = epoch - continue - } - if epoch.Base() == hint.Base() { - if lastFound != nil { - return lastFound, nil - } - // we have reached the hint itself - if hint == worstHint { - return nil, nil - } - // check it out - value, err = read(ctx, hint, now) - if err != nil { - return nil, err - } - if value != nil { - return value, nil - } - // bad hint. - t = hint.Base() - hint = worstHint - continue - } - base := epoch.Base() - if base == 0 { - return nil, nil - } - t = base - 1 - } - -} diff --git a/swarm/storage/feed/lookup/algorithm_longearth.go b/swarm/storage/feed/lookup/algorithm_longearth.go deleted file mode 100644 index d0342f67cb..0000000000 --- a/swarm/storage/feed/lookup/algorithm_longearth.go +++ /dev/null @@ -1,185 +0,0 @@ -package lookup - -import ( - "context" - "sync/atomic" - "time" -) - -type stepFunc func(ctx context.Context, t uint64, hint Epoch) interface{} - -// LongEarthLookaheadDelay is the headstart the lookahead gives R before it launches -var LongEarthLookaheadDelay = 250 * time.Millisecond - -// LongEarthLookbackDelay is the headstart the lookback gives R before it launches -var LongEarthLookbackDelay = 250 * time.Millisecond - -// LongEarthAlgorithm explores possible lookup paths in parallel, pruning paths as soon -// as a more promising lookup path is found. As a result, this lookup algorithm is an order -// of magnitude faster than the FluzCapacitor algorithm, but at the expense of more exploratory reads. -// This algorithm works as follows. On each step, the next epoch is immediately looked up (R) -// and given a head start, while two parallel "steps" are launched a short time after: -// look ahead (A) is the path the algorithm would take if the R lookup returns a value, whereas -// look back (B) is the path the algorithm would take if the R lookup failed. -// as soon as R is actually finished, the A or B paths are pruned depending on the value of R. -// if A returns earlier than R, then R and B read operations can be safely canceled, saving time. -// The maximum number of active read operations is calculated as 2^(timeout/headstart). -// If headstart is infinite, this algorithm behaves as FluzCapacitor. -// timeout is the maximum execution time of the passed `read` function. -// the two head starts can be configured by changing LongEarthLookaheadDelay or LongEarthLookbackDelay -func LongEarthAlgorithm(ctx context.Context, now uint64, hint Epoch, read ReadFunc) (interface{}, error) { - if hint == NoClue { - hint = worstHint - } - - var stepCounter int32 // for debugging, stepCounter allows to give an ID to each step instance - - errc := make(chan struct{}) // errc will help as an error shortcut signal - var gerr error // in case of error, this variable will be set - - var step stepFunc // For efficiency, the algorithm step is defined as a closure - step = func(ctxS context.Context, t uint64, last Epoch) interface{} { - stepID := atomic.AddInt32(&stepCounter, 1) // give an ID to this call instance - trace(stepID, "init: t=%d, last=%s", t, last.String()) - var valueA, valueB, valueR interface{} - - // initialize the three read contexts - ctxR, cancelR := context.WithCancel(ctxS) // will handle the current read operation - ctxA, cancelA := context.WithCancel(ctxS) // will handle the lookahead path - ctxB, cancelB := context.WithCancel(ctxS) // will handle the lookback path - - epoch := GetNextEpoch(last, t) // calculate the epoch to look up in this step instance - - // define the lookAhead function, which will follow the path as if R was successful - lookAhead := func() { - valueA = step(ctxA, t, epoch) // launch the next step, recursively. - if valueA != nil { // if this path is successful, we don't need R or B. - cancelB() - cancelR() - } - } - - // define the lookBack function, which will follow the path as if R was unsuccessful - lookBack := func() { - if epoch.Base() == last.Base() { - return - } - base := epoch.Base() - if base == 0 { - return - } - valueB = step(ctxB, base-1, last) - } - - go func() { //goroutine to read the current epoch (R) - defer cancelR() - var err error - valueR, err = read(ctxR, epoch, now) // read this epoch - if valueR == nil { // if unsuccessful, cancel lookahead, otherwise cancel lookback. - cancelA() - } else { - cancelB() - } - if err != nil && err != context.Canceled { - gerr = err - close(errc) - } - }() - - go func() { // goroutine to give a headstart to R and then launch lookahead. - defer cancelA() - - // if we are at the lowest level or the epoch to look up equals the last one, - // then we cannot lookahead (can't go lower or repeat the same lookup, this would - // cause an infinite loop) - if epoch.Level == LowestLevel || epoch.Equals(last) { - return - } - - // give a head start to R, or launch immediately if R finishes early enough - select { - case <-TimeAfter(LongEarthLookaheadDelay): - lookAhead() - case <-ctxR.Done(): - if valueR != nil { - lookAhead() // only look ahead if R was successful - } - case <-ctxA.Done(): - } - }() - - go func() { // goroutine to give a headstart to R and then launch lookback. - defer cancelB() - - // give a head start to R, or launch immediately if R finishes early enough - select { - case <-TimeAfter(LongEarthLookbackDelay): - lookBack() - case <-ctxR.Done(): - if valueR == nil { - lookBack() // only look back in case R failed - } - case <-ctxB.Done(): - } - }() - - <-ctxA.Done() - if valueA != nil { - trace(stepID, "Returning valueA=%v", valueA) - return valueA - } - - <-ctxR.Done() - if valueR != nil { - trace(stepID, "Returning valueR=%v", valueR) - return valueR - } - <-ctxB.Done() - trace(stepID, "Returning valueB=%v", valueB) - return valueB - } - - var value interface{} - stepCtx, cancel := context.WithCancel(ctx) - - go func() { // launch the root step in its own goroutine to allow cancellation - defer cancel() - value = step(stepCtx, now, hint) - }() - - // wait for the algorithm to finish, but shortcut in case - // of errors - select { - case <-stepCtx.Done(): - case <-errc: - cancel() - return nil, gerr - } - - if ctx.Err() != nil { - return nil, ctx.Err() - } - - if value != nil || hint == worstHint { - return value, nil - } - - // at this point the algorithm did not return a value, - // so we challenge the hint given. - value, err := read(ctx, hint, now) - if err != nil { - return nil, err - } - if value != nil { - return value, nil // hint is valid, return it. - } - - // hint is invalid. Invoke the algorithm - // without hint. - now = hint.Base() - if hint.Level == HighestLevel { - now-- - } - - return LongEarthAlgorithm(ctx, now, NoClue, read) -} diff --git a/swarm/storage/feed/lookup/epoch.go b/swarm/storage/feed/lookup/epoch.go deleted file mode 100644 index 6d75ba2432..0000000000 --- a/swarm/storage/feed/lookup/epoch.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package lookup - -import ( - "encoding/binary" - "errors" - "fmt" -) - -// Epoch represents a time slot at a particular frequency level -type Epoch struct { - Time uint64 `json:"time"` // Time stores the time at which the update or lookup takes place - Level uint8 `json:"level"` // Level indicates the frequency level as the exponent of a power of 2 -} - -// EpochID is a unique identifier for an Epoch, based on its level and base time. -type EpochID [8]byte - -// EpochLength stores the serialized binary length of an Epoch -const EpochLength = 8 - -// MaxTime contains the highest possible time value an Epoch can handle -const MaxTime uint64 = (1 << 56) - 1 - -// Base returns the base time of the Epoch -func (e *Epoch) Base() uint64 { - return getBaseTime(e.Time, e.Level) -} - -// ID Returns the unique identifier of this epoch -func (e *Epoch) ID() EpochID { - base := e.Base() - var id EpochID - binary.LittleEndian.PutUint64(id[:], base) - id[7] = e.Level - return id -} - -// MarshalBinary implements the encoding.BinaryMarshaller interface -func (e *Epoch) MarshalBinary() (data []byte, err error) { - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b[:], e.Time) - b[7] = e.Level - return b, nil -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaller interface -func (e *Epoch) UnmarshalBinary(data []byte) error { - if len(data) != EpochLength { - return errors.New("Invalid data unmarshalling Epoch") - } - b := make([]byte, 8) - copy(b, data) - e.Level = b[7] - b[7] = 0 - e.Time = binary.LittleEndian.Uint64(b) - return nil -} - -// After returns true if this epoch occurs later or exactly at the other epoch. -func (e *Epoch) After(epoch Epoch) bool { - if e.Time == epoch.Time { - return e.Level < epoch.Level - } - return e.Time >= epoch.Time -} - -// Equals compares two epochs and returns true if they refer to the same time period. -func (e *Epoch) Equals(epoch Epoch) bool { - return e.Level == epoch.Level && e.Base() == epoch.Base() -} - -// String implements the Stringer interface. -func (e *Epoch) String() string { - return fmt.Sprintf("Epoch{Base: %d, Time:%d, Level:%d}", e.Base(), e.Time, e.Level) -} diff --git a/swarm/storage/feed/lookup/epoch_test.go b/swarm/storage/feed/lookup/epoch_test.go deleted file mode 100644 index 0629f3d1df..0000000000 --- a/swarm/storage/feed/lookup/epoch_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package lookup_test - -import ( - "testing" - - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" -) - -func TestMarshallers(t *testing.T) { - - for i := uint64(1); i < lookup.MaxTime; i *= 3 { - e := lookup.Epoch{ - Time: i, - Level: uint8(i % 20), - } - b, err := e.MarshalBinary() - if err != nil { - t.Fatal(err) - } - var e2 lookup.Epoch - if err := e2.UnmarshalBinary(b); err != nil { - t.Fatal(err) - } - if e != e2 { - t.Fatal("Expected unmarshalled epoch to be equal to marshalled onet.Fatal(err)") - } - } - -} - -func TestAfter(t *testing.T) { - a := lookup.Epoch{ - Time: 5, - Level: 3, - } - b := lookup.Epoch{ - Time: 6, - Level: 3, - } - c := lookup.Epoch{ - Time: 6, - Level: 4, - } - - if !b.After(a) { - t.Fatal("Expected 'after' to be true, got false") - } - - if b.After(b) { - t.Fatal("Expected 'after' to be false when both epochs are identical, got true") - } - - if !b.After(c) { - t.Fatal("Expected 'after' to be true when both epochs have the same time but the level is lower in the first one, but got false") - } - -} diff --git a/swarm/storage/feed/lookup/lookup.go b/swarm/storage/feed/lookup/lookup.go deleted file mode 100644 index 4b233a0e07..0000000000 --- a/swarm/storage/feed/lookup/lookup.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/* -Package lookup defines feed lookup algorithms and provides tools to place updates -so they can be found -*/ -package lookup - -import ( - "context" - "time" -) - -const maxuint64 = ^uint64(0) - -// LowestLevel establishes the frequency resolution of the lookup algorithm as a power of 2. -const LowestLevel uint8 = 0 // default is 0 (1 second) - -// HighestLevel sets the lowest frequency the algorithm will operate at, as a power of 2. -// 31 -> 2^31 equals to roughly 38 years. -const HighestLevel = 31 - -// DefaultLevel sets what level will be chosen to search when there is no hint -const DefaultLevel = HighestLevel - -//Algorithm is the function signature of a lookup algorithm -type Algorithm func(ctx context.Context, now uint64, hint Epoch, read ReadFunc) (value interface{}, err error) - -// Lookup finds the update with the highest timestamp that is smaller or equal than 'now' -// It takes a hint which should be the epoch where the last known update was -// If you don't know in what epoch the last update happened, simply submit lookup.NoClue -// read() will be called on each lookup attempt -// Returns an error only if read() returns an error -// Returns nil if an update was not found -var Lookup Algorithm = LongEarthAlgorithm - -// TimeAfter must point to a function that returns a timer -// This is here so that tests can replace it with -// a mock up timer factory to simulate time deterministically -var TimeAfter = time.After - -// ReadFunc is a handler called by Lookup each time it attempts to find a value -// It should return if a value is not found -// It should return if a value is found, but its timestamp is higher than "now" -// It should only return an error in case the handler wants to stop the -// lookup process entirely. -type ReadFunc func(ctx context.Context, epoch Epoch, now uint64) (interface{}, error) - -// NoClue is a hint that can be provided when the Lookup caller does not have -// a clue about where the last update may be -var NoClue = Epoch{} - -// getBaseTime returns the epoch base time of the given -// time and level -func getBaseTime(t uint64, level uint8) uint64 { - return t & (maxuint64 << level) -} - -// Hint creates a hint based only on the last known update time -func Hint(last uint64) Epoch { - return Epoch{ - Time: last, - Level: DefaultLevel, - } -} - -// GetNextLevel returns the frequency level a next update should be placed at, provided where -// the last update was and what time it is now. -// This is the first nonzero bit of the XOR of 'last' and 'now', counting from the highest significant bit -// but limited to not return a level that is smaller than the last-1 -func GetNextLevel(last Epoch, now uint64) uint8 { - // First XOR the last epoch base time with the current clock. - // This will set all the common most significant bits to zero. - mix := (last.Base() ^ now) - - // Then, make sure we stop the below loop before one level below the current, by setting - // that level's bit to 1. - // If the next level is lower than the current one, it must be exactly level-1 and not lower. - mix |= (1 << (last.Level - 1)) - - // if the last update was more than 2^highestLevel seconds ago, choose the highest level - if mix > (maxuint64 >> (64 - HighestLevel - 1)) { - return HighestLevel - } - - // set up a mask to scan for nonzero bits, starting at the highest level - mask := uint64(1 << (HighestLevel)) - - for i := uint8(HighestLevel); i > LowestLevel; i-- { - if mix&mask != 0 { // if we find a nonzero bit, this is the level the next update should be at. - return i - } - mask = mask >> 1 // move our bit one position to the right - } - return 0 -} - -// GetNextEpoch returns the epoch where the next update should be located -// according to where the previous update was -// and what time it is now. -func GetNextEpoch(last Epoch, now uint64) Epoch { - if last == NoClue { - return GetFirstEpoch(now) - } - level := GetNextLevel(last, now) - return Epoch{ - Level: level, - Time: now, - } -} - -// GetFirstEpoch returns the epoch where the first update should be located -// based on what time it is now. -func GetFirstEpoch(now uint64) Epoch { - return Epoch{Level: HighestLevel, Time: now} -} - -var worstHint = Epoch{Time: 0, Level: 63} - -var trace = func(id int32, formatString string, a ...interface{}) { - //fmt.Printf("Step ID #%d "+formatString+"\n", append([]interface{}{id}, a...)...) -} diff --git a/swarm/storage/feed/lookup/lookup_test.go b/swarm/storage/feed/lookup/lookup_test.go deleted file mode 100644 index b0d132de64..0000000000 --- a/swarm/storage/feed/lookup/lookup_test.go +++ /dev/null @@ -1,641 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package lookup_test - -import ( - "context" - "fmt" - "math/rand" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" -) - -type AlgorithmInfo struct { - Lookup lookup.Algorithm - Name string -} - -var algorithms = []AlgorithmInfo{ - {lookup.FluzCapacitorAlgorithm, "FluzCapacitor"}, - {lookup.LongEarthAlgorithm, "LongEarth"}, -} - -const enablePrintMetrics = false // set to true to display algorithm benchmarking stats - -func printMetric(metric string, store *Store, elapsed time.Duration) { - if enablePrintMetrics { - fmt.Printf("metric=%s, readcount=%d (successful=%d, failed=%d), cached=%d, canceled=%d, maxSimult=%d, elapsed=%s\n", metric, - store.reads, store.successful, store.failed, store.cacheHits, store.canceled, store.maxSimultaneous, elapsed) - } -} - -const Day = 60 * 60 * 24 -const Year = Day * 365 -const Month = Day * 30 - -// DefaultStoreConfig indicates the time the different read -// operations will take in the simulation -// This allows to measure an algorithm performance relative -// to other -var DefaultStoreConfig = &StoreConfig{ - CacheReadTime: 50 * time.Millisecond, - FailedReadTime: 1000 * time.Millisecond, - SuccessfulReadTime: 500 * time.Millisecond, -} - -// TestLookup verifies if the last update and intermediates are -// found and if that same last update is found faster if a hint is given -func TestLookup(t *testing.T) { - // ### 1.- Initialize stopwatch time sim - stopwatch := NewStopwatch(50 * time.Millisecond) - lookup.TimeAfter = stopwatch.TimeAfter() - defer stopwatch.Stop() - - // ### 2.- Setup mock storage and generate updates - store := NewStore(DefaultStoreConfig) - readFunc := store.MakeReadFunc() - - // write an update every month for 12 months 3 years ago and then silence for two years - now := uint64(1533799046) - var epoch lookup.Epoch - - var lastData *Data - for i := uint64(0); i < 12; i++ { - t := uint64(now - Year*3 + i*Month) - data := Data{ - Payload: t, //our "payload" will be the timestamp itself. - Time: t, - } - epoch = store.Update(epoch, t, &data) - lastData = &data - } - - // ### 3.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - - store.Reset() // reset the store read counters - - // ### 3.1.- Test how long it takes to find the last update without a hint: - timeElapsedWithoutHint := stopwatch.Measure(func() { - - // try to get the last value - value, err := algo.Lookup(context.Background(), now, lookup.NoClue, readFunc) - if err != nil { - t.Fatal(err) - } - if value != lastData { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) - } - - }) - printMetric("SIMPLE READ", store, timeElapsedWithoutHint) - - store.Reset() // reset the read counters for the next test - - // ### 3.2.- Test how long it takes to find the last update *with* a hint. - // it should take less time! - timeElapsed := stopwatch.Measure(func() { - // Provide a hint to get a faster lookup. In particular, we give the exact location of the last update - value, err := algo.Lookup(context.Background(), now, epoch, readFunc) - if err != nil { - t.Fatal(err) - } - if value != lastData { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) - } - }) - printMetric("WITH HINT", store, stopwatch.Elapsed()) - - if timeElapsed > timeElapsedWithoutHint { - t.Fatalf("Expected lookup to complete faster than %s since we provided a hint. Took %s", timeElapsedWithoutHint, timeElapsed) - } - - store.Reset() // reset the read counters for the next test - - // ### 3.3.- try to get an intermediate value - // if we look for a value in, e.g., now - Year*3 + 6*Month, we should get that value - // Since the "payload" is the timestamp itself, we can check this. - expectedTime := now - Year*3 + 6*Month - timeElapsed = stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), expectedTime, lookup.NoClue, readFunc) - if err != nil { - t.Fatal(err) - } - - data, ok := value.(*Data) - - if !ok { - t.Fatal("Expected value to contain data") - } - - if data.Time != expectedTime { - t.Fatalf("Expected value timestamp to be %d, got %d", data.Time, expectedTime) - } - }) - printMetric("INTERMEDIATE READ", store, timeElapsed) - }) - } -} - -// TestOneUpdateAt0 checks if the lookup algorithm can return an update that -// is precisely set at t=0 -func TestOneUpdateAt0(t *testing.T) { - // ### 1.- Initialize stopwatch time sim - stopwatch := NewStopwatch(50 * time.Millisecond) - lookup.TimeAfter = stopwatch.TimeAfter() - defer stopwatch.Stop() - - // ### 2.- Setup mock storage and generate updates - store := NewStore(DefaultStoreConfig) - readFunc := store.MakeReadFunc() - - now := uint64(1533903729) - - var epoch lookup.Epoch - data := Data{ - Payload: 79, - Time: 0, - } - store.Update(epoch, 0, &data) //place 1 update in t=0 - - // ### 3.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - store.Reset() // reset the read counters for the next test - timeElapsed := stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), now, lookup.NoClue, readFunc) - if err != nil { - t.Fatal(err) - } - if value != &data { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", data, value) - } - }) - printMetric("SIMPLE", store, timeElapsed) - }) - } -} - -// TestBadHint tests if the update is found even when a bad hint is given -func TestBadHint(t *testing.T) { - // ### 1.- Initialize stopwatch time sim - stopwatch := NewStopwatch(50 * time.Millisecond) - lookup.TimeAfter = stopwatch.TimeAfter() - defer stopwatch.Stop() - - // ### 2.- Setup mock storage and generate updates - store := NewStore(DefaultStoreConfig) - readFunc := store.MakeReadFunc() - - now := uint64(1533903729) - - var epoch lookup.Epoch - data := Data{ - Payload: 79, - Time: 0, - } - - // place an update for t=1200 - store.Update(epoch, 1200, &data) - - // come up with some evil hint - badHint := lookup.Epoch{ - Level: 18, - Time: 1200000000, - } - - // ### 3.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - store.Reset() - timeElapsed := stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), now, badHint, readFunc) - if err != nil { - t.Fatal(err) - } - if value != &data { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", data, value) - } - }) - printMetric("SIMPLE", store, timeElapsed) - }) - } -} - -// TestBadHintNextToUpdate checks whether the update is found when the bad hint is exactly below the last update -func TestBadHintNextToUpdate(t *testing.T) { - // ### 1.- Initialize stopwatch time sim - stopwatch := NewStopwatch(50 * time.Millisecond) - lookup.TimeAfter = stopwatch.TimeAfter() - defer stopwatch.Stop() - - // ### 2.- Setup mock storage and generate updates - store := NewStore(DefaultStoreConfig) - readFunc := store.MakeReadFunc() - - now := uint64(1533903729) - var last *Data - - /* the following loop places updates in the following epochs: - Update# Time Base Level - 0 1200000000 1174405120 25 - 1 1200000001 1191182336 24 - 2 1200000002 1199570944 23 - 3 1200000003 1199570944 22 - 4 1200000004 1199570944 21 - - The situation we want to trigger is to give a bad hint exactly - in T=1200000005, B=1199570944 and L=20, which is where the next - update would have logically been. - This affects only when the bad hint's base == previous update's base, - in this case 1199570944 - - */ - var epoch lookup.Epoch - for i := uint64(0); i < 5; i++ { - data := Data{ - Payload: i, - Time: 0, - } - last = &data - epoch = store.Update(epoch, 1200000000+i, &data) - } - - // come up with some evil hint: - // put it where the next update would have been - badHint := lookup.Epoch{ - Level: 20, - Time: 1200000005, - } - - // ### 3.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - store.Reset() // reset read counters for next test - - timeElapsed := stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), now, badHint, readFunc) - if err != nil { - t.Fatal(err) - } - if value != last { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", last, value) - } - }) - printMetric("SIMPLE", store, timeElapsed) - }) - } -} - -// TestContextCancellation checks whether a lookup can be canceled -func TestContextCancellation(t *testing.T) { - - // ### 1.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - - // ### 2.1.- Test a simple cancel of an always blocking read function - readFunc := func(ctx context.Context, epoch lookup.Epoch, now uint64) (interface{}, error) { - <-ctx.Done() - return nil, ctx.Err() - } - - ctx, cancel := context.WithCancel(context.Background()) - errc := make(chan error) - - go func() { - _, err := algo.Lookup(ctx, 1200000000, lookup.NoClue, readFunc) - errc <- err - }() - - cancel() //actually cancel the lookup - - if err := <-errc; err != context.Canceled { - t.Fatalf("Expected lookup to return a context canceled error, got %v", err) - } - - // ### 2.2.- Test context cancellation during hint lookup: - ctx, cancel = context.WithCancel(context.Background()) - errc = make(chan error) - someHint := lookup.Epoch{ - Level: 25, - Time: 300, - } - // put up a read function that gets canceled only on hint lookup - readFunc = func(ctx context.Context, epoch lookup.Epoch, now uint64) (interface{}, error) { - if epoch == someHint { - go cancel() - <-ctx.Done() - return nil, ctx.Err() - } - return nil, nil - } - - go func() { - _, err := algo.Lookup(ctx, 301, someHint, readFunc) - errc <- err - }() - - if err := <-errc; err != context.Canceled { - t.Fatalf("Expected lookup to return a context canceled error, got %v", err) - } - }) - } - -} - -// TestLookupFail makes sure the lookup function fails on a timely manner -// when there are no updates at all -func TestLookupFail(t *testing.T) { - // ### 1.- Initialize stopwatch time sim - stopwatch := NewStopwatch(50 * time.Millisecond) - lookup.TimeAfter = stopwatch.TimeAfter() - defer stopwatch.Stop() - - // ### 2.- Setup mock storage, without adding updates - // don't write anything and try to look up. - // we're testing we don't get stuck in a loop and that the lookup - // function converges in a timely fashion - store := NewStore(DefaultStoreConfig) - readFunc := store.MakeReadFunc() - - now := uint64(1533903729) - - // ### 3.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - store.Reset() - - stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), now, lookup.NoClue, readFunc) - if err != nil { - t.Fatal(err) - } - if value != nil { - t.Fatal("Expected value to be nil, since the update should've failed") - } - }) - - printMetric("SIMPLE", store, stopwatch.Elapsed()) - }) - } -} - -func TestHighFreqUpdates(t *testing.T) { - // ### 1.- Initialize stopwatch time sim - stopwatch := NewStopwatch(50 * time.Millisecond) - lookup.TimeAfter = stopwatch.TimeAfter() - defer stopwatch.Stop() - - // ### 2.- Setup mock storage and add one update per second - // for the last 1000 seconds: - store := NewStore(DefaultStoreConfig) - readFunc := store.MakeReadFunc() - - now := uint64(1533903729) - - var epoch lookup.Epoch - - var lastData *Data - for i := uint64(0); i <= 994; i++ { - T := uint64(now - 1000 + i) - data := Data{ - Payload: T, //our "payload" will be the timestamp itself. - Time: T, - } - epoch = store.Update(epoch, T, &data) - lastData = &data - } - - // ### 3.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - store.Reset() // reset read counters for next test - - // ### 3.1.- Test how long it takes to find the last update without a hint: - timeElapsedWithoutHint := stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), lastData.Time, lookup.NoClue, readFunc) - stopwatch.Stop() - if err != nil { - t.Fatal(err) - } - - if value != lastData { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) - } - }) - printMetric("SIMPLE", store, timeElapsedWithoutHint) - - // reset the read count for the next test - store.Reset() - - // ### 3.2.- Now test how long it takes to find the last update *with* a hint, - // it should take less time! - timeElapsed := stopwatch.Measure(func() { - // Provide a hint to get a faster lookup. In particular, we give the exact location of the last update - value, err := algo.Lookup(context.Background(), now, epoch, readFunc) - stopwatch.Stop() - if err != nil { - t.Fatal(err) - } - - if value != lastData { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) - } - - }) - if timeElapsed > timeElapsedWithoutHint { - t.Fatalf("Expected lookup to complete faster than %s since we provided a hint. Took %s", timeElapsedWithoutHint, timeElapsed) - } - printMetric("WITH HINT", store, timeElapsed) - - store.Reset() // reset read counters - - // ### 3.3.- Test multiple lookups at different intervals - timeElapsed = stopwatch.Measure(func() { - for i := uint64(0); i <= 10; i++ { - T := uint64(now - 1000 + i) - value, err := algo.Lookup(context.Background(), T, lookup.NoClue, readFunc) - if err != nil { - t.Fatal(err) - } - data, _ := value.(*Data) - if data == nil { - t.Fatalf("Expected lookup to return %d, got nil", T) - } - if data.Payload != T { - t.Fatalf("Expected lookup to return %d, got %d", T, data.Time) - } - } - }) - printMetric("MULTIPLE", store, timeElapsed) - }) - } -} - -// TestSparseUpdates checks the lookup algorithm when -// updates come sparsely and in bursts -func TestSparseUpdates(t *testing.T) { - // ### 1.- Initialize stopwatch time sim - stopwatch := NewStopwatch(50 * time.Millisecond) - lookup.TimeAfter = stopwatch.TimeAfter() - defer stopwatch.Stop() - - // ### 2.- Setup mock storage and write an updates sparsely in bursts, - // every 5 years 3 times starting in Jan 1st 1970 and then silence - store := NewStore(DefaultStoreConfig) - readFunc := store.MakeReadFunc() - - now := uint64(633799046) - var epoch lookup.Epoch - - var lastData *Data - for i := uint64(0); i < 3; i++ { - for j := uint64(0); j < 10; j++ { - T := uint64(Year*5*i + j) // write a burst of 10 updates every 5 years 3 times starting in Jan 1st 1970 and then silence - data := Data{ - Payload: T, //our "payload" will be the timestamp itself. - Time: T, - } - epoch = store.Update(epoch, T, &data) - lastData = &data - } - } - - // ### 3.- Test all algorithms - for _, algo := range algorithms { - t.Run(algo.Name, func(t *testing.T) { - store.Reset() // reset read counters for next test - - // ### 3.1.- Test how long it takes to find the last update without a hint: - timeElapsedWithoutHint := stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), now, lookup.NoClue, readFunc) - stopwatch.Stop() - if err != nil { - t.Fatal(err) - } - - if value != lastData { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) - } - }) - printMetric("SIMPLE", store, timeElapsedWithoutHint) - - // reset the read count for the next test - store.Reset() - - // ### 3.2.- Now test how long it takes to find the last update *with* a hint, - // it should take less time! - timeElapsed := stopwatch.Measure(func() { - value, err := algo.Lookup(context.Background(), now, epoch, readFunc) - if err != nil { - t.Fatal(err) - } - - if value != lastData { - t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value) - } - }) - if timeElapsed > timeElapsedWithoutHint { - t.Fatalf("Expected lookup to complete faster than %s since we provided a hint. Took %s", timeElapsedWithoutHint, timeElapsed) - } - - printMetric("WITH HINT", store, stopwatch.Elapsed()) - - }) - } -} - -// testG will hold precooked test results -// fields are abbreviated to reduce the size of the literal below -type testG struct { - e lookup.Epoch // last - n uint64 // next level - x uint8 // expected result -} - -// test cases -var testGetNextLevelCases = []testG{{e: lookup.Epoch{Time: 989875233, Level: 12}, n: 989807323, x: 24}, {e: lookup.Epoch{Time: 995807650, Level: 18}, n: 995807649, x: 17}, {e: lookup.Epoch{Time: 969167082, Level: 0}, n: 969111431, x: 18}, {e: lookup.Epoch{Time: 993087628, Level: 14}, n: 993087627, x: 13}, {e: lookup.Epoch{Time: 963364631, Level: 20}, n: 962941578, x: 19}, {e: lookup.Epoch{Time: 963497510, Level: 16}, n: 963497509, x: 15}, {e: lookup.Epoch{Time: 955421349, Level: 22}, n: 929292183, x: 27}, {e: lookup.Epoch{Time: 968220379, Level: 15}, n: 968220378, x: 14}, {e: lookup.Epoch{Time: 939129014, Level: 6}, n: 939126953, x: 11}, {e: lookup.Epoch{Time: 907847903, Level: 6}, n: 907846146, x: 11}, {e: lookup.Epoch{Time: 910835564, Level: 15}, n: 703619757, x: 28}, {e: lookup.Epoch{Time: 913578333, Level: 22}, n: 913578332, x: 21}, {e: lookup.Epoch{Time: 895818460, Level: 3}, n: 895818132, x: 9}, {e: lookup.Epoch{Time: 903843025, Level: 24}, n: 903843025, x: 23}, {e: lookup.Epoch{Time: 877889433, Level: 13}, n: 149120378, x: 29}, {e: lookup.Epoch{Time: 901450396, Level: 10}, n: 858997793, x: 26}, {e: lookup.Epoch{Time: 925179910, Level: 3}, n: 925177237, x: 13}, {e: lookup.Epoch{Time: 913485477, Level: 21}, n: 907146511, x: 22}, {e: lookup.Epoch{Time: 924462991, Level: 18}, n: 924462990, x: 17}, {e: lookup.Epoch{Time: 941175128, Level: 13}, n: 941168924, x: 13}, {e: lookup.Epoch{Time: 920126583, Level: 3}, n: 538054817, x: 28}, {e: lookup.Epoch{Time: 891721312, Level: 18}, n: 890975671, x: 21}, {e: lookup.Epoch{Time: 920397342, Level: 11}, n: 920396960, x: 10}, {e: lookup.Epoch{Time: 953406530, Level: 3}, n: 953406530, x: 2}, {e: lookup.Epoch{Time: 920024527, Level: 23}, n: 920024527, x: 22}, {e: lookup.Epoch{Time: 927050922, Level: 7}, n: 927049632, x: 11}, {e: lookup.Epoch{Time: 894599900, Level: 10}, n: 890021707, x: 22}, {e: lookup.Epoch{Time: 883010150, Level: 3}, n: 882969902, x: 15}, {e: lookup.Epoch{Time: 855561102, Level: 22}, n: 855561102, x: 21}, {e: lookup.Epoch{Time: 828245477, Level: 19}, n: 825245571, x: 22}, {e: lookup.Epoch{Time: 851095026, Level: 4}, n: 851083702, x: 13}, {e: lookup.Epoch{Time: 879209039, Level: 11}, n: 879209039, x: 10}, {e: lookup.Epoch{Time: 859265651, Level: 0}, n: 840582083, x: 24}, {e: lookup.Epoch{Time: 827349870, Level: 24}, n: 827349869, x: 23}, {e: lookup.Epoch{Time: 819602318, Level: 3}, n: 18446744073490860182, x: 31}, {e: lookup.Epoch{Time: 849708538, Level: 7}, n: 849708538, x: 6}, {e: lookup.Epoch{Time: 873885094, Level: 11}, n: 873881798, x: 11}, {e: lookup.Epoch{Time: 852169070, Level: 1}, n: 852049399, x: 17}, {e: lookup.Epoch{Time: 852885343, Level: 8}, n: 852875652, x: 13}, {e: lookup.Epoch{Time: 830957057, Level: 8}, n: 830955867, x: 10}, {e: lookup.Epoch{Time: 807353611, Level: 4}, n: 807325211, x: 16}, {e: lookup.Epoch{Time: 803198793, Level: 8}, n: 696477575, x: 26}, {e: lookup.Epoch{Time: 791356887, Level: 10}, n: 791356003, x: 10}, {e: lookup.Epoch{Time: 817771215, Level: 12}, n: 817708431, x: 17}, {e: lookup.Epoch{Time: 846211146, Level: 14}, n: 846211146, x: 13}, {e: lookup.Epoch{Time: 821849822, Level: 9}, n: 821849229, x: 9}, {e: lookup.Epoch{Time: 789508756, Level: 9}, n: 789508755, x: 8}, {e: lookup.Epoch{Time: 814088521, Level: 12}, n: 814088512, x: 11}, {e: lookup.Epoch{Time: 813665673, Level: 6}, n: 813548257, x: 17}, {e: lookup.Epoch{Time: 791472209, Level: 6}, n: 720857845, x: 26}, {e: lookup.Epoch{Time: 805687744, Level: 2}, n: 805687720, x: 6}, {e: lookup.Epoch{Time: 783153927, Level: 12}, n: 783134053, x: 14}, {e: lookup.Epoch{Time: 815033655, Level: 11}, n: 815033654, x: 10}, {e: lookup.Epoch{Time: 821184581, Level: 6}, n: 821184464, x: 11}, {e: lookup.Epoch{Time: 841908114, Level: 2}, n: 841636025, x: 18}, {e: lookup.Epoch{Time: 862969167, Level: 20}, n: 862919955, x: 19}, {e: lookup.Epoch{Time: 887604565, Level: 21}, n: 887604564, x: 20}, {e: lookup.Epoch{Time: 863723789, Level: 10}, n: 858274530, x: 22}, {e: lookup.Epoch{Time: 851533290, Level: 10}, n: 851531385, x: 11}, {e: lookup.Epoch{Time: 826032484, Level: 14}, n: 826032484, x: 13}, {e: lookup.Epoch{Time: 819401505, Level: 7}, n: 818943526, x: 18}, {e: lookup.Epoch{Time: 800886832, Level: 12}, n: 800563106, x: 19}, {e: lookup.Epoch{Time: 780767476, Level: 10}, n: 694450997, x: 26}, {e: lookup.Epoch{Time: 789209418, Level: 15}, n: 789209417, x: 14}, {e: lookup.Epoch{Time: 816086666, Level: 9}, n: 816034646, x: 18}, {e: lookup.Epoch{Time: 835407077, Level: 21}, n: 835407076, x: 20}, {e: lookup.Epoch{Time: 846527322, Level: 20}, n: 846527321, x: 19}, {e: lookup.Epoch{Time: 850131130, Level: 19}, n: 18446744073670013406, x: 31}, {e: lookup.Epoch{Time: 842248607, Level: 24}, n: 783963834, x: 28}, {e: lookup.Epoch{Time: 816181999, Level: 2}, n: 816124867, x: 15}, {e: lookup.Epoch{Time: 806627026, Level: 17}, n: 756013427, x: 28}, {e: lookup.Epoch{Time: 826223084, Level: 4}, n: 826169865, x: 16}, {e: lookup.Epoch{Time: 835380147, Level: 21}, n: 835380147, x: 20}, {e: lookup.Epoch{Time: 860137874, Level: 3}, n: 860137782, x: 7}, {e: lookup.Epoch{Time: 860623757, Level: 8}, n: 860621582, x: 12}, {e: lookup.Epoch{Time: 875464114, Level: 24}, n: 875464114, x: 23}, {e: lookup.Epoch{Time: 853804052, Level: 6}, n: 853804051, x: 5}, {e: lookup.Epoch{Time: 864150903, Level: 14}, n: 854360673, x: 24}, {e: lookup.Epoch{Time: 850104561, Level: 23}, n: 850104561, x: 22}, {e: lookup.Epoch{Time: 878020186, Level: 24}, n: 878020186, x: 23}, {e: lookup.Epoch{Time: 900150940, Level: 8}, n: 899224760, x: 21}, {e: lookup.Epoch{Time: 869566202, Level: 2}, n: 869566199, x: 3}, {e: lookup.Epoch{Time: 851878045, Level: 5}, n: 851878045, x: 4}, {e: lookup.Epoch{Time: 824469671, Level: 12}, n: 824466504, x: 13}, {e: lookup.Epoch{Time: 819830223, Level: 9}, n: 816550241, x: 22}, {e: lookup.Epoch{Time: 813720249, Level: 20}, n: 801351581, x: 28}, {e: lookup.Epoch{Time: 831200185, Level: 20}, n: 830760165, x: 19}, {e: lookup.Epoch{Time: 838915973, Level: 9}, n: 838915972, x: 8}, {e: lookup.Epoch{Time: 812902644, Level: 5}, n: 812902644, x: 4}, {e: lookup.Epoch{Time: 812755887, Level: 3}, n: 812755887, x: 2}, {e: lookup.Epoch{Time: 822497779, Level: 8}, n: 822486000, x: 14}, {e: lookup.Epoch{Time: 832407585, Level: 9}, n: 579450238, x: 28}, {e: lookup.Epoch{Time: 799645403, Level: 23}, n: 799645403, x: 22}, {e: lookup.Epoch{Time: 827279665, Level: 2}, n: 826723872, x: 19}, {e: lookup.Epoch{Time: 846062554, Level: 6}, n: 765881119, x: 28}, {e: lookup.Epoch{Time: 855122998, Level: 6}, n: 855122978, x: 5}, {e: lookup.Epoch{Time: 841905104, Level: 4}, n: 751401236, x: 28}, {e: lookup.Epoch{Time: 857737438, Level: 12}, n: 325468127, x: 29}, {e: lookup.Epoch{Time: 838103691, Level: 18}, n: 779030823, x: 28}, {e: lookup.Epoch{Time: 841581240, Level: 22}, n: 841581239, x: 21}} - -// TestGetNextLevel tests the lookup.GetNextLevel function -func TestGetNextLevel(t *testing.T) { - - // First, test well-known cases - last := lookup.Epoch{ - Time: 1533799046, - Level: 5, - } - - level := lookup.GetNextLevel(last, last.Time) - expected := uint8(4) - if level != expected { - t.Fatalf("Expected GetNextLevel to return %d for same-time updates at a nonzero level, got %d", expected, level) - } - - level = lookup.GetNextLevel(last, last.Time+(1< lookup.HighestLevel { - v = 0 - } - now = last.Time + uint64(rand.Intn(1< s.maxSimultaneous { - s.maxSimultaneous = s.activeReads - } - - // 1.- Simulate a cache read - item := s.cache[epochID] - operationTime += s.CacheReadTime - - if item != nil { - s.cacheHits++ - if item.Time <= now { - s.successful++ - return item, nil - } - return nil, nil - } - - // 2.- simulate a full read - - item = s.data[epochID] - if item != nil { - operationTime += s.SuccessfulReadTime - s.successful++ - s.cache[epochID] = item - if item.Time <= now { - return item, nil - } - } else { - operationTime += s.FailedReadTime - s.failed++ - } - return nil, nil -} - -// MakeReadFunc returns a read function suitable for the lookup algorithm, mapped -// to this mock storage -func (s *Store) MakeReadFunc() lookup.ReadFunc { - return func(ctx context.Context, epoch lookup.Epoch, now uint64) (interface{}, error) { - return s.Get(ctx, epoch, now) - } -} diff --git a/swarm/storage/feed/lookup/timesim_test.go b/swarm/storage/feed/lookup/timesim_test.go deleted file mode 100644 index 2a254188cc..0000000000 --- a/swarm/storage/feed/lookup/timesim_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package lookup_test - -// This file contains simple time simulation tools for testing -// and measuring time-aware algorithms - -import ( - "sync" - "time" -) - -// Timer tracks information about a simulated timer -type Timer struct { - deadline time.Time - signal chan time.Time - id int -} - -// Stopwatch measures simulated execution time and manages simulated timers -type Stopwatch struct { - t time.Time - resolution time.Duration - timers map[int]*Timer - timerCounter int - stopSignal chan struct{} - lock sync.RWMutex -} - -// NewStopwatch returns a simulated clock that ticks on `resolution` intervals -func NewStopwatch(resolution time.Duration) *Stopwatch { - s := &Stopwatch{ - resolution: resolution, - } - s.Reset() - return s -} - -// Reset clears all timers and sents the stopwatch to zero -func (s *Stopwatch) Reset() { - s.t = time.Time{} - s.timers = make(map[int]*Timer) - s.Stop() -} - -// Tick advances simulated time by the stopwatch's resolution and triggers -// all due timers -func (s *Stopwatch) Tick() { - s.t = s.t.Add(s.resolution) - - s.lock.Lock() - defer s.lock.Unlock() - - for id, timer := range s.timers { - if s.t.After(timer.deadline) || s.t.Equal(timer.deadline) { - timer.signal <- s.t - close(timer.signal) - delete(s.timers, id) - } - } -} - -// NewTimer returns a new timer that will trigger after `duration` elapses in the -// simulation -func (s *Stopwatch) NewTimer(duration time.Duration) <-chan time.Time { - s.lock.Lock() - defer s.lock.Unlock() - - s.timerCounter++ - timer := &Timer{ - deadline: s.t.Add(duration), - signal: make(chan time.Time, 1), - id: s.timerCounter, - } - - s.timers[timer.id] = timer - return timer.signal -} - -// TimeAfter returns a simulated timer factory that can replace `time.After` -func (s *Stopwatch) TimeAfter() func(d time.Duration) <-chan time.Time { - return func(d time.Duration) <-chan time.Time { - return s.NewTimer(d) - } -} - -// Elapsed returns the time that has passed in the simulation -func (s *Stopwatch) Elapsed() time.Duration { - return s.t.Sub(time.Time{}) -} - -// Run starts the time simulation -func (s *Stopwatch) Run() { - go func() { - stopSignal := make(chan struct{}) - s.lock.Lock() - if s.stopSignal != nil { - close(s.stopSignal) - } - s.stopSignal = stopSignal - s.lock.Unlock() - for { - select { - case <-time.After(1 * time.Millisecond): - s.Tick() - case <-stopSignal: - return - } - } - }() -} - -// Stop stops the time simulation -func (s *Stopwatch) Stop() { - s.lock.Lock() - defer s.lock.Unlock() - - if s.stopSignal != nil { - close(s.stopSignal) - s.stopSignal = nil - } -} - -func (s *Stopwatch) Measure(measuredFunc func()) time.Duration { - s.Reset() - s.Run() - defer s.Stop() - measuredFunc() - return s.Elapsed() -} diff --git a/swarm/storage/feed/query.go b/swarm/storage/feed/query.go deleted file mode 100644 index 8be78a9520..0000000000 --- a/swarm/storage/feed/query.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "fmt" - "strconv" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" -) - -// Query is used to specify constraints when performing an update lookup -// TimeLimit indicates an upper bound for the search. Set to 0 for "now" -type Query struct { - Feed - Hint lookup.Epoch - TimeLimit uint64 -} - -// FromValues deserializes this instance from a string key-value store -// useful to parse query strings -func (q *Query) FromValues(values Values) error { - time, _ := strconv.ParseUint(values.Get("time"), 10, 64) - q.TimeLimit = time - - level, _ := strconv.ParseUint(values.Get("hint.level"), 10, 32) - q.Hint.Level = uint8(level) - q.Hint.Time, _ = strconv.ParseUint(values.Get("hint.time"), 10, 64) - if q.Feed.User == (common.Address{}) { - return q.Feed.FromValues(values) - } - return nil -} - -// AppendValues serializes this structure into the provided string key-value store -// useful to build query strings -func (q *Query) AppendValues(values Values) { - if q.TimeLimit != 0 { - values.Set("time", fmt.Sprintf("%d", q.TimeLimit)) - } - if q.Hint.Level != 0 { - values.Set("hint.level", fmt.Sprintf("%d", q.Hint.Level)) - } - if q.Hint.Time != 0 { - values.Set("hint.time", fmt.Sprintf("%d", q.Hint.Time)) - } - q.Feed.AppendValues(values) -} - -// NewQuery constructs an Query structure to find updates on or before `time` -// if time == 0, the latest update will be looked up -func NewQuery(feed *Feed, time uint64, hint lookup.Epoch) *Query { - return &Query{ - TimeLimit: time, - Feed: *feed, - Hint: hint, - } -} - -// NewQueryLatest generates lookup parameters that look for the latest update to a feed -func NewQueryLatest(feed *Feed, hint lookup.Epoch) *Query { - return NewQuery(feed, 0, hint) -} diff --git a/swarm/storage/feed/query_test.go b/swarm/storage/feed/query_test.go deleted file mode 100644 index 1ec45762e4..0000000000 --- a/swarm/storage/feed/query_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "testing" -) - -func getTestQuery() *Query { - id := getTestID() - return &Query{ - TimeLimit: 5000, - Feed: id.Feed, - Hint: id.Epoch, - } -} - -func TestQueryValues(t *testing.T) { - var expected = KV{"hint.level": "31", "hint.time": "1000", "time": "5000", "topic": "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000", "user": "0x876A8936A7Cd0b79Ef0735AD0896c1AFe278781c"} - - query := getTestQuery() - testValueSerializer(t, query, expected) - -} diff --git a/swarm/storage/feed/request.go b/swarm/storage/feed/request.go deleted file mode 100644 index dd91a7cf45..0000000000 --- a/swarm/storage/feed/request.go +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "bytes" - "encoding/json" - "hash" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" -) - -// Request represents a request to sign or signed feed update message -type Request struct { - Update // actual content that will be put on the chunk, less signature - Signature *Signature - idAddr storage.Address // cached chunk address for the update (not serialized, for internal use) - binaryData []byte // cached serialized data (does not get serialized again!, for efficiency/internal use) -} - -// updateRequestJSON represents a JSON-serialized UpdateRequest -type updateRequestJSON struct { - ID - ProtocolVersion uint8 `json:"protocolVersion"` - Data string `json:"data,omitempty"` - Signature string `json:"signature,omitempty"` -} - -// Request layout -// Update bytes -// SignatureLength bytes -const minimumSignedUpdateLength = minimumUpdateDataLength + signatureLength - -// NewFirstRequest returns a ready to sign request to publish a first feed update -func NewFirstRequest(topic Topic) *Request { - - request := new(Request) - - // get the current time - now := TimestampProvider.Now().Time - request.Epoch = lookup.GetFirstEpoch(now) - request.Feed.Topic = topic - request.Header.Version = ProtocolVersion - - return request -} - -// SetData stores the payload data the feed update will be updated with -func (r *Request) SetData(data []byte) { - r.data = data - r.Signature = nil -} - -// IsUpdate returns true if this request models a signed update or otherwise it is a signature request -func (r *Request) IsUpdate() bool { - return r.Signature != nil -} - -// Verify checks that signatures are valid -func (r *Request) Verify() (err error) { - if len(r.data) == 0 { - return NewError(ErrInvalidValue, "Update does not contain data") - } - if r.Signature == nil { - return NewError(ErrInvalidSignature, "Missing signature field") - } - - digest, err := r.GetDigest() - if err != nil { - return err - } - - // get the address of the signer (which also checks that it's a valid signature) - r.Feed.User, err = getUserAddr(digest, *r.Signature) - if err != nil { - return err - } - - // check that the lookup information contained in the chunk matches the updateAddr (chunk search key) - // that was used to retrieve this chunk - // if this validation fails, someone forged a chunk. - if !bytes.Equal(r.idAddr, r.Addr()) { - return NewError(ErrInvalidSignature, "Signature address does not match with update user address") - } - - return nil -} - -// Sign executes the signature to validate the update message -func (r *Request) Sign(signer Signer) error { - r.Feed.User = signer.Address() - r.binaryData = nil //invalidate serialized data - digest, err := r.GetDigest() // computes digest and serializes into .binaryData - if err != nil { - return err - } - - signature, err := signer.Sign(digest) - if err != nil { - return err - } - - // Although the Signer interface returns the public address of the signer, - // recover it from the signature to see if they match - userAddr, err := getUserAddr(digest, signature) - if err != nil { - return NewError(ErrInvalidSignature, "Error verifying signature") - } - - if userAddr != signer.Address() { // sanity check to make sure the Signer is declaring the same address used to sign! - return NewError(ErrInvalidSignature, "Signer address does not match update user address") - } - - r.Signature = &signature - r.idAddr = r.Addr() - return nil -} - -// GetDigest creates the feed update digest used in signatures -// the serialized payload is cached in .binaryData -func (r *Request) GetDigest() (result common.Hash, err error) { - hasher := hashPool.Get().(hash.Hash) - defer hashPool.Put(hasher) - hasher.Reset() - dataLength := r.Update.binaryLength() - if r.binaryData == nil { - r.binaryData = make([]byte, dataLength+signatureLength) - if err := r.Update.binaryPut(r.binaryData[:dataLength]); err != nil { - return result, err - } - } - hasher.Write(r.binaryData[:dataLength]) //everything except the signature. - - return common.BytesToHash(hasher.Sum(nil)), nil -} - -// create an update chunk. -func (r *Request) toChunk() (storage.Chunk, error) { - - // Check that the update is signed and serialized - // For efficiency, data is serialized during signature and cached in - // the binaryData field when computing the signature digest in .getDigest() - if r.Signature == nil || r.binaryData == nil { - return nil, NewError(ErrInvalidSignature, "toChunk called without a valid signature or payload data. Call .Sign() first.") - } - - updateLength := r.Update.binaryLength() - - // signature is the last item in the chunk data - copy(r.binaryData[updateLength:], r.Signature[:]) - - chunk := storage.NewChunk(r.idAddr, r.binaryData) - return chunk, nil -} - -// fromChunk populates this structure from chunk data. It does not verify the signature is valid. -func (r *Request) fromChunk(chunk storage.Chunk) error { - // for update chunk layout see Request definition - - chunkdata := chunk.Data() - - //deserialize the feed update portion - if err := r.Update.binaryGet(chunkdata[:len(chunkdata)-signatureLength]); err != nil { - return err - } - - // Extract the signature - var signature *Signature - cursor := r.Update.binaryLength() - sigdata := chunkdata[cursor : cursor+signatureLength] - if len(sigdata) > 0 { - signature = &Signature{} - copy(signature[:], sigdata) - } - - r.Signature = signature - r.idAddr = chunk.Address() - r.binaryData = chunkdata - - return nil - -} - -// FromValues deserializes this instance from a string key-value store -// useful to parse query strings -func (r *Request) FromValues(values Values, data []byte) error { - signatureBytes, err := hexutil.Decode(values.Get("signature")) - if err != nil { - r.Signature = nil - } else { - if len(signatureBytes) != signatureLength { - return NewError(ErrInvalidSignature, "Incorrect signature length") - } - r.Signature = new(Signature) - copy(r.Signature[:], signatureBytes) - } - err = r.Update.FromValues(values, data) - if err != nil { - return err - } - r.idAddr = r.Addr() - return err -} - -// AppendValues serializes this structure into the provided string key-value store -// useful to build query strings -func (r *Request) AppendValues(values Values) []byte { - if r.Signature != nil { - values.Set("signature", hexutil.Encode(r.Signature[:])) - } - return r.Update.AppendValues(values) -} - -// fromJSON takes an update request JSON and populates an UpdateRequest -func (r *Request) fromJSON(j *updateRequestJSON) error { - - r.ID = j.ID - r.Header.Version = j.ProtocolVersion - - var err error - if j.Data != "" { - r.data, err = hexutil.Decode(j.Data) - if err != nil { - return NewError(ErrInvalidValue, "Cannot decode data") - } - } - - if j.Signature != "" { - sigBytes, err := hexutil.Decode(j.Signature) - if err != nil || len(sigBytes) != signatureLength { - return NewError(ErrInvalidSignature, "Cannot decode signature") - } - r.Signature = new(Signature) - r.idAddr = r.Addr() - copy(r.Signature[:], sigBytes) - } - return nil -} - -// UnmarshalJSON takes a JSON structure stored in a byte array and populates the Request object -// Implements json.Unmarshaler interface -func (r *Request) UnmarshalJSON(rawData []byte) error { - var requestJSON updateRequestJSON - if err := json.Unmarshal(rawData, &requestJSON); err != nil { - return err - } - return r.fromJSON(&requestJSON) -} - -// MarshalJSON takes an update request and encodes it as a JSON structure into a byte array -// Implements json.Marshaler interface -func (r *Request) MarshalJSON() (rawData []byte, err error) { - var signatureString, dataString string - if r.Signature != nil { - signatureString = hexutil.Encode(r.Signature[:]) - } - if r.data != nil { - dataString = hexutil.Encode(r.data) - } - - requestJSON := &updateRequestJSON{ - ID: r.ID, - ProtocolVersion: r.Header.Version, - Data: dataString, - Signature: signatureString, - } - - return json.Marshal(requestJSON) -} diff --git a/swarm/storage/feed/request_test.go b/swarm/storage/feed/request_test.go deleted file mode 100644 index b9c1381c65..0000000000 --- a/swarm/storage/feed/request_test.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "bytes" - "encoding/binary" - "encoding/json" - "fmt" - "reflect" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" -) - -func areEqualJSON(s1, s2 string) (bool, error) { - //credit for the trick: turtlemonvh https://gist.github.com/turtlemonvh/e4f7404e28387fadb8ad275a99596f67 - var o1 interface{} - var o2 interface{} - - err := json.Unmarshal([]byte(s1), &o1) - if err != nil { - return false, fmt.Errorf("Error mashalling string 1 :: %s", err.Error()) - } - err = json.Unmarshal([]byte(s2), &o2) - if err != nil { - return false, fmt.Errorf("Error mashalling string 2 :: %s", err.Error()) - } - - return reflect.DeepEqual(o1, o2), nil -} - -// TestEncodingDecodingUpdateRequests ensures that requests are serialized properly -// while also checking cryptographically that only the owner of a feed can update it. -func TestEncodingDecodingUpdateRequests(t *testing.T) { - - charlie := newCharlieSigner() //Charlie - bob := newBobSigner() //Bob - - // Create a feed to our good guy Charlie's name - topic, _ := NewTopic("a good topic name", nil) - firstRequest := NewFirstRequest(topic) - firstRequest.User = charlie.Address() - - // We now encode the create message to simulate we send it over the wire - messageRawData, err := firstRequest.MarshalJSON() - if err != nil { - t.Fatalf("Error encoding first feed update request: %s", err) - } - - // ... the message arrives and is decoded... - var recoveredFirstRequest Request - if err := recoveredFirstRequest.UnmarshalJSON(messageRawData); err != nil { - t.Fatalf("Error decoding first feed update request: %s", err) - } - - // ... but verification should fail because it is not signed! - if err := recoveredFirstRequest.Verify(); err == nil { - t.Fatal("Expected Verify to fail since the message is not signed") - } - - // We now assume that the feed ypdate was created and propagated. - - const expectedSignature = "0x7235b27a68372ddebcf78eba48543fa460864b0b0e99cb533fcd3664820e603312d29426dd00fb39628f5299480a69bf6e462838d78de49ce0704c754c9deb2601" - const expectedJSON = `{"feed":{"topic":"0x6120676f6f6420746f706963206e616d65000000000000000000000000000000","user":"0x876a8936a7cd0b79ef0735ad0896c1afe278781c"},"epoch":{"time":1000,"level":1},"protocolVersion":0,"data":"0x5468697320686f75722773207570646174653a20537761726d2039392e3020686173206265656e2072656c656173656421"}` - - //Put together an unsigned update request that we will serialize to send it to the signer. - data := []byte("This hour's update: Swarm 99.0 has been released!") - request := &Request{ - Update: Update{ - ID: ID{ - Epoch: lookup.Epoch{ - Time: 1000, - Level: 1, - }, - Feed: firstRequest.Update.Feed, - }, - data: data, - }, - } - - messageRawData, err = request.MarshalJSON() - if err != nil { - t.Fatalf("Error encoding update request: %s", err) - } - - equalJSON, err := areEqualJSON(string(messageRawData), expectedJSON) - if err != nil { - t.Fatalf("Error decoding update request JSON: %s", err) - } - if !equalJSON { - t.Fatalf("Received a different JSON message. Expected %s, got %s", expectedJSON, string(messageRawData)) - } - - // now the encoded message messageRawData is sent over the wire and arrives to the signer - - //Attempt to extract an UpdateRequest out of the encoded message - var recoveredRequest Request - if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil { - t.Fatalf("Error decoding update request: %s", err) - } - - //sign the request and see if it matches our predefined signature above. - if err := recoveredRequest.Sign(charlie); err != nil { - t.Fatalf("Error signing request: %s", err) - } - - compareByteSliceToExpectedHex(t, "signature", recoveredRequest.Signature[:], expectedSignature) - - // mess with the signature and see what happens. To alter the signature, we briefly decode it as JSON - // to alter the signature field. - var j updateRequestJSON - if err := json.Unmarshal([]byte(expectedJSON), &j); err != nil { - t.Fatal("Error unmarshalling test json, check expectedJSON constant") - } - j.Signature = "Certainly not a signature" - corruptMessage, _ := json.Marshal(j) // encode the message with the bad signature - var corruptRequest Request - if err = corruptRequest.UnmarshalJSON(corruptMessage); err == nil { - t.Fatal("Expected DecodeUpdateRequest to fail when trying to interpret a corrupt message with an invalid signature") - } - - // Now imagine Bob wants to create an update of his own about the same feed, - // signing a message with his private key - if err := request.Sign(bob); err != nil { - t.Fatalf("Error signing: %s", err) - } - - // Now Bob encodes the message to send it over the wire... - messageRawData, err = request.MarshalJSON() - if err != nil { - t.Fatalf("Error encoding message:%s", err) - } - - // ... the message arrives to our Swarm node and it is decoded. - recoveredRequest = Request{} - if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil { - t.Fatalf("Error decoding message:%s", err) - } - - // Before checking what happened with Bob's update, let's see what would happen if we mess - // with the signature big time to see if Verify catches it - savedSignature := *recoveredRequest.Signature // save the signature for later - binary.LittleEndian.PutUint64(recoveredRequest.Signature[5:], 556845463424) // write some random data to break the signature - if err = recoveredRequest.Verify(); err == nil { - t.Fatal("Expected Verify to fail on corrupt signature") - } - - // restore the Bob's signature from corruption - *recoveredRequest.Signature = savedSignature - - // Now the signature is not corrupt - if err = recoveredRequest.Verify(); err != nil { - t.Fatal(err) - } - - // Reuse object and sign with our friend Charlie's private key - if err := recoveredRequest.Sign(charlie); err != nil { - t.Fatalf("Error signing with the correct private key: %s", err) - } - - // And now, Verify should work since this update now belongs to Charlie - if err = recoveredRequest.Verify(); err != nil { - t.Fatalf("Error verifying that Charlie, can sign a reused request object:%s", err) - } - - // mess with the lookup key to make sure Verify fails: - recoveredRequest.Time = 77999 // this will alter the lookup key - if err = recoveredRequest.Verify(); err == nil { - t.Fatalf("Expected Verify to fail since the lookup key has been altered") - } -} - -func getTestRequest() *Request { - return &Request{ - Update: *getTestFeedUpdate(), - } -} - -func TestUpdateChunkSerializationErrorChecking(t *testing.T) { - - // Test that parseUpdate fails if the chunk is too small - var r Request - if err := r.fromChunk(storage.NewChunk(storage.ZeroAddr, make([]byte, minimumUpdateDataLength-1+signatureLength))); err == nil { - t.Fatalf("Expected request.fromChunk to fail when chunkData contains less than %d bytes", minimumUpdateDataLength) - } - - r = *getTestRequest() - - _, err := r.toChunk() - if err == nil { - t.Fatal("Expected request.toChunk to fail when there is no data") - } - r.data = []byte("Al bien hacer jamás le falta premio") // put some arbitrary length data - _, err = r.toChunk() - if err == nil { - t.Fatal("expected request.toChunk to fail when there is no signature") - } - - charlie := newCharlieSigner() - if err := r.Sign(charlie); err != nil { - t.Fatalf("error signing:%s", err) - } - - chunk, err := r.toChunk() - if err != nil { - t.Fatalf("error creating update chunk:%s", err) - } - - compareByteSliceToExpectedHex(t, "chunk", chunk.Data(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce80300000000001f416c206269656e206861636572206a616dc3a173206c652066616c7461207072656d696f9896df5937e64e51a7994479ff3fe0ed790d539b9b3e85e93c0014a8a64374f23603c79d16e99b50a757896d3816d7022ac594ad1415679a9b164afb2e5926d801") - - var recovered Request - recovered.fromChunk(chunk) - if !reflect.DeepEqual(recovered, r) { - t.Fatal("Expected recovered feed update request to equal the original one") - } -} - -// check that signature address matches update signer address -func TestReverse(t *testing.T) { - - epoch := lookup.Epoch{ - Time: 7888, - Level: 6, - } - - // make fake timeProvider - timeProvider := &fakeTimeProvider{ - currentTime: startTime.Time, - } - - // signer containing private key - signer := newAliceSigner() - - // set up rpc and create feeds handler - _, _, teardownTest, err := setupTest(timeProvider, signer) - if err != nil { - t.Fatal(err) - } - defer teardownTest() - - topic, _ := NewTopic("Cervantes quotes", nil) - fd := Feed{ - Topic: topic, - User: signer.Address(), - } - - data := []byte("Donde una puerta se cierra, otra se abre") - - request := new(Request) - request.Feed = fd - request.Epoch = epoch - request.data = data - - // generate a chunk key for this request - key := request.Addr() - - if err = request.Sign(signer); err != nil { - t.Fatal(err) - } - - chunk, err := request.toChunk() - if err != nil { - t.Fatal(err) - } - - // check that we can recover the owner account from the update chunk's signature - var checkUpdate Request - if err := checkUpdate.fromChunk(chunk); err != nil { - t.Fatal(err) - } - checkdigest, err := checkUpdate.GetDigest() - if err != nil { - t.Fatal(err) - } - recoveredAddr, err := getUserAddr(checkdigest, *checkUpdate.Signature) - if err != nil { - t.Fatalf("Retrieve address from signature fail: %v", err) - } - originalAddr := crypto.PubkeyToAddress(signer.PrivKey.PublicKey) - - // check that the metadata retrieved from the chunk matches what we gave it - if recoveredAddr != originalAddr { - t.Fatalf("addresses dont match: %x != %x", originalAddr, recoveredAddr) - } - - if !bytes.Equal(key[:], chunk.Address()[:]) { - t.Fatalf("Expected chunk key '%x', was '%x'", key, chunk.Address()) - } - if epoch != checkUpdate.Epoch { - t.Fatalf("Expected epoch to be '%s', was '%s'", epoch.String(), checkUpdate.Epoch.String()) - } - if !bytes.Equal(data, checkUpdate.data) { - t.Fatalf("Expected data '%x', was '%x'", data, checkUpdate.data) - } -} diff --git a/swarm/storage/feed/sign.go b/swarm/storage/feed/sign.go deleted file mode 100644 index 5f0ea0b33c..0000000000 --- a/swarm/storage/feed/sign.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "crypto/ecdsa" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -const signatureLength = 65 - -// Signature is an alias for a static byte array with the size of a signature -type Signature [signatureLength]byte - -// Signer signs feed update payloads -type Signer interface { - Sign(common.Hash) (Signature, error) - Address() common.Address -} - -// GenericSigner implements the Signer interface -// It is the vanilla signer that probably should be used in most cases -type GenericSigner struct { - PrivKey *ecdsa.PrivateKey - address common.Address -} - -// NewGenericSigner builds a signer that will sign everything with the provided private key -func NewGenericSigner(privKey *ecdsa.PrivateKey) *GenericSigner { - return &GenericSigner{ - PrivKey: privKey, - address: crypto.PubkeyToAddress(privKey.PublicKey), - } -} - -// Sign signs the supplied data -// It wraps the ethereum crypto.Sign() method -func (s *GenericSigner) Sign(data common.Hash) (signature Signature, err error) { - signaturebytes, err := crypto.Sign(data.Bytes(), s.PrivKey) - if err != nil { - return - } - copy(signature[:], signaturebytes) - return -} - -// Address returns the public key of the signer's private key -func (s *GenericSigner) Address() common.Address { - return s.address -} - -// getUserAddr extracts the address of the feed update signer -func getUserAddr(digest common.Hash, signature Signature) (common.Address, error) { - pub, err := crypto.SigToPub(digest.Bytes(), signature[:]) - if err != nil { - return common.Address{}, err - } - return crypto.PubkeyToAddress(*pub), nil -} diff --git a/swarm/storage/feed/testutil.go b/swarm/storage/feed/testutil.go deleted file mode 100644 index db2d989e18..0000000000 --- a/swarm/storage/feed/testutil.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "context" - "path/filepath" - "sync" - - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" -) - -const ( - testDbDirName = "feeds" -) - -type TestHandler struct { - *Handler -} - -func (t *TestHandler) Close() { - t.chunkStore.Close() -} - -type mockNetFetcher struct{} - -func (m *mockNetFetcher) Request(hopCount uint8) { -} -func (m *mockNetFetcher) Offer(source *enode.ID) { -} - -func newFakeNetFetcher(context.Context, storage.Address, *sync.Map) storage.NetFetcher { - return &mockNetFetcher{} -} - -// NewTestHandler creates Handler object to be used for testing purposes. -func NewTestHandler(datadir string, params *HandlerParams) (*TestHandler, error) { - path := filepath.Join(datadir, testDbDirName) - fh := NewHandler(params) - - db, err := localstore.New(filepath.Join(path, "chunks"), make([]byte, 32), nil) - if err != nil { - return nil, err - } - - localStore := chunk.NewValidatorStore(db, storage.NewContentAddressValidator(storage.MakeHashFunc(feedsHashAlgorithm)), fh) - - netStore, err := storage.NewNetStore(localStore, nil) - if err != nil { - return nil, err - } - netStore.NewNetFetcherFunc = newFakeNetFetcher - fh.SetStore(netStore) - return &TestHandler{fh}, nil -} diff --git a/swarm/storage/feed/timestampprovider.go b/swarm/storage/feed/timestampprovider.go deleted file mode 100644 index fb60cea9c3..0000000000 --- a/swarm/storage/feed/timestampprovider.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "encoding/json" - "time" -) - -// TimestampProvider sets the time source of the feeds package -var TimestampProvider timestampProvider = NewDefaultTimestampProvider() - -// Timestamp encodes a point in time as a Unix epoch -type Timestamp struct { - Time uint64 `json:"time"` // Unix epoch timestamp, in seconds -} - -// timestampProvider interface describes a source of timestamp information -type timestampProvider interface { - Now() Timestamp // returns the current timestamp information -} - -// UnmarshalJSON implements the json.Unmarshaller interface -func (t *Timestamp) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &t.Time) -} - -// MarshalJSON implements the json.Marshaller interface -func (t *Timestamp) MarshalJSON() ([]byte, error) { - return json.Marshal(t.Time) -} - -// DefaultTimestampProvider is a TimestampProvider that uses system time -// as time source -type DefaultTimestampProvider struct { -} - -// NewDefaultTimestampProvider creates a system clock based timestamp provider -func NewDefaultTimestampProvider() *DefaultTimestampProvider { - return &DefaultTimestampProvider{} -} - -// Now returns the current time according to this provider -func (dtp *DefaultTimestampProvider) Now() Timestamp { - return Timestamp{ - Time: uint64(time.Now().Unix()), - } -} diff --git a/swarm/storage/feed/topic.go b/swarm/storage/feed/topic.go deleted file mode 100644 index 43a7b4ba4c..0000000000 --- a/swarm/storage/feed/topic.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "bytes" - "encoding/json" - "fmt" - - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/swarm/storage" -) - -// TopicLength establishes the max length of a topic string -const TopicLength = storage.AddressLength - -// Topic represents what a feed is about -type Topic [TopicLength]byte - -// ErrTopicTooLong is returned when creating a topic with a name/related content too long -var ErrTopicTooLong = fmt.Errorf("Topic is too long. Max length is %d", TopicLength) - -// NewTopic creates a new topic from a provided name and "related content" byte array, -// merging the two together. -// If relatedContent or name are longer than TopicLength, they will be truncated and an error returned -// name can be an empty string -// relatedContent can be nil -func NewTopic(name string, relatedContent []byte) (topic Topic, err error) { - if relatedContent != nil { - contentLength := len(relatedContent) - if contentLength > TopicLength { - contentLength = TopicLength - err = ErrTopicTooLong - } - copy(topic[:], relatedContent[:contentLength]) - } - nameBytes := []byte(name) - nameLength := len(nameBytes) - if nameLength > TopicLength { - nameLength = TopicLength - err = ErrTopicTooLong - } - bitutil.XORBytes(topic[:], topic[:], nameBytes[:nameLength]) - return topic, err -} - -// Hex will return the topic encoded as an hex string -func (t *Topic) Hex() string { - return hexutil.Encode(t[:]) -} - -// FromHex will parse a hex string into this Topic instance -func (t *Topic) FromHex(hex string) error { - bytes, err := hexutil.Decode(hex) - if err != nil || len(bytes) != len(t) { - return NewErrorf(ErrInvalidValue, "Cannot decode topic") - } - copy(t[:], bytes) - return nil -} - -// Name will try to extract the topic name out of the Topic -func (t *Topic) Name(relatedContent []byte) string { - nameBytes := *t - if relatedContent != nil { - contentLength := len(relatedContent) - if contentLength > TopicLength { - contentLength = TopicLength - } - bitutil.XORBytes(nameBytes[:], t[:], relatedContent[:contentLength]) - } - z := bytes.IndexByte(nameBytes[:], 0) - if z < 0 { - z = TopicLength - } - return string(nameBytes[:z]) - -} - -// UnmarshalJSON implements the json.Unmarshaller interface -func (t *Topic) UnmarshalJSON(data []byte) error { - var hex string - json.Unmarshal(data, &hex) - return t.FromHex(hex) -} - -// MarshalJSON implements the json.Marshaller interface -func (t *Topic) MarshalJSON() ([]byte, error) { - return json.Marshal(t.Hex()) -} diff --git a/swarm/storage/feed/topic_test.go b/swarm/storage/feed/topic_test.go deleted file mode 100644 index 0403204f7f..0000000000 --- a/swarm/storage/feed/topic_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package feed - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common/hexutil" -) - -func TestTopic(t *testing.T) { - related, _ := hexutil.Decode("0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789") - topicName := "test-topic" - topic, _ := NewTopic(topicName, related) - hex := topic.Hex() - expectedHex := "0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789" - if hex != expectedHex { - t.Fatalf("Expected %s, got %s", expectedHex, hex) - } - - var topic2 Topic - topic2.FromHex(hex) - if topic2 != topic { - t.Fatal("Expected recovered topic to be equal to original one") - } - - if topic2.Name(related) != topicName { - t.Fatal("Retrieved name does not match") - } - - bytes, err := topic2.MarshalJSON() - if err != nil { - t.Fatal(err) - } - expectedJSON := `"0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789"` - equal, err := areEqualJSON(expectedJSON, string(bytes)) - if err != nil { - t.Fatal(err) - } - if !equal { - t.Fatalf("Expected JSON to be %s, got %s", expectedJSON, string(bytes)) - } - - err = topic2.UnmarshalJSON(bytes) - if err != nil { - t.Fatal(err) - } - if topic2 != topic { - t.Fatal("Expected recovered topic to be equal to original one") - } - -} diff --git a/swarm/storage/feed/update.go b/swarm/storage/feed/update.go deleted file mode 100644 index 21c004ca42..0000000000 --- a/swarm/storage/feed/update.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "fmt" - "strconv" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// ProtocolVersion defines the current version of the protocol that will be included in each update message -const ProtocolVersion uint8 = 0 - -const headerLength = 8 - -// Header defines a update message header including a protocol version byte -type Header struct { - Version uint8 // Protocol version - Padding [headerLength - 1]uint8 // reserved for future use -} - -// Update encapsulates the information sent as part of a feed update -type Update struct { - Header Header // - ID // Feed Update identifying information - data []byte // actual data payload -} - -const minimumUpdateDataLength = idLength + headerLength + 1 - -//MaxUpdateDataLength indicates the maximum payload size for a feed update -const MaxUpdateDataLength = chunk.DefaultSize - signatureLength - idLength - headerLength - -// binaryPut serializes the feed update information into the given slice -func (r *Update) binaryPut(serializedData []byte) error { - datalength := len(r.data) - if datalength == 0 { - return NewError(ErrInvalidValue, "a feed update must contain data") - } - - if datalength > MaxUpdateDataLength { - return NewErrorf(ErrInvalidValue, "feed update data is too big (length=%d). Max length=%d", datalength, MaxUpdateDataLength) - } - - if len(serializedData) != r.binaryLength() { - return NewErrorf(ErrInvalidValue, "slice passed to putBinary must be of exact size. Expected %d bytes", r.binaryLength()) - } - - var cursor int - // serialize Header - serializedData[cursor] = r.Header.Version - copy(serializedData[cursor+1:headerLength], r.Header.Padding[:headerLength-1]) - cursor += headerLength - - // serialize ID - if err := r.ID.binaryPut(serializedData[cursor : cursor+idLength]); err != nil { - return err - } - cursor += idLength - - // add the data - copy(serializedData[cursor:], r.data) - cursor += datalength - - return nil -} - -// binaryLength returns the expected number of bytes this structure will take to encode -func (r *Update) binaryLength() int { - return idLength + headerLength + len(r.data) -} - -// binaryGet populates this instance from the information contained in the passed byte slice -func (r *Update) binaryGet(serializedData []byte) error { - if len(serializedData) < minimumUpdateDataLength { - return NewErrorf(ErrNothingToReturn, "chunk less than %d bytes cannot be a feed update chunk", minimumUpdateDataLength) - } - dataLength := len(serializedData) - idLength - headerLength - // at this point we can be satisfied that we have the correct data length to read - - var cursor int - - // deserialize Header - r.Header.Version = serializedData[cursor] // extract the protocol version - copy(r.Header.Padding[:headerLength-1], serializedData[cursor+1:headerLength]) // extract the padding - cursor += headerLength - - if err := r.ID.binaryGet(serializedData[cursor : cursor+idLength]); err != nil { - return err - } - cursor += idLength - - data := serializedData[cursor : cursor+dataLength] - cursor += dataLength - - // now that all checks have passed, copy data into structure - r.data = make([]byte, dataLength) - copy(r.data, data) - - return nil - -} - -// FromValues deserializes this instance from a string key-value store -// useful to parse query strings -func (r *Update) FromValues(values Values, data []byte) error { - r.data = data - version, _ := strconv.ParseUint(values.Get("protocolVersion"), 10, 32) - r.Header.Version = uint8(version) - return r.ID.FromValues(values) -} - -// AppendValues serializes this structure into the provided string key-value store -// useful to build query strings -func (r *Update) AppendValues(values Values) []byte { - r.ID.AppendValues(values) - values.Set("protocolVersion", fmt.Sprintf("%d", r.Header.Version)) - return r.data -} diff --git a/swarm/storage/feed/update_test.go b/swarm/storage/feed/update_test.go deleted file mode 100644 index e4e0963e9f..0000000000 --- a/swarm/storage/feed/update_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package feed - -import ( - "testing" -) - -func getTestFeedUpdate() *Update { - return &Update{ - ID: *getTestID(), - data: []byte("El que lee mucho y anda mucho, ve mucho y sabe mucho"), - } -} - -func TestUpdateSerializer(t *testing.T) { - testBinarySerializerRecovery(t, getTestFeedUpdate(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce80300000000001f456c20717565206c6565206d7563686f207920616e6461206d7563686f2c207665206d7563686f20792073616265206d7563686f") -} - -func TestUpdateLengthCheck(t *testing.T) { - testBinarySerializerLengthCheck(t, getTestFeedUpdate()) - // Test fail if update is too big - update := getTestFeedUpdate() - update.data = make([]byte, MaxUpdateDataLength+100) - serialized := make([]byte, update.binaryLength()) - if err := update.binaryPut(serialized); err == nil { - t.Fatal("Expected update.binaryPut to fail since update is too big") - } - - // test fail if data is empty or nil - update.data = nil - serialized = make([]byte, update.binaryLength()) - if err := update.binaryPut(serialized); err == nil { - t.Fatal("Expected update.binaryPut to fail since data is empty") - } -} diff --git a/swarm/storage/filestore.go b/swarm/storage/filestore.go deleted file mode 100644 index dc096e56cb..0000000000 --- a/swarm/storage/filestore.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "context" - "io" - "sort" - "sync" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" -) - -/* -FileStore provides the client API entrypoints Store and Retrieve to store and retrieve -It can store anything that has a byte slice representation, so files or serialised objects etc. - -Storage: FileStore calls the Chunker to segment the input datastream of any size to a merkle hashed tree of chunks. The key of the root block is returned to the client. - -Retrieval: given the key of the root block, the FileStore retrieves the block chunks and reconstructs the original data and passes it back as a lazy reader. A lazy reader is a reader with on-demand delayed processing, i.e. the chunks needed to reconstruct a large file are only fetched and processed if that particular part of the document is actually read. - -As the chunker produces chunks, FileStore dispatches them to its own chunk store -implementation for storage or retrieval. -*/ - -const ( - defaultLDBCapacity = 5000000 // capacity for LevelDB, by default 5*10^6*4096 bytes == 20GB - defaultCacheCapacity = 10000 // capacity for in-memory chunks' cache - defaultChunkRequestsCacheCapacity = 5000000 // capacity for container holding outgoing requests for chunks. should be set to LevelDB capacity -) - -type FileStore struct { - ChunkStore - hashFunc SwarmHasher - tags *chunk.Tags -} - -type FileStoreParams struct { - Hash string -} - -func NewFileStoreParams() *FileStoreParams { - return &FileStoreParams{ - Hash: DefaultHash, - } -} - -// for testing locally -func NewLocalFileStore(datadir string, basekey []byte, tags *chunk.Tags) (*FileStore, error) { - localStore, err := localstore.New(datadir, basekey, nil) - if err != nil { - return nil, err - } - return NewFileStore(chunk.NewValidatorStore(localStore, NewContentAddressValidator(MakeHashFunc(DefaultHash))), NewFileStoreParams(), tags), nil -} - -func NewFileStore(store ChunkStore, params *FileStoreParams, tags *chunk.Tags) *FileStore { - hashFunc := MakeHashFunc(params.Hash) - return &FileStore{ - ChunkStore: store, - hashFunc: hashFunc, - tags: tags, - } -} - -// Retrieve is a public API. Main entry point for document retrieval directly. Used by the -// FS-aware API and httpaccess -// Chunk retrieval blocks on netStore requests with a timeout so reader will -// report error if retrieval of chunks within requested range time out. -// It returns a reader with the chunk data and whether the content was encrypted -func (f *FileStore) Retrieve(ctx context.Context, addr Address) (reader *LazyChunkReader, isEncrypted bool) { - isEncrypted = len(addr) > f.hashFunc().Size() - tag, err := f.tags.GetFromContext(ctx) - if err != nil { - tag = chunk.NewTag(0, "ephemeral-retrieval-tag", 0) - } - getter := NewHasherStore(f.ChunkStore, f.hashFunc, isEncrypted, tag) - reader = TreeJoin(ctx, addr, getter, 0) - return -} - -// Store is a public API. Main entry point for document storage directly. Used by the -// FS-aware API and httpaccess -func (f *FileStore) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr Address, wait func(context.Context) error, err error) { - tag, err := f.tags.GetFromContext(ctx) - if err != nil { - // some of the parts of the codebase, namely the manifest trie, do not store the context - // of the original request nor the tag with the trie, recalculating the trie hence - // loses the tag uid. thus we create an ephemeral tag here for that purpose - - tag = chunk.NewTag(0, "", 0) - //return nil, nil, err - } - putter := NewHasherStore(f.ChunkStore, f.hashFunc, toEncrypt, tag) - return PyramidSplit(ctx, data, putter, putter, tag) -} - -func (f *FileStore) HashSize() int { - return f.hashFunc().Size() -} - -// GetAllReferences is a public API. This endpoint returns all chunk hashes (only) for a given file -func (f *FileStore) GetAllReferences(ctx context.Context, data io.Reader, toEncrypt bool) (addrs AddressCollection, err error) { - tag := chunk.NewTag(0, "ephemeral-tag", 0) //this tag is just a mock ephemeral tag since we don't want to save these results - - // create a special kind of putter, which only will store the references - putter := &hashExplorer{ - hasherStore: NewHasherStore(f.ChunkStore, f.hashFunc, toEncrypt, tag), - } - // do the actual splitting anyway, no way around it - _, wait, err := PyramidSplit(ctx, data, putter, putter, tag) - if err != nil { - return nil, err - } - // wait for splitting to be complete and all chunks processed - err = wait(ctx) - if err != nil { - return nil, err - } - // collect all references - addrs = NewAddressCollection(0) - for _, ref := range putter.references { - addrs = append(addrs, Address(ref)) - } - sort.Sort(addrs) - return addrs, nil -} - -// hashExplorer is a special kind of putter which will only store chunk references -type hashExplorer struct { - *hasherStore - references []Reference - lock sync.Mutex -} - -// HashExplorer's Put will add just the chunk hashes to its `References` -func (he *hashExplorer) Put(ctx context.Context, chunkData ChunkData) (Reference, error) { - // Need to do the actual Put, which returns the references - ref, err := he.hasherStore.Put(ctx, chunkData) - if err != nil { - return nil, err - } - // internally store the reference - he.lock.Lock() - he.references = append(he.references, ref) - he.lock.Unlock() - return ref, nil -} diff --git a/swarm/storage/filestore_test.go b/swarm/storage/filestore_test.go deleted file mode 100644 index d0a167a244..0000000000 --- a/swarm/storage/filestore_test.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "bytes" - "context" - "io" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" - "github.com/ethereum/go-ethereum/swarm/testutil" -) - -const testDataSize = 0x0001000 - -func TestFileStorerandom(t *testing.T) { - testFileStoreRandom(false, t) - testFileStoreRandom(true, t) -} - -func testFileStoreRandom(toEncrypt bool, t *testing.T) { - dir, err := ioutil.TempDir("", "swarm-storage-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - localStore, err := localstore.New(dir, make([]byte, 32), nil) - if err != nil { - t.Fatal(err) - } - defer localStore.Close() - - fileStore := NewFileStore(localStore, NewFileStoreParams(), chunk.NewTags()) - - slice := testutil.RandomBytes(1, testDataSize) - ctx := context.TODO() - key, wait, err := fileStore.Store(ctx, bytes.NewReader(slice), testDataSize, toEncrypt) - if err != nil { - t.Fatalf("Store error: %v", err) - } - err = wait(ctx) - if err != nil { - t.Fatalf("Store waitt error: %v", err.Error()) - } - resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key) - if isEncrypted != toEncrypt { - t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) - } - resultSlice := make([]byte, testDataSize) - n, err := resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Fatalf("Retrieve error: %v", err) - } - if n != testDataSize { - t.Fatalf("Slice size error got %d, expected %d.", n, testDataSize) - } - if !bytes.Equal(slice, resultSlice) { - t.Fatalf("Comparison error.") - } - ioutil.WriteFile(filepath.Join(dir, "slice.bzz.16M"), slice, 0666) - ioutil.WriteFile(filepath.Join(dir, "result.bzz.16M"), resultSlice, 0666) - resultReader, isEncrypted = fileStore.Retrieve(context.TODO(), key) - if isEncrypted != toEncrypt { - t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) - } - for i := range resultSlice { - resultSlice[i] = 0 - } - n, err = resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Fatalf("Retrieve error after removing memStore: %v", err) - } - if n != len(slice) { - t.Fatalf("Slice size error after removing memStore got %d, expected %d.", n, len(slice)) - } - if !bytes.Equal(slice, resultSlice) { - t.Fatalf("Comparison error after removing memStore.") - } -} - -func TestFileStoreCapacity(t *testing.T) { - testFileStoreCapacity(false, t) - testFileStoreCapacity(true, t) -} - -func testFileStoreCapacity(toEncrypt bool, t *testing.T) { - dir, err := ioutil.TempDir("", "swarm-storage-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - localStore, err := localstore.New(dir, make([]byte, 32), nil) - if err != nil { - t.Fatal(err) - } - defer localStore.Close() - - fileStore := NewFileStore(localStore, NewFileStoreParams(), chunk.NewTags()) - slice := testutil.RandomBytes(1, testDataSize) - ctx := context.TODO() - key, wait, err := fileStore.Store(ctx, bytes.NewReader(slice), testDataSize, toEncrypt) - if err != nil { - t.Errorf("Store error: %v", err) - } - err = wait(ctx) - if err != nil { - t.Fatalf("Store error: %v", err) - } - resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key) - if isEncrypted != toEncrypt { - t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) - } - resultSlice := make([]byte, len(slice)) - n, err := resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Fatalf("Retrieve error: %v", err) - } - if n != len(slice) { - t.Fatalf("Slice size error got %d, expected %d.", n, len(slice)) - } - if !bytes.Equal(slice, resultSlice) { - t.Fatalf("Comparison error.") - } - resultReader, isEncrypted = fileStore.Retrieve(context.TODO(), key) - if isEncrypted != toEncrypt { - t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) - } - if _, err = resultReader.ReadAt(resultSlice, 0); err == nil { - t.Fatalf("Was able to read %d bytes from an empty memStore.", len(slice)) - } - // check how it works with localStore - fileStore.ChunkStore = localStore - // localStore.dbStore.setCapacity(0) - resultReader, isEncrypted = fileStore.Retrieve(context.TODO(), key) - if isEncrypted != toEncrypt { - t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) - } - for i := range resultSlice { - resultSlice[i] = 0 - } - n, err = resultReader.ReadAt(resultSlice, 0) - if err != io.EOF { - t.Fatalf("Retrieve error after clearing memStore: %v", err) - } - if n != len(slice) { - t.Fatalf("Slice size error after clearing memStore got %d, expected %d.", n, len(slice)) - } - if !bytes.Equal(slice, resultSlice) { - t.Fatalf("Comparison error after clearing memStore.") - } -} - -// TestGetAllReferences only tests that GetAllReferences returns an expected -// number of references for a given file -func TestGetAllReferences(t *testing.T) { - dir, err := ioutil.TempDir("", "swarm-storage-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - localStore, err := localstore.New(dir, make([]byte, 32), nil) - if err != nil { - t.Fatal(err) - } - defer localStore.Close() - - fileStore := NewFileStore(localStore, NewFileStoreParams(), chunk.NewTags()) - - // testRuns[i] and expectedLen[i] are dataSize and expected length respectively - testRuns := []int{1024, 8192, 16000, 30000, 1000000} - expectedLens := []int{1, 3, 5, 9, 248} - for i, r := range testRuns { - slice := testutil.RandomBytes(1, r) - - addrs, err := fileStore.GetAllReferences(context.Background(), bytes.NewReader(slice), false) - if err != nil { - t.Fatal(err) - } - if len(addrs) != expectedLens[i] { - t.Fatalf("Expected reference array length to be %d, but is %d", expectedLens[i], len(addrs)) - } - } -} diff --git a/swarm/storage/hasherstore.go b/swarm/storage/hasherstore.go deleted file mode 100644 index 1e702f11ae..0000000000 --- a/swarm/storage/hasherstore.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "context" - "fmt" - "sync/atomic" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage/encryption" - "golang.org/x/crypto/sha3" -) - -type hasherStore struct { - store ChunkStore - tag *chunk.Tag - toEncrypt bool - hashFunc SwarmHasher - hashSize int // content hash size - refSize int64 // reference size (content hash + possibly encryption key) - errC chan error // global error channel - doneC chan struct{} // closed by Close() call to indicate that count is the final number of chunks - quitC chan struct{} // closed to quit unterminated routines - // nrChunks is used with atomic functions - // it is required to be at the end of the struct to ensure 64bit alignment for arm architecture - // see: https://golang.org/pkg/sync/atomic/#pkg-note-BUG - nrChunks uint64 // number of chunks to store -} - -// NewHasherStore creates a hasherStore object, which implements Putter and Getter interfaces. -// With the HasherStore you can put and get chunk data (which is just []byte) into a ChunkStore -// and the hasherStore will take core of encryption/decryption of data if necessary -func NewHasherStore(store ChunkStore, hashFunc SwarmHasher, toEncrypt bool, tag *chunk.Tag) *hasherStore { - hashSize := hashFunc().Size() - refSize := int64(hashSize) - if toEncrypt { - refSize += encryption.KeyLength - } - - h := &hasherStore{ - store: store, - tag: tag, - toEncrypt: toEncrypt, - hashFunc: hashFunc, - hashSize: hashSize, - refSize: refSize, - errC: make(chan error), - doneC: make(chan struct{}), - quitC: make(chan struct{}), - } - - return h -} - -// Put stores the chunkData into the ChunkStore of the hasherStore and returns the reference. -// If hasherStore has a chunkEncryption object, the data will be encrypted. -// Asynchronous function, the data will not necessarily be stored when it returns. -func (h *hasherStore) Put(ctx context.Context, chunkData ChunkData) (Reference, error) { - c := chunkData - var encryptionKey encryption.Key - if h.toEncrypt { - var err error - c, encryptionKey, err = h.encryptChunkData(chunkData) - if err != nil { - return nil, err - } - } - chunk := h.createChunk(c) - h.storeChunk(ctx, chunk) - - return Reference(append(chunk.Address(), encryptionKey...)), nil -} - -// Get returns data of the chunk with the given reference (retrieved from the ChunkStore of hasherStore). -// If the data is encrypted and the reference contains an encryption key, it will be decrypted before -// return. -func (h *hasherStore) Get(ctx context.Context, ref Reference) (ChunkData, error) { - addr, encryptionKey, err := parseReference(ref, h.hashSize) - if err != nil { - return nil, err - } - - chunk, err := h.store.Get(ctx, chunk.ModeGetRequest, addr) - if err != nil { - return nil, err - } - - chunkData := ChunkData(chunk.Data()) - toDecrypt := (encryptionKey != nil) - if toDecrypt { - var err error - chunkData, err = h.decryptChunkData(chunkData, encryptionKey) - if err != nil { - return nil, err - } - } - return chunkData, nil -} - -// Close indicates that no more chunks will be put with the hasherStore, so the Wait -// function can return when all the previously put chunks has been stored. -func (h *hasherStore) Close() { - close(h.doneC) -} - -// Wait returns when -// 1) the Close() function has been called and -// 2) all the chunks which has been Put has been stored -func (h *hasherStore) Wait(ctx context.Context) error { - defer close(h.quitC) - var nrStoredChunks uint64 // number of stored chunks - var done bool - doneC := h.doneC - for { - select { - // if context is done earlier, just return with the error - case <-ctx.Done(): - return ctx.Err() - // doneC is closed if all chunks have been submitted, from then we just wait until all of them are also stored - case <-doneC: - done = true - doneC = nil - // a chunk has been stored, if err is nil, then successfully, so increase the stored chunk counter - case err := <-h.errC: - if err != nil { - return err - } - nrStoredChunks++ - } - // if all the chunks have been submitted and all of them are stored, then we can return - if done { - if nrStoredChunks >= atomic.LoadUint64(&h.nrChunks) { - return nil - } - } - } -} - -func (h *hasherStore) createHash(chunkData ChunkData) Address { - hasher := h.hashFunc() - hasher.ResetWithLength(chunkData[:8]) // 8 bytes of length - hasher.Write(chunkData[8:]) // minus 8 []byte length - return hasher.Sum(nil) -} - -func (h *hasherStore) createChunk(chunkData ChunkData) Chunk { - hash := h.createHash(chunkData) - chunk := NewChunk(hash, chunkData) - return chunk -} - -func (h *hasherStore) encryptChunkData(chunkData ChunkData) (ChunkData, encryption.Key, error) { - if len(chunkData) < 8 { - return nil, nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData)) - } - - key, encryptedSpan, encryptedData, err := h.encrypt(chunkData) - if err != nil { - return nil, nil, err - } - c := make(ChunkData, len(encryptedSpan)+len(encryptedData)) - copy(c[:8], encryptedSpan) - copy(c[8:], encryptedData) - return c, key, nil -} - -func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryption.Key) (ChunkData, error) { - if len(chunkData) < 8 { - return nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData)) - } - - decryptedSpan, decryptedData, err := h.decrypt(chunkData, encryptionKey) - if err != nil { - return nil, err - } - - // removing extra bytes which were just added for padding - length := ChunkData(decryptedSpan).Size() - for length > chunk.DefaultSize { - length = length + (chunk.DefaultSize - 1) - length = length / chunk.DefaultSize - length *= uint64(h.refSize) - } - - c := make(ChunkData, length+8) - copy(c[:8], decryptedSpan) - copy(c[8:], decryptedData[:length]) - - return c, nil -} - -func (h *hasherStore) RefSize() int64 { - return h.refSize -} - -func (h *hasherStore) encrypt(chunkData ChunkData) (encryption.Key, []byte, []byte, error) { - key := encryption.GenerateRandomKey(encryption.KeyLength) - encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8]) - if err != nil { - return nil, nil, nil, err - } - encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:]) - if err != nil { - return nil, nil, nil, err - } - return key, encryptedSpan, encryptedData, nil -} - -func (h *hasherStore) decrypt(chunkData ChunkData, key encryption.Key) ([]byte, []byte, error) { - encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8]) - if err != nil { - return nil, nil, err - } - encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:]) - if err != nil { - return nil, nil, err - } - return encryptedSpan, encryptedData, nil -} - -func (h *hasherStore) newSpanEncryption(key encryption.Key) encryption.Encryption { - return encryption.New(key, 0, uint32(chunk.DefaultSize/h.refSize), sha3.NewLegacyKeccak256) -} - -func (h *hasherStore) newDataEncryption(key encryption.Key) encryption.Encryption { - return encryption.New(key, int(chunk.DefaultSize), 0, sha3.NewLegacyKeccak256) -} - -func (h *hasherStore) storeChunk(ctx context.Context, ch Chunk) { - atomic.AddUint64(&h.nrChunks, 1) - go func() { - seen, err := h.store.Put(ctx, chunk.ModePutUpload, ch) - h.tag.Inc(chunk.StateStored) - if seen { - h.tag.Inc(chunk.StateSeen) - } - select { - case h.errC <- err: - case <-h.quitC: - } - }() -} - -func parseReference(ref Reference, hashSize int) (Address, encryption.Key, error) { - encryptedRefLength := hashSize + encryption.KeyLength - switch len(ref) { - case AddressLength: - return Address(ref), nil, nil - case encryptedRefLength: - encKeyIdx := len(ref) - encryption.KeyLength - return Address(ref[:encKeyIdx]), encryption.Key(ref[encKeyIdx:]), nil - default: - return nil, nil, fmt.Errorf("Invalid reference length, expected %v or %v got %v", hashSize, encryptedRefLength, len(ref)) - } -} diff --git a/swarm/storage/hasherstore_test.go b/swarm/storage/hasherstore_test.go deleted file mode 100644 index 9dfd7ab1d9..0000000000 --- a/swarm/storage/hasherstore_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "bytes" - "context" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage/encryption" -) - -func TestHasherStore(t *testing.T) { - var tests = []struct { - chunkLength int - toEncrypt bool - }{ - {10, false}, - {100, false}, - {1000, false}, - {4096, false}, - {10, true}, - {100, true}, - {1000, true}, - {4096, true}, - } - - for _, tt := range tests { - chunkStore := NewMapChunkStore() - hasherStore := NewHasherStore(chunkStore, MakeHashFunc(DefaultHash), tt.toEncrypt, chunk.NewTag(0, "test-tag", 0)) - - // Put two random chunks into the hasherStore - chunkData1 := GenerateRandomChunk(int64(tt.chunkLength)).Data() - ctx, cancel := context.WithTimeout(context.Background(), getTimeout) - defer cancel() - key1, err := hasherStore.Put(ctx, chunkData1) - if err != nil { - t.Fatalf("Expected no error got \"%v\"", err) - } - - chunkData2 := GenerateRandomChunk(int64(tt.chunkLength)).Data() - key2, err := hasherStore.Put(ctx, chunkData2) - if err != nil { - t.Fatalf("Expected no error got \"%v\"", err) - } - - hasherStore.Close() - - // Wait until chunks are really stored - err = hasherStore.Wait(ctx) - if err != nil { - t.Fatalf("Expected no error got \"%v\"", err) - } - - // Get the first chunk - retrievedChunkData1, err := hasherStore.Get(ctx, key1) - if err != nil { - t.Fatalf("Expected no error, got \"%v\"", err) - } - - // Retrieved data should be same as the original - if !bytes.Equal(chunkData1, retrievedChunkData1) { - t.Fatalf("Expected retrieved chunk data %v, got %v", common.Bytes2Hex(chunkData1), common.Bytes2Hex(retrievedChunkData1)) - } - - // Get the second chunk - retrievedChunkData2, err := hasherStore.Get(ctx, key2) - if err != nil { - t.Fatalf("Expected no error, got \"%v\"", err) - } - - // Retrieved data should be same as the original - if !bytes.Equal(chunkData2, retrievedChunkData2) { - t.Fatalf("Expected retrieved chunk data %v, got %v", common.Bytes2Hex(chunkData2), common.Bytes2Hex(retrievedChunkData2)) - } - - hash1, encryptionKey1, err := parseReference(key1, hasherStore.hashSize) - if err != nil { - t.Fatalf("Expected no error, got \"%v\"", err) - } - - if tt.toEncrypt { - if encryptionKey1 == nil { - t.Fatal("Expected non-nil encryption key, got nil") - } else if len(encryptionKey1) != encryption.KeyLength { - t.Fatalf("Expected encryption key length %v, got %v", encryption.KeyLength, len(encryptionKey1)) - } - } - if !tt.toEncrypt && encryptionKey1 != nil { - t.Fatalf("Expected nil encryption key, got key with length %v", len(encryptionKey1)) - } - - // Check if chunk data in store is encrypted or not - chunkInStore, err := chunkStore.Get(ctx, chunk.ModeGetRequest, hash1) - if err != nil { - t.Fatalf("Expected no error got \"%v\"", err) - } - - chunkDataInStore := chunkInStore.Data() - - if tt.toEncrypt && bytes.Equal(chunkData1, chunkDataInStore) { - t.Fatalf("Chunk expected to be encrypted but it is stored without encryption") - } - if !tt.toEncrypt && !bytes.Equal(chunkData1, chunkDataInStore) { - t.Fatalf("Chunk expected to be not encrypted but stored content is different. Expected %v got %v", common.Bytes2Hex(chunkData1), common.Bytes2Hex(chunkDataInStore)) - } - } -} diff --git a/swarm/storage/localstore/doc.go b/swarm/storage/localstore/doc.go deleted file mode 100644 index 98f6fc40aa..0000000000 --- a/swarm/storage/localstore/doc.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/* -Package localstore provides disk storage layer for Swarm Chunk persistence. -It uses swarm/shed abstractions on top of github.com/syndtr/goleveldb LevelDB -implementation. - -The main type is DB which manages the storage by providing methods to -access and add Chunks and to manage their status. - -Modes are abstractions that do specific changes to Chunks. There are three -mode types: - - - ModeGet, for Chunk access - - ModePut, for adding Chunks to the database - - ModeSet, for changing Chunk statuses - -Every mode type has a corresponding type (Getter, Putter and Setter) -that provides adequate method to perform the opperation and that type -should be injected into localstore consumers instead the whole DB. -This provides more clear insight which operations consumer is performing -on the database. - -Getters, Putters and Setters accept different get, put and set modes -to perform different actions. For example, ModeGet has two different -variables ModeGetRequest and ModeGetSync and two different Getters -can be constructed with them that are used when the chunk is requested -or when the chunk is synced as this two events are differently changing -the database. - -Subscription methods are implemented for a specific purpose of -continuous iterations over Chunks that should be provided to -Push and Pull syncing. - -DB implements an internal garbage collector that removes only synced -Chunks from the database based on their most recent access time. - -Internally, DB stores Chunk data and any required information, such as -store and access timestamps in different shed indexes that can be -iterated on by garbage collector or subscriptions. -*/ -package localstore diff --git a/swarm/storage/localstore/export.go b/swarm/storage/localstore/export.go deleted file mode 100644 index 411392b4e6..0000000000 --- a/swarm/storage/localstore/export.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "archive/tar" - "context" - "encoding/hex" - "fmt" - "io" - "io/ioutil" - "sync" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/shed" -) - -const ( - // filename in tar archive that holds the information - // about exported data format version - exportVersionFilename = ".swarm-export-version" - // legacy version for previous LDBStore - legacyExportVersion = "1" - // current export format version - currentExportVersion = "2" -) - -// Export writes a tar structured data to the writer of -// all chunks in the retrieval data index. It returns the -// number of chunks exported. -func (db *DB) Export(w io.Writer) (count int64, err error) { - tw := tar.NewWriter(w) - defer tw.Close() - - if err := tw.WriteHeader(&tar.Header{ - Name: exportVersionFilename, - Mode: 0644, - Size: int64(len(currentExportVersion)), - }); err != nil { - return 0, err - } - if _, err := tw.Write([]byte(currentExportVersion)); err != nil { - return 0, err - } - - err = db.retrievalDataIndex.Iterate(func(item shed.Item) (stop bool, err error) { - hdr := &tar.Header{ - Name: hex.EncodeToString(item.Address), - Mode: 0644, - Size: int64(len(item.Data)), - } - if err := tw.WriteHeader(hdr); err != nil { - return false, err - } - if _, err := tw.Write(item.Data); err != nil { - return false, err - } - count++ - return false, nil - }, nil) - - return count, err -} - -// Import reads a tar structured data from the reader and -// stores chunks in the database. It returns the number of -// chunks imported. -func (db *DB) Import(r io.Reader, legacy bool) (count int64, err error) { - tr := tar.NewReader(r) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - errC := make(chan error) - doneC := make(chan struct{}) - tokenPool := make(chan struct{}, 100) - var wg sync.WaitGroup - go func() { - var ( - firstFile = true - // if exportVersionFilename file is not present - // assume legacy version - version = legacyExportVersion - ) - for { - hdr, err := tr.Next() - if err != nil { - if err == io.EOF { - break - } - select { - case errC <- err: - case <-ctx.Done(): - } - } - if firstFile { - firstFile = false - if hdr.Name == exportVersionFilename { - data, err := ioutil.ReadAll(tr) - if err != nil { - select { - case errC <- err: - case <-ctx.Done(): - } - } - version = string(data) - continue - } - } - - if len(hdr.Name) != 64 { - log.Warn("ignoring non-chunk file", "name", hdr.Name) - continue - } - - keybytes, err := hex.DecodeString(hdr.Name) - if err != nil { - log.Warn("ignoring invalid chunk file", "name", hdr.Name, "err", err) - continue - } - - data, err := ioutil.ReadAll(tr) - if err != nil { - select { - case errC <- err: - case <-ctx.Done(): - } - } - key := chunk.Address(keybytes) - - var ch chunk.Chunk - switch version { - case legacyExportVersion: - // LDBStore Export exported chunk data prefixed with the chunk key. - // That is not necessary, as the key is in the chunk filename, - // but backward compatibility needs to be preserved. - ch = chunk.NewChunk(key, data[32:]) - case currentExportVersion: - ch = chunk.NewChunk(key, data) - default: - select { - case errC <- fmt.Errorf("unsupported export data version %q", version): - case <-ctx.Done(): - } - } - tokenPool <- struct{}{} - wg.Add(1) - - go func() { - _, err := db.Put(ctx, chunk.ModePutUpload, ch) - select { - case errC <- err: - case <-ctx.Done(): - wg.Done() - <-tokenPool - default: - _, err := db.Put(ctx, chunk.ModePutUpload, ch) - if err != nil { - errC <- err - } - wg.Done() - <-tokenPool - } - }() - - count++ - } - wg.Wait() - close(doneC) - }() - - // wait for all chunks to be stored - for { - select { - case err := <-errC: - if err != nil { - return count, err - } - case <-ctx.Done(): - return count, ctx.Err() - default: - select { - case <-doneC: - return count, nil - default: - } - } - } -} diff --git a/swarm/storage/localstore/export_test.go b/swarm/storage/localstore/export_test.go deleted file mode 100644 index d7f848f809..0000000000 --- a/swarm/storage/localstore/export_test.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "bytes" - "context" - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// TestExportImport constructs two databases, one to put and export -// chunks and another one to import and validate that all chunks are -// imported. -func TestExportImport(t *testing.T) { - db1, cleanup1 := newTestDB(t, nil) - defer cleanup1() - - var chunkCount = 100 - - chunks := make(map[string][]byte, chunkCount) - for i := 0; i < chunkCount; i++ { - ch := generateTestRandomChunk() - - _, err := db1.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - chunks[string(ch.Address())] = ch.Data() - } - - var buf bytes.Buffer - - c, err := db1.Export(&buf) - if err != nil { - t.Fatal(err) - } - wantChunksCount := int64(len(chunks)) - if c != wantChunksCount { - t.Errorf("got export count %v, want %v", c, wantChunksCount) - } - - db2, cleanup2 := newTestDB(t, nil) - defer cleanup2() - - c, err = db2.Import(&buf, false) - if err != nil { - t.Fatal(err) - } - if c != wantChunksCount { - t.Errorf("got import count %v, want %v", c, wantChunksCount) - } - - for a, want := range chunks { - addr := chunk.Address([]byte(a)) - ch, err := db2.Get(context.Background(), chunk.ModeGetRequest, addr) - if err != nil { - t.Fatal(err) - } - got := ch.Data() - if !bytes.Equal(got, want) { - t.Fatalf("chunk %s: got data %x, want %x", addr.Hex(), got, want) - } - } -} diff --git a/swarm/storage/localstore/gc.go b/swarm/storage/localstore/gc.go deleted file mode 100644 index 748e0d6630..0000000000 --- a/swarm/storage/localstore/gc.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/shed" - "github.com/syndtr/goleveldb/leveldb" -) - -var ( - // gcTargetRatio defines the target number of items - // in garbage collection index that will not be removed - // on garbage collection. The target number of items - // is calculated by gcTarget function. This value must be - // in range (0,1]. For example, with 0.9 value, - // garbage collection will leave 90% of defined capacity - // in database after its run. This prevents frequent - // garbage collection runs. - gcTargetRatio = 0.9 - // gcBatchSize limits the number of chunks in a single - // leveldb batch on garbage collection. - gcBatchSize uint64 = 1000 -) - -// collectGarbageWorker is a long running function that waits for -// collectGarbageTrigger channel to signal a garbage collection -// run. GC run iterates on gcIndex and removes older items -// form retrieval and other indexes. -func (db *DB) collectGarbageWorker() { - defer close(db.collectGarbageWorkerDone) - - for { - select { - case <-db.collectGarbageTrigger: - // run a single collect garbage run and - // if done is false, gcBatchSize is reached and - // another collect garbage run is needed - collectedCount, done, err := db.collectGarbage() - if err != nil { - log.Error("localstore collect garbage", "err", err) - } - // check if another gc run is needed - if !done { - db.triggerGarbageCollection() - } - - if collectedCount > 0 && testHookCollectGarbage != nil { - testHookCollectGarbage(collectedCount) - } - case <-db.close: - return - } - } -} - -// collectGarbage removes chunks from retrieval and other -// indexes if maximal number of chunks in database is reached. -// This function returns the number of removed chunks. If done -// is false, another call to this function is needed to collect -// the rest of the garbage as the batch size limit is reached. -// This function is called in collectGarbageWorker. -func (db *DB) collectGarbage() (collectedCount uint64, done bool, err error) { - metricName := "localstore.gc" - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - defer totalTimeMetric(metricName, time.Now()) - defer func() { - if err != nil { - metrics.GetOrRegisterCounter(metricName+".error", nil).Inc(1) - } - }() - - batch := new(leveldb.Batch) - target := db.gcTarget() - - // protect database from changing idexes and gcSize - db.batchMu.Lock() - defer db.batchMu.Unlock() - - gcSize, err := db.gcSize.Get() - if err != nil { - return 0, true, err - } - metrics.GetOrRegisterGauge(metricName+".gcsize", nil).Update(int64(gcSize)) - - done = true - err = db.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { - if gcSize-collectedCount <= target { - return true, nil - } - - metrics.GetOrRegisterGauge(metricName+".storets", nil).Update(item.StoreTimestamp) - metrics.GetOrRegisterGauge(metricName+".accessts", nil).Update(item.AccessTimestamp) - - // delete from retrieve, pull, gc - db.retrievalDataIndex.DeleteInBatch(batch, item) - db.retrievalAccessIndex.DeleteInBatch(batch, item) - db.pullIndex.DeleteInBatch(batch, item) - db.gcIndex.DeleteInBatch(batch, item) - collectedCount++ - if collectedCount >= gcBatchSize { - // bach size limit reached, - // another gc run is needed - done = false - return true, nil - } - return false, nil - }, nil) - if err != nil { - return 0, false, err - } - metrics.GetOrRegisterCounter(metricName+".collected-count", nil).Inc(int64(collectedCount)) - - db.gcSize.PutInBatch(batch, gcSize-collectedCount) - - err = db.shed.WriteBatch(batch) - if err != nil { - metrics.GetOrRegisterCounter(metricName+".writebatch.err", nil).Inc(1) - return 0, false, err - } - return collectedCount, done, nil -} - -// gcTrigger retruns the absolute value for garbage collection -// target value, calculated from db.capacity and gcTargetRatio. -func (db *DB) gcTarget() (target uint64) { - return uint64(float64(db.capacity) * gcTargetRatio) -} - -// triggerGarbageCollection signals collectGarbageWorker -// to call collectGarbage. -func (db *DB) triggerGarbageCollection() { - select { - case db.collectGarbageTrigger <- struct{}{}: - case <-db.close: - default: - } -} - -// incGCSizeInBatch changes gcSize field value -// by change which can be negative. This function -// must be called under batchMu lock. -func (db *DB) incGCSizeInBatch(batch *leveldb.Batch, change int64) (err error) { - if change == 0 { - return nil - } - gcSize, err := db.gcSize.Get() - if err != nil { - return err - } - - var new uint64 - if change > 0 { - new = gcSize + uint64(change) - } else { - // 'change' is an int64 and is negative - // a conversion is needed with correct sign - c := uint64(-change) - if c > gcSize { - // protect uint64 undeflow - return nil - } - new = gcSize - c - } - db.gcSize.PutInBatch(batch, new) - - // trigger garbage collection if we reached the capacity - if new >= db.capacity { - db.triggerGarbageCollection() - } - return nil -} - -// testHookCollectGarbage is a hook that can provide -// information when a garbage collection run is done -// and how many items it removed. -var testHookCollectGarbage func(collectedCount uint64) diff --git a/swarm/storage/localstore/gc_test.go b/swarm/storage/localstore/gc_test.go deleted file mode 100644 index 4a6e0a5f41..0000000000 --- a/swarm/storage/localstore/gc_test.go +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "io/ioutil" - "math/rand" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// TestDB_collectGarbageWorker tests garbage collection runs -// by uploading and syncing a number of chunks. -func TestDB_collectGarbageWorker(t *testing.T) { - testDB_collectGarbageWorker(t) -} - -// TestDB_collectGarbageWorker_multipleBatches tests garbage -// collection runs by uploading and syncing a number of -// chunks by having multiple smaller batches. -func TestDB_collectGarbageWorker_multipleBatches(t *testing.T) { - // lower the maximal number of chunks in a single - // gc batch to ensure multiple batches. - defer func(s uint64) { gcBatchSize = s }(gcBatchSize) - gcBatchSize = 2 - - testDB_collectGarbageWorker(t) -} - -// testDB_collectGarbageWorker is a helper test function to test -// garbage collection runs by uploading and syncing a number of chunks. -func testDB_collectGarbageWorker(t *testing.T) { - t.Helper() - - chunkCount := 150 - - db, cleanupFunc := newTestDB(t, &Options{ - Capacity: 100, - }) - testHookCollectGarbageChan := make(chan uint64) - defer setTestHookCollectGarbage(func(collectedCount uint64) { - select { - case testHookCollectGarbageChan <- collectedCount: - case <-db.close: - } - })() - defer cleanupFunc() - - addrs := make([]chunk.Address, 0) - - // upload random chunks - for i := 0; i < chunkCount; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - err = db.Set(context.Background(), chunk.ModeSetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - - addrs = append(addrs, ch.Address()) - } - - gcTarget := db.gcTarget() - - for { - select { - case <-testHookCollectGarbageChan: - case <-time.After(10 * time.Second): - t.Error("collect garbage timeout") - } - gcSize, err := db.gcSize.Get() - if err != nil { - t.Fatal(err) - } - if gcSize == gcTarget { - break - } - } - - t.Run("pull index count", newItemsCountTest(db.pullIndex, int(gcTarget))) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, int(gcTarget))) - - t.Run("gc size", newIndexGCSizeTest(db)) - - // the first synced chunk should be removed - t.Run("get the first synced chunk", func(t *testing.T) { - _, err := db.Get(context.Background(), chunk.ModeGetRequest, addrs[0]) - if err != chunk.ErrChunkNotFound { - t.Errorf("got error %v, want %v", err, chunk.ErrChunkNotFound) - } - }) - - // last synced chunk should not be removed - t.Run("get most recent synced chunk", func(t *testing.T) { - _, err := db.Get(context.Background(), chunk.ModeGetRequest, addrs[len(addrs)-1]) - if err != nil { - t.Fatal(err) - } - }) -} - -// TestDB_collectGarbageWorker_withRequests is a helper test function -// to test garbage collection runs by uploading, syncing and -// requesting a number of chunks. -func TestDB_collectGarbageWorker_withRequests(t *testing.T) { - db, cleanupFunc := newTestDB(t, &Options{ - Capacity: 100, - }) - defer cleanupFunc() - - testHookCollectGarbageChan := make(chan uint64) - defer setTestHookCollectGarbage(func(collectedCount uint64) { - testHookCollectGarbageChan <- collectedCount - })() - - addrs := make([]chunk.Address, 0) - - // upload random chunks just up to the capacity - for i := 0; i < int(db.capacity)-1; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - err = db.Set(context.Background(), chunk.ModeSetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - - addrs = append(addrs, ch.Address()) - } - - // set update gc test hook to signal when - // update gc goroutine is done by closing - // testHookUpdateGCChan channel - testHookUpdateGCChan := make(chan struct{}) - resetTestHookUpdateGC := setTestHookUpdateGC(func() { - close(testHookUpdateGCChan) - }) - - // request the latest synced chunk - // to prioritize it in the gc index - // not to be collected - _, err := db.Get(context.Background(), chunk.ModeGetRequest, addrs[0]) - if err != nil { - t.Fatal(err) - } - - // wait for update gc goroutine to finish for garbage - // collector to be correctly triggered after the last upload - select { - case <-testHookUpdateGCChan: - case <-time.After(10 * time.Second): - t.Fatal("updateGC was not called after getting chunk with ModeGetRequest") - } - - // no need to wait for update gc hook anymore - resetTestHookUpdateGC() - - // upload and sync another chunk to trigger - // garbage collection - ch := generateTestRandomChunk() - _, err = db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - err = db.Set(context.Background(), chunk.ModeSetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - addrs = append(addrs, ch.Address()) - - // wait for garbage collection - - gcTarget := db.gcTarget() - - var totalCollectedCount uint64 - for { - select { - case c := <-testHookCollectGarbageChan: - totalCollectedCount += c - case <-time.After(10 * time.Second): - t.Error("collect garbage timeout") - } - gcSize, err := db.gcSize.Get() - if err != nil { - t.Fatal(err) - } - if gcSize == gcTarget { - break - } - } - - wantTotalCollectedCount := uint64(len(addrs)) - gcTarget - if totalCollectedCount != wantTotalCollectedCount { - t.Errorf("total collected chunks %v, want %v", totalCollectedCount, wantTotalCollectedCount) - } - - t.Run("pull index count", newItemsCountTest(db.pullIndex, int(gcTarget))) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, int(gcTarget))) - - t.Run("gc size", newIndexGCSizeTest(db)) - - // requested chunk should not be removed - t.Run("get requested chunk", func(t *testing.T) { - _, err := db.Get(context.Background(), chunk.ModeGetRequest, addrs[0]) - if err != nil { - t.Fatal(err) - } - }) - - // the second synced chunk should be removed - t.Run("get gc-ed chunk", func(t *testing.T) { - _, err := db.Get(context.Background(), chunk.ModeGetRequest, addrs[1]) - if err != chunk.ErrChunkNotFound { - t.Errorf("got error %v, want %v", err, chunk.ErrChunkNotFound) - } - }) - - // last synced chunk should not be removed - t.Run("get most recent synced chunk", func(t *testing.T) { - _, err := db.Get(context.Background(), chunk.ModeGetRequest, addrs[len(addrs)-1]) - if err != nil { - t.Fatal(err) - } - }) -} - -// TestDB_gcSize checks if gcSize has a correct value after -// database is initialized with existing data. -func TestDB_gcSize(t *testing.T) { - dir, err := ioutil.TempDir("", "localstore-stored-gc-size") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - baseKey := make([]byte, 32) - if _, err := rand.Read(baseKey); err != nil { - t.Fatal(err) - } - db, err := New(dir, baseKey, nil) - if err != nil { - t.Fatal(err) - } - - count := 100 - - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - err = db.Set(context.Background(), chunk.ModeSetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - } - - if err := db.Close(); err != nil { - t.Fatal(err) - } - - db, err = New(dir, baseKey, nil) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - t.Run("gc index size", newIndexGCSizeTest(db)) -} - -// setTestHookCollectGarbage sets testHookCollectGarbage and -// returns a function that will reset it to the -// value before the change. -func setTestHookCollectGarbage(h func(collectedCount uint64)) (reset func()) { - current := testHookCollectGarbage - reset = func() { testHookCollectGarbage = current } - testHookCollectGarbage = h - return reset -} - -// TestSetTestHookCollectGarbage tests if setTestHookCollectGarbage changes -// testHookCollectGarbage function correctly and if its reset function -// resets the original function. -func TestSetTestHookCollectGarbage(t *testing.T) { - // Set the current function after the test finishes. - defer func(h func(collectedCount uint64)) { testHookCollectGarbage = h }(testHookCollectGarbage) - - // expected value for the unchanged function - original := 1 - // expected value for the changed function - changed := 2 - - // this variable will be set with two different functions - var got int - - // define the original (unchanged) functions - testHookCollectGarbage = func(_ uint64) { - got = original - } - - // set got variable - testHookCollectGarbage(0) - - // test if got variable is set correctly - if got != original { - t.Errorf("got hook value %v, want %v", got, original) - } - - // set the new function - reset := setTestHookCollectGarbage(func(_ uint64) { - got = changed - }) - - // set got variable - testHookCollectGarbage(0) - - // test if got variable is set correctly to changed value - if got != changed { - t.Errorf("got hook value %v, want %v", got, changed) - } - - // set the function to the original one - reset() - - // set got variable - testHookCollectGarbage(0) - - // test if got variable is set correctly to original value - if got != original { - t.Errorf("got hook value %v, want %v", got, original) - } -} diff --git a/swarm/storage/localstore/index_test.go b/swarm/storage/localstore/index_test.go deleted file mode 100644 index 0f23aa10a2..0000000000 --- a/swarm/storage/localstore/index_test.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "bytes" - "context" - "math/rand" - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// TestDB_pullIndex validates the ordering of keys in pull index. -// Pull index key contains PO prefix which is calculated from -// DB base key and chunk address. This is not an Item field -// which are checked in Mode tests. -// This test uploads chunks, sorts them in expected order and -// validates that pull index iterator will iterate it the same -// order. -func TestDB_pullIndex(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - chunkCount := 50 - - chunks := make([]testIndexChunk, chunkCount) - - // upload random chunks - for i := 0; i < chunkCount; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - chunks[i] = testIndexChunk{ - Chunk: ch, - binID: uint64(i), - } - } - - testItemsOrder(t, db.pullIndex, chunks, func(i, j int) (less bool) { - poi := chunk.Proximity(db.baseKey, chunks[i].Address()) - poj := chunk.Proximity(db.baseKey, chunks[j].Address()) - if poi < poj { - return true - } - if poi > poj { - return false - } - if chunks[i].binID < chunks[j].binID { - return true - } - if chunks[i].binID > chunks[j].binID { - return false - } - return bytes.Compare(chunks[i].Address(), chunks[j].Address()) == -1 - }) -} - -// TestDB_gcIndex validates garbage collection index by uploading -// a chunk with and performing operations using synced, access and -// request modes. -func TestDB_gcIndex(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - chunkCount := 50 - - chunks := make([]testIndexChunk, chunkCount) - - // upload random chunks - for i := 0; i < chunkCount; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - chunks[i] = testIndexChunk{ - Chunk: ch, - } - } - - // check if all chunks are stored - newItemsCountTest(db.pullIndex, chunkCount)(t) - - // check that chunks are not collectable for garbage - newItemsCountTest(db.gcIndex, 0)(t) - - // set update gc test hook to signal when - // update gc goroutine is done by sending to - // testHookUpdateGCChan channel, which is - // used to wait for indexes change verifications - testHookUpdateGCChan := make(chan struct{}) - defer setTestHookUpdateGC(func() { - testHookUpdateGCChan <- struct{}{} - })() - - t.Run("request unsynced", func(t *testing.T) { - ch := chunks[1] - - _, err := db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - // wait for update gc goroutine to be done - <-testHookUpdateGCChan - - // the chunk is not synced - // should not be in the garbace collection index - newItemsCountTest(db.gcIndex, 0)(t) - - newIndexGCSizeTest(db)(t) - }) - - t.Run("sync one chunk", func(t *testing.T) { - ch := chunks[0] - - err := db.Set(context.Background(), chunk.ModeSetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - - // the chunk is synced and should be in gc index - newItemsCountTest(db.gcIndex, 1)(t) - - newIndexGCSizeTest(db)(t) - }) - - t.Run("sync all chunks", func(t *testing.T) { - for i := range chunks { - err := db.Set(context.Background(), chunk.ModeSetSync, chunks[i].Address()) - if err != nil { - t.Fatal(err) - } - } - - testItemsOrder(t, db.gcIndex, chunks, nil) - - newIndexGCSizeTest(db)(t) - }) - - t.Run("request one chunk", func(t *testing.T) { - i := 6 - - _, err := db.Get(context.Background(), chunk.ModeGetRequest, chunks[i].Address()) - if err != nil { - t.Fatal(err) - } - // wait for update gc goroutine to be done - <-testHookUpdateGCChan - - // move the chunk to the end of the expected gc - c := chunks[i] - chunks = append(chunks[:i], chunks[i+1:]...) - chunks = append(chunks, c) - - testItemsOrder(t, db.gcIndex, chunks, nil) - - newIndexGCSizeTest(db)(t) - }) - - t.Run("random chunk request", func(t *testing.T) { - - rand.Shuffle(len(chunks), func(i, j int) { - chunks[i], chunks[j] = chunks[j], chunks[i] - }) - - for _, ch := range chunks { - _, err := db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - // wait for update gc goroutine to be done - <-testHookUpdateGCChan - } - - testItemsOrder(t, db.gcIndex, chunks, nil) - - newIndexGCSizeTest(db)(t) - }) - - t.Run("remove one chunk", func(t *testing.T) { - i := 3 - - err := db.Set(context.Background(), chunk.ModeSetRemove, chunks[i].Address()) - if err != nil { - t.Fatal(err) - } - - // remove the chunk from the expected chunks in gc index - chunks = append(chunks[:i], chunks[i+1:]...) - - testItemsOrder(t, db.gcIndex, chunks, nil) - - newIndexGCSizeTest(db)(t) - }) -} diff --git a/swarm/storage/localstore/localstore.go b/swarm/storage/localstore/localstore.go deleted file mode 100644 index 3b0bd8a936..0000000000 --- a/swarm/storage/localstore/localstore.go +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "encoding/binary" - "errors" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/shed" - "github.com/ethereum/go-ethereum/swarm/storage/mock" -) - -// DB implements chunk.Store. -var _ chunk.Store = &DB{} - -var ( - // ErrInvalidMode is retuned when an unknown Mode - // is provided to the function. - ErrInvalidMode = errors.New("invalid mode") - // ErrAddressLockTimeout is returned when the same chunk - // is updated in parallel and one of the updates - // takes longer then the configured timeout duration. - ErrAddressLockTimeout = errors.New("address lock timeout") -) - -var ( - // Default value for Capacity DB option. - defaultCapacity uint64 = 5000000 - // Limit the number of goroutines created by Getters - // that call updateGC function. Value 0 sets no limit. - maxParallelUpdateGC = 1000 -) - -// DB is the local store implementation and holds -// database related objects. -type DB struct { - shed *shed.DB - - // schema name of loaded data - schemaName shed.StringField - - // retrieval indexes - retrievalDataIndex shed.Index - retrievalAccessIndex shed.Index - // push syncing index - pushIndex shed.Index - // push syncing subscriptions triggers - pushTriggers []chan struct{} - pushTriggersMu sync.RWMutex - - // pull syncing index - pullIndex shed.Index - // pull syncing subscriptions triggers per bin - pullTriggers map[uint8][]chan struct{} - pullTriggersMu sync.RWMutex - - // binIDs stores the latest chunk serial ID for every - // proximity order bin - binIDs shed.Uint64Vector - - // garbage collection index - gcIndex shed.Index - - // field that stores number of intems in gc index - gcSize shed.Uint64Field - - // garbage collection is triggered when gcSize exceeds - // the capacity value - capacity uint64 - - // triggers garbage collection event loop - collectGarbageTrigger chan struct{} - - // a buffered channel acting as a semaphore - // to limit the maximal number of goroutines - // created by Getters to call updateGC function - updateGCSem chan struct{} - // a wait group to ensure all updateGC goroutines - // are done before closing the database - updateGCWG sync.WaitGroup - - baseKey []byte - - batchMu sync.Mutex - - // this channel is closed when close function is called - // to terminate other goroutines - close chan struct{} - - // protect Close method from exiting before - // garbage collection and gc size write workers - // are done - collectGarbageWorkerDone chan struct{} -} - -// Options struct holds optional parameters for configuring DB. -type Options struct { - // MockStore is a mock node store that is used to store - // chunk data in a central store. It can be used to reduce - // total storage space requirements in testing large number - // of swarm nodes with chunk data deduplication provided by - // the mock global store. - MockStore *mock.NodeStore - // Capacity is a limit that triggers garbage collection when - // number of items in gcIndex equals or exceeds it. - Capacity uint64 - // MetricsPrefix defines a prefix for metrics names. - MetricsPrefix string -} - -// New returns a new DB. All fields and indexes are initialized -// and possible conflicts with schema from existing database is checked. -// One goroutine for writing batches is created. -func New(path string, baseKey []byte, o *Options) (db *DB, err error) { - if o == nil { - // default options - o = &Options{ - Capacity: 5000000, - } - } - db = &DB{ - capacity: o.Capacity, - baseKey: baseKey, - // channel collectGarbageTrigger - // needs to be buffered with the size of 1 - // to signal another event if it - // is triggered during already running function - collectGarbageTrigger: make(chan struct{}, 1), - close: make(chan struct{}), - collectGarbageWorkerDone: make(chan struct{}), - } - if db.capacity <= 0 { - db.capacity = defaultCapacity - } - if maxParallelUpdateGC > 0 { - db.updateGCSem = make(chan struct{}, maxParallelUpdateGC) - } - - db.shed, err = shed.NewDB(path, o.MetricsPrefix) - if err != nil { - return nil, err - } - - // Identify current storage schema by arbitrary name. - db.schemaName, err = db.shed.NewStringField("schema-name") - if err != nil { - return nil, err - } - schemaName, err := db.schemaName.Get() - if err != nil { - return nil, err - } - if schemaName == "" { - // initial new localstore run - err := db.schemaName.Put(DbSchemaSanctuary) - if err != nil { - return nil, err - } - } - // Persist gc size. - db.gcSize, err = db.shed.NewUint64Field("gc-size") - if err != nil { - return nil, err - } - // Functions for retrieval data index. - var ( - encodeValueFunc func(fields shed.Item) (value []byte, err error) - decodeValueFunc func(keyItem shed.Item, value []byte) (e shed.Item, err error) - ) - if o.MockStore != nil { - encodeValueFunc = func(fields shed.Item) (value []byte, err error) { - b := make([]byte, 16) - binary.BigEndian.PutUint64(b[:8], fields.BinID) - binary.BigEndian.PutUint64(b[8:16], uint64(fields.StoreTimestamp)) - err = o.MockStore.Put(fields.Address, fields.Data) - if err != nil { - return nil, err - } - return b, nil - } - decodeValueFunc = func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[8:16])) - e.BinID = binary.BigEndian.Uint64(value[:8]) - e.Data, err = o.MockStore.Get(keyItem.Address) - return e, err - } - } else { - encodeValueFunc = func(fields shed.Item) (value []byte, err error) { - b := make([]byte, 16) - binary.BigEndian.PutUint64(b[:8], fields.BinID) - binary.BigEndian.PutUint64(b[8:16], uint64(fields.StoreTimestamp)) - value = append(b, fields.Data...) - return value, nil - } - decodeValueFunc = func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - e.StoreTimestamp = int64(binary.BigEndian.Uint64(value[8:16])) - e.BinID = binary.BigEndian.Uint64(value[:8]) - e.Data = value[16:] - return e, nil - } - } - // Index storing actual chunk address, data and bin id. - db.retrievalDataIndex, err = db.shed.NewIndex("Address->StoreTimestamp|BinID|Data", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - return fields.Address, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.Address = key - return e, nil - }, - EncodeValue: encodeValueFunc, - DecodeValue: decodeValueFunc, - }) - if err != nil { - return nil, err - } - // Index storing access timestamp for a particular address. - // It is needed in order to update gc index keys for iteration order. - db.retrievalAccessIndex, err = db.shed.NewIndex("Address->AccessTimestamp", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - return fields.Address, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.Address = key - return e, nil - }, - EncodeValue: func(fields shed.Item) (value []byte, err error) { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(fields.AccessTimestamp)) - return b, nil - }, - DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - e.AccessTimestamp = int64(binary.BigEndian.Uint64(value)) - return e, nil - }, - }) - if err != nil { - return nil, err - } - // pull index allows history and live syncing per po bin - db.pullIndex, err = db.shed.NewIndex("PO|BinID->Hash", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - key = make([]byte, 41) - key[0] = db.po(fields.Address) - binary.BigEndian.PutUint64(key[1:9], fields.BinID) - return key, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.BinID = binary.BigEndian.Uint64(key[1:9]) - return e, nil - }, - EncodeValue: func(fields shed.Item) (value []byte, err error) { - return fields.Address, nil - }, - DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - e.Address = value - return e, nil - }, - }) - if err != nil { - return nil, err - } - // create a vector for bin IDs - db.binIDs, err = db.shed.NewUint64Vector("bin-ids") - if err != nil { - return nil, err - } - // create a pull syncing triggers used by SubscribePull function - db.pullTriggers = make(map[uint8][]chan struct{}) - // push index contains as yet unsynced chunks - db.pushIndex, err = db.shed.NewIndex("StoreTimestamp|Hash->Tags", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - key = make([]byte, 40) - binary.BigEndian.PutUint64(key[:8], uint64(fields.StoreTimestamp)) - copy(key[8:], fields.Address[:]) - return key, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.Address = key[8:] - e.StoreTimestamp = int64(binary.BigEndian.Uint64(key[:8])) - return e, nil - }, - EncodeValue: func(fields shed.Item) (value []byte, err error) { - return nil, nil - }, - DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - return e, nil - }, - }) - if err != nil { - return nil, err - } - // create a push syncing triggers used by SubscribePush function - db.pushTriggers = make([]chan struct{}, 0) - // gc index for removable chunk ordered by ascending last access time - db.gcIndex, err = db.shed.NewIndex("AccessTimestamp|BinID|Hash->nil", shed.IndexFuncs{ - EncodeKey: func(fields shed.Item) (key []byte, err error) { - b := make([]byte, 16, 16+len(fields.Address)) - binary.BigEndian.PutUint64(b[:8], uint64(fields.AccessTimestamp)) - binary.BigEndian.PutUint64(b[8:16], fields.BinID) - key = append(b, fields.Address...) - return key, nil - }, - DecodeKey: func(key []byte) (e shed.Item, err error) { - e.AccessTimestamp = int64(binary.BigEndian.Uint64(key[:8])) - e.BinID = binary.BigEndian.Uint64(key[8:16]) - e.Address = key[16:] - return e, nil - }, - EncodeValue: func(fields shed.Item) (value []byte, err error) { - return nil, nil - }, - DecodeValue: func(keyItem shed.Item, value []byte) (e shed.Item, err error) { - return e, nil - }, - }) - if err != nil { - return nil, err - } - // start garbage collection worker - go db.collectGarbageWorker() - return db, nil -} - -// Close closes the underlying database. -func (db *DB) Close() (err error) { - close(db.close) - db.updateGCWG.Wait() - - // wait for gc worker to - // return before closing the shed - select { - case <-db.collectGarbageWorkerDone: - case <-time.After(5 * time.Second): - log.Error("localstore: collect garbage worker did not return after db close") - } - return db.shed.Close() -} - -// po computes the proximity order between the address -// and database base key. -func (db *DB) po(addr chunk.Address) (bin uint8) { - return uint8(chunk.Proximity(db.baseKey, addr)) -} - -// chunkToItem creates new Item with data provided by the Chunk. -func chunkToItem(ch chunk.Chunk) shed.Item { - return shed.Item{ - Address: ch.Address(), - Data: ch.Data(), - } -} - -// addressToItem creates new Item with a provided address. -func addressToItem(addr chunk.Address) shed.Item { - return shed.Item{ - Address: addr, - } -} - -// now is a helper function that returns a current unix timestamp -// in UTC timezone. -// It is set in the init function for usage in production, and -// optionally overridden in tests for data validation. -var now func() int64 - -func init() { - // set the now function - now = func() (t int64) { - return time.Now().UTC().UnixNano() - } -} - -// totalTimeMetric logs a message about time between provided start time -// and the time when the function is called and sends a resetting timer metric -// with provided name appended with ".total-time". -func totalTimeMetric(name string, start time.Time) { - totalTime := time.Since(start) - log.Trace(name+" total time", "time", totalTime) - metrics.GetOrRegisterResettingTimer(name+".total-time", nil).Update(totalTime) -} diff --git a/swarm/storage/localstore/localstore_test.go b/swarm/storage/localstore/localstore_test.go deleted file mode 100644 index 6dbc4b7ad0..0000000000 --- a/swarm/storage/localstore/localstore_test.go +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "math/rand" - "os" - "runtime" - "sort" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/shed" - "github.com/syndtr/goleveldb/leveldb" -) - -func init() { - // Some of the tests in localstore package rely on the same ordering of - // items uploaded or accessed compared to the ordering of items in indexes - // that contain StoreTimestamp or AccessTimestamp in keys. In tests - // where the same order is required from the database as the order - // in which chunks are put or accessed, if the StoreTimestamp or - // AccessTimestamp are the same for two or more sequential items - // their order in database will be based on the chunk address value, - // in which case the ordering of items/chunks stored in a test slice - // will not be the same. To ensure the same ordering in database on such - // indexes on windows systems, an additional short sleep is added to - // the now function. - if runtime.GOOS == "windows" { - setNow(func() int64 { - time.Sleep(time.Microsecond) - return time.Now().UTC().UnixNano() - }) - } -} - -// TestDB validates if the chunk can be uploaded and -// correctly retrieved. -func TestDB(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - got, err := db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(got.Address(), ch.Address()) { - t.Errorf("got address %x, want %x", got.Address(), ch.Address()) - } - if !bytes.Equal(got.Data(), ch.Data()) { - t.Errorf("got data %x, want %x", got.Data(), ch.Data()) - } -} - -// TestDB_updateGCSem tests maxParallelUpdateGC limit. -// This test temporary sets the limit to a low number, -// makes updateGC function execution time longer by -// setting a custom testHookUpdateGC function with a sleep -// and a count current and maximal number of goroutines. -func TestDB_updateGCSem(t *testing.T) { - updateGCSleep := time.Second - var count int - var max int - var mu sync.Mutex - defer setTestHookUpdateGC(func() { - mu.Lock() - // add to the count of current goroutines - count++ - if count > max { - // set maximal detected numbers of goroutines - max = count - } - mu.Unlock() - - // wait for some time to ensure multiple parallel goroutines - time.Sleep(updateGCSleep) - - mu.Lock() - count-- - mu.Unlock() - })() - - defer func(m int) { maxParallelUpdateGC = m }(maxParallelUpdateGC) - maxParallelUpdateGC = 3 - - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - // get more chunks then maxParallelUpdateGC - // in time shorter then updateGCSleep - for i := 0; i < 5; i++ { - _, err = db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - } - - if max != maxParallelUpdateGC { - t.Errorf("got max %v, want %v", max, maxParallelUpdateGC) - } -} - -// newTestDB is a helper function that constructs a -// temporary database and returns a cleanup function that must -// be called to remove the data. -func newTestDB(t testing.TB, o *Options) (db *DB, cleanupFunc func()) { - t.Helper() - - dir, err := ioutil.TempDir("", "localstore-test") - if err != nil { - t.Fatal(err) - } - cleanupFunc = func() { os.RemoveAll(dir) } - baseKey := make([]byte, 32) - if _, err := rand.Read(baseKey); err != nil { - t.Fatal(err) - } - db, err = New(dir, baseKey, o) - if err != nil { - cleanupFunc() - t.Fatal(err) - } - cleanupFunc = func() { - err := db.Close() - if err != nil { - t.Error(err) - } - os.RemoveAll(dir) - } - return db, cleanupFunc -} - -func init() { - // needed for generateTestRandomChunk - rand.Seed(time.Now().UnixNano()) -} - -// generateTestRandomChunk generates a Chunk that is not -// valid, but it contains a random key and a random value. -// This function is faster then storage.generateTestRandomChunk -// which generates a valid chunk. -// Some tests in this package do not need valid chunks, just -// random data, and their execution time can be decreased -// using this function. -func generateTestRandomChunk() chunk.Chunk { - data := make([]byte, chunk.DefaultSize) - rand.Read(data) - key := make([]byte, 32) - rand.Read(key) - return chunk.NewChunk(key, data) -} - -// TestGenerateTestRandomChunk validates that -// generateTestRandomChunk returns random data by comparing -// two generated chunks. -func TestGenerateTestRandomChunk(t *testing.T) { - c1 := generateTestRandomChunk() - c2 := generateTestRandomChunk() - addrLen := len(c1.Address()) - if addrLen != 32 { - t.Errorf("first chunk address length %v, want %v", addrLen, 32) - } - dataLen := len(c1.Data()) - if dataLen != chunk.DefaultSize { - t.Errorf("first chunk data length %v, want %v", dataLen, chunk.DefaultSize) - } - addrLen = len(c2.Address()) - if addrLen != 32 { - t.Errorf("second chunk address length %v, want %v", addrLen, 32) - } - dataLen = len(c2.Data()) - if dataLen != chunk.DefaultSize { - t.Errorf("second chunk data length %v, want %v", dataLen, chunk.DefaultSize) - } - if bytes.Equal(c1.Address(), c2.Address()) { - t.Error("fake chunks addresses do not differ") - } - if bytes.Equal(c1.Data(), c2.Data()) { - t.Error("fake chunks data bytes do not differ") - } -} - -// newRetrieveIndexesTest returns a test function that validates if the right -// chunk values are in the retrieval indexes. -func newRetrieveIndexesTest(db *DB, chunk chunk.Chunk, storeTimestamp, accessTimestamp int64) func(t *testing.T) { - return func(t *testing.T) { - item, err := db.retrievalDataIndex.Get(addressToItem(chunk.Address())) - if err != nil { - t.Fatal(err) - } - validateItem(t, item, chunk.Address(), chunk.Data(), storeTimestamp, 0) - - // access index should not be set - wantErr := leveldb.ErrNotFound - item, err = db.retrievalAccessIndex.Get(addressToItem(chunk.Address())) - if err != wantErr { - t.Errorf("got error %v, want %v", err, wantErr) - } - } -} - -// newRetrieveIndexesTestWithAccess returns a test function that validates if the right -// chunk values are in the retrieval indexes when access time must be stored. -func newRetrieveIndexesTestWithAccess(db *DB, ch chunk.Chunk, storeTimestamp, accessTimestamp int64) func(t *testing.T) { - return func(t *testing.T) { - item, err := db.retrievalDataIndex.Get(addressToItem(ch.Address())) - if err != nil { - t.Fatal(err) - } - validateItem(t, item, ch.Address(), ch.Data(), storeTimestamp, 0) - - if accessTimestamp > 0 { - item, err = db.retrievalAccessIndex.Get(addressToItem(ch.Address())) - if err != nil { - t.Fatal(err) - } - validateItem(t, item, ch.Address(), nil, 0, accessTimestamp) - } - } -} - -// newPullIndexTest returns a test function that validates if the right -// chunk values are in the pull index. -func newPullIndexTest(db *DB, ch chunk.Chunk, binID uint64, wantError error) func(t *testing.T) { - return func(t *testing.T) { - item, err := db.pullIndex.Get(shed.Item{ - Address: ch.Address(), - BinID: binID, - }) - if err != wantError { - t.Errorf("got error %v, want %v", err, wantError) - } - if err == nil { - validateItem(t, item, ch.Address(), nil, 0, 0) - } - } -} - -// newPushIndexTest returns a test function that validates if the right -// chunk values are in the push index. -func newPushIndexTest(db *DB, ch chunk.Chunk, storeTimestamp int64, wantError error) func(t *testing.T) { - return func(t *testing.T) { - item, err := db.pushIndex.Get(shed.Item{ - Address: ch.Address(), - StoreTimestamp: storeTimestamp, - }) - if err != wantError { - t.Errorf("got error %v, want %v", err, wantError) - } - if err == nil { - validateItem(t, item, ch.Address(), nil, storeTimestamp, 0) - } - } -} - -// newGCIndexTest returns a test function that validates if the right -// chunk values are in the push index. -func newGCIndexTest(db *DB, chunk chunk.Chunk, storeTimestamp, accessTimestamp int64, binID uint64) func(t *testing.T) { - return func(t *testing.T) { - item, err := db.gcIndex.Get(shed.Item{ - Address: chunk.Address(), - BinID: binID, - AccessTimestamp: accessTimestamp, - }) - if err != nil { - t.Fatal(err) - } - validateItem(t, item, chunk.Address(), nil, 0, accessTimestamp) - } -} - -// newItemsCountTest returns a test function that validates if -// an index contains expected number of key/value pairs. -func newItemsCountTest(i shed.Index, want int) func(t *testing.T) { - return func(t *testing.T) { - var c int - err := i.Iterate(func(item shed.Item) (stop bool, err error) { - c++ - return - }, nil) - if err != nil { - t.Fatal(err) - } - if c != want { - t.Errorf("got %v items in index, want %v", c, want) - } - } -} - -// newIndexGCSizeTest retruns a test function that validates if DB.gcSize -// value is the same as the number of items in DB.gcIndex. -func newIndexGCSizeTest(db *DB) func(t *testing.T) { - return func(t *testing.T) { - var want uint64 - err := db.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) { - want++ - return - }, nil) - if err != nil { - t.Fatal(err) - } - got, err := db.gcSize.Get() - if err != nil { - t.Fatal(err) - } - if got != want { - t.Errorf("got gc size %v, want %v", got, want) - } - } -} - -// testIndexChunk embeds storageChunk with additional data that is stored -// in database. It is used for index values validations. -type testIndexChunk struct { - chunk.Chunk - binID uint64 -} - -// testItemsOrder tests the order of chunks in the index. If sortFunc is not nil, -// chunks will be sorted with it before validation. -func testItemsOrder(t *testing.T, i shed.Index, chunks []testIndexChunk, sortFunc func(i, j int) (less bool)) { - newItemsCountTest(i, len(chunks))(t) - - if sortFunc != nil { - sort.Slice(chunks, sortFunc) - } - - var cursor int - err := i.Iterate(func(item shed.Item) (stop bool, err error) { - want := chunks[cursor].Address() - got := item.Address - if !bytes.Equal(got, want) { - return true, fmt.Errorf("got address %x at position %v, want %x", got, cursor, want) - } - cursor++ - return false, nil - }, nil) - if err != nil { - t.Fatal(err) - } -} - -// validateItem is a helper function that checks Item values. -func validateItem(t *testing.T, item shed.Item, address, data []byte, storeTimestamp, accessTimestamp int64) { - t.Helper() - - if !bytes.Equal(item.Address, address) { - t.Errorf("got item address %x, want %x", item.Address, address) - } - if !bytes.Equal(item.Data, data) { - t.Errorf("got item data %x, want %x", item.Data, data) - } - if item.StoreTimestamp != storeTimestamp { - t.Errorf("got item store timestamp %v, want %v", item.StoreTimestamp, storeTimestamp) - } - if item.AccessTimestamp != accessTimestamp { - t.Errorf("got item access timestamp %v, want %v", item.AccessTimestamp, accessTimestamp) - } -} - -// setNow replaces now function and -// returns a function that will reset it to the -// value before the change. -func setNow(f func() int64) (reset func()) { - current := now - reset = func() { now = current } - now = f - return reset -} - -// TestSetNow tests if setNow function changes now function -// correctly and if its reset function resets the original function. -func TestSetNow(t *testing.T) { - // set the current function after the test finishes - defer func(f func() int64) { now = f }(now) - - // expected value for the unchanged function - var original int64 = 1 - // expected value for the changed function - var changed int64 = 2 - - // define the original (unchanged) functions - now = func() int64 { - return original - } - - // get the time - got := now() - - // test if got variable is set correctly - if got != original { - t.Errorf("got now value %v, want %v", got, original) - } - - // set the new function - reset := setNow(func() int64 { - return changed - }) - - // get the time - got = now() - - // test if got variable is set correctly to changed value - if got != changed { - t.Errorf("got hook value %v, want %v", got, changed) - } - - // set the function to the original one - reset() - - // get the time - got = now() - - // test if got variable is set correctly to original value - if got != original { - t.Errorf("got hook value %v, want %v", got, original) - } -} diff --git a/swarm/storage/localstore/mode_get.go b/swarm/storage/localstore/mode_get.go deleted file mode 100644 index efef828586..0000000000 --- a/swarm/storage/localstore/mode_get.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/shed" - "github.com/syndtr/goleveldb/leveldb" -) - -// Get returns a chunk from the database. If the chunk is -// not found chunk.ErrChunkNotFound will be returned. -// All required indexes will be updated required by the -// Getter Mode. Get is required to implement chunk.Store -// interface. -func (db *DB) Get(ctx context.Context, mode chunk.ModeGet, addr chunk.Address) (ch chunk.Chunk, err error) { - metricName := fmt.Sprintf("localstore.Get.%s", mode) - - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - defer totalTimeMetric(metricName, time.Now()) - - defer func() { - if err != nil { - metrics.GetOrRegisterCounter(metricName+".error", nil).Inc(1) - } - }() - - out, err := db.get(mode, addr) - if err != nil { - if err == leveldb.ErrNotFound { - return nil, chunk.ErrChunkNotFound - } - return nil, err - } - return chunk.NewChunk(out.Address, out.Data), nil -} - -// get returns Item from the retrieval index -// and updates other indexes. -func (db *DB) get(mode chunk.ModeGet, addr chunk.Address) (out shed.Item, err error) { - item := addressToItem(addr) - - out, err = db.retrievalDataIndex.Get(item) - if err != nil { - return out, err - } - switch mode { - // update the access timestamp and gc index - case chunk.ModeGetRequest: - if db.updateGCSem != nil { - // wait before creating new goroutines - // if updateGCSem buffer id full - db.updateGCSem <- struct{}{} - } - db.updateGCWG.Add(1) - go func() { - defer db.updateGCWG.Done() - if db.updateGCSem != nil { - // free a spot in updateGCSem buffer - // for a new goroutine - defer func() { <-db.updateGCSem }() - } - - metricName := "localstore.updateGC" - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - defer totalTimeMetric(metricName, time.Now()) - - err := db.updateGC(out) - if err != nil { - metrics.GetOrRegisterCounter(metricName+".error", nil).Inc(1) - log.Error("localstore update gc", "err", err) - } - // if gc update hook is defined, call it - if testHookUpdateGC != nil { - testHookUpdateGC() - } - }() - - // no updates to indexes - case chunk.ModeGetSync: - case chunk.ModeGetLookup: - default: - return out, ErrInvalidMode - } - return out, nil -} - -// updateGC updates garbage collection index for -// a single item. Provided item is expected to have -// only Address and Data fields with non zero values, -// which is ensured by the get function. -func (db *DB) updateGC(item shed.Item) (err error) { - db.batchMu.Lock() - defer db.batchMu.Unlock() - - batch := new(leveldb.Batch) - - // update accessTimeStamp in retrieve, gc - - i, err := db.retrievalAccessIndex.Get(item) - switch err { - case nil: - item.AccessTimestamp = i.AccessTimestamp - case leveldb.ErrNotFound: - // no chunk accesses - default: - return err - } - if item.AccessTimestamp == 0 { - // chunk is not yet synced - // do not add it to the gc index - return nil - } - // delete current entry from the gc index - db.gcIndex.DeleteInBatch(batch, item) - // update access timestamp - item.AccessTimestamp = now() - // update retrieve access index - db.retrievalAccessIndex.PutInBatch(batch, item) - // add new entry to gc index - db.gcIndex.PutInBatch(batch, item) - - return db.shed.WriteBatch(batch) -} - -// testHookUpdateGC is a hook that can provide -// information when a garbage collection index is updated. -var testHookUpdateGC func() diff --git a/swarm/storage/localstore/mode_get_test.go b/swarm/storage/localstore/mode_get_test.go deleted file mode 100644 index 217fa5d2d2..0000000000 --- a/swarm/storage/localstore/mode_get_test.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "bytes" - "context" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// TestModeGetRequest validates ModeGetRequest index values on the provided DB. -func TestModeGetRequest(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - uploadTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return uploadTimestamp - })() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - // set update gc test hook to signal when - // update gc goroutine is done by sending to - // testHookUpdateGCChan channel, which is - // used to wait for garbage colletion index - // changes - testHookUpdateGCChan := make(chan struct{}) - defer setTestHookUpdateGC(func() { - testHookUpdateGCChan <- struct{}{} - })() - - t.Run("get unsynced", func(t *testing.T) { - got, err := db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - // wait for update gc goroutine to be done - <-testHookUpdateGCChan - - if !bytes.Equal(got.Address(), ch.Address()) { - t.Errorf("got chunk address %x, want %x", got.Address(), ch.Address()) - } - - if !bytes.Equal(got.Data(), ch.Data()) { - t.Errorf("got chunk data %x, want %x", got.Data(), ch.Data()) - } - - t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, ch, uploadTimestamp, 0)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 0)) - - t.Run("gc size", newIndexGCSizeTest(db)) - }) - - // set chunk to synced state - err = db.Set(context.Background(), chunk.ModeSetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - - t.Run("first get", func(t *testing.T) { - got, err := db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - // wait for update gc goroutine to be done - <-testHookUpdateGCChan - - if !bytes.Equal(got.Address(), ch.Address()) { - t.Errorf("got chunk address %x, want %x", got.Address(), ch.Address()) - } - - if !bytes.Equal(got.Data(), ch.Data()) { - t.Errorf("got chunk data %x, want %x", got.Data(), ch.Data()) - } - - t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, ch, uploadTimestamp, uploadTimestamp)) - - t.Run("gc index", newGCIndexTest(db, ch, uploadTimestamp, uploadTimestamp, 1)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) - - t.Run("gc size", newIndexGCSizeTest(db)) - }) - - t.Run("second get", func(t *testing.T) { - accessTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return accessTimestamp - })() - - got, err := db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - // wait for update gc goroutine to be done - <-testHookUpdateGCChan - - if !bytes.Equal(got.Address(), ch.Address()) { - t.Errorf("got chunk address %x, want %x", got.Address(), ch.Address()) - } - - if !bytes.Equal(got.Data(), ch.Data()) { - t.Errorf("got chunk data %x, want %x", got.Data(), ch.Data()) - } - - t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, ch, uploadTimestamp, accessTimestamp)) - - t.Run("gc index", newGCIndexTest(db, ch, uploadTimestamp, accessTimestamp, 1)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) - - t.Run("gc size", newIndexGCSizeTest(db)) - }) -} - -// TestModeGetSync validates ModeGetSync index values on the provided DB. -func TestModeGetSync(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - uploadTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return uploadTimestamp - })() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - got, err := db.Get(context.Background(), chunk.ModeGetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(got.Address(), ch.Address()) { - t.Errorf("got chunk address %x, want %x", got.Address(), ch.Address()) - } - - if !bytes.Equal(got.Data(), ch.Data()) { - t.Errorf("got chunk data %x, want %x", got.Data(), ch.Data()) - } - - t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, ch, uploadTimestamp, 0)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 0)) - - t.Run("gc size", newIndexGCSizeTest(db)) -} - -// setTestHookUpdateGC sets testHookUpdateGC and -// returns a function that will reset it to the -// value before the change. -func setTestHookUpdateGC(h func()) (reset func()) { - current := testHookUpdateGC - reset = func() { testHookUpdateGC = current } - testHookUpdateGC = h - return reset -} - -// TestSetTestHookUpdateGC tests if setTestHookUpdateGC changes -// testHookUpdateGC function correctly and if its reset function -// resets the original function. -func TestSetTestHookUpdateGC(t *testing.T) { - // Set the current function after the test finishes. - defer func(h func()) { testHookUpdateGC = h }(testHookUpdateGC) - - // expected value for the unchanged function - original := 1 - // expected value for the changed function - changed := 2 - - // this variable will be set with two different functions - var got int - - // define the original (unchanged) functions - testHookUpdateGC = func() { - got = original - } - - // set got variable - testHookUpdateGC() - - // test if got variable is set correctly - if got != original { - t.Errorf("got hook value %v, want %v", got, original) - } - - // set the new function - reset := setTestHookUpdateGC(func() { - got = changed - }) - - // set got variable - testHookUpdateGC() - - // test if got variable is set correctly to changed value - if got != changed { - t.Errorf("got hook value %v, want %v", got, changed) - } - - // set the function to the original one - reset() - - // set got variable - testHookUpdateGC() - - // test if got variable is set correctly to original value - if got != original { - t.Errorf("got hook value %v, want %v", got, original) - } -} diff --git a/swarm/storage/localstore/mode_has.go b/swarm/storage/localstore/mode_has.go deleted file mode 100644 index a70ee31b23..0000000000 --- a/swarm/storage/localstore/mode_has.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// Has returns true if the chunk is stored in database. -func (db *DB) Has(ctx context.Context, addr chunk.Address) (bool, error) { - metricName := "localstore.Has" - - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - defer totalTimeMetric(metricName, time.Now()) - - has, err := db.retrievalDataIndex.Has(addressToItem(addr)) - if err != nil { - metrics.GetOrRegisterCounter(metricName+".error", nil).Inc(1) - } - return has, err -} diff --git a/swarm/storage/localstore/mode_has_test.go b/swarm/storage/localstore/mode_has_test.go deleted file mode 100644 index 043b21a2b1..0000000000 --- a/swarm/storage/localstore/mode_has_test.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// TestHas validates that Hasser is returning true for -// the stored chunk and false for one that is not stored. -func TestHas(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - has, err := db.Has(context.Background(), ch.Address()) - if err != nil { - t.Fatal(err) - } - if !has { - t.Error("chunk not found") - } - - missingChunk := generateTestRandomChunk() - - has, err = db.Has(context.Background(), missingChunk.Address()) - if err != nil { - t.Fatal(err) - } - if has { - t.Error("unexpected chunk is found") - } -} diff --git a/swarm/storage/localstore/mode_put.go b/swarm/storage/localstore/mode_put.go deleted file mode 100644 index a8e355ad0c..0000000000 --- a/swarm/storage/localstore/mode_put.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/shed" - "github.com/syndtr/goleveldb/leveldb" -) - -// Put stores the Chunk to database and depending -// on the Putter mode, it updates required indexes. -// Put is required to implement chunk.Store -// interface. -func (db *DB) Put(ctx context.Context, mode chunk.ModePut, ch chunk.Chunk) (exists bool, err error) { - metricName := fmt.Sprintf("localstore.Put.%s", mode) - - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - defer totalTimeMetric(metricName, time.Now()) - - exists, err = db.put(mode, chunkToItem(ch)) - if err != nil { - metrics.GetOrRegisterCounter(metricName+".error", nil).Inc(1) - } - return exists, err -} - -// put stores Item to database and updates other -// indexes. It acquires lockAddr to protect two calls -// of this function for the same address in parallel. -// Item fields Address and Data must not be -// with their nil values. -func (db *DB) put(mode chunk.ModePut, item shed.Item) (exists bool, err error) { - // protect parallel updates - db.batchMu.Lock() - defer db.batchMu.Unlock() - - batch := new(leveldb.Batch) - - // variables that provide information for operations - // to be done after write batch function successfully executes - var gcSizeChange int64 // number to add or subtract from gcSize - var triggerPullFeed bool // signal pull feed subscriptions to iterate - var triggerPushFeed bool // signal push feed subscriptions to iterate - - switch mode { - case chunk.ModePutRequest: - // put to indexes: retrieve, gc; it does not enter the syncpool - - // check if the chunk already is in the database - // as gc index is updated - i, err := db.retrievalAccessIndex.Get(item) - switch err { - case nil: - exists = true - item.AccessTimestamp = i.AccessTimestamp - case leveldb.ErrNotFound: - exists = false - // no chunk accesses - default: - return false, err - } - i, err = db.retrievalDataIndex.Get(item) - switch err { - case nil: - exists = true - item.StoreTimestamp = i.StoreTimestamp - item.BinID = i.BinID - case leveldb.ErrNotFound: - // no chunk accesses - exists = false - default: - return false, err - } - if item.AccessTimestamp != 0 { - // delete current entry from the gc index - db.gcIndex.DeleteInBatch(batch, item) - gcSizeChange-- - } - if item.StoreTimestamp == 0 { - item.StoreTimestamp = now() - } - if item.BinID == 0 { - item.BinID, err = db.binIDs.IncInBatch(batch, uint64(db.po(item.Address))) - if err != nil { - return false, err - } - } - // update access timestamp - item.AccessTimestamp = now() - // update retrieve access index - db.retrievalAccessIndex.PutInBatch(batch, item) - // add new entry to gc index - db.gcIndex.PutInBatch(batch, item) - gcSizeChange++ - - db.retrievalDataIndex.PutInBatch(batch, item) - - case chunk.ModePutUpload: - // put to indexes: retrieve, push, pull - - exists, err = db.retrievalDataIndex.Has(item) - if err != nil { - return false, err - } - if !exists { - item.StoreTimestamp = now() - item.BinID, err = db.binIDs.IncInBatch(batch, uint64(db.po(item.Address))) - if err != nil { - return false, err - } - db.retrievalDataIndex.PutInBatch(batch, item) - db.pullIndex.PutInBatch(batch, item) - triggerPullFeed = true - db.pushIndex.PutInBatch(batch, item) - triggerPushFeed = true - } - - case chunk.ModePutSync: - // put to indexes: retrieve, pull - - exists, err = db.retrievalDataIndex.Has(item) - if err != nil { - return exists, err - } - if !exists { - item.StoreTimestamp = now() - item.BinID, err = db.binIDs.IncInBatch(batch, uint64(db.po(item.Address))) - if err != nil { - return false, err - } - db.retrievalDataIndex.PutInBatch(batch, item) - db.pullIndex.PutInBatch(batch, item) - triggerPullFeed = true - } - - default: - return false, ErrInvalidMode - } - - err = db.incGCSizeInBatch(batch, gcSizeChange) - if err != nil { - return false, err - } - - err = db.shed.WriteBatch(batch) - if err != nil { - return false, err - } - if triggerPullFeed { - db.triggerPullSubscriptions(db.po(item.Address)) - } - if triggerPushFeed { - db.triggerPushSubscriptions() - } - return exists, nil -} diff --git a/swarm/storage/localstore/mode_put_test.go b/swarm/storage/localstore/mode_put_test.go deleted file mode 100644 index 5376aa8b38..0000000000 --- a/swarm/storage/localstore/mode_put_test.go +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "bytes" - "context" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// TestModePutRequest validates ModePutRequest index values on the provided DB. -func TestModePutRequest(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - ch := generateTestRandomChunk() - - // keep the record when the chunk is stored - var storeTimestamp int64 - - t.Run("first put", func(t *testing.T) { - wantTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return wantTimestamp - })() - - storeTimestamp = wantTimestamp - - _, err := db.Put(context.Background(), chunk.ModePutRequest, ch) - if err != nil { - t.Fatal(err) - } - - t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, ch, wantTimestamp, wantTimestamp)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) - - t.Run("gc size", newIndexGCSizeTest(db)) - }) - - t.Run("second put", func(t *testing.T) { - wantTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return wantTimestamp - })() - - _, err := db.Put(context.Background(), chunk.ModePutRequest, ch) - if err != nil { - t.Fatal(err) - } - - t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, ch, storeTimestamp, wantTimestamp)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) - - t.Run("gc size", newIndexGCSizeTest(db)) - }) -} - -// TestModePutSync validates ModePutSync index values on the provided DB. -func TestModePutSync(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - wantTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return wantTimestamp - })() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutSync, ch) - if err != nil { - t.Fatal(err) - } - - t.Run("retrieve indexes", newRetrieveIndexesTest(db, ch, wantTimestamp, 0)) - - t.Run("pull index", newPullIndexTest(db, ch, 1, nil)) -} - -// TestModePutUpload validates ModePutUpload index values on the provided DB. -func TestModePutUpload(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - wantTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return wantTimestamp - })() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - t.Run("retrieve indexes", newRetrieveIndexesTest(db, ch, wantTimestamp, 0)) - - t.Run("pull index", newPullIndexTest(db, ch, 1, nil)) - - t.Run("push index", newPushIndexTest(db, ch, wantTimestamp, nil)) -} - -// TestModePutUpload_parallel uploads chunks in parallel -// and validates if all chunks can be retrieved with correct data. -func TestModePutUpload_parallel(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - chunkCount := 1000 - workerCount := 100 - - chunkChan := make(chan chunk.Chunk) - errChan := make(chan error) - doneChan := make(chan struct{}) - defer close(doneChan) - - // start uploader workers - for i := 0; i < workerCount; i++ { - go func(i int) { - for { - select { - case ch, ok := <-chunkChan: - if !ok { - return - } - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - select { - case errChan <- err: - case <-doneChan: - } - case <-doneChan: - return - } - } - }(i) - } - - chunks := make([]chunk.Chunk, 0) - var chunksMu sync.Mutex - - // send chunks to workers - go func() { - for i := 0; i < chunkCount; i++ { - chunk := generateTestRandomChunk() - select { - case chunkChan <- chunk: - case <-doneChan: - return - } - chunksMu.Lock() - chunks = append(chunks, chunk) - chunksMu.Unlock() - } - - close(chunkChan) - }() - - // validate every error from workers - for i := 0; i < chunkCount; i++ { - err := <-errChan - if err != nil { - t.Fatal(err) - } - } - - // get every chunk and validate its data - chunksMu.Lock() - defer chunksMu.Unlock() - for _, ch := range chunks { - got, err := db.Get(context.Background(), chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(got.Data(), ch.Data()) { - t.Fatalf("got chunk %s data %x, want %x", ch.Address().Hex(), got.Data(), ch.Data()) - } - } -} - -// TestModePut_sameChunk puts the same chunk multiple times -// and validates that all relevant indexes have only one item -// in them. -func TestModePut_sameChunk(t *testing.T) { - ch := generateTestRandomChunk() - - for _, tc := range []struct { - name string - mode chunk.ModePut - pullIndex bool - pushIndex bool - }{ - { - name: "ModePutRequest", - mode: chunk.ModePutRequest, - pullIndex: false, - pushIndex: false, - }, - { - name: "ModePutUpload", - mode: chunk.ModePutUpload, - pullIndex: true, - pushIndex: true, - }, - { - name: "ModePutSync", - mode: chunk.ModePutSync, - pullIndex: true, - pushIndex: false, - }, - } { - t.Run(tc.name, func(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - for i := 0; i < 10; i++ { - exists, err := db.Put(context.Background(), tc.mode, ch) - if err != nil { - t.Fatal(err) - } - switch exists { - case false: - if i != 0 { - t.Fatal("should not exist only on first Put") - } - case true: - if i == 0 { - t.Fatal("should exist on all cases other than the first one") - } - } - - count := func(b bool) (c int) { - if b { - return 1 - } - return 0 - } - - newItemsCountTest(db.retrievalDataIndex, 1)(t) - newItemsCountTest(db.pullIndex, count(tc.pullIndex))(t) - newItemsCountTest(db.pushIndex, count(tc.pushIndex))(t) - } - }) - } -} - -// BenchmarkPutUpload runs a series of benchmarks that upload -// a specific number of chunks in parallel. -// -// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014) -// -// # go test -benchmem -run=none github.com/ethereum/go-ethereum/swarm/storage/localstore -bench BenchmarkPutUpload -v -// -// goos: darwin -// goarch: amd64 -// pkg: github.com/ethereum/go-ethereum/swarm/storage/localstore -// BenchmarkPutUpload/count_100_parallel_1-8 300 5107704 ns/op 2081461 B/op 2374 allocs/op -// BenchmarkPutUpload/count_100_parallel_2-8 300 5411742 ns/op 2081608 B/op 2364 allocs/op -// BenchmarkPutUpload/count_100_parallel_4-8 500 3704964 ns/op 2081696 B/op 2324 allocs/op -// BenchmarkPutUpload/count_100_parallel_8-8 500 2932663 ns/op 2082594 B/op 2295 allocs/op -// BenchmarkPutUpload/count_100_parallel_16-8 500 3117157 ns/op 2085438 B/op 2282 allocs/op -// BenchmarkPutUpload/count_100_parallel_32-8 500 3449122 ns/op 2089721 B/op 2286 allocs/op -// BenchmarkPutUpload/count_1000_parallel_1-8 20 79784470 ns/op 25211240 B/op 23225 allocs/op -// BenchmarkPutUpload/count_1000_parallel_2-8 20 75422164 ns/op 25210730 B/op 23187 allocs/op -// BenchmarkPutUpload/count_1000_parallel_4-8 20 70698378 ns/op 25206522 B/op 22692 allocs/op -// BenchmarkPutUpload/count_1000_parallel_8-8 20 71285528 ns/op 25213436 B/op 22345 allocs/op -// BenchmarkPutUpload/count_1000_parallel_16-8 20 71301826 ns/op 25205040 B/op 22090 allocs/op -// BenchmarkPutUpload/count_1000_parallel_32-8 30 57713506 ns/op 25219781 B/op 21848 allocs/op -// BenchmarkPutUpload/count_10000_parallel_1-8 2 656719345 ns/op 216792908 B/op 248940 allocs/op -// BenchmarkPutUpload/count_10000_parallel_2-8 2 646301962 ns/op 216730800 B/op 248270 allocs/op -// BenchmarkPutUpload/count_10000_parallel_4-8 2 532784228 ns/op 216667080 B/op 241910 allocs/op -// BenchmarkPutUpload/count_10000_parallel_8-8 3 494290188 ns/op 216297749 B/op 236247 allocs/op -// BenchmarkPutUpload/count_10000_parallel_16-8 3 483485315 ns/op 216060384 B/op 231090 allocs/op -// BenchmarkPutUpload/count_10000_parallel_32-8 3 434461294 ns/op 215371280 B/op 224800 allocs/op -// BenchmarkPutUpload/count_100000_parallel_1-8 1 22767894338 ns/op 2331372088 B/op 4049876 allocs/op -// BenchmarkPutUpload/count_100000_parallel_2-8 1 25347872677 ns/op 2344140160 B/op 4106763 allocs/op -// BenchmarkPutUpload/count_100000_parallel_4-8 1 23580460174 ns/op 2338582576 B/op 4027452 allocs/op -// BenchmarkPutUpload/count_100000_parallel_8-8 1 22197559193 ns/op 2321803496 B/op 3877553 allocs/op -// BenchmarkPutUpload/count_100000_parallel_16-8 1 22527046476 ns/op 2327854800 B/op 3885455 allocs/op -// BenchmarkPutUpload/count_100000_parallel_32-8 1 21332243613 ns/op 2299654568 B/op 3697181 allocs/op -// PASS -func BenchmarkPutUpload(b *testing.B) { - for _, count := range []int{ - 100, - 1000, - 10000, - 100000, - } { - for _, maxParallelUploads := range []int{ - 1, - 2, - 4, - 8, - 16, - 32, - } { - name := fmt.Sprintf("count %v parallel %v", count, maxParallelUploads) - b.Run(name, func(b *testing.B) { - for n := 0; n < b.N; n++ { - benchmarkPutUpload(b, nil, count, maxParallelUploads) - } - }) - } - } -} - -// benchmarkPutUpload runs a benchmark by uploading a specific number -// of chunks with specified max parallel uploads. -func benchmarkPutUpload(b *testing.B, o *Options, count, maxParallelUploads int) { - b.StopTimer() - db, cleanupFunc := newTestDB(b, o) - defer cleanupFunc() - - chunks := make([]chunk.Chunk, count) - for i := 0; i < count; i++ { - chunks[i] = generateTestRandomChunk() - } - errs := make(chan error) - b.StartTimer() - - go func() { - sem := make(chan struct{}, maxParallelUploads) - for i := 0; i < count; i++ { - sem <- struct{}{} - - go func(i int) { - defer func() { <-sem }() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, chunks[i]) - errs <- err - }(i) - } - }() - - for i := 0; i < count; i++ { - err := <-errs - if err != nil { - b.Fatal(err) - } - } -} diff --git a/swarm/storage/localstore/mode_set.go b/swarm/storage/localstore/mode_set.go deleted file mode 100644 index 14b48a22e6..0000000000 --- a/swarm/storage/localstore/mode_set.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/syndtr/goleveldb/leveldb" -) - -// Set updates database indexes for a specific -// chunk represented by the address. -// Set is required to implement chunk.Store -// interface. -func (db *DB) Set(ctx context.Context, mode chunk.ModeSet, addr chunk.Address) (err error) { - metricName := fmt.Sprintf("localstore.Set.%s", mode) - - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - defer totalTimeMetric(metricName, time.Now()) - - err = db.set(mode, addr) - if err != nil { - metrics.GetOrRegisterCounter(metricName+".error", nil).Inc(1) - } - return err -} - -// set updates database indexes for a specific -// chunk represented by the address. -// It acquires lockAddr to protect two calls -// of this function for the same address in parallel. -func (db *DB) set(mode chunk.ModeSet, addr chunk.Address) (err error) { - // protect parallel updates - db.batchMu.Lock() - defer db.batchMu.Unlock() - - batch := new(leveldb.Batch) - - // variables that provide information for operations - // to be done after write batch function successfully executes - var gcSizeChange int64 // number to add or subtract from gcSize - var triggerPullFeed bool // signal pull feed subscriptions to iterate - - item := addressToItem(addr) - - switch mode { - case chunk.ModeSetAccess: - // add to pull, insert to gc - - // need to get access timestamp here as it is not - // provided by the access function, and it is not - // a property of a chunk provided to Accessor.Put. - - i, err := db.retrievalDataIndex.Get(item) - switch err { - case nil: - item.StoreTimestamp = i.StoreTimestamp - item.BinID = i.BinID - case leveldb.ErrNotFound: - db.pushIndex.DeleteInBatch(batch, item) - item.StoreTimestamp = now() - item.BinID, err = db.binIDs.Inc(uint64(db.po(item.Address))) - if err != nil { - return err - } - default: - return err - } - - i, err = db.retrievalAccessIndex.Get(item) - switch err { - case nil: - item.AccessTimestamp = i.AccessTimestamp - db.gcIndex.DeleteInBatch(batch, item) - gcSizeChange-- - case leveldb.ErrNotFound: - // the chunk is not accessed before - default: - return err - } - item.AccessTimestamp = now() - db.retrievalAccessIndex.PutInBatch(batch, item) - db.pullIndex.PutInBatch(batch, item) - triggerPullFeed = true - db.gcIndex.PutInBatch(batch, item) - gcSizeChange++ - - case chunk.ModeSetSync: - // delete from push, insert to gc - - // need to get access timestamp here as it is not - // provided by the access function, and it is not - // a property of a chunk provided to Accessor.Put. - i, err := db.retrievalDataIndex.Get(item) - if err != nil { - if err == leveldb.ErrNotFound { - // chunk is not found, - // no need to update gc index - // just delete from the push index - // if it is there - db.pushIndex.DeleteInBatch(batch, item) - return nil - } - return err - } - item.StoreTimestamp = i.StoreTimestamp - item.BinID = i.BinID - - i, err = db.retrievalAccessIndex.Get(item) - switch err { - case nil: - item.AccessTimestamp = i.AccessTimestamp - db.gcIndex.DeleteInBatch(batch, item) - gcSizeChange-- - case leveldb.ErrNotFound: - // the chunk is not accessed before - default: - return err - } - item.AccessTimestamp = now() - db.retrievalAccessIndex.PutInBatch(batch, item) - db.pushIndex.DeleteInBatch(batch, item) - db.gcIndex.PutInBatch(batch, item) - gcSizeChange++ - - case chunk.ModeSetRemove: - // delete from retrieve, pull, gc - - // need to get access timestamp here as it is not - // provided by the access function, and it is not - // a property of a chunk provided to Accessor.Put. - - i, err := db.retrievalAccessIndex.Get(item) - switch err { - case nil: - item.AccessTimestamp = i.AccessTimestamp - case leveldb.ErrNotFound: - default: - return err - } - i, err = db.retrievalDataIndex.Get(item) - if err != nil { - return err - } - item.StoreTimestamp = i.StoreTimestamp - item.BinID = i.BinID - - db.retrievalDataIndex.DeleteInBatch(batch, item) - db.retrievalAccessIndex.DeleteInBatch(batch, item) - db.pullIndex.DeleteInBatch(batch, item) - db.gcIndex.DeleteInBatch(batch, item) - // a check is needed for decrementing gcSize - // as delete is not reporting if the key/value pair - // is deleted or not - if _, err := db.gcIndex.Get(item); err == nil { - gcSizeChange = -1 - } - - default: - return ErrInvalidMode - } - - err = db.incGCSizeInBatch(batch, gcSizeChange) - if err != nil { - return err - } - - err = db.shed.WriteBatch(batch) - if err != nil { - return err - } - if triggerPullFeed { - db.triggerPullSubscriptions(db.po(item.Address)) - } - return nil -} diff --git a/swarm/storage/localstore/mode_set_test.go b/swarm/storage/localstore/mode_set_test.go deleted file mode 100644 index 9ba62cd206..0000000000 --- a/swarm/storage/localstore/mode_set_test.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/syndtr/goleveldb/leveldb" -) - -// TestModeSetAccess validates ModeSetAccess index values on the provided DB. -func TestModeSetAccess(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - ch := generateTestRandomChunk() - - wantTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return wantTimestamp - })() - - err := db.Set(context.Background(), chunk.ModeSetAccess, ch.Address()) - if err != nil { - t.Fatal(err) - } - - t.Run("pull index", newPullIndexTest(db, ch, 1, nil)) - - t.Run("pull index count", newItemsCountTest(db.pullIndex, 1)) - - t.Run("gc index", newGCIndexTest(db, ch, wantTimestamp, wantTimestamp, 1)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) - - t.Run("gc size", newIndexGCSizeTest(db)) -} - -// TestModeSetSync validates ModeSetSync index values on the provided DB. -func TestModeSetSync(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - ch := generateTestRandomChunk() - - wantTimestamp := time.Now().UTC().UnixNano() - defer setNow(func() (t int64) { - return wantTimestamp - })() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - err = db.Set(context.Background(), chunk.ModeSetSync, ch.Address()) - if err != nil { - t.Fatal(err) - } - - t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, ch, wantTimestamp, wantTimestamp)) - - t.Run("push index", newPushIndexTest(db, ch, wantTimestamp, leveldb.ErrNotFound)) - - t.Run("gc index", newGCIndexTest(db, ch, wantTimestamp, wantTimestamp, 1)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 1)) - - t.Run("gc size", newIndexGCSizeTest(db)) -} - -// TestModeSetRemove validates ModeSetRemove index values on the provided DB. -func TestModeSetRemove(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - err = db.Set(context.Background(), chunk.ModeSetRemove, ch.Address()) - if err != nil { - t.Fatal(err) - } - - t.Run("retrieve indexes", func(t *testing.T) { - wantErr := leveldb.ErrNotFound - _, err := db.retrievalDataIndex.Get(addressToItem(ch.Address())) - if err != wantErr { - t.Errorf("got error %v, want %v", err, wantErr) - } - t.Run("retrieve data index count", newItemsCountTest(db.retrievalDataIndex, 0)) - - // access index should not be set - _, err = db.retrievalAccessIndex.Get(addressToItem(ch.Address())) - if err != wantErr { - t.Errorf("got error %v, want %v", err, wantErr) - } - t.Run("retrieve access index count", newItemsCountTest(db.retrievalAccessIndex, 0)) - }) - - t.Run("pull index", newPullIndexTest(db, ch, 0, leveldb.ErrNotFound)) - - t.Run("pull index count", newItemsCountTest(db.pullIndex, 0)) - - t.Run("gc index count", newItemsCountTest(db.gcIndex, 0)) - - t.Run("gc size", newIndexGCSizeTest(db)) -} diff --git a/swarm/storage/localstore/retrieval_index_test.go b/swarm/storage/localstore/retrieval_index_test.go deleted file mode 100644 index 4ca2e32e61..0000000000 --- a/swarm/storage/localstore/retrieval_index_test.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "strconv" - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// BenchmarkRetrievalIndexes uploads a number of chunks in order to measure -// total time of updating their retrieval indexes by setting them -// to synced state and requesting them. -// -// This benchmark takes significant amount of time. -// -// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014) show -// that two separated indexes perform better. -// -// # go test -benchmem -run=none github.com/ethereum/go-ethereum/swarm/storage/localstore -bench BenchmarkRetrievalIndexes -v -// goos: darwin -// goarch: amd64 -// pkg: github.com/ethereum/go-ethereum/swarm/storage/localstore -// BenchmarkRetrievalIndexes/1000-8 20 75556686 ns/op 19033493 B/op 84500 allocs/op -// BenchmarkRetrievalIndexes/10000-8 1 1079084922 ns/op 382792064 B/op 1429644 allocs/op -// BenchmarkRetrievalIndexes/100000-8 1 16891305737 ns/op 2629165304 B/op 12465019 allocs/op -// PASS -func BenchmarkRetrievalIndexes(b *testing.B) { - for _, count := range []int{ - 1000, - 10000, - 100000, - } { - b.Run(strconv.Itoa(count)+"-split", func(b *testing.B) { - for n := 0; n < b.N; n++ { - benchmarkRetrievalIndexes(b, nil, count) - } - }) - } -} - -// benchmarkRetrievalIndexes is used in BenchmarkRetrievalIndexes -// to do benchmarks with a specific number of chunks and different -// database options. -func benchmarkRetrievalIndexes(b *testing.B, o *Options, count int) { - b.StopTimer() - db, cleanupFunc := newTestDB(b, o) - defer cleanupFunc() - addrs := make([]chunk.Address, count) - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - b.Fatal(err) - } - addrs[i] = ch.Address() - } - // set update gc test hook to signal when - // update gc goroutine is done by sending to - // testHookUpdateGCChan channel, which is - // used to wait for gc index updates to be - // included in the benchmark time - testHookUpdateGCChan := make(chan struct{}) - defer setTestHookUpdateGC(func() { - testHookUpdateGCChan <- struct{}{} - })() - b.StartTimer() - - for i := 0; i < count; i++ { - err := db.Set(context.Background(), chunk.ModeSetSync, addrs[i]) - if err != nil { - b.Fatal(err) - } - - _, err = db.Get(context.Background(), chunk.ModeGetRequest, addrs[i]) - if err != nil { - b.Fatal(err) - } - // wait for update gc goroutine to be done - <-testHookUpdateGCChan - } -} - -// BenchmarkUpload compares uploading speed for different -// retrieval indexes and various number of chunks. -// -// Measurements on MacBook Pro (Retina, 15-inch, Mid 2014). -// -// go test -benchmem -run=none github.com/ethereum/go-ethereum/swarm/storage/localstore -bench BenchmarkUpload -v -// goos: darwin -// goarch: amd64 -// pkg: github.com/ethereum/go-ethereum/swarm/storage/localstore -// BenchmarkUpload/1000-8 20 59437463 ns/op 25205193 B/op 23208 allocs/op -// BenchmarkUpload/10000-8 2 580646362 ns/op 216532932 B/op 248090 allocs/op -// BenchmarkUpload/100000-8 1 22373390892 ns/op 2323055312 B/op 3995903 allocs/op -// PASS -func BenchmarkUpload(b *testing.B) { - for _, count := range []int{ - 1000, - 10000, - 100000, - } { - b.Run(strconv.Itoa(count), func(b *testing.B) { - for n := 0; n < b.N; n++ { - benchmarkUpload(b, nil, count) - } - }) - } -} - -// benchmarkUpload is used in BenchmarkUpload -// to do benchmarks with a specific number of chunks and different -// database options. -func benchmarkUpload(b *testing.B, o *Options, count int) { - b.StopTimer() - db, cleanupFunc := newTestDB(b, o) - defer cleanupFunc() - chunks := make([]chunk.Chunk, count) - for i := 0; i < count; i++ { - chunk := generateTestRandomChunk() - chunks[i] = chunk - } - b.StartTimer() - - for i := 0; i < count; i++ { - _, err := db.Put(context.Background(), chunk.ModePutUpload, chunks[i]) - if err != nil { - b.Fatal(err) - } - } -} diff --git a/swarm/storage/localstore/schema.go b/swarm/storage/localstore/schema.go deleted file mode 100644 index 538c75d1f8..0000000000 --- a/swarm/storage/localstore/schema.go +++ /dev/null @@ -1,52 +0,0 @@ -package localstore - -import ( - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/opt" -) - -// The DB schema we want to use. The actual/current DB schema might differ -// until migrations are run. -const CurrentDbSchema = DbSchemaSanctuary - -// There was a time when we had no schema at all. -const DbSchemaNone = "" - -// "purity" is the first formal schema of LevelDB we release together with Swarm 0.3.5 -const DbSchemaPurity = "purity" - -// "halloween" is here because we had a screw in the garbage collector index. -// Because of that we had to rebuild the GC index to get rid of erroneous -// entries and that takes a long time. This schema is used for bookkeeping, -// so rebuild index will run just once. -const DbSchemaHalloween = "halloween" - -const DbSchemaSanctuary = "sanctuary" - -// returns true if legacy database is in the datadir -func IsLegacyDatabase(datadir string) bool { - - var ( - legacyDbSchemaKey = []byte{8} - ) - - db, err := leveldb.OpenFile(datadir, &opt.Options{OpenFilesCacheCapacity: 128}) - if err != nil { - log.Error("got an error while trying to open leveldb path", "path", datadir, "err", err) - return false - } - defer db.Close() - - data, err := db.Get(legacyDbSchemaKey, nil) - if err != nil { - if err == leveldb.ErrNotFound { - // if we haven't found anything under the legacy db schema key- we are not on legacy - return false - } - - log.Error("got an unexpected error fetching legacy name from the database", "err", err) - } - log.Trace("checking if database scheme is legacy", "schema name", string(data)) - return string(data) == DbSchemaHalloween || string(data) == DbSchemaPurity -} diff --git a/swarm/storage/localstore/subscription_pull.go b/swarm/storage/localstore/subscription_pull.go deleted file mode 100644 index 0f7e487295..0000000000 --- a/swarm/storage/localstore/subscription_pull.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "errors" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/shed" - "github.com/syndtr/goleveldb/leveldb" -) - -// SubscribePull returns a channel that provides chunk addresses and stored times from pull syncing index. -// Pull syncing index can be only subscribed to a particular proximity order bin. If since -// is not 0, the iteration will start from the since item (the item with binID == since). If until is not 0, -// only chunks stored up to this id will be sent to the channel, and the returned channel will be -// closed. The since-until interval is closed on since side, and closed on until side: [since,until]. Returned stop -// function will terminate current and further iterations without errors, and also close the returned channel. -// Make sure that you check the second returned parameter from the channel to stop iteration when its value -// is false. -func (db *DB) SubscribePull(ctx context.Context, bin uint8, since, until uint64) (c <-chan chunk.Descriptor, stop func()) { - metricName := "localstore.SubscribePull" - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - - chunkDescriptors := make(chan chunk.Descriptor) - trigger := make(chan struct{}, 1) - - db.pullTriggersMu.Lock() - if _, ok := db.pullTriggers[bin]; !ok { - db.pullTriggers[bin] = make([]chan struct{}, 0) - } - db.pullTriggers[bin] = append(db.pullTriggers[bin], trigger) - db.pullTriggersMu.Unlock() - - // send signal for the initial iteration - trigger <- struct{}{} - - stopChan := make(chan struct{}) - var stopChanOnce sync.Once - - // used to provide information from the iterator to - // stop subscription when until chunk descriptor is reached - var errStopSubscription = errors.New("stop subscription") - - go func() { - defer metrics.GetOrRegisterCounter(metricName+".stop", nil).Inc(1) - // close the returned chunk.Descriptor channel at the end to - // signal that the subscription is done - defer close(chunkDescriptors) - // sinceItem is the Item from which the next iteration - // should start. The first iteration starts from the first Item. - var sinceItem *shed.Item - if since > 0 { - sinceItem = &shed.Item{ - Address: db.addressInBin(bin), - BinID: since, - } - } - first := true // first iteration flag for SkipStartFromItem - for { - select { - case <-trigger: - // iterate until: - // - last index Item is reached - // - subscription stop is called - // - context is done - metrics.GetOrRegisterCounter(metricName+".iter", nil).Inc(1) - - iterStart := time.Now() - var count int - err := db.pullIndex.Iterate(func(item shed.Item) (stop bool, err error) { - select { - case chunkDescriptors <- chunk.Descriptor{ - Address: item.Address, - BinID: item.BinID, - }: - count++ - // until chunk descriptor is sent - // break the iteration - if until > 0 && item.BinID >= until { - return true, errStopSubscription - } - // set next iteration start item - // when its chunk is successfully sent to channel - sinceItem = &item - return false, nil - case <-stopChan: - // gracefully stop the iteration - // on stop - return true, nil - case <-db.close: - // gracefully stop the iteration - // on database close - return true, nil - case <-ctx.Done(): - return true, ctx.Err() - } - }, &shed.IterateOptions{ - StartFrom: sinceItem, - // sinceItem was sent as the last Address in the previous - // iterator call, skip it in this one, but not the item with - // the provided since bin id as it should be sent to a channel - SkipStartFromItem: !first, - Prefix: []byte{bin}, - }) - - totalTimeMetric(metricName+".iter", iterStart) - - if err != nil { - if err == errStopSubscription { - // stop subscription without any errors - // if until is reached - return - } - metrics.GetOrRegisterCounter(metricName+".iter.error", nil).Inc(1) - log.Error("localstore pull subscription iteration", "bin", bin, "since", since, "until", until, "err", err) - return - } - if count > 0 { - first = false - } - case <-stopChan: - // terminate the subscription - // on stop - return - case <-db.close: - // terminate the subscription - // on database close - return - case <-ctx.Done(): - err := ctx.Err() - if err != nil { - log.Error("localstore pull subscription", "bin", bin, "since", since, "until", until, "err", err) - } - return - } - } - }() - - stop = func() { - stopChanOnce.Do(func() { - close(stopChan) - }) - - db.pullTriggersMu.Lock() - defer db.pullTriggersMu.Unlock() - - for i, t := range db.pullTriggers[bin] { - if t == trigger { - db.pullTriggers[bin] = append(db.pullTriggers[bin][:i], db.pullTriggers[bin][i+1:]...) - break - } - } - } - - return chunkDescriptors, stop -} - -// LastPullSubscriptionBinID returns chunk bin id of the latest Chunk -// in pull syncing index for a provided bin. If there are no chunks in -// that bin, 0 value is returned. -func (db *DB) LastPullSubscriptionBinID(bin uint8) (id uint64, err error) { - metrics.GetOrRegisterCounter("localstore.LastPullSubscriptionBinID", nil).Inc(1) - - item, err := db.pullIndex.Last([]byte{bin}) - if err != nil { - if err == leveldb.ErrNotFound { - return 0, nil - } - return 0, err - } - return item.BinID, nil -} - -// triggerPullSubscriptions is used internally for starting iterations -// on Pull subscriptions for a particular bin. When new item with address -// that is in particular bin for DB's baseKey is added to pull index -// this function should be called. -func (db *DB) triggerPullSubscriptions(bin uint8) { - db.pullTriggersMu.RLock() - triggers, ok := db.pullTriggers[bin] - db.pullTriggersMu.RUnlock() - if !ok { - return - } - - for _, t := range triggers { - select { - case t <- struct{}{}: - default: - } - } -} - -// addressInBin returns an address that is in a specific -// proximity order bin from database base key. -func (db *DB) addressInBin(bin uint8) (addr chunk.Address) { - addr = append([]byte(nil), db.baseKey...) - b := bin / 8 - addr[b] = addr[b] ^ (1 << (7 - bin%8)) - return addr -} diff --git a/swarm/storage/localstore/subscription_pull_test.go b/swarm/storage/localstore/subscription_pull_test.go deleted file mode 100644 index 95a2fa8b13..0000000000 --- a/swarm/storage/localstore/subscription_pull_test.go +++ /dev/null @@ -1,585 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "bytes" - "context" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/shed" -) - -// TestDB_SubscribePull_first is a regression test for the first=false (from-1) bug -// The bug was that `first=false` was not behind an if-condition `if count > 0`. This resulted in chunks being missed, when -// the subscription is established before the chunk is actually uploaded. For example if a subscription is established with since=49, -// which means that the `SubscribePull` method should return chunk with BinID=49 via the channel, and the chunk for BinID=49 is uploaded, -// after the subscription, then it would have been skipped, where the correct behaviour is to not skip it and return it via the channel. -func TestDB_SubscribePull_first(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make(map[uint8][]chunk.Address) - var addrsMu sync.Mutex - var wantedChunksCount int - - // prepopulate database with some chunks - // before the subscription - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 100) - - // any bin should do the trick - bin := uint8(1) - - chunksInGivenBin := uint64(len(addrs[bin])) - - errc := make(chan error) - - since := chunksInGivenBin + 1 - - go func() { - ch, stop := db.SubscribePull(context.TODO(), bin, since, 0) - defer stop() - - chnk := <-ch - - if chnk.BinID != since { - errc <- fmt.Errorf("expected chunk.BinID to be %v , but got %v", since, chnk.BinID) - } else { - errc <- nil - } - }() - - time.Sleep(100 * time.Millisecond) - - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 100) - - err := <-errc - if err != nil { - t.Fatal(err) - } -} - -// TestDB_SubscribePull uploads some chunks before and after -// pull syncing subscription is created and validates if -// all addresses are received in the right order -// for expected proximity order bins. -func TestDB_SubscribePull(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make(map[uint8][]chunk.Address) - var addrsMu sync.Mutex - var wantedChunksCount int - - // prepopulate database with some chunks - // before the subscription - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 10) - - // set a timeout on subscription - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // collect all errors from validating addresses, even nil ones - // to validate the number of addresses received by the subscription - errChan := make(chan error) - - for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { - ch, stop := db.SubscribePull(ctx, bin, 0, 0) - defer stop() - - // receive and validate addresses from the subscription - go readPullSubscriptionBin(ctx, db, bin, ch, addrs, &addrsMu, errChan) - } - - // upload some chunks just after subscribe - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 5) - - time.Sleep(200 * time.Millisecond) - - // upload some chunks after some short time - // to ensure that subscription will include them - // in a dynamic environment - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 3) - - checkErrChan(ctx, t, errChan, wantedChunksCount) -} - -// TestDB_SubscribePull_multiple uploads chunks before and after -// multiple pull syncing subscriptions are created and -// validates if all addresses are received in the right order -// for expected proximity order bins. -func TestDB_SubscribePull_multiple(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make(map[uint8][]chunk.Address) - var addrsMu sync.Mutex - var wantedChunksCount int - - // prepopulate database with some chunks - // before the subscription - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 10) - - // set a timeout on subscription - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // collect all errors from validating addresses, even nil ones - // to validate the number of addresses received by the subscription - errChan := make(chan error) - - subsCount := 10 - - // start a number of subscriptions - // that all of them will write every address error to errChan - for j := 0; j < subsCount; j++ { - for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { - ch, stop := db.SubscribePull(ctx, bin, 0, 0) - defer stop() - - // receive and validate addresses from the subscription - go readPullSubscriptionBin(ctx, db, bin, ch, addrs, &addrsMu, errChan) - } - } - - // upload some chunks just after subscribe - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 5) - - time.Sleep(200 * time.Millisecond) - - // upload some chunks after some short time - // to ensure that subscription will include them - // in a dynamic environment - uploadRandomChunksBin(t, db, addrs, &addrsMu, &wantedChunksCount, 3) - - checkErrChan(ctx, t, errChan, wantedChunksCount*subsCount) -} - -// TestDB_SubscribePull_since uploads chunks before and after -// pull syncing subscriptions are created with a since argument -// and validates if all expected addresses are received in the -// right order for expected proximity order bins. -func TestDB_SubscribePull_since(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make(map[uint8][]chunk.Address) - var addrsMu sync.Mutex - var wantedChunksCount int - - binIDCounter := make(map[uint8]uint64) - var binIDCounterMu sync.RWMutex - - uploadRandomChunks := func(count int, wanted bool) (first map[uint8]uint64) { - addrsMu.Lock() - defer addrsMu.Unlock() - - first = make(map[uint8]uint64) - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - bin := db.po(ch.Address()) - - binIDCounterMu.RLock() - binIDCounter[bin]++ - binIDCounterMu.RUnlock() - - if wanted { - if _, ok := addrs[bin]; !ok { - addrs[bin] = make([]chunk.Address, 0) - } - addrs[bin] = append(addrs[bin], ch.Address()) - wantedChunksCount++ - - if _, ok := first[bin]; !ok { - first[bin] = binIDCounter[bin] - } - } - } - return first - } - - // prepopulate database with some chunks - // before the subscription - uploadRandomChunks(30, false) - - first := uploadRandomChunks(25, true) - - // set a timeout on subscription - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // collect all errors from validating addresses, even nil ones - // to validate the number of addresses received by the subscription - errChan := make(chan error) - - for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { - since, ok := first[bin] - if !ok { - continue - } - ch, stop := db.SubscribePull(ctx, bin, since, 0) - defer stop() - - // receive and validate addresses from the subscription - go readPullSubscriptionBin(ctx, db, bin, ch, addrs, &addrsMu, errChan) - - } - - checkErrChan(ctx, t, errChan, wantedChunksCount) -} - -// TestDB_SubscribePull_until uploads chunks before and after -// pull syncing subscriptions are created with an until argument -// and validates if all expected addresses are received in the -// right order for expected proximity order bins. -func TestDB_SubscribePull_until(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make(map[uint8][]chunk.Address) - var addrsMu sync.Mutex - var wantedChunksCount int - - binIDCounter := make(map[uint8]uint64) - var binIDCounterMu sync.RWMutex - - uploadRandomChunks := func(count int, wanted bool) (last map[uint8]uint64) { - addrsMu.Lock() - defer addrsMu.Unlock() - - last = make(map[uint8]uint64) - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - bin := db.po(ch.Address()) - - if _, ok := addrs[bin]; !ok { - addrs[bin] = make([]chunk.Address, 0) - } - if wanted { - addrs[bin] = append(addrs[bin], ch.Address()) - wantedChunksCount++ - } - - binIDCounterMu.RLock() - binIDCounter[bin]++ - binIDCounterMu.RUnlock() - - last[bin] = binIDCounter[bin] - } - return last - } - - // prepopulate database with some chunks - // before the subscription - last := uploadRandomChunks(30, true) - - uploadRandomChunks(25, false) - - // set a timeout on subscription - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // collect all errors from validating addresses, even nil ones - // to validate the number of addresses received by the subscription - errChan := make(chan error) - - for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { - until, ok := last[bin] - if !ok { - continue - } - ch, stop := db.SubscribePull(ctx, bin, 0, until) - defer stop() - - // receive and validate addresses from the subscription - go readPullSubscriptionBin(ctx, db, bin, ch, addrs, &addrsMu, errChan) - } - - // upload some chunks just after subscribe - uploadRandomChunks(15, false) - - checkErrChan(ctx, t, errChan, wantedChunksCount) -} - -// TestDB_SubscribePull_sinceAndUntil uploads chunks before and -// after pull syncing subscriptions are created with since -// and until arguments, and validates if all expected addresses -// are received in the right order for expected proximity order bins. -func TestDB_SubscribePull_sinceAndUntil(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make(map[uint8][]chunk.Address) - var addrsMu sync.Mutex - var wantedChunksCount int - - binIDCounter := make(map[uint8]uint64) - var binIDCounterMu sync.RWMutex - - uploadRandomChunks := func(count int, wanted bool) (last map[uint8]uint64) { - addrsMu.Lock() - defer addrsMu.Unlock() - - last = make(map[uint8]uint64) - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - bin := db.po(ch.Address()) - - if _, ok := addrs[bin]; !ok { - addrs[bin] = make([]chunk.Address, 0) - } - if wanted { - addrs[bin] = append(addrs[bin], ch.Address()) - wantedChunksCount++ - } - - binIDCounterMu.RLock() - binIDCounter[bin]++ - binIDCounterMu.RUnlock() - - last[bin] = binIDCounter[bin] - } - return last - } - - // all chunks from upload1 are not expected - // as upload1 chunk is used as since for subscriptions - upload1 := uploadRandomChunks(100, false) - - // all chunks from upload2 are expected - // as upload2 chunk is used as until for subscriptions - upload2 := uploadRandomChunks(100, true) - - // upload some chunks before subscribe but after - // wanted chunks - uploadRandomChunks(8, false) - - // set a timeout on subscription - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // collect all errors from validating addresses, even nil ones - // to validate the number of addresses received by the subscription - errChan := make(chan error) - - for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { - since, ok := upload1[bin] - if ok { - // start from the next uploaded chunk - since++ - } - until, ok := upload2[bin] - if !ok { - // no chunks un this bin uploaded in the upload2 - // skip this bin from testing - continue - } - ch, stop := db.SubscribePull(ctx, bin, since, until) - defer stop() - - // receive and validate addresses from the subscription - go readPullSubscriptionBin(ctx, db, bin, ch, addrs, &addrsMu, errChan) - } - - // upload some chunks just after subscribe - uploadRandomChunks(15, false) - - checkErrChan(ctx, t, errChan, wantedChunksCount) -} - -// uploadRandomChunksBin uploads random chunks to database and adds them to -// the map of addresses ber bin. -func uploadRandomChunksBin(t *testing.T, db *DB, addrs map[uint8][]chunk.Address, addrsMu *sync.Mutex, wantedChunksCount *int, count int) { - addrsMu.Lock() - defer addrsMu.Unlock() - - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - bin := db.po(ch.Address()) - if _, ok := addrs[bin]; !ok { - addrs[bin] = make([]chunk.Address, 0) - } - addrs[bin] = append(addrs[bin], ch.Address()) - - *wantedChunksCount++ - } -} - -// readPullSubscriptionBin is a helper function that reads all chunk.Descriptors from a channel and -// sends error to errChan, even if it is nil, to count the number of chunk.Descriptors -// returned by the channel. -func readPullSubscriptionBin(ctx context.Context, db *DB, bin uint8, ch <-chan chunk.Descriptor, addrs map[uint8][]chunk.Address, addrsMu *sync.Mutex, errChan chan error) { - var i int // address index - for { - select { - case got, ok := <-ch: - if !ok { - return - } - var err error - addrsMu.Lock() - if i+1 > len(addrs[bin]) { - err = fmt.Errorf("got more chunk addresses %v, then expected %v, for bin %v", i+1, len(addrs[bin]), bin) - } else { - addr := addrs[bin][i] - if !bytes.Equal(got.Address, addr) { - err = fmt.Errorf("got chunk bin id %v in bin %v %v, want %v", i, bin, got.Address.Hex(), addr.Hex()) - } else { - want, err := db.retrievalDataIndex.Get(shed.Item{ - Address: addr, - }) - if err != nil { - err = fmt.Errorf("got chunk (bin id %v in bin %v) from retrieval index %s: %v", i, bin, addrs[bin][i].Hex(), err) - } else { - if got.BinID != want.BinID { - err = fmt.Errorf("got chunk bin id %v in bin %v %v, want %v", i, bin, got, want) - } - } - } - } - addrsMu.Unlock() - i++ - // send one and only one error per received address - select { - case errChan <- err: - case <-ctx.Done(): - return - } - case <-ctx.Done(): - return - } - } -} - -// checkErrChan expects the number of wantedChunksCount errors from errChan -// and calls t.Error for the ones that are not nil. -func checkErrChan(ctx context.Context, t *testing.T, errChan chan error, wantedChunksCount int) { - t.Helper() - - for i := 0; i < wantedChunksCount; i++ { - select { - case err := <-errChan: - if err != nil { - t.Error(err) - } - case <-ctx.Done(): - t.Fatal(ctx.Err()) - } - } -} - -// TestDB_LastPullSubscriptionBinID validates that LastPullSubscriptionBinID -// is returning the last chunk descriptor for proximity order bins by -// doing a few rounds of chunk uploads. -func TestDB_LastPullSubscriptionBinID(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make(map[uint8][]chunk.Address) - - binIDCounter := make(map[uint8]uint64) - var binIDCounterMu sync.RWMutex - - last := make(map[uint8]uint64) - - // do a few rounds of uploads and check if - // last pull subscription chunk is correct - for _, count := range []int{1, 3, 10, 11, 100, 120} { - - // upload - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - bin := db.po(ch.Address()) - - if _, ok := addrs[bin]; !ok { - addrs[bin] = make([]chunk.Address, 0) - } - addrs[bin] = append(addrs[bin], ch.Address()) - - binIDCounterMu.RLock() - binIDCounter[bin]++ - binIDCounterMu.RUnlock() - - last[bin] = binIDCounter[bin] - } - - // check - for bin := uint8(0); bin <= uint8(chunk.MaxPO); bin++ { - want, ok := last[bin] - got, err := db.LastPullSubscriptionBinID(bin) - if ok { - if err != nil { - t.Errorf("got unexpected error value %v", err) - } - } - if got != want { - t.Errorf("got last bin id %v, want %v", got, want) - } - } - } -} - -// TestAddressInBin validates that function addressInBin -// returns a valid address for every proximity order bin. -func TestAddressInBin(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - for po := uint8(0); po < chunk.MaxPO; po++ { - addr := db.addressInBin(po) - - got := db.po(addr) - - if got != uint8(po) { - t.Errorf("got po %v, want %v", got, po) - } - } -} diff --git a/swarm/storage/localstore/subscription_push.go b/swarm/storage/localstore/subscription_push.go deleted file mode 100644 index c43a751f41..0000000000 --- a/swarm/storage/localstore/subscription_push.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "context" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/shed" -) - -// SubscribePush returns a channel that provides storage chunks with ordering from push syncing index. -// Returned stop function will terminate current and further iterations, and also it will close -// the returned channel without any errors. Make sure that you check the second returned parameter -// from the channel to stop iteration when its value is false. -func (db *DB) SubscribePush(ctx context.Context) (c <-chan chunk.Chunk, stop func()) { - metricName := "localstore.SubscribePush" - metrics.GetOrRegisterCounter(metricName, nil).Inc(1) - - chunks := make(chan chunk.Chunk) - trigger := make(chan struct{}, 1) - - db.pushTriggersMu.Lock() - db.pushTriggers = append(db.pushTriggers, trigger) - db.pushTriggersMu.Unlock() - - // send signal for the initial iteration - trigger <- struct{}{} - - stopChan := make(chan struct{}) - var stopChanOnce sync.Once - - go func() { - defer metrics.GetOrRegisterCounter(metricName+".done", nil).Inc(1) - // close the returned chunkInfo channel at the end to - // signal that the subscription is done - defer close(chunks) - // sinceItem is the Item from which the next iteration - // should start. The first iteration starts from the first Item. - var sinceItem *shed.Item - for { - select { - case <-trigger: - // iterate until: - // - last index Item is reached - // - subscription stop is called - // - context is done - metrics.GetOrRegisterCounter(metricName+".iter", nil).Inc(1) - - iterStart := time.Now() - var count int - err := db.pushIndex.Iterate(func(item shed.Item) (stop bool, err error) { - // get chunk data - dataItem, err := db.retrievalDataIndex.Get(item) - if err != nil { - return true, err - } - - select { - case chunks <- chunk.NewChunk(dataItem.Address, dataItem.Data): - count++ - // set next iteration start item - // when its chunk is successfully sent to channel - sinceItem = &item - return false, nil - case <-stopChan: - // gracefully stop the iteration - // on stop - return true, nil - case <-db.close: - // gracefully stop the iteration - // on database close - return true, nil - case <-ctx.Done(): - return true, ctx.Err() - } - }, &shed.IterateOptions{ - StartFrom: sinceItem, - // sinceItem was sent as the last Address in the previous - // iterator call, skip it in this one - SkipStartFromItem: true, - }) - - totalTimeMetric(metricName+".iter", iterStart) - - if err != nil { - metrics.GetOrRegisterCounter(metricName+".iter.error", nil).Inc(1) - log.Error("localstore push subscription iteration", "err", err) - return - } - case <-stopChan: - // terminate the subscription - // on stop - return - case <-db.close: - // terminate the subscription - // on database close - return - case <-ctx.Done(): - err := ctx.Err() - if err != nil { - log.Error("localstore push subscription", "err", err) - } - return - } - } - }() - - stop = func() { - stopChanOnce.Do(func() { - close(stopChan) - }) - - db.pushTriggersMu.Lock() - defer db.pushTriggersMu.Unlock() - - for i, t := range db.pushTriggers { - if t == trigger { - db.pushTriggers = append(db.pushTriggers[:i], db.pushTriggers[i+1:]...) - break - } - } - } - - return chunks, stop -} - -// triggerPushSubscriptions is used internally for starting iterations -// on Push subscriptions. Whenever new item is added to the push index, -// this function should be called. -func (db *DB) triggerPushSubscriptions() { - db.pushTriggersMu.RLock() - triggers := db.pushTriggers - db.pushTriggersMu.RUnlock() - - for _, t := range triggers { - select { - case t <- struct{}{}: - default: - } - } -} diff --git a/swarm/storage/localstore/subscription_push_test.go b/swarm/storage/localstore/subscription_push_test.go deleted file mode 100644 index 6124a534bd..0000000000 --- a/swarm/storage/localstore/subscription_push_test.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package localstore - -import ( - "bytes" - "context" - "fmt" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// TestDB_SubscribePush uploads some chunks before and after -// push syncing subscription is created and validates if -// all addresses are received in the right order. -func TestDB_SubscribePush(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - chunks := make([]chunk.Chunk, 0) - var chunksMu sync.Mutex - - uploadRandomChunks := func(count int) { - chunksMu.Lock() - defer chunksMu.Unlock() - - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - chunks = append(chunks, ch) - } - } - - // prepopulate database with some chunks - // before the subscription - uploadRandomChunks(10) - - // set a timeout on subscription - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // collect all errors from validating addresses, even nil ones - // to validate the number of addresses received by the subscription - errChan := make(chan error) - - ch, stop := db.SubscribePush(ctx) - defer stop() - - // receive and validate addresses from the subscription - go func() { - var i int // address index - for { - select { - case got, ok := <-ch: - if !ok { - return - } - chunksMu.Lock() - want := chunks[i] - chunksMu.Unlock() - var err error - if !bytes.Equal(got.Data(), want.Data()) { - err = fmt.Errorf("got chunk %v data %x, want %x", i, got.Data(), want.Data()) - } - if !bytes.Equal(got.Address(), want.Address()) { - err = fmt.Errorf("got chunk %v address %s, want %s", i, got.Address().Hex(), want.Address().Hex()) - } - i++ - // send one and only one error per received address - select { - case errChan <- err: - case <-ctx.Done(): - return - } - case <-ctx.Done(): - return - } - } - }() - - // upload some chunks just after subscribe - uploadRandomChunks(5) - - time.Sleep(200 * time.Millisecond) - - // upload some chunks after some short time - // to ensure that subscription will include them - // in a dynamic environment - uploadRandomChunks(3) - - checkErrChan(ctx, t, errChan, len(chunks)) -} - -// TestDB_SubscribePush_multiple uploads chunks before and after -// multiple push syncing subscriptions are created and -// validates if all addresses are received in the right order. -func TestDB_SubscribePush_multiple(t *testing.T) { - db, cleanupFunc := newTestDB(t, nil) - defer cleanupFunc() - - addrs := make([]chunk.Address, 0) - var addrsMu sync.Mutex - - uploadRandomChunks := func(count int) { - addrsMu.Lock() - defer addrsMu.Unlock() - - for i := 0; i < count; i++ { - ch := generateTestRandomChunk() - - _, err := db.Put(context.Background(), chunk.ModePutUpload, ch) - if err != nil { - t.Fatal(err) - } - - addrs = append(addrs, ch.Address()) - } - } - - // prepopulate database with some chunks - // before the subscription - uploadRandomChunks(10) - - // set a timeout on subscription - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // collect all errors from validating addresses, even nil ones - // to validate the number of addresses received by the subscription - errChan := make(chan error) - - subsCount := 10 - - // start a number of subscriptions - // that all of them will write every addresses error to errChan - for j := 0; j < subsCount; j++ { - ch, stop := db.SubscribePush(ctx) - defer stop() - - // receive and validate addresses from the subscription - go func(j int) { - var i int // address index - for { - select { - case got, ok := <-ch: - if !ok { - return - } - addrsMu.Lock() - want := addrs[i] - addrsMu.Unlock() - var err error - if !bytes.Equal(got.Address(), want) { - err = fmt.Errorf("got chunk %v address on subscription %v %s, want %s", i, j, got, want) - } - i++ - // send one and only one error per received address - select { - case errChan <- err: - case <-ctx.Done(): - return - } - case <-ctx.Done(): - return - } - } - }(j) - } - - // upload some chunks just after subscribe - uploadRandomChunks(5) - - time.Sleep(200 * time.Millisecond) - - // upload some chunks after some short time - // to ensure that subscription will include them - // in a dynamic environment - uploadRandomChunks(3) - - // number of addresses received by all subscriptions - wantedChunksCount := len(addrs) * subsCount - - checkErrChan(ctx, t, errChan, wantedChunksCount) -} diff --git a/swarm/storage/mock/db/db.go b/swarm/storage/mock/db/db.go deleted file mode 100644 index 313a61b43e..0000000000 --- a/swarm/storage/mock/db/db.go +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package db implements a mock store that keeps all chunk data in LevelDB database. -package db - -import ( - "archive/tar" - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "sync" - "time" - - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/util" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage/mock" -) - -// GlobalStore contains the LevelDB database that is storing -// chunk data for all swarm nodes. -// Closing the GlobalStore with Close method is required to -// release resources used by the database. -type GlobalStore struct { - db *leveldb.DB - // protects nodes and keys indexes - // in Put and Delete methods - nodesLocks sync.Map - keysLocks sync.Map -} - -// NewGlobalStore creates a new instance of GlobalStore. -func NewGlobalStore(path string) (s *GlobalStore, err error) { - db, err := leveldb.OpenFile(path, nil) - if err != nil { - return nil, err - } - return &GlobalStore{ - db: db, - }, nil -} - -// Close releases the resources used by the underlying LevelDB. -func (s *GlobalStore) Close() error { - return s.db.Close() -} - -// NewNodeStore returns a new instance of NodeStore that retrieves and stores -// chunk data only for a node with address addr. -func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { - return mock.NewNodeStore(addr, s) -} - -// Get returns chunk data if the chunk with key exists for node -// on address addr. -func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { - has, err := s.db.Has(indexForHashesPerNode(addr, key), nil) - if err != nil { - return nil, mock.ErrNotFound - } - if !has { - return nil, mock.ErrNotFound - } - data, err = s.db.Get(indexDataKey(key), nil) - if err == leveldb.ErrNotFound { - err = mock.ErrNotFound - } - return -} - -// Put saves the chunk data for node with address addr. -func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { - unlock, err := s.lock(addr, key) - if err != nil { - return err - } - defer unlock() - - batch := new(leveldb.Batch) - batch.Put(indexForHashesPerNode(addr, key), nil) - batch.Put(indexForNodesWithHash(key, addr), nil) - batch.Put(indexForNodes(addr), nil) - batch.Put(indexForHashes(key), nil) - batch.Put(indexDataKey(key), data) - return s.db.Write(batch, nil) -} - -// Delete removes the chunk reference to node with address addr. -func (s *GlobalStore) Delete(addr common.Address, key []byte) error { - unlock, err := s.lock(addr, key) - if err != nil { - return err - } - defer unlock() - - batch := new(leveldb.Batch) - batch.Delete(indexForHashesPerNode(addr, key)) - batch.Delete(indexForNodesWithHash(key, addr)) - - // check if this node contains any keys, and if not - // remove it from the - x := indexForHashesPerNodePrefix(addr) - if k, _ := s.db.Get(x, nil); !bytes.HasPrefix(k, x) { - batch.Delete(indexForNodes(addr)) - } - - x = indexForNodesWithHashPrefix(key) - if k, _ := s.db.Get(x, nil); !bytes.HasPrefix(k, x) { - batch.Delete(indexForHashes(key)) - } - return s.db.Write(batch, nil) -} - -// HasKey returns whether a node with addr contains the key. -func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { - has, err := s.db.Has(indexForHashesPerNode(addr, key), nil) - if err != nil { - has = false - } - return has -} - -// Keys returns a paginated list of keys on all nodes. -func (s *GlobalStore) Keys(startKey []byte, limit int) (keys mock.Keys, err error) { - return s.keys(nil, startKey, limit) -} - -// Nodes returns a paginated list of all known nodes. -func (s *GlobalStore) Nodes(startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { - return s.nodes(nil, startAddr, limit) -} - -// NodeKeys returns a paginated list of keys on a node with provided address. -func (s *GlobalStore) NodeKeys(addr common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { - return s.keys(&addr, startKey, limit) -} - -// KeyNodes returns a paginated list of nodes that contain a particular key. -func (s *GlobalStore) KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { - return s.nodes(key, startAddr, limit) -} - -// keys returns a paginated list of keys. If addr is not nil, only keys on that -// node will be returned. -func (s *GlobalStore) keys(addr *common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { - iter := s.db.NewIterator(nil, nil) - defer iter.Release() - - if limit <= 0 { - limit = mock.DefaultLimit - } - - prefix := []byte{indexForHashesPrefix} - if addr != nil { - prefix = indexForHashesPerNodePrefix(*addr) - } - if startKey != nil { - if addr != nil { - startKey = indexForHashesPerNode(*addr, startKey) - } else { - startKey = indexForHashes(startKey) - } - } else { - startKey = prefix - } - - ok := iter.Seek(startKey) - if !ok { - return keys, iter.Error() - } - for ; ok; ok = iter.Next() { - k := iter.Key() - if !bytes.HasPrefix(k, prefix) { - break - } - key := append([]byte(nil), bytes.TrimPrefix(k, prefix)...) - - if len(keys.Keys) >= limit { - keys.Next = key - break - } - - keys.Keys = append(keys.Keys, key) - } - return keys, iter.Error() -} - -// nodes returns a paginated list of node addresses. If key is not nil, -// only nodes that contain that key will be returned. -func (s *GlobalStore) nodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { - iter := s.db.NewIterator(nil, nil) - defer iter.Release() - - if limit <= 0 { - limit = mock.DefaultLimit - } - - prefix := []byte{indexForNodesPrefix} - if key != nil { - prefix = indexForNodesWithHashPrefix(key) - } - startKey := prefix - if startAddr != nil { - if key != nil { - startKey = indexForNodesWithHash(key, *startAddr) - } else { - startKey = indexForNodes(*startAddr) - } - } - - ok := iter.Seek(startKey) - if !ok { - return nodes, iter.Error() - } - for ; ok; ok = iter.Next() { - k := iter.Key() - if !bytes.HasPrefix(k, prefix) { - break - } - addr := common.BytesToAddress(append([]byte(nil), bytes.TrimPrefix(k, prefix)...)) - - if len(nodes.Addrs) >= limit { - nodes.Next = &addr - break - } - - nodes.Addrs = append(nodes.Addrs, addr) - } - return nodes, iter.Error() -} - -// Import reads tar archive from a reader that contains exported chunk data. -// It returns the number of chunks imported and an error. -func (s *GlobalStore) Import(r io.Reader) (n int, err error) { - tr := tar.NewReader(r) - - for { - hdr, err := tr.Next() - if err != nil { - if err == io.EOF { - break - } - return n, err - } - - data, err := ioutil.ReadAll(tr) - if err != nil { - return n, err - } - - var c mock.ExportedChunk - if err = json.Unmarshal(data, &c); err != nil { - return n, err - } - - key := common.Hex2Bytes(hdr.Name) - - batch := new(leveldb.Batch) - for _, addr := range c.Addrs { - batch.Put(indexForHashesPerNode(addr, key), nil) - batch.Put(indexForNodesWithHash(key, addr), nil) - batch.Put(indexForNodes(addr), nil) - } - - batch.Put(indexForHashes(key), nil) - batch.Put(indexDataKey(key), c.Data) - - if err = s.db.Write(batch, nil); err != nil { - return n, err - } - - n++ - } - return n, err -} - -// Export writes to a writer a tar archive with all chunk data from -// the store. It returns the number fo chunks exported and an error. -func (s *GlobalStore) Export(w io.Writer) (n int, err error) { - tw := tar.NewWriter(w) - defer tw.Close() - - buf := bytes.NewBuffer(make([]byte, 0, 1024)) - encoder := json.NewEncoder(buf) - - snap, err := s.db.GetSnapshot() - if err != nil { - return 0, err - } - - iter := snap.NewIterator(util.BytesPrefix([]byte{indexForHashesByNodePrefix}), nil) - defer iter.Release() - - var currentKey string - var addrs []common.Address - - saveChunk := func() error { - hexKey := currentKey - - data, err := snap.Get(indexDataKey(common.Hex2Bytes(hexKey)), nil) - if err != nil { - return fmt.Errorf("get data %s: %v", hexKey, err) - } - - buf.Reset() - if err = encoder.Encode(mock.ExportedChunk{ - Addrs: addrs, - Data: data, - }); err != nil { - return err - } - - d := buf.Bytes() - hdr := &tar.Header{ - Name: hexKey, - Mode: 0644, - Size: int64(len(d)), - } - if err := tw.WriteHeader(hdr); err != nil { - return err - } - if _, err := tw.Write(d); err != nil { - return err - } - n++ - return nil - } - - for iter.Next() { - k := bytes.TrimPrefix(iter.Key(), []byte{indexForHashesByNodePrefix}) - i := bytes.Index(k, []byte{keyTermByte}) - if i < 0 { - continue - } - hexKey := string(k[:i]) - - if currentKey == "" { - currentKey = hexKey - } - - if hexKey != currentKey { - if err = saveChunk(); err != nil { - return n, err - } - - addrs = addrs[:0] - } - - currentKey = hexKey - addrs = append(addrs, common.BytesToAddress(k[i+1:])) - } - - if len(addrs) > 0 { - if err = saveChunk(); err != nil { - return n, err - } - } - - return n, iter.Error() -} - -var ( - // maximal time for lock to wait until it returns error - lockTimeout = 3 * time.Second - // duration between two lock checks. - lockCheckDelay = 30 * time.Microsecond - // error returned by lock method when lock timeout is reached - errLockTimeout = errors.New("lock timeout") -) - -// lock protects parallel writes in Put and Delete methods for both -// node with provided address and for data with provided key. -func (s *GlobalStore) lock(addr common.Address, key []byte) (unlock func(), err error) { - start := time.Now() - nodeLockKey := addr.Hex() - for { - _, loaded := s.nodesLocks.LoadOrStore(nodeLockKey, struct{}{}) - if !loaded { - break - } - time.Sleep(lockCheckDelay) - if time.Since(start) > lockTimeout { - return nil, errLockTimeout - } - } - start = time.Now() - keyLockKey := common.Bytes2Hex(key) - for { - _, loaded := s.keysLocks.LoadOrStore(keyLockKey, struct{}{}) - if !loaded { - break - } - time.Sleep(lockCheckDelay) - if time.Since(start) > lockTimeout { - return nil, errLockTimeout - } - } - return func() { - s.nodesLocks.Delete(nodeLockKey) - s.keysLocks.Delete(keyLockKey) - }, nil -} - -const ( - // prefixes for different indexes - indexDataPrefix = 0 - indexForNodesWithHashesPrefix = 1 - indexForHashesByNodePrefix = 2 - indexForNodesPrefix = 3 - indexForHashesPrefix = 4 - - // keyTermByte splits keys and node addresses - // in database keys - keyTermByte = 0xff -) - -// indexForHashesPerNode constructs a database key to store keys used in -// NodeKeys method. -func indexForHashesPerNode(addr common.Address, key []byte) []byte { - return append(indexForHashesPerNodePrefix(addr), key...) -} - -// indexForHashesPerNodePrefix returns a prefix containing a node address used in -// NodeKeys method. Node address is hex encoded to be able to use keyTermByte -// for splitting node address and key. -func indexForHashesPerNodePrefix(addr common.Address) []byte { - return append([]byte{indexForNodesWithHashesPrefix}, append([]byte(addr.Hex()), keyTermByte)...) -} - -// indexForNodesWithHash constructs a database key to store keys used in -// KeyNodes method. -func indexForNodesWithHash(key []byte, addr common.Address) []byte { - return append(indexForNodesWithHashPrefix(key), addr[:]...) -} - -// indexForNodesWithHashPrefix returns a prefix containing a key used in -// KeyNodes method. Key is hex encoded to be able to use keyTermByte -// for splitting key and node address. -func indexForNodesWithHashPrefix(key []byte) []byte { - return append([]byte{indexForHashesByNodePrefix}, append([]byte(common.Bytes2Hex(key)), keyTermByte)...) -} - -// indexForNodes constructs a database key to store keys used in -// Nodes method. -func indexForNodes(addr common.Address) []byte { - return append([]byte{indexForNodesPrefix}, addr[:]...) -} - -// indexForHashes constructs a database key to store keys used in -// Keys method. -func indexForHashes(key []byte) []byte { - return append([]byte{indexForHashesPrefix}, key...) -} - -// indexDataKey constructs a database key for key/data storage. -func indexDataKey(key []byte) []byte { - return append([]byte{indexDataPrefix}, key...) -} diff --git a/swarm/storage/mock/db/db_test.go b/swarm/storage/mock/db/db_test.go deleted file mode 100644 index efbf942f68..0000000000 --- a/swarm/storage/mock/db/db_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package db - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/ethereum/go-ethereum/swarm/storage/mock/test" -) - -// TestDBStore is running a test.MockStore tests -// using test.MockStore function. -func TestDBStore(t *testing.T) { - store, cleanup := newTestStore(t) - defer cleanup() - - test.MockStore(t, store, 100) -} - -// TestDBStoreListings is running test.MockStoreListings tests. -func TestDBStoreListings(t *testing.T) { - store, cleanup := newTestStore(t) - defer cleanup() - - test.MockStoreListings(t, store, 1000) -} - -// TestImportExport is running a test.ImportExport tests -// using test.MockStore function. -func TestImportExport(t *testing.T) { - store1, cleanup := newTestStore(t) - defer cleanup() - - store2, cleanup := newTestStore(t) - defer cleanup() - - test.ImportExport(t, store1, store2, 100) -} - -// newTestStore creates a temporary GlobalStore -// that will be closed and data deleted when -// calling returned cleanup function. -func newTestStore(t *testing.T) (s *GlobalStore, cleanup func()) { - dir, err := ioutil.TempDir("", "swarm-mock-db-") - if err != nil { - t.Fatal(err) - } - - s, err = NewGlobalStore(dir) - if err != nil { - os.RemoveAll(dir) - t.Fatal(err) - } - - return s, func() { - s.Close() - os.RemoveAll(dir) - } -} diff --git a/swarm/storage/mock/explorer/explorer.go b/swarm/storage/mock/explorer/explorer.go deleted file mode 100644 index 8fffff8fde..0000000000 --- a/swarm/storage/mock/explorer/explorer.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package explorer - -import ( - "bytes" - "encoding/json" - "io" - "net/http" - "net/url" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - "github.com/rs/cors" -) - -const jsonContentType = "application/json; charset=utf-8" - -// NewHandler constructs an http.Handler with router -// that servers requests required by chunk explorer. -// -// /api/has-key/{node}/{key} -// /api/keys?start={key}&node={node}&limit={int[0..1000]} -// /api/nodes?start={node}&key={key}&limit={int[0..1000]} -// -// Data from global store will be served and appropriate -// CORS headers will be sent if allowed origins are provided. -func NewHandler(store mock.GlobalStorer, corsOrigins []string) (handler http.Handler) { - mux := http.NewServeMux() - mux.Handle("/api/has-key/", newHasKeyHandler(store)) - mux.Handle("/api/keys", newKeysHandler(store)) - mux.Handle("/api/nodes", newNodesHandler(store)) - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - jsonStatusResponse(w, http.StatusNotFound) - }) - handler = noCacheHandler(mux) - if corsOrigins != nil { - handler = cors.New(cors.Options{ - AllowedOrigins: corsOrigins, - AllowedMethods: []string{"GET"}, - MaxAge: 600, - }).Handler(handler) - } - return handler -} - -// newHasKeyHandler returns a new handler that serves -// requests for HasKey global store method. -// Possible responses are StatusResponse with -// status codes 200 or 404 if the chunk is found or not. -func newHasKeyHandler(store mock.GlobalStorer) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - addr, key, ok := parseHasKeyPath(r.URL.Path) - if !ok { - jsonStatusResponse(w, http.StatusNotFound) - return - } - found := store.HasKey(addr, key) - if !found { - jsonStatusResponse(w, http.StatusNotFound) - return - } - jsonStatusResponse(w, http.StatusOK) - } -} - -// KeysResponse is a JSON-encoded response for global store -// Keys and NodeKeys methods. -type KeysResponse struct { - Keys []string `json:"keys"` - Next string `json:"next,omitempty"` -} - -// newKeysHandler returns a new handler that serves -// requests for Key global store method. -// HTTP response body will be JSON-encoded KeysResponse. -func newKeysHandler(store mock.GlobalStorer) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - q := r.URL.Query() - node := q.Get("node") - start, limit := listingPage(q) - - var keys mock.Keys - if node == "" { - var err error - keys, err = store.Keys(common.Hex2Bytes(start), limit) - if err != nil { - log.Error("chunk explorer: keys handler: get keys", "start", start, "err", err) - jsonStatusResponse(w, http.StatusInternalServerError) - return - } - } else { - var err error - keys, err = store.NodeKeys(common.HexToAddress(node), common.Hex2Bytes(start), limit) - if err != nil { - log.Error("chunk explorer: keys handler: get node keys", "node", node, "start", start, "err", err) - jsonStatusResponse(w, http.StatusInternalServerError) - return - } - } - ks := make([]string, len(keys.Keys)) - for i, k := range keys.Keys { - ks[i] = common.Bytes2Hex(k) - } - data, err := json.Marshal(KeysResponse{ - Keys: ks, - Next: common.Bytes2Hex(keys.Next), - }) - if err != nil { - log.Error("chunk explorer: keys handler: json marshal", "err", err) - jsonStatusResponse(w, http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", jsonContentType) - _, err = io.Copy(w, bytes.NewReader(data)) - if err != nil { - log.Error("chunk explorer: keys handler: write response", "err", err) - } - } -} - -// NodesResponse is a JSON-encoded response for global store -// Nodes and KeyNodes methods. -type NodesResponse struct { - Nodes []string `json:"nodes"` - Next string `json:"next,omitempty"` -} - -// newNodesHandler returns a new handler that serves -// requests for Nodes global store method. -// HTTP response body will be JSON-encoded NodesResponse. -func newNodesHandler(store mock.GlobalStorer) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - q := r.URL.Query() - key := q.Get("key") - var start *common.Address - queryStart, limit := listingPage(q) - if queryStart != "" { - s := common.HexToAddress(queryStart) - start = &s - } - - var nodes mock.Nodes - if key == "" { - var err error - nodes, err = store.Nodes(start, limit) - if err != nil { - log.Error("chunk explorer: nodes handler: get nodes", "start", queryStart, "err", err) - jsonStatusResponse(w, http.StatusInternalServerError) - return - } - } else { - var err error - nodes, err = store.KeyNodes(common.Hex2Bytes(key), start, limit) - if err != nil { - log.Error("chunk explorer: nodes handler: get key nodes", "key", key, "start", queryStart, "err", err) - jsonStatusResponse(w, http.StatusInternalServerError) - return - } - } - ns := make([]string, len(nodes.Addrs)) - for i, n := range nodes.Addrs { - ns[i] = n.Hex() - } - var next string - if nodes.Next != nil { - next = nodes.Next.Hex() - } - data, err := json.Marshal(NodesResponse{ - Nodes: ns, - Next: next, - }) - if err != nil { - log.Error("chunk explorer: nodes handler", "err", err) - jsonStatusResponse(w, http.StatusInternalServerError) - return - } - w.Header().Set("Content-Type", jsonContentType) - _, err = io.Copy(w, bytes.NewReader(data)) - if err != nil { - log.Error("chunk explorer: nodes handler: write response", "err", err) - } - } -} - -// parseHasKeyPath extracts address and key from HTTP request -// path for HasKey route: /api/has-key/{node}/{key}. -// If ok is false, the provided path is not matched. -func parseHasKeyPath(p string) (addr common.Address, key []byte, ok bool) { - p = strings.TrimPrefix(p, "/api/has-key/") - parts := strings.SplitN(p, "/", 2) - if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return addr, nil, false - } - addr = common.HexToAddress(parts[0]) - key = common.Hex2Bytes(parts[1]) - return addr, key, true -} - -// listingPage returns start value and listing limit -// from url query values. -func listingPage(q url.Values) (start string, limit int) { - // if limit is not a valid integer (or blank string), - // ignore the error and use the returned 0 value - limit, _ = strconv.Atoi(q.Get("limit")) - return q.Get("start"), limit -} - -// StatusResponse is a standardized JSON-encoded response -// that contains information about HTTP response code -// for easier status identification. -type StatusResponse struct { - Message string `json:"message"` - Code int `json:"code"` -} - -// jsonStatusResponse writes to the response writer -// JSON-encoded StatusResponse based on the provided status code. -func jsonStatusResponse(w http.ResponseWriter, code int) { - w.Header().Set("Content-Type", jsonContentType) - w.WriteHeader(code) - err := json.NewEncoder(w).Encode(StatusResponse{ - Message: http.StatusText(code), - Code: code, - }) - if err != nil { - log.Error("chunk explorer: json status response", "err", err) - } -} - -// noCacheHandler sets required HTTP headers to prevent -// response caching at the client side. -func noCacheHandler(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - w.Header().Set("Pragma", "no-cache") - w.Header().Set("Expires", "0") - h.ServeHTTP(w, r) - }) -} diff --git a/swarm/storage/mock/explorer/explorer_test.go b/swarm/storage/mock/explorer/explorer_test.go deleted file mode 100644 index be26684266..0000000000 --- a/swarm/storage/mock/explorer/explorer_test.go +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package explorer - -import ( - "encoding/binary" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "os" - "sort" - "strconv" - "strings" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - "github.com/ethereum/go-ethereum/swarm/storage/mock/db" - "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" -) - -// TestHandler_memGlobalStore runs a set of tests -// to validate handler with mem global store. -func TestHandler_memGlobalStore(t *testing.T) { - t.Parallel() - - globalStore := mem.NewGlobalStore() - - testHandler(t, globalStore) -} - -// TestHandler_dbGlobalStore runs a set of tests -// to validate handler with database global store. -func TestHandler_dbGlobalStore(t *testing.T) { - t.Parallel() - - dir, err := ioutil.TempDir("", "swarm-mock-explorer-db-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - globalStore, err := db.NewGlobalStore(dir) - if err != nil { - t.Fatal(err) - } - defer globalStore.Close() - - testHandler(t, globalStore) -} - -// testHandler stores data distributed by node addresses -// and validates if this data is correctly retrievable -// by using the http.Handler returned by NewHandler function. -// This test covers all HTTP routes and various get parameters -// on them to check paginated results. -func testHandler(t *testing.T, globalStore mock.GlobalStorer) { - const ( - nodeCount = 350 - keyCount = 250 - keysOnNodeCount = 150 - ) - - // keys for every node - nodeKeys := make(map[string][]string) - - // a node address that is not present in global store - invalidAddr := "0x7b8b72938c254cf002c4e1e714d27e022be88d93" - - // a key that is not present in global store - invalidKey := "f9824192fb515cfb" - - for i := 1; i <= nodeCount; i++ { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(i)) - addr := common.BytesToAddress(b).Hex() - nodeKeys[addr] = make([]string, 0) - } - - for i := 1; i <= keyCount; i++ { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(i)) - - key := common.Bytes2Hex(b) - - var c int - for addr := range nodeKeys { - nodeKeys[addr] = append(nodeKeys[addr], key) - c++ - if c >= keysOnNodeCount { - break - } - } - } - - // sort keys for every node as they are expected to be - // sorted in HTTP responses - for _, keys := range nodeKeys { - sort.Strings(keys) - } - - // nodes for every key - keyNodes := make(map[string][]string) - - // construct a reverse mapping of nodes for every key - for addr, keys := range nodeKeys { - for _, key := range keys { - keyNodes[key] = append(keyNodes[key], addr) - } - } - - // sort node addresses with case insensitive sort, - // as hex letters in node addresses are in mixed caps - for _, addrs := range keyNodes { - sortCaseInsensitive(addrs) - } - - // find a key that is not stored at the address - var ( - unmatchedAddr string - unmatchedKey string - ) - for addr, keys := range nodeKeys { - for key := range keyNodes { - var found bool - for _, k := range keys { - if k == key { - found = true - break - } - } - if !found { - unmatchedAddr = addr - unmatchedKey = key - } - break - } - if unmatchedAddr != "" { - break - } - } - // check if unmatched key/address pair is found - if unmatchedAddr == "" || unmatchedKey == "" { - t.Fatalf("could not find a key that is not associated with a node") - } - - // store the data - for addr, keys := range nodeKeys { - for _, key := range keys { - err := globalStore.Put(common.HexToAddress(addr), common.Hex2Bytes(key), []byte("data")) - if err != nil { - t.Fatal(err) - } - } - } - - handler := NewHandler(globalStore, nil) - - // this subtest confirms that it has uploaded key and that it does not have invalid keys - t.Run("has key", func(t *testing.T) { - for addr, keys := range nodeKeys { - for _, key := range keys { - testStatusResponse(t, handler, "/api/has-key/"+addr+"/"+key, http.StatusOK) - testStatusResponse(t, handler, "/api/has-key/"+invalidAddr+"/"+key, http.StatusNotFound) - } - testStatusResponse(t, handler, "/api/has-key/"+addr+"/"+invalidKey, http.StatusNotFound) - } - testStatusResponse(t, handler, "/api/has-key/"+invalidAddr+"/"+invalidKey, http.StatusNotFound) - testStatusResponse(t, handler, "/api/has-key/"+unmatchedAddr+"/"+unmatchedKey, http.StatusNotFound) - }) - - // this subtest confirms that all keys are are listed in correct order with expected pagination - t.Run("keys", func(t *testing.T) { - var allKeys []string - for key := range keyNodes { - allKeys = append(allKeys, key) - } - sort.Strings(allKeys) - - t.Run("limit 0", testKeys(handler, allKeys, 0, "")) - t.Run("limit default", testKeys(handler, allKeys, mock.DefaultLimit, "")) - t.Run("limit 2x default", testKeys(handler, allKeys, 2*mock.DefaultLimit, "")) - t.Run("limit 0.5x default", testKeys(handler, allKeys, mock.DefaultLimit/2, "")) - t.Run("limit max", testKeys(handler, allKeys, mock.MaxLimit, "")) - t.Run("limit 2x max", testKeys(handler, allKeys, 2*mock.MaxLimit, "")) - t.Run("limit negative", testKeys(handler, allKeys, -10, "")) - }) - - // this subtest confirms that all keys are are listed for every node in correct order - // and that for one node different pagination options are correct - t.Run("node keys", func(t *testing.T) { - var limitCheckAddr string - - for addr, keys := range nodeKeys { - testKeys(handler, keys, 0, addr)(t) - if limitCheckAddr == "" { - limitCheckAddr = addr - } - } - testKeys(handler, nil, 0, invalidAddr)(t) - - limitCheckKeys := nodeKeys[limitCheckAddr] - t.Run("limit 0", testKeys(handler, limitCheckKeys, 0, limitCheckAddr)) - t.Run("limit default", testKeys(handler, limitCheckKeys, mock.DefaultLimit, limitCheckAddr)) - t.Run("limit 2x default", testKeys(handler, limitCheckKeys, 2*mock.DefaultLimit, limitCheckAddr)) - t.Run("limit 0.5x default", testKeys(handler, limitCheckKeys, mock.DefaultLimit/2, limitCheckAddr)) - t.Run("limit max", testKeys(handler, limitCheckKeys, mock.MaxLimit, limitCheckAddr)) - t.Run("limit 2x max", testKeys(handler, limitCheckKeys, 2*mock.MaxLimit, limitCheckAddr)) - t.Run("limit negative", testKeys(handler, limitCheckKeys, -10, limitCheckAddr)) - }) - - // this subtest confirms that all nodes are are listed in correct order with expected pagination - t.Run("nodes", func(t *testing.T) { - var allNodes []string - for addr := range nodeKeys { - allNodes = append(allNodes, addr) - } - sortCaseInsensitive(allNodes) - - t.Run("limit 0", testNodes(handler, allNodes, 0, "")) - t.Run("limit default", testNodes(handler, allNodes, mock.DefaultLimit, "")) - t.Run("limit 2x default", testNodes(handler, allNodes, 2*mock.DefaultLimit, "")) - t.Run("limit 0.5x default", testNodes(handler, allNodes, mock.DefaultLimit/2, "")) - t.Run("limit max", testNodes(handler, allNodes, mock.MaxLimit, "")) - t.Run("limit 2x max", testNodes(handler, allNodes, 2*mock.MaxLimit, "")) - t.Run("limit negative", testNodes(handler, allNodes, -10, "")) - }) - - // this subtest confirms that all nodes are are listed that contain a a particular key in correct order - // and that for one key different node pagination options are correct - t.Run("key nodes", func(t *testing.T) { - var limitCheckKey string - - for key, addrs := range keyNodes { - testNodes(handler, addrs, 0, key)(t) - if limitCheckKey == "" { - limitCheckKey = key - } - } - testNodes(handler, nil, 0, invalidKey)(t) - - limitCheckKeys := keyNodes[limitCheckKey] - t.Run("limit 0", testNodes(handler, limitCheckKeys, 0, limitCheckKey)) - t.Run("limit default", testNodes(handler, limitCheckKeys, mock.DefaultLimit, limitCheckKey)) - t.Run("limit 2x default", testNodes(handler, limitCheckKeys, 2*mock.DefaultLimit, limitCheckKey)) - t.Run("limit 0.5x default", testNodes(handler, limitCheckKeys, mock.DefaultLimit/2, limitCheckKey)) - t.Run("limit max", testNodes(handler, limitCheckKeys, mock.MaxLimit, limitCheckKey)) - t.Run("limit 2x max", testNodes(handler, limitCheckKeys, 2*mock.MaxLimit, limitCheckKey)) - t.Run("limit negative", testNodes(handler, limitCheckKeys, -10, limitCheckKey)) - }) -} - -// testsKeys returns a test function that validates wantKeys against a series of /api/keys -// HTTP responses with provided limit and node options. -func testKeys(handler http.Handler, wantKeys []string, limit int, node string) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - wantLimit := limit - if wantLimit <= 0 { - wantLimit = mock.DefaultLimit - } - if wantLimit > mock.MaxLimit { - wantLimit = mock.MaxLimit - } - wantKeysLen := len(wantKeys) - var i int - var startKey string - for { - var wantNext string - start := i * wantLimit - end := (i + 1) * wantLimit - if end < wantKeysLen { - wantNext = wantKeys[end] - } else { - end = wantKeysLen - } - testKeysResponse(t, handler, node, startKey, limit, KeysResponse{ - Keys: wantKeys[start:end], - Next: wantNext, - }) - if wantNext == "" { - break - } - startKey = wantNext - i++ - } - } -} - -// testNodes returns a test function that validates wantAddrs against a series of /api/nodes -// HTTP responses with provided limit and key options. -func testNodes(handler http.Handler, wantAddrs []string, limit int, key string) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - wantLimit := limit - if wantLimit <= 0 { - wantLimit = mock.DefaultLimit - } - if wantLimit > mock.MaxLimit { - wantLimit = mock.MaxLimit - } - wantAddrsLen := len(wantAddrs) - var i int - var startKey string - for { - var wantNext string - start := i * wantLimit - end := (i + 1) * wantLimit - if end < wantAddrsLen { - wantNext = wantAddrs[end] - } else { - end = wantAddrsLen - } - testNodesResponse(t, handler, key, startKey, limit, NodesResponse{ - Nodes: wantAddrs[start:end], - Next: wantNext, - }) - if wantNext == "" { - break - } - startKey = wantNext - i++ - } - } -} - -// testStatusResponse validates a response made on url if it matches -// the expected StatusResponse. -func testStatusResponse(t *testing.T, handler http.Handler, url string, code int) { - t.Helper() - - resp := httpGet(t, handler, url) - - if resp.StatusCode != code { - t.Errorf("got status code %v, want %v", resp.StatusCode, code) - } - if got := resp.Header.Get("Content-Type"); got != jsonContentType { - t.Errorf("got Content-Type header %q, want %q", got, jsonContentType) - } - var r StatusResponse - if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { - t.Fatal(err) - } - if r.Code != code { - t.Errorf("got response code %v, want %v", r.Code, code) - } - if r.Message != http.StatusText(code) { - t.Errorf("got response message %q, want %q", r.Message, http.StatusText(code)) - } -} - -// testKeysResponse validates response returned from handler on /api/keys -// with node, start and limit options against KeysResponse. -func testKeysResponse(t *testing.T, handler http.Handler, node, start string, limit int, want KeysResponse) { - t.Helper() - - u, err := url.Parse("/api/keys") - if err != nil { - t.Fatal(err) - } - q := u.Query() - if node != "" { - q.Set("node", node) - } - if start != "" { - q.Set("start", start) - } - if limit != 0 { - q.Set("limit", strconv.Itoa(limit)) - } - u.RawQuery = q.Encode() - - resp := httpGet(t, handler, u.String()) - - if resp.StatusCode != http.StatusOK { - t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) - } - if got := resp.Header.Get("Content-Type"); got != jsonContentType { - t.Errorf("got Content-Type header %q, want %q", got, jsonContentType) - } - var r KeysResponse - if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { - t.Fatal(err) - } - if fmt.Sprint(r.Keys) != fmt.Sprint(want.Keys) { - t.Errorf("got keys %v, want %v", r.Keys, want.Keys) - } - if r.Next != want.Next { - t.Errorf("got next %s, want %s", r.Next, want.Next) - } -} - -// testNodesResponse validates response returned from handler on /api/nodes -// with key, start and limit options against NodesResponse. -func testNodesResponse(t *testing.T, handler http.Handler, key, start string, limit int, want NodesResponse) { - t.Helper() - - u, err := url.Parse("/api/nodes") - if err != nil { - t.Fatal(err) - } - q := u.Query() - if key != "" { - q.Set("key", key) - } - if start != "" { - q.Set("start", start) - } - if limit != 0 { - q.Set("limit", strconv.Itoa(limit)) - } - u.RawQuery = q.Encode() - - resp := httpGet(t, handler, u.String()) - - if resp.StatusCode != http.StatusOK { - t.Errorf("got status code %v, want %v", resp.StatusCode, http.StatusOK) - } - if got := resp.Header.Get("Content-Type"); got != jsonContentType { - t.Errorf("got Content-Type header %q, want %q", got, jsonContentType) - } - var r NodesResponse - if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { - t.Fatal(err) - } - if fmt.Sprint(r.Nodes) != fmt.Sprint(want.Nodes) { - t.Errorf("got nodes %v, want %v", r.Nodes, want.Nodes) - } - if r.Next != want.Next { - t.Errorf("got next %s, want %s", r.Next, want.Next) - } -} - -// httpGet uses httptest recorder to provide a response on handler's url. -func httpGet(t *testing.T, handler http.Handler, url string) (r *http.Response) { - t.Helper() - - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - t.Fatal(err) - } - w := httptest.NewRecorder() - handler.ServeHTTP(w, req) - return w.Result() -} - -// sortCaseInsensitive performs a case insensitive sort on a string slice. -func sortCaseInsensitive(s []string) { - sort.Slice(s, func(i, j int) bool { - return strings.ToLower(s[i]) < strings.ToLower(s[j]) - }) -} diff --git a/swarm/storage/mock/explorer/headers_test.go b/swarm/storage/mock/explorer/headers_test.go deleted file mode 100644 index 5b8e05ffde..0000000000 --- a/swarm/storage/mock/explorer/headers_test.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package explorer - -import ( - "fmt" - "net/http" - "net/http/httptest" - "testing" - - "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" -) - -// TestHandler_CORSOrigin validates that the correct Access-Control-Allow-Origin -// header is served with various allowed origin settings. -func TestHandler_CORSOrigin(t *testing.T) { - notAllowedOrigin := "http://not-allowed-origin.com/" - - for _, tc := range []struct { - name string - origins []string - }{ - { - name: "no origin", - origins: nil, - }, - { - name: "single origin", - origins: []string{"http://localhost/"}, - }, - { - name: "multiple origins", - origins: []string{"http://localhost/", "http://ethereum.org/"}, - }, - } { - t.Run(tc.name, func(t *testing.T) { - handler := NewHandler(mem.NewGlobalStore(), tc.origins) - - origins := tc.origins - if origins == nil { - // handle the "no origin" test case - origins = []string{""} - } - - for _, origin := range origins { - t.Run(fmt.Sprintf("get %q", origin), newTestCORSOrigin(handler, origin, origin)) - t.Run(fmt.Sprintf("preflight %q", origin), newTestCORSPreflight(handler, origin, origin)) - } - - t.Run(fmt.Sprintf("get %q", notAllowedOrigin), newTestCORSOrigin(handler, notAllowedOrigin, "")) - t.Run(fmt.Sprintf("preflight %q", notAllowedOrigin), newTestCORSPreflight(handler, notAllowedOrigin, "")) - }) - } - - t.Run("wildcard", func(t *testing.T) { - handler := NewHandler(mem.NewGlobalStore(), []string{"*"}) - - for _, origin := range []string{ - "http://example.com/", - "http://ethereum.org", - "http://localhost", - } { - t.Run(fmt.Sprintf("get %q", origin), newTestCORSOrigin(handler, origin, origin)) - t.Run(fmt.Sprintf("preflight %q", origin), newTestCORSPreflight(handler, origin, origin)) - } - }) -} - -// newTestCORSOrigin returns a test function that validates if wantOrigin CORS header is -// served by the handler for a GET request. -func newTestCORSOrigin(handler http.Handler, origin, wantOrigin string) func(t *testing.T) { - return func(t *testing.T) { - req, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - req.Header.Set("Origin", origin) - - w := httptest.NewRecorder() - handler.ServeHTTP(w, req) - resp := w.Result() - - header := resp.Header.Get("Access-Control-Allow-Origin") - if header != wantOrigin { - t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, wantOrigin) - } - } -} - -// newTestCORSPreflight returns a test function that validates if wantOrigin CORS header is -// served by the handler for an OPTIONS CORS preflight request. -func newTestCORSPreflight(handler http.Handler, origin, wantOrigin string) func(t *testing.T) { - return func(t *testing.T) { - req, err := http.NewRequest(http.MethodOptions, "/", nil) - if err != nil { - t.Fatal(err) - } - req.Header.Set("Origin", origin) - req.Header.Set("Access-Control-Request-Method", "GET") - - w := httptest.NewRecorder() - handler.ServeHTTP(w, req) - resp := w.Result() - - header := resp.Header.Get("Access-Control-Allow-Origin") - if header != wantOrigin { - t.Errorf("got Access-Control-Allow-Origin header %q, want %q", header, wantOrigin) - } - } -} - -// TestHandler_noCacheHeaders validates that no cache headers are server. -func TestHandler_noCacheHeaders(t *testing.T) { - handler := NewHandler(mem.NewGlobalStore(), nil) - - for _, tc := range []struct { - url string - }{ - { - url: "/", - }, - { - url: "/api/nodes", - }, - { - url: "/api/keys", - }, - } { - req, err := http.NewRequest(http.MethodGet, tc.url, nil) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - handler.ServeHTTP(w, req) - resp := w.Result() - - for header, want := range map[string]string{ - "Cache-Control": "no-cache, no-store, must-revalidate", - "Pragma": "no-cache", - "Expires": "0", - } { - got := resp.Header.Get(header) - if got != want { - t.Errorf("got %q header %q for url %q, want %q", header, tc.url, got, want) - } - } - } -} diff --git a/swarm/storage/mock/explorer/swagger.yaml b/swarm/storage/mock/explorer/swagger.yaml deleted file mode 100644 index 2c014e927e..0000000000 --- a/swarm/storage/mock/explorer/swagger.yaml +++ /dev/null @@ -1,176 +0,0 @@ -swagger: '2.0' -info: - title: Swarm Global Store API - version: 0.1.0 -tags: - - name: Has Key - description: Checks if a Key is stored on a Node - - name: Keys - description: Lists Keys - - name: Nodes - description: Lists Node addresses - -paths: - '/api/has-key/{node}/{key}': - get: - tags: - - Has Key - summary: Checks if a Key is stored on a Node - operationId: hasKey - produces: - - application/json - - parameters: - - name: node - in: path - required: true - type: string - format: hex-endoded - description: Node address. - - - name: key - in: path - required: true - type: string - format: hex-endoded - description: Key. - - responses: - '200': - description: Key is stored on Node - schema: - $ref: '#/definitions/Status' - '404': - description: Key is not stored on Node - schema: - $ref: '#/definitions/Status' - '500': - description: Internal Server Error - schema: - $ref: '#/definitions/Status' - - '/api/keys': - get: - tags: - - Keys - summary: Lists Keys - operationId: keys - produces: - - application/json - - parameters: - - name: start - in: query - required: false - type: string - format: hex-encoded Key - description: A Key as the starting point for the returned list. It is usually a value from the returned "next" field in the Keys repsonse. - - - name: limit - in: query - required: false - type: integer - default: 100 - minimum: 1 - maximum: 1000 - description: Limits the number of Keys returned in on response. - - - name: node - in: query - required: false - type: string - format: hex-encoded Node address - description: If this parameter is provided, only Keys that are stored on this Node be returned in the response. If not, all known Keys will be returned. - - responses: - '200': - description: List of Keys - schema: - $ref: '#/definitions/Keys' - '500': - description: Internal Server Error - schema: - $ref: '#/definitions/Status' - - '/api/nodes': - get: - tags: - - Nodes - summary: Lists Node addresses - operationId: nodes - produces: - - application/json - - parameters: - - name: start - in: query - required: false - type: string - format: hex-encoded Node address - description: A Node address as the starting point for the returned list. It is usually a value from the returned "next" field in the Nodes repsonse. - - - name: limit - in: query - required: false - type: integer - default: 100 - minimum: 1 - maximum: 1000 - description: Limits the number of Node addresses returned in on response. - - - name: key - in: query - required: false - type: string - format: hex-encoded Key - description: If this parameter is provided, only addresses of Nodes that store this Key will be returned in the response. If not, all known Node addresses will be returned. - - responses: - '200': - description: List of Node addresses - schema: - $ref: '#/definitions/Nodes' - '500': - description: Internal Server Error - schema: - $ref: '#/definitions/Status' - -definitions: - - Status: - type: object - properties: - message: - type: string - description: HTTP Status Code name. - code: - type: integer - description: HTTP Status Code. - - Keys: - type: object - properties: - keys: - type: array - description: A list of Keys. - items: - type: string - format: hex-encoded Key - next: - type: string - format: hex-encoded Key - description: If present, the next Key in listing. Can be passed as "start" query parameter to continue the listing. If not present, the end of the listing is reached. - - Nodes: - type: object - properties: - nodes: - type: array - description: A list of Node addresses. - items: - type: string - format: hex-encoded Node address - next: - type: string - format: hex-encoded Node address - description: If present, the next Node address in listing. Can be passed as "start" query parameter to continue the listing. If not present, the end of the listing is reached. diff --git a/swarm/storage/mock/mem/mem.go b/swarm/storage/mock/mem/mem.go deleted file mode 100644 index 38bf098df4..0000000000 --- a/swarm/storage/mock/mem/mem.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package mem implements a mock store that keeps all chunk data in memory. -// While it can be used for testing on smaller scales, the main purpose of this -// package is to provide the simplest reference implementation of a mock store. -package mem - -import ( - "archive/tar" - "bytes" - "encoding/json" - "io" - "io/ioutil" - "sort" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage/mock" -) - -// GlobalStore stores all chunk data and also keys and node addresses relations. -// It implements mock.GlobalStore interface. -type GlobalStore struct { - // holds a slice of keys per node - nodeKeys map[common.Address][][]byte - // holds which key is stored on which nodes - keyNodes map[string][]common.Address - // all node addresses - nodes []common.Address - // all keys - keys [][]byte - // all keys data - data map[string][]byte - mu sync.RWMutex -} - -// NewGlobalStore creates a new instance of GlobalStore. -func NewGlobalStore() *GlobalStore { - return &GlobalStore{ - nodeKeys: make(map[common.Address][][]byte), - keyNodes: make(map[string][]common.Address), - nodes: make([]common.Address, 0), - keys: make([][]byte, 0), - data: make(map[string][]byte), - } -} - -// NewNodeStore returns a new instance of NodeStore that retrieves and stores -// chunk data only for a node with address addr. -func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { - return mock.NewNodeStore(addr, s) -} - -// Get returns chunk data if the chunk with key exists for node -// on address addr. -func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { - s.mu.RLock() - defer s.mu.RUnlock() - - if _, has := s.nodeKeyIndex(addr, key); !has { - return nil, mock.ErrNotFound - } - - data, ok := s.data[string(key)] - if !ok { - return nil, mock.ErrNotFound - } - return data, nil -} - -// Put saves the chunk data for node with address addr. -func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { - s.mu.Lock() - defer s.mu.Unlock() - - if i, found := s.nodeKeyIndex(addr, key); !found { - s.nodeKeys[addr] = append(s.nodeKeys[addr], nil) - copy(s.nodeKeys[addr][i+1:], s.nodeKeys[addr][i:]) - s.nodeKeys[addr][i] = key - } - - if i, found := s.keyNodeIndex(key, addr); !found { - k := string(key) - s.keyNodes[k] = append(s.keyNodes[k], addr) - copy(s.keyNodes[k][i+1:], s.keyNodes[k][i:]) - s.keyNodes[k][i] = addr - } - - if i, found := s.nodeIndex(addr); !found { - s.nodes = append(s.nodes, addr) - copy(s.nodes[i+1:], s.nodes[i:]) - s.nodes[i] = addr - } - - if i, found := s.keyIndex(key); !found { - s.keys = append(s.keys, nil) - copy(s.keys[i+1:], s.keys[i:]) - s.keys[i] = key - } - - s.data[string(key)] = data - - return nil -} - -// Delete removes the chunk data for node with address addr. -func (s *GlobalStore) Delete(addr common.Address, key []byte) error { - s.mu.Lock() - defer s.mu.Unlock() - - if i, has := s.nodeKeyIndex(addr, key); has { - s.nodeKeys[addr] = append(s.nodeKeys[addr][:i], s.nodeKeys[addr][i+1:]...) - } - - k := string(key) - if i, on := s.keyNodeIndex(key, addr); on { - s.keyNodes[k] = append(s.keyNodes[k][:i], s.keyNodes[k][i+1:]...) - } - - if len(s.nodeKeys[addr]) == 0 { - if i, found := s.nodeIndex(addr); found { - s.nodes = append(s.nodes[:i], s.nodes[i+1:]...) - } - } - - if len(s.keyNodes[k]) == 0 { - if i, found := s.keyIndex(key); found { - s.keys = append(s.keys[:i], s.keys[i+1:]...) - } - } - return nil -} - -// HasKey returns whether a node with addr contains the key. -func (s *GlobalStore) HasKey(addr common.Address, key []byte) (yes bool) { - s.mu.RLock() - defer s.mu.RUnlock() - - _, yes = s.nodeKeyIndex(addr, key) - return yes -} - -// keyIndex returns the index of a key in keys slice. -func (s *GlobalStore) keyIndex(key []byte) (index int, found bool) { - l := len(s.keys) - index = sort.Search(l, func(i int) bool { - return bytes.Compare(s.keys[i], key) >= 0 - }) - found = index < l && bytes.Equal(s.keys[index], key) - return index, found -} - -// nodeIndex returns the index of a node address in nodes slice. -func (s *GlobalStore) nodeIndex(addr common.Address) (index int, found bool) { - l := len(s.nodes) - index = sort.Search(l, func(i int) bool { - return bytes.Compare(s.nodes[i][:], addr[:]) >= 0 - }) - found = index < l && bytes.Equal(s.nodes[index][:], addr[:]) - return index, found -} - -// nodeKeyIndex returns the index of a key in nodeKeys slice. -func (s *GlobalStore) nodeKeyIndex(addr common.Address, key []byte) (index int, found bool) { - l := len(s.nodeKeys[addr]) - index = sort.Search(l, func(i int) bool { - return bytes.Compare(s.nodeKeys[addr][i], key) >= 0 - }) - found = index < l && bytes.Equal(s.nodeKeys[addr][index], key) - return index, found -} - -// keyNodeIndex returns the index of a node address in keyNodes slice. -func (s *GlobalStore) keyNodeIndex(key []byte, addr common.Address) (index int, found bool) { - k := string(key) - l := len(s.keyNodes[k]) - index = sort.Search(l, func(i int) bool { - return bytes.Compare(s.keyNodes[k][i][:], addr[:]) >= 0 - }) - found = index < l && s.keyNodes[k][index] == addr - return index, found -} - -// Keys returns a paginated list of keys on all nodes. -func (s *GlobalStore) Keys(startKey []byte, limit int) (keys mock.Keys, err error) { - s.mu.RLock() - defer s.mu.RUnlock() - - var i int - if startKey != nil { - i, _ = s.keyIndex(startKey) - } - total := len(s.keys) - max := maxIndex(i, limit, total) - keys.Keys = make([][]byte, 0, max-i) - for ; i < max; i++ { - keys.Keys = append(keys.Keys, append([]byte(nil), s.keys[i]...)) - } - if total > max { - keys.Next = s.keys[max] - } - return keys, nil -} - -// Nodes returns a paginated list of all known nodes. -func (s *GlobalStore) Nodes(startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { - s.mu.RLock() - defer s.mu.RUnlock() - - var i int - if startAddr != nil { - i, _ = s.nodeIndex(*startAddr) - } - total := len(s.nodes) - max := maxIndex(i, limit, total) - nodes.Addrs = make([]common.Address, 0, max-i) - for ; i < max; i++ { - nodes.Addrs = append(nodes.Addrs, s.nodes[i]) - } - if total > max { - nodes.Next = &s.nodes[max] - } - return nodes, nil -} - -// NodeKeys returns a paginated list of keys on a node with provided address. -func (s *GlobalStore) NodeKeys(addr common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { - s.mu.RLock() - defer s.mu.RUnlock() - - var i int - if startKey != nil { - i, _ = s.nodeKeyIndex(addr, startKey) - } - total := len(s.nodeKeys[addr]) - max := maxIndex(i, limit, total) - keys.Keys = make([][]byte, 0, max-i) - for ; i < max; i++ { - keys.Keys = append(keys.Keys, append([]byte(nil), s.nodeKeys[addr][i]...)) - } - if total > max { - keys.Next = s.nodeKeys[addr][max] - } - return keys, nil -} - -// KeyNodes returns a paginated list of nodes that contain a particular key. -func (s *GlobalStore) KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { - s.mu.RLock() - defer s.mu.RUnlock() - - var i int - if startAddr != nil { - i, _ = s.keyNodeIndex(key, *startAddr) - } - total := len(s.keyNodes[string(key)]) - max := maxIndex(i, limit, total) - nodes.Addrs = make([]common.Address, 0, max-i) - for ; i < max; i++ { - nodes.Addrs = append(nodes.Addrs, s.keyNodes[string(key)][i]) - } - if total > max { - nodes.Next = &s.keyNodes[string(key)][max] - } - return nodes, nil -} - -// maxIndex returns the end index for one page listing -// based on the start index, limit and total number of elements. -func maxIndex(start, limit, total int) (max int) { - if limit <= 0 { - limit = mock.DefaultLimit - } - if limit > mock.MaxLimit { - limit = mock.MaxLimit - } - max = total - if start+limit < max { - max = start + limit - } - return max -} - -// Import reads tar archive from a reader that contains exported chunk data. -// It returns the number of chunks imported and an error. -func (s *GlobalStore) Import(r io.Reader) (n int, err error) { - s.mu.Lock() - defer s.mu.Unlock() - - tr := tar.NewReader(r) - - for { - hdr, err := tr.Next() - if err != nil { - if err == io.EOF { - break - } - return n, err - } - - data, err := ioutil.ReadAll(tr) - if err != nil { - return n, err - } - - var c mock.ExportedChunk - if err = json.Unmarshal(data, &c); err != nil { - return n, err - } - - key := common.Hex2Bytes(hdr.Name) - s.keyNodes[string(key)] = c.Addrs - for _, addr := range c.Addrs { - if i, has := s.nodeKeyIndex(addr, key); !has { - s.nodeKeys[addr] = append(s.nodeKeys[addr], nil) - copy(s.nodeKeys[addr][i+1:], s.nodeKeys[addr][i:]) - s.nodeKeys[addr][i] = key - } - if i, found := s.nodeIndex(addr); !found { - s.nodes = append(s.nodes, addr) - copy(s.nodes[i+1:], s.nodes[i:]) - s.nodes[i] = addr - } - } - if i, found := s.keyIndex(key); !found { - s.keys = append(s.keys, nil) - copy(s.keys[i+1:], s.keys[i:]) - s.keys[i] = key - } - s.data[string(key)] = c.Data - n++ - } - return n, err -} - -// Export writes to a writer a tar archive with all chunk data from -// the store. It returns the number of chunks exported and an error. -func (s *GlobalStore) Export(w io.Writer) (n int, err error) { - s.mu.RLock() - defer s.mu.RUnlock() - - tw := tar.NewWriter(w) - defer tw.Close() - - buf := bytes.NewBuffer(make([]byte, 0, 1024)) - encoder := json.NewEncoder(buf) - for key, addrs := range s.keyNodes { - buf.Reset() - if err = encoder.Encode(mock.ExportedChunk{ - Addrs: addrs, - Data: s.data[key], - }); err != nil { - return n, err - } - - data := buf.Bytes() - hdr := &tar.Header{ - Name: common.Bytes2Hex([]byte(key)), - Mode: 0644, - Size: int64(len(data)), - } - if err := tw.WriteHeader(hdr); err != nil { - return n, err - } - if _, err := tw.Write(data); err != nil { - return n, err - } - n++ - } - return n, err -} diff --git a/swarm/storage/mock/mem/mem_test.go b/swarm/storage/mock/mem/mem_test.go deleted file mode 100644 index d39aaef454..0000000000 --- a/swarm/storage/mock/mem/mem_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package mem - -import ( - "testing" - - "github.com/ethereum/go-ethereum/swarm/storage/mock/test" -) - -// TestGlobalStore is running test for a GlobalStore -// using test.MockStore function. -func TestGlobalStore(t *testing.T) { - test.MockStore(t, NewGlobalStore(), 100) -} - -// TestGlobalStoreListings is running test for a GlobalStore -// using test.MockStoreListings function. -func TestGlobalStoreListings(t *testing.T) { - test.MockStoreListings(t, NewGlobalStore(), 1000) -} - -// TestImportExport is running tests for importing and -// exporting data between two GlobalStores -// using test.ImportExport function. -func TestImportExport(t *testing.T) { - test.ImportExport(t, NewGlobalStore(), NewGlobalStore(), 100) -} diff --git a/swarm/storage/mock/mock.go b/swarm/storage/mock/mock.go deleted file mode 100644 index 586112a98b..0000000000 --- a/swarm/storage/mock/mock.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package mock defines types that are used by different implementations -// of mock storages. -// -// Implementations of mock storages are located in directories -// under this package: -// -// - db - LevelDB backend -// - mem - in memory map backend -// - rpc - RPC client that can connect to other backends -// -// Mock storages can implement Importer and Exporter interfaces -// for importing and exporting all chunk data that they contain. -// The exported file is a tar archive with all files named by -// hexadecimal representations of chunk keys and with content -// with JSON-encoded ExportedChunk structure. Exported format -// should be preserved across all mock store implementations. -package mock - -import ( - "errors" - "io" - - "github.com/ethereum/go-ethereum/common" -) - -const ( - // DefaultLimit should be used as default limit for - // Keys, Nodes, NodeKeys and KeyNodes GlobarStorer - // methids implementations. - DefaultLimit = 100 - // MaxLimit should be used as the maximal returned number - // of items for Keys, Nodes, NodeKeys and KeyNodes GlobarStorer - // methids implementations, regardless of provided limit. - MaxLimit = 1000 -) - -// ErrNotFound indicates that the chunk is not found. -var ErrNotFound = errors.New("not found") - -// NodeStore holds the node address and a reference to the GlobalStore -// in order to access and store chunk data only for one node. -type NodeStore struct { - store GlobalStorer - addr common.Address -} - -// NewNodeStore creates a new instance of NodeStore that keeps -// chunk data using GlobalStorer with a provided address. -func NewNodeStore(addr common.Address, store GlobalStorer) *NodeStore { - return &NodeStore{ - store: store, - addr: addr, - } -} - -// Get returns chunk data for a key for a node that has the address -// provided on NodeStore initialization. -func (n *NodeStore) Get(key []byte) (data []byte, err error) { - return n.store.Get(n.addr, key) -} - -// Put saves chunk data for a key for a node that has the address -// provided on NodeStore initialization. -func (n *NodeStore) Put(key []byte, data []byte) error { - return n.store.Put(n.addr, key, data) -} - -// Delete removes chunk data for a key for a node that has the address -// provided on NodeStore initialization. -func (n *NodeStore) Delete(key []byte) error { - return n.store.Delete(n.addr, key) -} - -func (n *NodeStore) Keys(startKey []byte, limit int) (keys Keys, err error) { - return n.store.NodeKeys(n.addr, startKey, limit) -} - -// GlobalStorer defines methods for mock db store -// that stores chunk data for all swarm nodes. -// It is used in tests to construct mock NodeStores -// for swarm nodes and to track and validate chunks. -type GlobalStorer interface { - Get(addr common.Address, key []byte) (data []byte, err error) - Put(addr common.Address, key []byte, data []byte) error - Delete(addr common.Address, key []byte) error - HasKey(addr common.Address, key []byte) bool - Keys(startKey []byte, limit int) (keys Keys, err error) - Nodes(startAddr *common.Address, limit int) (nodes Nodes, err error) - NodeKeys(addr common.Address, startKey []byte, limit int) (keys Keys, err error) - KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes Nodes, err error) - // NewNodeStore creates an instance of NodeStore - // to be used by a single swarm node with - // address addr. - NewNodeStore(addr common.Address) *NodeStore -} - -// Keys are returned results by Keys and NodeKeys GlobalStorer methods. -type Keys struct { - Keys [][]byte - Next []byte -} - -// Nodes are returned results by Nodes and KeyNodes GlobalStorer methods. -type Nodes struct { - Addrs []common.Address - Next *common.Address -} - -// Importer defines method for importing mock store data -// from an exported tar archive. -type Importer interface { - Import(r io.Reader) (n int, err error) -} - -// Exporter defines method for exporting mock store data -// to a tar archive. -type Exporter interface { - Export(w io.Writer) (n int, err error) -} - -// ExportedChunk is the structure that is saved in tar archive for -// each chunk as JSON-encoded bytes. -type ExportedChunk struct { - Data []byte `json:"d"` - Addrs []common.Address `json:"a"` -} diff --git a/swarm/storage/mock/rpc/rpc.go b/swarm/storage/mock/rpc/rpc.go deleted file mode 100644 index 8150ccff13..0000000000 --- a/swarm/storage/mock/rpc/rpc.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package rpc implements an RPC client that connect to a centralized mock store. -// Centralazied mock store can be any other mock store implementation that is -// registered to Ethereum RPC server under mockStore name. Methods that defines -// mock.GlobalStore are the same that are used by RPC. Example: -// -// server := rpc.NewServer() -// server.RegisterName("mockStore", mem.NewGlobalStore()) -package rpc - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/storage/mock" -) - -// GlobalStore is rpc.Client that connects to a centralized mock store. -// Closing GlobalStore instance is required to release RPC client resources. -type GlobalStore struct { - client *rpc.Client -} - -// NewGlobalStore creates a new instance of GlobalStore. -func NewGlobalStore(client *rpc.Client) *GlobalStore { - return &GlobalStore{ - client: client, - } -} - -// Close closes RPC client. -func (s *GlobalStore) Close() error { - s.client.Close() - return nil -} - -// NewNodeStore returns a new instance of NodeStore that retrieves and stores -// chunk data only for a node with address addr. -func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { - return mock.NewNodeStore(addr, s) -} - -// Get calls a Get method to RPC server. -func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { - err = s.client.Call(&data, "mockStore_get", addr, key) - if err != nil && err.Error() == "not found" { - // pass the mock package value of error instead an rpc error - return data, mock.ErrNotFound - } - return data, err -} - -// Put calls a Put method to RPC server. -func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { - err := s.client.Call(nil, "mockStore_put", addr, key, data) - return err -} - -// Delete calls a Delete method to RPC server. -func (s *GlobalStore) Delete(addr common.Address, key []byte) error { - err := s.client.Call(nil, "mockStore_delete", addr, key) - return err -} - -// HasKey calls a HasKey method to RPC server. -func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { - var has bool - if err := s.client.Call(&has, "mockStore_hasKey", addr, key); err != nil { - log.Error(fmt.Sprintf("mock store HasKey: addr %s, key %064x: %v", addr, key, err)) - return false - } - return has -} - -// Keys returns a paginated list of keys on all nodes. -func (s *GlobalStore) Keys(startKey []byte, limit int) (keys mock.Keys, err error) { - err = s.client.Call(&keys, "mockStore_keys", startKey, limit) - return keys, err -} - -// Nodes returns a paginated list of all known nodes. -func (s *GlobalStore) Nodes(startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { - err = s.client.Call(&nodes, "mockStore_nodes", startAddr, limit) - return nodes, err -} - -// NodeKeys returns a paginated list of keys on a node with provided address. -func (s *GlobalStore) NodeKeys(addr common.Address, startKey []byte, limit int) (keys mock.Keys, err error) { - err = s.client.Call(&keys, "mockStore_nodeKeys", addr, startKey, limit) - return keys, err -} - -// KeyNodes returns a paginated list of nodes that contain a particular key. -func (s *GlobalStore) KeyNodes(key []byte, startAddr *common.Address, limit int) (nodes mock.Nodes, err error) { - err = s.client.Call(&nodes, "mockStore_keyNodes", key, startAddr, limit) - return nodes, err -} diff --git a/swarm/storage/mock/rpc/rpc_test.go b/swarm/storage/mock/rpc/rpc_test.go deleted file mode 100644 index 6c46523558..0000000000 --- a/swarm/storage/mock/rpc/rpc_test.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "testing" - - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" - "github.com/ethereum/go-ethereum/swarm/storage/mock/test" -) - -// TestDBStore is running test for a GlobalStore -// using test.MockStore function. -func TestRPCStore(t *testing.T) { - store, cleanup := newTestStore(t) - defer cleanup() - - test.MockStore(t, store, 30) -} - -// TestRPCStoreListings is running test for a GlobalStore -// using test.MockStoreListings function. -func TestRPCStoreListings(t *testing.T) { - store, cleanup := newTestStore(t) - defer cleanup() - - test.MockStoreListings(t, store, 1000) -} - -// newTestStore creates a temporary GlobalStore -// that will be closed when returned cleanup function -// is called. -func newTestStore(t *testing.T) (s *GlobalStore, cleanup func()) { - t.Helper() - - serverStore := mem.NewGlobalStore() - - server := rpc.NewServer() - if err := server.RegisterName("mockStore", serverStore); err != nil { - t.Fatal(err) - } - - store := NewGlobalStore(rpc.DialInProc(server)) - return store, func() { - if err := store.Close(); err != nil { - t.Error(err) - } - } -} diff --git a/swarm/storage/mock/test/test.go b/swarm/storage/mock/test/test.go deleted file mode 100644 index cc837f0b77..0000000000 --- a/swarm/storage/mock/test/test.go +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package test provides functions that are used for testing -// GlobalStorer implementations. -package test - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" - "strconv" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/mock" -) - -// MockStore creates NodeStore instances from provided GlobalStorer, -// each one with a unique address, stores different chunks on them -// and checks if they are retrievable or not on all nodes. -// Attribute n defines the number of NodeStores that will be created. -func MockStore(t *testing.T, globalStore mock.GlobalStorer, n int) { - t.Run("GlobalStore", func(t *testing.T) { - addrs := make([]common.Address, n) - for i := 0; i < n; i++ { - addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) - } - - for i, addr := range addrs { - chunkAddr := storage.Address(append(addr[:], []byte(strconv.FormatInt(int64(i)+1, 16))...)) - data := []byte(strconv.FormatInt(int64(i)+1, 16)) - data = append(data, make([]byte, 4096-len(data))...) - globalStore.Put(addr, chunkAddr, data) - - for _, cAddr := range addrs { - cData, err := globalStore.Get(cAddr, chunkAddr) - if cAddr == addr { - if err != nil { - t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err) - } - if !bytes.Equal(data, cData) { - t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData) - } - if !globalStore.HasKey(cAddr, chunkAddr) { - t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex()) - } - } else { - if err != mock.ErrNotFound { - t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err) - } - if len(cData) > 0 { - t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData) - } - if globalStore.HasKey(cAddr, chunkAddr) { - t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex()) - } - } - } - } - t.Run("delete", func(t *testing.T) { - chunkAddr := storage.Address([]byte("1234567890abcd")) - for _, addr := range addrs { - err := globalStore.Put(addr, chunkAddr, []byte("data")) - if err != nil { - t.Fatalf("put data to store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) - } - } - firstNodeAddr := addrs[0] - if err := globalStore.Delete(firstNodeAddr, chunkAddr); err != nil { - t.Fatalf("delete from store %s key %s: %v", firstNodeAddr.Hex(), chunkAddr.Hex(), err) - } - for i, addr := range addrs { - _, err := globalStore.Get(addr, chunkAddr) - if i == 0 { - if err != mock.ErrNotFound { - t.Errorf("get data from store %s key %s: expected mock.ErrNotFound error, got %v", addr.Hex(), chunkAddr.Hex(), err) - } - } else { - if err != nil { - t.Errorf("get data from store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) - } - } - } - }) - }) - - t.Run("NodeStore", func(t *testing.T) { - nodes := make(map[common.Address]*mock.NodeStore) - for i := 0; i < n; i++ { - addr := common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) - nodes[addr] = globalStore.NewNodeStore(addr) - } - - i := 0 - for addr, store := range nodes { - i++ - chunkAddr := storage.Address(append(addr[:], []byte(fmt.Sprintf("%x", i))...)) - data := []byte(strconv.FormatInt(int64(i)+1, 16)) - data = append(data, make([]byte, 4096-len(data))...) - store.Put(chunkAddr, data) - - for cAddr, cStore := range nodes { - cData, err := cStore.Get(chunkAddr) - if cAddr == addr { - if err != nil { - t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err) - } - if !bytes.Equal(data, cData) { - t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData) - } - if !globalStore.HasKey(cAddr, chunkAddr) { - t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex()) - } - } else { - if err != mock.ErrNotFound { - t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err) - } - if len(cData) > 0 { - t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData) - } - if globalStore.HasKey(cAddr, chunkAddr) { - t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex()) - } - } - } - } - t.Run("delete", func(t *testing.T) { - chunkAddr := storage.Address([]byte("1234567890abcd")) - var chosenStore *mock.NodeStore - for addr, store := range nodes { - if chosenStore == nil { - chosenStore = store - } - err := store.Put(chunkAddr, []byte("data")) - if err != nil { - t.Fatalf("put data to store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) - } - } - if err := chosenStore.Delete(chunkAddr); err != nil { - t.Fatalf("delete key %s: %v", chunkAddr.Hex(), err) - } - for addr, store := range nodes { - _, err := store.Get(chunkAddr) - if store == chosenStore { - if err != mock.ErrNotFound { - t.Errorf("get data from store %s key %s: expected mock.ErrNotFound error, got %v", addr.Hex(), chunkAddr.Hex(), err) - } - } else { - if err != nil { - t.Errorf("get data from store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err) - } - } - } - }) - }) -} - -// MockStoreListings tests global store methods Keys, Nodes, NodeKeys and KeyNodes. -// It uses a provided globalstore to put chunks for n number of node addresses -// and to validate that methods are returning the right responses. -func MockStoreListings(t *testing.T, globalStore mock.GlobalStorer, n int) { - addrs := make([]common.Address, n) - for i := 0; i < n; i++ { - addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) - } - type chunk struct { - key []byte - data []byte - } - const chunksPerNode = 5 - keys := make([][]byte, n*chunksPerNode) - for i := 0; i < n*chunksPerNode; i++ { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(i)) - keys[i] = b - } - - // keep track of keys on every node - nodeKeys := make(map[common.Address][][]byte) - // keep track of nodes that store particular key - keyNodes := make(map[string][]common.Address) - for i := 0; i < chunksPerNode; i++ { - // put chunks for every address - for j := 0; j < n; j++ { - addr := addrs[j] - key := keys[(i*n)+j] - err := globalStore.Put(addr, key, []byte("data")) - if err != nil { - t.Fatal(err) - } - nodeKeys[addr] = append(nodeKeys[addr], key) - keyNodes[string(key)] = append(keyNodes[string(key)], addr) - } - - // test Keys method - var startKey []byte - var gotKeys [][]byte - for { - keys, err := globalStore.Keys(startKey, 0) - if err != nil { - t.Fatal(err) - } - gotKeys = append(gotKeys, keys.Keys...) - if keys.Next == nil { - break - } - startKey = keys.Next - } - wantKeys := keys[:(i+1)*n] - if fmt.Sprint(gotKeys) != fmt.Sprint(wantKeys) { - t.Fatalf("got #%v keys %v, want %v", i+1, gotKeys, wantKeys) - } - - // test Nodes method - var startNode *common.Address - var gotNodes []common.Address - for { - nodes, err := globalStore.Nodes(startNode, 0) - if err != nil { - t.Fatal(err) - } - gotNodes = append(gotNodes, nodes.Addrs...) - if nodes.Next == nil { - break - } - startNode = nodes.Next - } - wantNodes := addrs - if fmt.Sprint(gotNodes) != fmt.Sprint(wantNodes) { - t.Fatalf("got #%v nodes %v, want %v", i+1, gotNodes, wantNodes) - } - - // test NodeKeys method - for addr, wantKeys := range nodeKeys { - var startKey []byte - var gotKeys [][]byte - for { - keys, err := globalStore.NodeKeys(addr, startKey, 0) - if err != nil { - t.Fatal(err) - } - gotKeys = append(gotKeys, keys.Keys...) - if keys.Next == nil { - break - } - startKey = keys.Next - } - if fmt.Sprint(gotKeys) != fmt.Sprint(wantKeys) { - t.Fatalf("got #%v %s node keys %v, want %v", i+1, addr.Hex(), gotKeys, wantKeys) - } - } - - // test KeyNodes method - for key, wantNodes := range keyNodes { - var startNode *common.Address - var gotNodes []common.Address - for { - nodes, err := globalStore.KeyNodes([]byte(key), startNode, 0) - if err != nil { - t.Fatal(err) - } - gotNodes = append(gotNodes, nodes.Addrs...) - if nodes.Next == nil { - break - } - startNode = nodes.Next - } - if fmt.Sprint(gotNodes) != fmt.Sprint(wantNodes) { - t.Fatalf("got #%v %x key nodes %v, want %v", i+1, []byte(key), gotNodes, wantNodes) - } - } - } -} - -// ImportExport saves chunks to the outStore, exports them to the tar archive, -// imports tar archive to the inStore and checks if all chunks are imported correctly. -func ImportExport(t *testing.T, outStore, inStore mock.GlobalStorer, n int) { - exporter, ok := outStore.(mock.Exporter) - if !ok { - t.Fatal("outStore does not implement mock.Exporter") - } - importer, ok := inStore.(mock.Importer) - if !ok { - t.Fatal("inStore does not implement mock.Importer") - } - addrs := make([]common.Address, n) - for i := 0; i < n; i++ { - addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16)) - } - - for i, addr := range addrs { - chunkAddr := storage.Address(append(addr[:], []byte(strconv.FormatInt(int64(i)+1, 16))...)) - data := []byte(strconv.FormatInt(int64(i)+1, 16)) - data = append(data, make([]byte, 4096-len(data))...) - outStore.Put(addr, chunkAddr, data) - } - - r, w := io.Pipe() - defer r.Close() - - exportErrChan := make(chan error) - go func() { - defer w.Close() - - _, err := exporter.Export(w) - exportErrChan <- err - }() - - if _, err := importer.Import(r); err != nil { - t.Fatalf("import: %v", err) - } - - if err := <-exportErrChan; err != nil { - t.Fatalf("export: %v", err) - } - - for i, addr := range addrs { - chunkAddr := storage.Address(append(addr[:], []byte(strconv.FormatInt(int64(i)+1, 16))...)) - data := []byte(strconv.FormatInt(int64(i)+1, 16)) - data = append(data, make([]byte, 4096-len(data))...) - for _, cAddr := range addrs { - cData, err := inStore.Get(cAddr, chunkAddr) - if cAddr == addr { - if err != nil { - t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err) - } - if !bytes.Equal(data, cData) { - t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData) - } - if !inStore.HasKey(cAddr, chunkAddr) { - t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex()) - } - } else { - if err != mock.ErrNotFound { - t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err) - } - if len(cData) > 0 { - t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData) - } - if inStore.HasKey(cAddr, chunkAddr) { - t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex()) - } - } - } - } -} diff --git a/swarm/storage/netstore.go b/swarm/storage/netstore.go deleted file mode 100644 index b675384ce7..0000000000 --- a/swarm/storage/netstore.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "context" - "encoding/hex" - "fmt" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/spancontext" - "github.com/opentracing/opentracing-go" - olog "github.com/opentracing/opentracing-go/log" - "github.com/syndtr/goleveldb/leveldb" - - lru "github.com/hashicorp/golang-lru" -) - -type ( - NewNetFetcherFunc func(ctx context.Context, addr Address, peers *sync.Map) NetFetcher -) - -type NetFetcher interface { - Request(hopCount uint8) - Offer(source *enode.ID) -} - -// NetStore is an extension of local storage -// it implements the ChunkStore interface -// on request it initiates remote cloud retrieval using a fetcher -// fetchers are unique to a chunk and are stored in fetchers LRU memory cache -// fetchFuncFactory is a factory object to create a fetch function for a specific chunk address -type NetStore struct { - chunk.Store - mu sync.Mutex - fetchers *lru.Cache - NewNetFetcherFunc NewNetFetcherFunc - closeC chan struct{} -} - -var fetcherTimeout = 2 * time.Minute // timeout to cancel the fetcher even if requests are coming in - -// NewNetStore creates a new NetStore object using the given local store. newFetchFunc is a -// constructor function that can create a fetch function for a specific chunk address. -func NewNetStore(store chunk.Store, nnf NewNetFetcherFunc) (*NetStore, error) { - fetchers, err := lru.New(defaultChunkRequestsCacheCapacity) - if err != nil { - return nil, err - } - return &NetStore{ - Store: store, - fetchers: fetchers, - NewNetFetcherFunc: nnf, - closeC: make(chan struct{}), - }, nil -} - -// Put stores a chunk in localstore, and delivers to all requestor peers using the fetcher stored in -// the fetchers cache -func (n *NetStore) Put(ctx context.Context, mode chunk.ModePut, ch Chunk) (bool, error) { - n.mu.Lock() - defer n.mu.Unlock() - - // put to the chunk to the store, there should be no error - exists, err := n.Store.Put(ctx, mode, ch) - if err != nil { - return exists, err - } - - // if chunk is now put in the store, check if there was an active fetcher and call deliver on it - // (this delivers the chunk to requestors via the fetcher) - log.Trace("n.getFetcher", "ref", ch.Address()) - if f := n.getFetcher(ch.Address()); f != nil { - log.Trace("n.getFetcher deliver", "ref", ch.Address()) - f.deliver(ctx, ch) - } - return exists, nil -} - -// Get retrieves the chunk from the NetStore DPA synchronously. -// It calls NetStore.get, and if the chunk is not in local Storage -// it calls fetch with the request, which blocks until the chunk -// arrived or context is done -func (n *NetStore) Get(rctx context.Context, mode chunk.ModeGet, ref Address) (Chunk, error) { - chunk, fetch, err := n.get(rctx, mode, ref) - if err != nil { - return nil, err - } - if chunk != nil { - // this is not measuring how long it takes to get the chunk for the localstore, but - // rather just adding a span for clarity when inspecting traces in Jaeger, in order - // to make it easier to reason which is the node that actually delivered a chunk. - _, sp := spancontext.StartSpan( - rctx, - "localstore.get") - defer sp.Finish() - - return chunk, nil - } - return fetch(rctx) -} - -// FetchFunc returns nil if the store contains the given address. Otherwise it returns a wait function, -// which returns after the chunk is available or the context is done -func (n *NetStore) FetchFunc(ctx context.Context, ref Address) func(context.Context) error { - chunk, fetch, _ := n.get(ctx, chunk.ModeGetRequest, ref) - if chunk != nil { - return nil - } - return func(ctx context.Context) error { - _, err := fetch(ctx) - return err - } -} - -// Close chunk store -func (n *NetStore) Close() (err error) { - close(n.closeC) - - wg := sync.WaitGroup{} - for _, key := range n.fetchers.Keys() { - if f, ok := n.fetchers.Get(key); ok { - if fetch, ok := f.(*fetcher); ok { - wg.Add(1) - go func(fetch *fetcher) { - defer wg.Done() - fetch.cancel() - - select { - case <-fetch.deliveredC: - case <-fetch.cancelledC: - } - }(fetch) - } - } - } - wg.Wait() - - return n.Store.Close() -} - -// get attempts at retrieving the chunk from LocalStore -// If it is not found then using getOrCreateFetcher: -// 1. Either there is already a fetcher to retrieve it -// 2. A new fetcher is created and saved in the fetchers cache -// From here on, all Get will hit on this fetcher until the chunk is delivered -// or all fetcher contexts are done. -// It returns a chunk, a fetcher function and an error -// If chunk is nil, the returned fetch function needs to be called with a context to return the chunk. -func (n *NetStore) get(ctx context.Context, mode chunk.ModeGet, ref Address) (Chunk, func(context.Context) (Chunk, error), error) { - n.mu.Lock() - defer n.mu.Unlock() - - chunk, err := n.Store.Get(ctx, mode, ref) - if err != nil { - // TODO: Fix comparison - we should be comparing against leveldb.ErrNotFound, this error should be wrapped. - if err != ErrChunkNotFound && err != leveldb.ErrNotFound { - log.Debug("Received error from LocalStore other than ErrNotFound", "err", err) - } - // The chunk is not available in the LocalStore, let's get the fetcher for it, or create a new one - // if it doesn't exist yet - f := n.getOrCreateFetcher(ctx, ref) - // If the caller needs the chunk, it has to use the returned fetch function to get it - return nil, f.Fetch, nil - } - - return chunk, nil, nil -} - -// getOrCreateFetcher attempts at retrieving an existing fetchers -// if none exists, creates one and saves it in the fetchers cache -// caller must hold the lock -func (n *NetStore) getOrCreateFetcher(ctx context.Context, ref Address) *fetcher { - if f := n.getFetcher(ref); f != nil { - return f - } - - // no fetcher for the given address, we have to create a new one - key := hex.EncodeToString(ref) - // create the context during which fetching is kept alive - cctx, cancel := context.WithTimeout(ctx, fetcherTimeout) - // destroy is called when all requests finish - destroy := func() { - // remove fetcher from fetchers - n.fetchers.Remove(key) - // stop fetcher by cancelling context called when - // all requests cancelled/timedout or chunk is delivered - cancel() - } - // peers always stores all the peers which have an active request for the chunk. It is shared - // between fetcher and the NewFetchFunc function. It is needed by the NewFetchFunc because - // the peers which requested the chunk should not be requested to deliver it. - peers := &sync.Map{} - - cctx, sp := spancontext.StartSpan( - cctx, - "netstore.fetcher", - ) - - sp.LogFields(olog.String("ref", ref.String())) - fetcher := newFetcher(sp, ref, n.NewNetFetcherFunc(cctx, ref, peers), destroy, peers, n.closeC) - n.fetchers.Add(key, fetcher) - - return fetcher -} - -// getFetcher retrieves the fetcher for the given address from the fetchers cache if it exists, -// otherwise it returns nil -func (n *NetStore) getFetcher(ref Address) *fetcher { - key := hex.EncodeToString(ref) - f, ok := n.fetchers.Get(key) - if ok { - return f.(*fetcher) - } - return nil -} - -// RequestsCacheLen returns the current number of outgoing requests stored in the cache -func (n *NetStore) RequestsCacheLen() int { - return n.fetchers.Len() -} - -// One fetcher object is responsible to fetch one chunk for one address, and keep track of all the -// peers who have requested it and did not receive it yet. -type fetcher struct { - addr Address // address of chunk - chunk Chunk // fetcher can set the chunk on the fetcher - deliveredC chan struct{} // chan signalling chunk delivery to requests - cancelledC chan struct{} // chan signalling the fetcher has been cancelled (removed from fetchers in NetStore) - netFetcher NetFetcher // remote fetch function to be called with a request source taken from the context - cancel func() // cleanup function for the remote fetcher to call when all upstream contexts are called - peers *sync.Map // the peers which asked for the chunk - requestCnt int32 // number of requests on this chunk. If all the requests are done (delivered or context is done) the cancel function is called - deliverOnce *sync.Once // guarantees that we only close deliveredC once - span opentracing.Span // measure retrieve time per chunk -} - -// newFetcher creates a new fetcher object for the fiven addr. fetch is the function which actually -// does the retrieval (in non-test cases this is coming from the network package). cancel function is -// called either -// 1. when the chunk has been fetched all peers have been either notified or their context has been done -// 2. the chunk has not been fetched but all context from all the requests has been done -// The peers map stores all the peers which have requested chunk. -func newFetcher(span opentracing.Span, addr Address, nf NetFetcher, cancel func(), peers *sync.Map, closeC chan struct{}) *fetcher { - cancelOnce := &sync.Once{} // cancel should only be called once - return &fetcher{ - addr: addr, - deliveredC: make(chan struct{}), - deliverOnce: &sync.Once{}, - cancelledC: closeC, - netFetcher: nf, - cancel: func() { - cancelOnce.Do(func() { - cancel() - }) - }, - peers: peers, - span: span, - } -} - -// Fetch fetches the chunk synchronously, it is called by NetStore.Get is the chunk is not available -// locally. -func (f *fetcher) Fetch(rctx context.Context) (Chunk, error) { - atomic.AddInt32(&f.requestCnt, 1) - defer func() { - // if all the requests are done the fetcher can be cancelled - if atomic.AddInt32(&f.requestCnt, -1) == 0 { - f.cancel() - } - f.span.Finish() - }() - - // The peer asking for the chunk. Store in the shared peers map, but delete after the request - // has been delivered - peer := rctx.Value("peer") - if peer != nil { - f.peers.Store(peer, time.Now()) - defer f.peers.Delete(peer) - } - - // If there is a source in the context then it is an offer, otherwise a request - sourceIF := rctx.Value("source") - - hopCount, _ := rctx.Value("hopcount").(uint8) - - if sourceIF != nil { - var source enode.ID - if err := source.UnmarshalText([]byte(sourceIF.(string))); err != nil { - return nil, err - } - f.netFetcher.Offer(&source) - } else { - f.netFetcher.Request(hopCount) - } - - // wait until either the chunk is delivered or the context is done - select { - case <-rctx.Done(): - return nil, rctx.Err() - case <-f.deliveredC: - return f.chunk, nil - case <-f.cancelledC: - return nil, fmt.Errorf("fetcher cancelled") - } -} - -// deliver is called by NetStore.Put to notify all pending requests -func (f *fetcher) deliver(ctx context.Context, ch Chunk) { - f.deliverOnce.Do(func() { - f.chunk = ch - // closing the deliveredC channel will terminate ongoing requests - close(f.deliveredC) - log.Trace("n.getFetcher close deliveredC", "ref", ch.Address()) - }) -} diff --git a/swarm/storage/netstore_test.go b/swarm/storage/netstore_test.go deleted file mode 100644 index dc0727987f..0000000000 --- a/swarm/storage/netstore_test.go +++ /dev/null @@ -1,702 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "bytes" - "context" - "crypto/rand" - "errors" - "fmt" - "io/ioutil" - "os" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" -) - -var sourcePeerID = enode.HexID("99d8594b52298567d2ca3f4c441a5ba0140ee9245e26460d01102a52773c73b9") - -type mockNetFetcher struct { - peers *sync.Map - sources []*enode.ID - peersPerRequest [][]Address - requestCalled bool - offerCalled bool - quit <-chan struct{} - ctx context.Context - hopCounts []uint8 - mu sync.Mutex -} - -func (m *mockNetFetcher) Offer(source *enode.ID) { - m.offerCalled = true - m.sources = append(m.sources, source) -} - -func (m *mockNetFetcher) Request(hopCount uint8) { - m.mu.Lock() - defer m.mu.Unlock() - - m.requestCalled = true - var peers []Address - m.peers.Range(func(key interface{}, _ interface{}) bool { - peers = append(peers, common.FromHex(key.(string))) - return true - }) - m.peersPerRequest = append(m.peersPerRequest, peers) - m.hopCounts = append(m.hopCounts, hopCount) -} - -type mockNetFetchFuncFactory struct { - fetcher *mockNetFetcher -} - -func (m *mockNetFetchFuncFactory) newMockNetFetcher(ctx context.Context, _ Address, peers *sync.Map) NetFetcher { - m.fetcher.peers = peers - m.fetcher.quit = ctx.Done() - m.fetcher.ctx = ctx - return m.fetcher -} - -func newTestNetStore(t *testing.T) (netStore *NetStore, fetcher *mockNetFetcher, cleanup func()) { - t.Helper() - - dir, err := ioutil.TempDir("", "swarm-storage-") - if err != nil { - t.Fatal(err) - } - localStore, err := localstore.New(dir, make([]byte, 32), nil) - if err != nil { - os.RemoveAll(dir) - t.Fatal(err) - } - cleanup = func() { - localStore.Close() - os.RemoveAll(dir) - } - - fetcher = new(mockNetFetcher) - mockNetFetchFuncFactory := &mockNetFetchFuncFactory{ - fetcher: fetcher, - } - netStore, err = NewNetStore(localStore, mockNetFetchFuncFactory.newMockNetFetcher) - if err != nil { - cleanup() - t.Fatal(err) - } - return netStore, fetcher, cleanup -} - -// TestNetStoreGetAndPut tests calling NetStore.Get which is blocked until the same chunk is Put. -// After the Put there should no active fetchers, and the context created for the fetcher should -// be cancelled. -func TestNetStoreGetAndPut(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - - c := make(chan struct{}) // this channel ensures that the gouroutine with the Put does not run earlier than the Get - putErrC := make(chan error) - go func() { - <-c // wait for the Get to be called - time.Sleep(200 * time.Millisecond) // and a little more so it is surely called - - // check if netStore created a fetcher in the Get call for the unavailable chunk - if netStore.fetchers.Len() != 1 || netStore.getFetcher(ch.Address()) == nil { - putErrC <- errors.New("Expected netStore to use a fetcher for the Get call") - return - } - - _, err := netStore.Put(ctx, chunk.ModePutRequest, ch) - if err != nil { - putErrC <- fmt.Errorf("Expected no err got %v", err) - return - } - - putErrC <- nil - }() - - close(c) - recChunk, err := netStore.Get(ctx, chunk.ModeGetRequest, ch.Address()) // this is blocked until the Put above is done - if err != nil { - t.Fatalf("Expected no err got %v", err) - } - - if err := <-putErrC; err != nil { - t.Fatal(err) - } - // the retrieved chunk should be the same as what we Put - if !bytes.Equal(recChunk.Address(), ch.Address()) || !bytes.Equal(recChunk.Data(), ch.Data()) { - t.Fatalf("Different chunk received than what was put") - } - // the chunk is already available locally, so there should be no active fetchers waiting for it - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to remove the fetcher after delivery") - } - - // A fetcher was created when the Get was called (and the chunk was not available). The chunk - // was delivered with the Put call, so the fetcher should be cancelled now. - select { - case <-fetcher.ctx.Done(): - default: - t.Fatal("Expected fetcher context to be cancelled") - } - -} - -// TestNetStoreGetAndPut tests calling NetStore.Put and then NetStore.Get. -// After the Put the chunk is available locally, so the Get can just retrieve it from LocalStore, -// there is no need to create fetchers. -func TestNetStoreGetAfterPut(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) - defer cancel() - - // First we Put the chunk, so the chunk will be available locally - _, err := netStore.Put(ctx, chunk.ModePutRequest, ch) - if err != nil { - t.Fatalf("Expected no err got %v", err) - } - - // Get should retrieve the chunk from LocalStore, without creating fetcher - recChunk, err := netStore.Get(ctx, chunk.ModeGetRequest, ch.Address()) - if err != nil { - t.Fatalf("Expected no err got %v", err) - } - // the retrieved chunk should be the same as what we Put - if !bytes.Equal(recChunk.Address(), ch.Address()) || !bytes.Equal(recChunk.Data(), ch.Data()) { - t.Fatalf("Different chunk received than what was put") - } - // no fetcher offer or request should be created for a locally available chunk - if fetcher.offerCalled || fetcher.requestCalled { - t.Fatal("NetFetcher.offerCalled or requestCalled not expected to be called") - } - // no fetchers should be created for a locally available chunk - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to not have fetcher") - } - -} - -// TestNetStoreGetTimeout tests a Get call for an unavailable chunk and waits for timeout -func TestNetStoreGetTimeout(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) - defer cancel() - - c := make(chan struct{}) // this channel ensures that the gouroutine does not run earlier than the Get - fetcherErrC := make(chan error) - go func() { - <-c // wait for the Get to be called - time.Sleep(200 * time.Millisecond) // and a little more so it is surely called - - // check if netStore created a fetcher in the Get call for the unavailable chunk - if netStore.fetchers.Len() != 1 || netStore.getFetcher(ch.Address()) == nil { - fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") - return - } - - fetcherErrC <- nil - }() - - close(c) - // We call Get on this chunk, which is not in LocalStore. We don't Put it at all, so there will - // be a timeout - _, err := netStore.Get(ctx, chunk.ModeGetRequest, ch.Address()) - - // Check if the timeout happened - if err != context.DeadlineExceeded { - t.Fatalf("Expected context.DeadLineExceeded err got %v", err) - } - - if err := <-fetcherErrC; err != nil { - t.Fatal(err) - } - - // A fetcher was created, check if it has been removed after timeout - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to remove the fetcher after timeout") - } - - // Check if the fetcher context has been cancelled after the timeout - select { - case <-fetcher.ctx.Done(): - default: - t.Fatal("Expected fetcher context to be cancelled") - } -} - -// TestNetStoreGetCancel tests a Get call for an unavailable chunk, then cancels the context and checks -// the errors -func TestNetStoreGetCancel(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - - c := make(chan struct{}) // this channel ensures that the gouroutine with the cancel does not run earlier than the Get - fetcherErrC := make(chan error, 1) - go func() { - <-c // wait for the Get to be called - time.Sleep(200 * time.Millisecond) // and a little more so it is surely called - // check if netStore created a fetcher in the Get call for the unavailable chunk - if netStore.fetchers.Len() != 1 || netStore.getFetcher(ch.Address()) == nil { - fetcherErrC <- errors.New("Expected netStore to use a fetcher for the Get call") - return - } - - fetcherErrC <- nil - cancel() - }() - - close(c) - - // We call Get with an unavailable chunk, so it will create a fetcher and wait for delivery - _, err := netStore.Get(ctx, chunk.ModeGetRequest, ch.Address()) - - if err := <-fetcherErrC; err != nil { - t.Fatal(err) - } - - // After the context is cancelled above Get should return with an error - if err != context.Canceled { - t.Fatalf("Expected context.Canceled err got %v", err) - } - - // A fetcher was created, check if it has been removed after cancel - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to remove the fetcher after cancel") - } - - // Check if the fetcher context has been cancelled after the request context cancel - select { - case <-fetcher.ctx.Done(): - default: - t.Fatal("Expected fetcher context to be cancelled") - } -} - -// TestNetStoreMultipleGetAndPut tests four Get calls for the same unavailable chunk. The chunk is -// delivered with a Put, we have to make sure all Get calls return, and they use a single fetcher -// for the chunk retrieval -func TestNetStoreMultipleGetAndPut(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - - putErrC := make(chan error) - go func() { - // sleep to make sure Put is called after all the Get - time.Sleep(500 * time.Millisecond) - // check if netStore created exactly one fetcher for all Get calls - if netStore.fetchers.Len() != 1 { - putErrC <- errors.New("Expected netStore to use one fetcher for all Get calls") - return - } - _, err := netStore.Put(ctx, chunk.ModePutRequest, ch) - if err != nil { - putErrC <- fmt.Errorf("Expected no err got %v", err) - return - } - putErrC <- nil - }() - - count := 4 - // call Get 4 times for the same unavailable chunk. The calls will be blocked until the Put above. - errC := make(chan error) - for i := 0; i < count; i++ { - go func() { - recChunk, err := netStore.Get(ctx, chunk.ModeGetRequest, ch.Address()) - if err != nil { - errC <- fmt.Errorf("Expected no err got %v", err) - } - if !bytes.Equal(recChunk.Address(), ch.Address()) || !bytes.Equal(recChunk.Data(), ch.Data()) { - errC <- errors.New("Different chunk received than what was put") - } - errC <- nil - }() - } - - if err := <-putErrC; err != nil { - t.Fatal(err) - } - - timeout := time.After(1 * time.Second) - - // The Get calls should return after Put, so no timeout expected - for i := 0; i < count; i++ { - select { - case err := <-errC: - if err != nil { - t.Fatal(err) - } - case <-timeout: - t.Fatalf("Timeout waiting for Get calls to return") - } - } - - // A fetcher was created, check if it has been removed after cancel - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to remove the fetcher after delivery") - } - - // A fetcher was created, check if it has been removed after delivery - select { - case <-fetcher.ctx.Done(): - default: - t.Fatal("Expected fetcher context to be cancelled") - } - -} - -// TestNetStoreFetchFuncTimeout tests a FetchFunc call for an unavailable chunk and waits for timeout -func TestNetStoreFetchFuncTimeout(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - chunk := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) - defer cancel() - - // FetchFunc is called for an unavaible chunk, so the returned wait function should not be nil - wait := netStore.FetchFunc(ctx, chunk.Address()) - if wait == nil { - t.Fatal("Expected wait function to be not nil") - } - - // There should an active fetcher for the chunk after the FetchFunc call - if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { - t.Fatalf("Expected netStore to have one fetcher for the requested chunk") - } - - // wait function should timeout because we don't deliver the chunk with a Put - err := wait(ctx) - if err != context.DeadlineExceeded { - t.Fatalf("Expected context.DeadLineExceeded err got %v", err) - } - - // the fetcher should be removed after timeout - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to remove the fetcher after timeout") - } - - // the fetcher context should be cancelled after timeout - select { - case <-fetcher.ctx.Done(): - default: - t.Fatal("Expected fetcher context to be cancelled") - } -} - -// TestNetStoreFetchFuncAfterPut tests that the FetchFunc should return nil for a locally available chunk -func TestNetStoreFetchFuncAfterPut(t *testing.T) { - netStore, _, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - - // We deliver the created the chunk with a Put - _, err := netStore.Put(ctx, chunk.ModePutRequest, ch) - if err != nil { - t.Fatalf("Expected no err got %v", err) - } - - // FetchFunc should return nil, because the chunk is available locally, no need to fetch it - wait := netStore.FetchFunc(ctx, ch.Address()) - if wait != nil { - t.Fatal("Expected wait to be nil") - } - - // No fetchers should be created at all - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to not have fetcher") - } -} - -// TestNetStoreGetCallsRequest tests if Get created a request on the NetFetcher for an unavailable chunk -func TestNetStoreGetCallsRequest(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx := context.WithValue(context.Background(), "hopcount", uint8(5)) - ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) - defer cancel() - - // We call get for a not available chunk, it will timeout because the chunk is not delivered - _, err := netStore.Get(ctx, chunk.ModeGetRequest, ch.Address()) - - if err != context.DeadlineExceeded { - t.Fatalf("Expected context.DeadlineExceeded err got %v", err) - } - - // NetStore should call NetFetcher.Request and wait for the chunk - if !fetcher.requestCalled { - t.Fatal("Expected NetFetcher.Request to be called") - } - - if fetcher.hopCounts[0] != 5 { - t.Fatalf("Expected NetFetcher.Request be called with hopCount 5, got %v", fetcher.hopCounts[0]) - } -} - -// TestNetStoreGetCallsOffer tests if Get created a request on the NetFetcher for an unavailable chunk -// in case of a source peer provided in the context. -func TestNetStoreGetCallsOffer(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - // If a source peer is added to the context, NetStore will handle it as an offer - ctx := context.WithValue(context.Background(), "source", sourcePeerID.String()) - ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond) - defer cancel() - - // We call get for a not available chunk, it will timeout because the chunk is not delivered - _, err := netStore.Get(ctx, chunk.ModeGetRequest, ch.Address()) - - if err != context.DeadlineExceeded { - t.Fatalf("Expect error %v got %v", context.DeadlineExceeded, err) - } - - // NetStore should call NetFetcher.Offer with the source peer - if !fetcher.offerCalled { - t.Fatal("Expected NetFetcher.Request to be called") - } - - if len(fetcher.sources) != 1 { - t.Fatalf("Expected fetcher sources length 1 got %v", len(fetcher.sources)) - } - - if fetcher.sources[0].String() != sourcePeerID.String() { - t.Fatalf("Expected fetcher source %v got %v", sourcePeerID, fetcher.sources[0]) - } - -} - -// TestNetStoreFetcherCountPeers tests multiple NetStore.Get calls with peer in the context. -// There is no Put call, so the Get calls timeout -func TestNetStoreFetcherCountPeers(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - addr := randomAddr() - peers := []string{randomAddr().Hex(), randomAddr().Hex(), randomAddr().Hex()} - - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - errC := make(chan error) - nrGets := 3 - - // Call Get 3 times with a peer in context - for i := 0; i < nrGets; i++ { - peer := peers[i] - go func() { - ctx := context.WithValue(ctx, "peer", peer) - _, err := netStore.Get(ctx, chunk.ModeGetRequest, addr) - errC <- err - }() - } - - // All 3 Get calls should timeout - for i := 0; i < nrGets; i++ { - err := <-errC - if err != context.DeadlineExceeded { - t.Fatalf("Expected \"%v\" error got \"%v\"", context.DeadlineExceeded, err) - } - } - - // fetcher should be closed after timeout - select { - case <-fetcher.quit: - case <-time.After(3 * time.Second): - t.Fatalf("mockNetFetcher not closed after timeout") - } - - // All 3 peers should be given to NetFetcher after the 3 Get calls - if len(fetcher.peersPerRequest) != nrGets { - t.Fatalf("Expected 3 got %v", len(fetcher.peersPerRequest)) - } - - for i, peers := range fetcher.peersPerRequest { - if len(peers) < i+1 { - t.Fatalf("Expected at least %v got %v", i+1, len(peers)) - } - } -} - -// TestNetStoreFetchFuncCalledMultipleTimes calls the wait function given by FetchFunc three times, -// and checks there is still exactly one fetcher for one chunk. Afthe chunk is delivered, it checks -// if the fetcher is closed. -func TestNetStoreFetchFuncCalledMultipleTimes(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - ch := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) - defer cancel() - - // FetchFunc should return a non-nil wait function, because the chunk is not available - wait := netStore.FetchFunc(ctx, ch.Address()) - if wait == nil { - t.Fatal("Expected wait function to be not nil") - } - - // There should be exactly one fetcher for the chunk - if netStore.fetchers.Len() != 1 || netStore.getFetcher(ch.Address()) == nil { - t.Fatalf("Expected netStore to have one fetcher for the requested chunk") - } - - // Call wait three times in parallel - count := 3 - errC := make(chan error) - for i := 0; i < count; i++ { - go func() { - errC <- wait(ctx) - }() - } - - // sleep a little so the wait functions are called above - time.Sleep(100 * time.Millisecond) - - // there should be still only one fetcher, because all wait calls are for the same chunk - if netStore.fetchers.Len() != 1 || netStore.getFetcher(ch.Address()) == nil { - t.Fatal("Expected netStore to have one fetcher for the requested chunk") - } - - // Deliver the chunk with a Put - _, err := netStore.Put(ctx, chunk.ModePutRequest, ch) - if err != nil { - t.Fatalf("Expected no err got %v", err) - } - - // wait until all wait calls return (because the chunk is delivered) - for i := 0; i < count; i++ { - err := <-errC - if err != nil { - t.Fatal(err) - } - } - - // There should be no more fetchers for the delivered chunk - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to remove the fetcher after delivery") - } - - // The context for the fetcher should be cancelled after delivery - select { - case <-fetcher.ctx.Done(): - default: - t.Fatal("Expected fetcher context to be cancelled") - } -} - -// TestNetStoreFetcherLifeCycleWithTimeout is similar to TestNetStoreFetchFuncCalledMultipleTimes, -// the only difference is that we don't deilver the chunk, just wait for timeout -func TestNetStoreFetcherLifeCycleWithTimeout(t *testing.T) { - netStore, fetcher, cleanup := newTestNetStore(t) - defer cleanup() - - chunk := GenerateRandomChunk(chunk.DefaultSize) - - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - - // FetchFunc should return a non-nil wait function, because the chunk is not available - wait := netStore.FetchFunc(ctx, chunk.Address()) - if wait == nil { - t.Fatal("Expected wait function to be not nil") - } - - // There should be exactly one fetcher for the chunk - if netStore.fetchers.Len() != 1 || netStore.getFetcher(chunk.Address()) == nil { - t.Fatalf("Expected netStore to have one fetcher for the requested chunk") - } - - // Call wait three times in parallel - count := 3 - errC := make(chan error) - for i := 0; i < count; i++ { - go func() { - rctx, rcancel := context.WithTimeout(context.Background(), 100*time.Millisecond) - defer rcancel() - err := wait(rctx) - if err != context.DeadlineExceeded { - errC <- fmt.Errorf("Expected err %v got %v", context.DeadlineExceeded, err) - return - } - errC <- nil - }() - } - - // wait until all wait calls timeout - for i := 0; i < count; i++ { - err := <-errC - if err != nil { - t.Fatal(err) - } - } - - // There should be no more fetchers after timeout - if netStore.fetchers.Len() != 0 { - t.Fatal("Expected netStore to remove the fetcher after delivery") - } - - // The context for the fetcher should be cancelled after timeout - select { - case <-fetcher.ctx.Done(): - default: - t.Fatal("Expected fetcher context to be cancelled") - } -} - -func randomAddr() Address { - addr := make([]byte, 32) - rand.Read(addr) - return Address(addr) -} diff --git a/swarm/storage/pyramid.go b/swarm/storage/pyramid.go deleted file mode 100644 index 9b0d5397b8..0000000000 --- a/swarm/storage/pyramid.go +++ /dev/null @@ -1,697 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "context" - "encoding/binary" - "errors" - "io" - "io/ioutil" - "sync" - "time" - - "github.com/ethereum/go-ethereum/swarm/chunk" - "github.com/ethereum/go-ethereum/swarm/log" -) - -/* - The main idea of a pyramid chunker is to process the input data without knowing the entire size apriori. - For this to be achieved, the chunker tree is built from the ground up until the data is exhausted. - This opens up new aveneus such as easy append and other sort of modifications to the tree thereby avoiding - duplication of data chunks. - - - Below is an example of a two level chunks tree. The leaf chunks are called data chunks and all the above - chunks are called tree chunks. The tree chunk above data chunks is level 0 and so on until it reaches - the root tree chunk. - - - - T10 <- Tree chunk lvl1 - | - __________________________|_____________________________ - / | | \ - / | \ \ - __T00__ ___T01__ ___T02__ ___T03__ <- Tree chunks lvl 0 - / / \ / / \ / / \ / / \ - / / \ / / \ / / \ / / \ - D1 D2 ... D128 D1 D2 ... D128 D1 D2 ... D128 D1 D2 ... D128 <- Data Chunks - - - The split function continuously read the data and creates data chunks and send them to storage. - When certain no of data chunks are created (defaultBranches), a signal is sent to create a tree - entry. When the level 0 tree entries reaches certain threshold (defaultBranches), another signal - is sent to a tree entry one level up.. and so on... until only the data is exhausted AND only one - tree entry is present in certain level. The key of tree entry is given out as the rootAddress of the file. - -*/ - -var ( - errLoadingTreeRootChunk = errors.New("LoadTree Error: Could not load root chunk") - errLoadingTreeChunk = errors.New("LoadTree Error: Could not load chunk") -) - -const ( - ChunkProcessors = 8 - splitTimeout = time.Minute * 5 -) - -type PyramidSplitterParams struct { - SplitterParams - getter Getter -} - -func NewPyramidSplitterParams(addr Address, reader io.Reader, putter Putter, getter Getter, chunkSize int64) *PyramidSplitterParams { - hashSize := putter.RefSize() - return &PyramidSplitterParams{ - SplitterParams: SplitterParams{ - ChunkerParams: ChunkerParams{ - chunkSize: chunkSize, - hashSize: hashSize, - }, - reader: reader, - putter: putter, - addr: addr, - }, - getter: getter, - } -} - -/* - When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Address), the root hash of the entire content will fill this once processing finishes. - New chunks to store are store using the putter which the caller provides. -*/ -func PyramidSplit(ctx context.Context, reader io.Reader, putter Putter, getter Getter, tag *chunk.Tag) (Address, func(context.Context) error, error) { - return NewPyramidSplitter(NewPyramidSplitterParams(nil, reader, putter, getter, chunk.DefaultSize), tag).Split(ctx) -} - -func PyramidAppend(ctx context.Context, addr Address, reader io.Reader, putter Putter, getter Getter, tag *chunk.Tag) (Address, func(context.Context) error, error) { - return NewPyramidSplitter(NewPyramidSplitterParams(addr, reader, putter, getter, chunk.DefaultSize), tag).Append(ctx) -} - -// Entry to create a tree node -type TreeEntry struct { - level int - branchCount int64 - subtreeSize uint64 - chunk []byte - key []byte - index int // used in append to indicate the index of existing tree entry - updatePending bool // indicates if the entry is loaded from existing tree -} - -func NewTreeEntry(pyramid *PyramidChunker) *TreeEntry { - return &TreeEntry{ - level: 0, - branchCount: 0, - subtreeSize: 0, - chunk: make([]byte, pyramid.chunkSize+8), - key: make([]byte, pyramid.hashSize), - index: 0, - updatePending: false, - } -} - -// Used by the hash processor to create a data/tree chunk and send to storage -type chunkJob struct { - key Address - chunk []byte - parentWg *sync.WaitGroup -} - -type PyramidChunker struct { - chunkSize int64 - hashSize int64 - branches int64 - reader io.Reader - putter Putter - getter Getter - key Address - tag *chunk.Tag - workerCount int64 - workerLock sync.RWMutex - jobC chan *chunkJob - wg *sync.WaitGroup - errC chan error - quitC chan bool - rootAddress []byte - chunkLevel [][]*TreeEntry -} - -func NewPyramidSplitter(params *PyramidSplitterParams, tag *chunk.Tag) (pc *PyramidChunker) { - pc = &PyramidChunker{} - pc.reader = params.reader - pc.hashSize = params.hashSize - pc.branches = params.chunkSize / pc.hashSize - pc.chunkSize = pc.hashSize * pc.branches - pc.putter = params.putter - pc.getter = params.getter - pc.key = params.addr - pc.tag = tag - pc.workerCount = 0 - pc.jobC = make(chan *chunkJob, 2*ChunkProcessors) - pc.wg = &sync.WaitGroup{} - pc.errC = make(chan error) - pc.quitC = make(chan bool) - pc.rootAddress = make([]byte, pc.hashSize) - pc.chunkLevel = make([][]*TreeEntry, pc.branches) - return -} - -func (pc *PyramidChunker) Join(addr Address, getter Getter, depth int) LazySectionReader { - return &LazyChunkReader{ - addr: addr, - depth: depth, - chunkSize: pc.chunkSize, - branches: pc.branches, - hashSize: pc.hashSize, - getter: getter, - } -} - -func (pc *PyramidChunker) incrementWorkerCount() { - pc.workerLock.Lock() - defer pc.workerLock.Unlock() - pc.workerCount += 1 -} - -func (pc *PyramidChunker) getWorkerCount() int64 { - pc.workerLock.Lock() - defer pc.workerLock.Unlock() - return pc.workerCount -} - -func (pc *PyramidChunker) decrementWorkerCount() { - pc.workerLock.Lock() - defer pc.workerLock.Unlock() - pc.workerCount -= 1 -} - -func (pc *PyramidChunker) Split(ctx context.Context) (k Address, wait func(context.Context) error, err error) { - pc.wg.Add(1) - pc.prepareChunks(ctx, false) - - // closes internal error channel if all subprocesses in the workgroup finished - go func() { - - // waiting for all chunks to finish - pc.wg.Wait() - - //We close errC here because this is passed down to 8 parallel routines underneath. - // if a error happens in one of them.. that particular routine raises error... - // once they all complete successfully, the control comes back and we can safely close this here. - close(pc.errC) - }() - - defer close(pc.quitC) - defer pc.putter.Close() - - select { - case err := <-pc.errC: - if err != nil { - return nil, nil, err - } - case <-ctx.Done(): - _ = pc.putter.Wait(ctx) //??? - return nil, nil, ctx.Err() - } - return pc.rootAddress, pc.putter.Wait, nil - -} - -func (pc *PyramidChunker) Append(ctx context.Context) (k Address, wait func(context.Context) error, err error) { - // Load the right most unfinished tree chunks in every level - pc.loadTree(ctx) - - pc.wg.Add(1) - pc.prepareChunks(ctx, true) - - // closes internal error channel if all subprocesses in the workgroup finished - go func() { - - // waiting for all chunks to finish - pc.wg.Wait() - - close(pc.errC) - }() - - defer close(pc.quitC) - defer pc.putter.Close() - - select { - case err := <-pc.errC: - if err != nil { - return nil, nil, err - } - case <-time.NewTimer(splitTimeout).C: - } - - return pc.rootAddress, pc.putter.Wait, nil - -} - -func (pc *PyramidChunker) processor(ctx context.Context, id int64) { - defer pc.decrementWorkerCount() - for { - select { - - case job, ok := <-pc.jobC: - if !ok { - return - } - pc.processChunk(ctx, id, job) - pc.tag.Inc(chunk.StateSplit) - case <-pc.quitC: - return - } - } -} - -func (pc *PyramidChunker) processChunk(ctx context.Context, id int64, job *chunkJob) { - ref, err := pc.putter.Put(ctx, job.chunk) - if err != nil { - select { - case pc.errC <- err: - case <-pc.quitC: - } - } - - // report hash of this chunk one level up (keys corresponds to the proper subslice of the parent chunk) - copy(job.key, ref) - - // send off new chunk to storage - job.parentWg.Done() -} - -func (pc *PyramidChunker) loadTree(ctx context.Context) error { - // Get the root chunk to get the total size - chunkData, err := pc.getter.Get(ctx, Reference(pc.key)) - if err != nil { - return errLoadingTreeRootChunk - } - chunkSize := int64(chunkData.Size()) - log.Trace("pyramid.chunker: root chunk", "chunk.Size", chunkSize, "pc.chunkSize", pc.chunkSize) - - //if data size is less than a chunk... add a parent with update as pending - if chunkSize <= pc.chunkSize { - newEntry := &TreeEntry{ - level: 0, - branchCount: 1, - subtreeSize: uint64(chunkSize), - chunk: make([]byte, pc.chunkSize+8), - key: make([]byte, pc.hashSize), - index: 0, - updatePending: true, - } - copy(newEntry.chunk[8:], pc.key) - pc.chunkLevel[0] = append(pc.chunkLevel[0], newEntry) - return nil - } - - var treeSize int64 - var depth int - treeSize = pc.chunkSize - for ; treeSize < chunkSize; treeSize *= pc.branches { - depth++ - } - log.Trace("pyramid.chunker", "depth", depth) - - // Add the root chunk entry - branchCount := int64(len(chunkData)-8) / pc.hashSize - newEntry := &TreeEntry{ - level: depth - 1, - branchCount: branchCount, - subtreeSize: uint64(chunkSize), - chunk: chunkData, - key: pc.key, - index: 0, - updatePending: true, - } - pc.chunkLevel[depth-1] = append(pc.chunkLevel[depth-1], newEntry) - - // Add the rest of the tree - for lvl := depth - 1; lvl >= 1; lvl-- { - - //TODO(jmozah): instead of loading finished branches and then trim in the end, - //avoid loading them in the first place - for _, ent := range pc.chunkLevel[lvl] { - branchCount = int64(len(ent.chunk)-8) / pc.hashSize - for i := int64(0); i < branchCount; i++ { - key := ent.chunk[8+(i*pc.hashSize) : 8+((i+1)*pc.hashSize)] - newChunkData, err := pc.getter.Get(ctx, Reference(key)) - if err != nil { - return errLoadingTreeChunk - } - newChunkSize := newChunkData.Size() - bewBranchCount := int64(len(newChunkData)-8) / pc.hashSize - newEntry := &TreeEntry{ - level: lvl - 1, - branchCount: bewBranchCount, - subtreeSize: newChunkSize, - chunk: newChunkData, - key: key, - index: 0, - updatePending: true, - } - pc.chunkLevel[lvl-1] = append(pc.chunkLevel[lvl-1], newEntry) - - } - - // We need to get only the right most unfinished branch.. so trim all finished branches - if int64(len(pc.chunkLevel[lvl-1])) >= pc.branches { - pc.chunkLevel[lvl-1] = nil - } - } - } - - return nil -} - -func (pc *PyramidChunker) prepareChunks(ctx context.Context, isAppend bool) { - defer pc.wg.Done() - - chunkWG := &sync.WaitGroup{} - - pc.incrementWorkerCount() - - go pc.processor(ctx, pc.workerCount) - - parent := NewTreeEntry(pc) - var unfinishedChunkData ChunkData - var unfinishedChunkSize uint64 - - if isAppend && len(pc.chunkLevel[0]) != 0 { - lastIndex := len(pc.chunkLevel[0]) - 1 - ent := pc.chunkLevel[0][lastIndex] - - if ent.branchCount < pc.branches { - parent = &TreeEntry{ - level: 0, - branchCount: ent.branchCount, - subtreeSize: ent.subtreeSize, - chunk: ent.chunk, - key: ent.key, - index: lastIndex, - updatePending: true, - } - - lastBranch := parent.branchCount - 1 - lastAddress := parent.chunk[8+lastBranch*pc.hashSize : 8+(lastBranch+1)*pc.hashSize] - - var err error - unfinishedChunkData, err = pc.getter.Get(ctx, lastAddress) - if err != nil { - pc.errC <- err - } - unfinishedChunkSize = unfinishedChunkData.Size() - if unfinishedChunkSize < uint64(pc.chunkSize) { - parent.subtreeSize = parent.subtreeSize - unfinishedChunkSize - parent.branchCount = parent.branchCount - 1 - } else { - unfinishedChunkData = nil - } - } - } - - for index := 0; ; index++ { - var err error - chunkData := make([]byte, pc.chunkSize+8) - - var readBytes int - - if unfinishedChunkData != nil { - copy(chunkData, unfinishedChunkData) - readBytes += int(unfinishedChunkSize) - unfinishedChunkData = nil - log.Trace("pyramid.chunker: found unfinished chunk", "readBytes", readBytes) - } - - var res []byte - res, err = ioutil.ReadAll(io.LimitReader(pc.reader, int64(len(chunkData)-(8+readBytes)))) - - // hack for ioutil.ReadAll: - // a successful call to ioutil.ReadAll returns err == nil, not err == EOF, whereas we - // want to propagate the io.EOF error - if len(res) == 0 && err == nil { - err = io.EOF - } - copy(chunkData[8+readBytes:], res) - - readBytes += len(res) - log.Trace("pyramid.chunker: copied all data", "readBytes", readBytes) - - if err != nil { - if err == io.EOF || err == io.ErrUnexpectedEOF { - - pc.cleanChunkLevels() - - // Check if we are appending or the chunk is the only one. - if parent.branchCount == 1 && (pc.depth() == 0 || isAppend) { - // Data is exactly one chunk.. pick the last chunk key as root - chunkWG.Wait() - lastChunksAddress := parent.chunk[8 : 8+pc.hashSize] - copy(pc.rootAddress, lastChunksAddress) - break - } - } else { - close(pc.quitC) - break - } - } - - // Data ended in chunk boundary.. just signal to start bulding tree - if readBytes == 0 { - pc.buildTree(isAppend, parent, chunkWG, true, nil) - break - } else { - pkey := pc.enqueueDataChunk(chunkData, uint64(readBytes), parent, chunkWG) - - // update tree related parent data structures - parent.subtreeSize += uint64(readBytes) - parent.branchCount++ - - // Data got exhausted... signal to send any parent tree related chunks - if int64(readBytes) < pc.chunkSize { - - pc.cleanChunkLevels() - - // only one data chunk .. so dont add any parent chunk - if parent.branchCount <= 1 { - chunkWG.Wait() - - if isAppend || pc.depth() == 0 { - // No need to build the tree if the depth is 0 - // or we are appending. - // Just use the last key. - copy(pc.rootAddress, pkey) - } else { - // We need to build the tree and and provide the lonely - // chunk key to replace the last tree chunk key. - pc.buildTree(isAppend, parent, chunkWG, true, pkey) - } - break - } - - pc.buildTree(isAppend, parent, chunkWG, true, nil) - break - } - - if parent.branchCount == pc.branches { - pc.buildTree(isAppend, parent, chunkWG, false, nil) - parent = NewTreeEntry(pc) - } - - } - - workers := pc.getWorkerCount() - if int64(len(pc.jobC)) > workers && workers < ChunkProcessors { - pc.incrementWorkerCount() - go pc.processor(ctx, pc.workerCount) - } - - } - -} - -func (pc *PyramidChunker) buildTree(isAppend bool, ent *TreeEntry, chunkWG *sync.WaitGroup, last bool, lonelyChunkKey []byte) { - chunkWG.Wait() - pc.enqueueTreeChunk(ent, chunkWG, last) - - compress := false - endLvl := pc.branches - for lvl := int64(0); lvl < pc.branches; lvl++ { - lvlCount := int64(len(pc.chunkLevel[lvl])) - if lvlCount >= pc.branches { - endLvl = lvl + 1 - compress = true - break - } - } - - if !compress && !last { - return - } - - // Wait for all the keys to be processed before compressing the tree - chunkWG.Wait() - - for lvl := int64(ent.level); lvl < endLvl; lvl++ { - - lvlCount := int64(len(pc.chunkLevel[lvl])) - if lvlCount == 1 && last { - copy(pc.rootAddress, pc.chunkLevel[lvl][0].key) - return - } - - for startCount := int64(0); startCount < lvlCount; startCount += pc.branches { - - endCount := startCount + pc.branches - if endCount > lvlCount { - endCount = lvlCount - } - - var nextLvlCount int64 - var tempEntry *TreeEntry - if len(pc.chunkLevel[lvl+1]) > 0 { - nextLvlCount = int64(len(pc.chunkLevel[lvl+1]) - 1) - tempEntry = pc.chunkLevel[lvl+1][nextLvlCount] - } - if isAppend && tempEntry != nil && tempEntry.updatePending { - updateEntry := &TreeEntry{ - level: int(lvl + 1), - branchCount: 0, - subtreeSize: 0, - chunk: make([]byte, pc.chunkSize+8), - key: make([]byte, pc.hashSize), - index: int(nextLvlCount), - updatePending: true, - } - for index := int64(0); index < lvlCount; index++ { - updateEntry.branchCount++ - updateEntry.subtreeSize += pc.chunkLevel[lvl][index].subtreeSize - copy(updateEntry.chunk[8+(index*pc.hashSize):8+((index+1)*pc.hashSize)], pc.chunkLevel[lvl][index].key[:pc.hashSize]) - } - - pc.enqueueTreeChunk(updateEntry, chunkWG, last) - - } else { - - noOfBranches := endCount - startCount - newEntry := &TreeEntry{ - level: int(lvl + 1), - branchCount: noOfBranches, - subtreeSize: 0, - chunk: make([]byte, (noOfBranches*pc.hashSize)+8), - key: make([]byte, pc.hashSize), - index: int(nextLvlCount), - updatePending: false, - } - - index := int64(0) - for i := startCount; i < endCount; i++ { - entry := pc.chunkLevel[lvl][i] - newEntry.subtreeSize += entry.subtreeSize - copy(newEntry.chunk[8+(index*pc.hashSize):8+((index+1)*pc.hashSize)], entry.key[:pc.hashSize]) - index++ - } - // Lonely chunk key is the key of the last chunk that is only one on the last branch. - // In this case, ignore the its tree chunk key and replace it with the lonely chunk key. - if lonelyChunkKey != nil { - // Overwrite the last tree chunk key with the lonely data chunk key. - copy(newEntry.chunk[int64(len(newEntry.chunk))-pc.hashSize:], lonelyChunkKey[:pc.hashSize]) - } - - pc.enqueueTreeChunk(newEntry, chunkWG, last) - - } - - } - - if !isAppend { - chunkWG.Wait() - if compress { - pc.chunkLevel[lvl] = nil - } - } - } - -} - -func (pc *PyramidChunker) enqueueTreeChunk(ent *TreeEntry, chunkWG *sync.WaitGroup, last bool) { - if ent != nil && ent.branchCount > 0 { - - // wait for data chunks to get over before processing the tree chunk - if last { - chunkWG.Wait() - } - - binary.LittleEndian.PutUint64(ent.chunk[:8], ent.subtreeSize) - ent.key = make([]byte, pc.hashSize) - chunkWG.Add(1) - select { - case pc.jobC <- &chunkJob{ent.key, ent.chunk[:ent.branchCount*pc.hashSize+8], chunkWG}: - case <-pc.quitC: - } - - // Update or append based on weather it is a new entry or being reused - if ent.updatePending { - chunkWG.Wait() - pc.chunkLevel[ent.level][ent.index] = ent - } else { - pc.chunkLevel[ent.level] = append(pc.chunkLevel[ent.level], ent) - } - - } -} - -func (pc *PyramidChunker) enqueueDataChunk(chunkData []byte, size uint64, parent *TreeEntry, chunkWG *sync.WaitGroup) Address { - binary.LittleEndian.PutUint64(chunkData[:8], size) - pkey := parent.chunk[8+parent.branchCount*pc.hashSize : 8+(parent.branchCount+1)*pc.hashSize] - - chunkWG.Add(1) - select { - case pc.jobC <- &chunkJob{pkey, chunkData[:size+8], chunkWG}: - case <-pc.quitC: - } - - return pkey - -} - -// depth returns the number of chunk levels. -// It is used to detect if there is only one data chunk -// left for the last branch. -func (pc *PyramidChunker) depth() (d int) { - for _, l := range pc.chunkLevel { - if l == nil { - return - } - d++ - } - return -} - -// cleanChunkLevels removes gaps (nil levels) between chunk levels -// that are not nil. -func (pc *PyramidChunker) cleanChunkLevels() { - for i, l := range pc.chunkLevel { - if l == nil { - pc.chunkLevel = append(pc.chunkLevel[:i], append(pc.chunkLevel[i+1:], nil)...) - } - } -} diff --git a/swarm/storage/swarmhasher.go b/swarm/storage/swarmhasher.go deleted file mode 100644 index fae03f0c72..0000000000 --- a/swarm/storage/swarmhasher.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "hash" -) - -const ( - BMTHash = "BMT" - SHA3Hash = "SHA3" // http://golang.org/pkg/hash/#Hash - DefaultHash = BMTHash -) - -type SwarmHash interface { - hash.Hash - ResetWithLength([]byte) -} - -type HashWithLength struct { - hash.Hash -} - -func (h *HashWithLength) ResetWithLength(length []byte) { - h.Reset() - h.Write(length) -} diff --git a/swarm/storage/types.go b/swarm/storage/types.go deleted file mode 100644 index d1d47dbe85..0000000000 --- a/swarm/storage/types.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package storage - -import ( - "bytes" - "context" - "crypto" - "crypto/rand" - "encoding/binary" - "io" - - "github.com/ethereum/go-ethereum/swarm/bmt" - "github.com/ethereum/go-ethereum/swarm/chunk" - "golang.org/x/crypto/sha3" -) - -// MaxPO is the same as chunk.MaxPO for backward compatibility. -const MaxPO = chunk.MaxPO - -// AddressLength is the same as chunk.AddressLength for backward compatibility. -const AddressLength = chunk.AddressLength - -type SwarmHasher func() SwarmHash - -// Address is an alias for chunk.Address for backward compatibility. -type Address = chunk.Address - -// Proximity is the same as chunk.Proximity for backward compatibility. -var Proximity = chunk.Proximity - -// ZeroAddr is the same as chunk.ZeroAddr for backward compatibility. -var ZeroAddr = chunk.ZeroAddr - -func MakeHashFunc(hash string) SwarmHasher { - switch hash { - case "SHA256": - return func() SwarmHash { return &HashWithLength{crypto.SHA256.New()} } - case "SHA3": - return func() SwarmHash { return &HashWithLength{sha3.NewLegacyKeccak256()} } - case "BMT": - return func() SwarmHash { - hasher := sha3.NewLegacyKeccak256 - hasherSize := hasher().Size() - segmentCount := chunk.DefaultSize / hasherSize - pool := bmt.NewTreePool(hasher, segmentCount, bmt.PoolSize) - return bmt.New(pool) - } - } - return nil -} - -type AddressCollection []Address - -func NewAddressCollection(l int) AddressCollection { - return make(AddressCollection, l) -} - -func (c AddressCollection) Len() int { - return len(c) -} - -func (c AddressCollection) Less(i, j int) bool { - return bytes.Compare(c[i], c[j]) == -1 -} - -func (c AddressCollection) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -// Chunk is an alias for chunk.Chunk for backward compatibility. -type Chunk = chunk.Chunk - -// NewChunk is the same as chunk.NewChunk for backward compatibility. -var NewChunk = chunk.NewChunk - -func GenerateRandomChunk(dataSize int64) Chunk { - hasher := MakeHashFunc(DefaultHash)() - sdata := make([]byte, dataSize+8) - rand.Read(sdata[8:]) - binary.LittleEndian.PutUint64(sdata[:8], uint64(dataSize)) - hasher.ResetWithLength(sdata[:8]) - hasher.Write(sdata[8:]) - return NewChunk(hasher.Sum(nil), sdata) -} - -func GenerateRandomChunks(dataSize int64, count int) (chunks []Chunk) { - for i := 0; i < count; i++ { - ch := GenerateRandomChunk(dataSize) - chunks = append(chunks, ch) - } - return chunks -} - -// Size, Seek, Read, ReadAt -type LazySectionReader interface { - Context() context.Context - Size(context.Context, chan bool) (int64, error) - io.Seeker - io.Reader - io.ReaderAt -} - -type LazyTestSectionReader struct { - *io.SectionReader -} - -func (r *LazyTestSectionReader) Size(context.Context, chan bool) (int64, error) { - return r.SectionReader.Size(), nil -} - -func (r *LazyTestSectionReader) Context() context.Context { - return context.TODO() -} - -type StoreParams struct { - Hash SwarmHasher `toml:"-"` - DbCapacity uint64 - CacheCapacity uint - BaseKey []byte -} - -func NewDefaultStoreParams() *StoreParams { - return NewStoreParams(defaultLDBCapacity, defaultCacheCapacity, nil, nil) -} - -func NewStoreParams(ldbCap uint64, cacheCap uint, hash SwarmHasher, basekey []byte) *StoreParams { - if basekey == nil { - basekey = make([]byte, 32) - } - if hash == nil { - hash = MakeHashFunc(DefaultHash) - } - return &StoreParams{ - Hash: hash, - DbCapacity: ldbCap, - CacheCapacity: cacheCap, - BaseKey: basekey, - } -} - -type ChunkData []byte - -type Reference []byte - -// Putter is responsible to store data and create a reference for it -type Putter interface { - Put(context.Context, ChunkData) (Reference, error) - // RefSize returns the length of the Reference created by this Putter - RefSize() int64 - // Close is to indicate that no more chunk data will be Put on this Putter - Close() - // Wait returns if all data has been store and the Close() was called. - Wait(context.Context) error -} - -// Getter is an interface to retrieve a chunk's data by its reference -type Getter interface { - Get(context.Context, Reference) (ChunkData, error) -} - -// NOTE: this returns invalid data if chunk is encrypted -func (c ChunkData) Size() uint64 { - return binary.LittleEndian.Uint64(c[:8]) -} - -type ChunkValidator = chunk.Validator - -// Provides method for validation of content address in chunks -// Holds the corresponding hasher to create the address -type ContentAddressValidator struct { - Hasher SwarmHasher -} - -// Constructor -func NewContentAddressValidator(hasher SwarmHasher) *ContentAddressValidator { - return &ContentAddressValidator{ - Hasher: hasher, - } -} - -// Validate that the given key is a valid content address for the given data -func (v *ContentAddressValidator) Validate(ch Chunk) bool { - data := ch.Data() - if l := len(data); l < 9 || l > chunk.DefaultSize+8 { - // log.Error("invalid chunk size", "chunk", addr.Hex(), "size", l) - return false - } - - hasher := v.Hasher() - hasher.ResetWithLength(data[:8]) - hasher.Write(data[8:]) - hash := hasher.Sum(nil) - - return bytes.Equal(hash, ch.Address()) -} - -type ChunkStore = chunk.Store - -// FakeChunkStore doesn't store anything, just implements the ChunkStore interface -// It can be used to inject into a hasherStore if you don't want to actually store data just do the -// hashing -type FakeChunkStore struct { -} - -// Put doesn't store anything it is just here to implement ChunkStore -func (f *FakeChunkStore) Put(_ context.Context, _ chunk.ModePut, ch Chunk) (bool, error) { - return false, nil -} - -// Has doesn't do anything it is just here to implement ChunkStore -func (f *FakeChunkStore) Has(_ context.Context, ref Address) (bool, error) { - panic("FakeChunkStore doesn't support Has") -} - -// Get doesn't store anything it is just here to implement ChunkStore -func (f *FakeChunkStore) Get(_ context.Context, _ chunk.ModeGet, ref Address) (Chunk, error) { - panic("FakeChunkStore doesn't support Get") -} - -func (f *FakeChunkStore) Set(ctx context.Context, mode chunk.ModeSet, addr chunk.Address) (err error) { - panic("FakeChunkStore doesn't support Set") -} - -func (f *FakeChunkStore) LastPullSubscriptionBinID(bin uint8) (id uint64, err error) { - panic("FakeChunkStore doesn't support LastPullSubscriptionBinID") -} - -func (f *FakeChunkStore) SubscribePull(ctx context.Context, bin uint8, since, until uint64) (c <-chan chunk.Descriptor, stop func()) { - panic("FakeChunkStore doesn't support SubscribePull") -} - -// Close doesn't store anything it is just here to implement ChunkStore -func (f *FakeChunkStore) Close() error { - return nil -} diff --git a/swarm/swap/swap.go b/swarm/swap/swap.go deleted file mode 100644 index 5d636dc205..0000000000 --- a/swarm/swap/swap.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swap - -import ( - "errors" - "fmt" - "strconv" - "sync" - - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/state" -) - -// SwAP Swarm Accounting Protocol -// a peer to peer micropayment system -// A node maintains an individual balance with every peer -// Only messages which have a price will be accounted for -type Swap struct { - stateStore state.Store //stateStore is needed in order to keep balances across sessions - lock sync.RWMutex //lock the balances - balances map[enode.ID]int64 //map of balances for each peer -} - -// New - swap constructor -func New(stateStore state.Store) (swap *Swap) { - swap = &Swap{ - stateStore: stateStore, - balances: make(map[enode.ID]int64), - } - return -} - -//Swap implements the protocols.Balance interface -//Add is the (sole) accounting function -func (s *Swap) Add(amount int64, peer *protocols.Peer) (err error) { - s.lock.Lock() - defer s.lock.Unlock() - - //load existing balances from the state store - err = s.loadState(peer) - if err != nil && err != state.ErrNotFound { - return - } - //adjust the balance - //if amount is negative, it will decrease, otherwise increase - s.balances[peer.ID()] += amount - //save the new balance to the state store - peerBalance := s.balances[peer.ID()] - err = s.stateStore.Put(peer.ID().String(), &peerBalance) - - log.Debug(fmt.Sprintf("balance for peer %s: %s", peer.ID().String(), strconv.FormatInt(peerBalance, 10))) - return err -} - -//GetPeerBalance returns the balance for a given peer -func (swap *Swap) GetPeerBalance(peer enode.ID) (int64, error) { - swap.lock.RLock() - defer swap.lock.RUnlock() - if p, ok := swap.balances[peer]; ok { - return p, nil - } - return 0, errors.New("Peer not found") -} - -//load balances from the state store (persisted) -func (s *Swap) loadState(peer *protocols.Peer) (err error) { - var peerBalance int64 - peerID := peer.ID() - //only load if the current instance doesn't already have this peer's - //balance in memory - if _, ok := s.balances[peerID]; !ok { - err = s.stateStore.Get(peerID.String(), &peerBalance) - s.balances[peerID] = peerBalance - } - return -} - -//Clean up Swap -func (swap *Swap) Close() { - swap.stateStore.Close() -} diff --git a/swarm/swap/swap_test.go b/swarm/swap/swap_test.go deleted file mode 100644 index f2e3ba168a..0000000000 --- a/swarm/swap/swap_test.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swap - -import ( - "flag" - "fmt" - "io/ioutil" - mrand "math/rand" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/swarm/state" - colorable "github.com/mattn/go-colorable" -) - -var ( - loglevel = flag.Int("loglevel", 2, "verbosity of logs") -) - -func init() { - flag.Parse() - mrand.Seed(time.Now().UnixNano()) - - log.PrintOrigins(true) - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) -} - -//Test getting a peer's balance -func TestGetPeerBalance(t *testing.T) { - //create a test swap account - swap, testDir := createTestSwap(t) - defer os.RemoveAll(testDir) - - //test for correct value - testPeer := newDummyPeer() - swap.balances[testPeer.ID()] = 888 - b, err := swap.GetPeerBalance(testPeer.ID()) - if err != nil { - t.Fatal(err) - } - if b != 888 { - t.Fatalf("Expected peer's balance to be %d, but is %d", 888, b) - } - - //test for inexistent node - id := adapters.RandomNodeConfig().ID - _, err = swap.GetPeerBalance(id) - if err == nil { - t.Fatal("Expected call to fail, but it didn't!") - } - if err.Error() != "Peer not found" { - t.Fatalf("Expected test to fail with %s, but is %s", "Peer not found", err.Error()) - } -} - -//Test that repeated bookings do correct accounting -func TestRepeatedBookings(t *testing.T) { - //create a test swap account - swap, testDir := createTestSwap(t) - defer os.RemoveAll(testDir) - - testPeer := newDummyPeer() - amount := mrand.Intn(100) - cnt := 1 + mrand.Intn(10) - for i := 0; i < cnt; i++ { - swap.Add(int64(amount), testPeer.Peer) - } - expectedBalance := int64(cnt * amount) - realBalance := swap.balances[testPeer.ID()] - if expectedBalance != realBalance { - t.Fatal(fmt.Sprintf("After %d credits of %d, expected balance to be: %d, but is: %d", cnt, amount, expectedBalance, realBalance)) - } - - testPeer2 := newDummyPeer() - amount = mrand.Intn(100) - cnt = 1 + mrand.Intn(10) - for i := 0; i < cnt; i++ { - swap.Add(0-int64(amount), testPeer2.Peer) - } - expectedBalance = int64(0 - (cnt * amount)) - realBalance = swap.balances[testPeer2.ID()] - if expectedBalance != realBalance { - t.Fatal(fmt.Sprintf("After %d debits of %d, expected balance to be: %d, but is: %d", cnt, amount, expectedBalance, realBalance)) - } - - //mixed debits and credits - amount1 := mrand.Intn(100) - amount2 := mrand.Intn(55) - amount3 := mrand.Intn(999) - swap.Add(int64(amount1), testPeer2.Peer) - swap.Add(int64(0-amount2), testPeer2.Peer) - swap.Add(int64(0-amount3), testPeer2.Peer) - - expectedBalance = expectedBalance + int64(amount1-amount2-amount3) - realBalance = swap.balances[testPeer2.ID()] - - if expectedBalance != realBalance { - t.Fatal(fmt.Sprintf("After mixed debits and credits, expected balance to be: %d, but is: %d", expectedBalance, realBalance)) - } -} - -//try restoring a balance from state store -//this is simulated by creating a node, -//assigning it an arbitrary balance, -//then closing the state store. -//Then we re-open the state store and check that -//the balance is still the same -func TestRestoreBalanceFromStateStore(t *testing.T) { - //create a test swap account - swap, testDir := createTestSwap(t) - defer os.RemoveAll(testDir) - - testPeer := newDummyPeer() - swap.balances[testPeer.ID()] = -8888 - - tmpBalance := swap.balances[testPeer.ID()] - swap.stateStore.Put(testPeer.ID().String(), &tmpBalance) - - swap.stateStore.Close() - swap.stateStore = nil - - stateStore, err := state.NewDBStore(testDir) - if err != nil { - t.Fatal(err) - } - - var newBalance int64 - stateStore.Get(testPeer.ID().String(), &newBalance) - - //compare the balances - if tmpBalance != newBalance { - t.Fatal(fmt.Sprintf("Unexpected balance value after sending cheap message test. Expected balance: %d, balance is: %d", - tmpBalance, newBalance)) - } -} - -//create a test swap account -//creates a stateStore for persistence and a Swap account -func createTestSwap(t *testing.T) (*Swap, string) { - dir, err := ioutil.TempDir("", "swap_test_store") - if err != nil { - t.Fatal(err) - } - stateStore, err2 := state.NewDBStore(dir) - if err2 != nil { - t.Fatal(err2) - } - swap := New(stateStore) - return swap, dir -} - -type dummyPeer struct { - *protocols.Peer -} - -//creates a dummy protocols.Peer with dummy MsgReadWriter -func newDummyPeer() *dummyPeer { - id := adapters.RandomNodeConfig().ID - protoPeer := protocols.NewPeer(p2p.NewPeer(id, "testPeer", nil), nil, nil) - dummy := &dummyPeer{ - Peer: protoPeer, - } - return dummy -} diff --git a/swarm/swarm.go b/swarm/swarm.go deleted file mode 100644 index d004bcd2f4..0000000000 --- a/swarm/swarm.go +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swarm - -import ( - "bytes" - "context" - "crypto/ecdsa" - "errors" - "fmt" - "io" - "math/big" - "net" - "path/filepath" - "strings" - "time" - "unicode" - - "github.com/ethereum/go-ethereum/swarm/chunk" - - "github.com/ethereum/go-ethereum/swarm/storage/feed" - "github.com/ethereum/go-ethereum/swarm/storage/localstore" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/chequebook" - "github.com/ethereum/go-ethereum/contracts/ens" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/api" - httpapi "github.com/ethereum/go-ethereum/swarm/api/http" - "github.com/ethereum/go-ethereum/swarm/fuse" - "github.com/ethereum/go-ethereum/swarm/log" - "github.com/ethereum/go-ethereum/swarm/network" - "github.com/ethereum/go-ethereum/swarm/network/stream" - "github.com/ethereum/go-ethereum/swarm/pss" - "github.com/ethereum/go-ethereum/swarm/state" - "github.com/ethereum/go-ethereum/swarm/storage" - "github.com/ethereum/go-ethereum/swarm/storage/mock" - "github.com/ethereum/go-ethereum/swarm/swap" - "github.com/ethereum/go-ethereum/swarm/tracing" -) - -var ( - updateGaugesPeriod = 5 * time.Second - startCounter = metrics.NewRegisteredCounter("stack,start", nil) - stopCounter = metrics.NewRegisteredCounter("stack,stop", nil) - uptimeGauge = metrics.NewRegisteredGauge("stack.uptime", nil) - requestsCacheGauge = metrics.NewRegisteredGauge("storage.cache.requests.size", nil) -) - -// the swarm stack -type Swarm struct { - config *api.Config // swarm configuration - api *api.API // high level api layer (fs/manifest) - dns api.Resolver // DNS registrar - fileStore *storage.FileStore // distributed preimage archive, the local API to the storage with document level storage/retrieval support - streamer *stream.Registry - bzz *network.Bzz // the logistic manager - backend chequebook.Backend // simple blockchain Backend - privateKey *ecdsa.PrivateKey - netStore *storage.NetStore - sfs *fuse.SwarmFS // need this to cleanup all the active mounts on node exit - ps *pss.Pss - swap *swap.Swap - stateStore *state.DBStore - accountingMetrics *protocols.AccountingMetrics - cleanupFuncs []func() error - - tracerClose io.Closer -} - -// NewSwarm creates a new swarm service instance -// implements node.Service -// If mockStore is not nil, it will be used as the storage for chunk data. -// MockStore should be used only for testing. -func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err error) { - if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroAddr) { - return nil, fmt.Errorf("empty public key") - } - if bytes.Equal(common.FromHex(config.BzzKey), storage.ZeroAddr) { - return nil, fmt.Errorf("empty bzz key") - } - - var backend chequebook.Backend - if config.SwapAPI != "" && config.SwapEnabled { - log.Info("connecting to SWAP API", "url", config.SwapAPI) - backend, err = ethclient.Dial(config.SwapAPI) - if err != nil { - return nil, fmt.Errorf("error connecting to SWAP API %s: %s", config.SwapAPI, err) - } - } - - self = &Swarm{ - config: config, - backend: backend, - privateKey: config.ShiftPrivateKey(), - cleanupFuncs: []func() error{}, - } - log.Debug("Setting up Swarm service components") - - config.HiveParams.Discovery = true - - bzzconfig := &network.BzzConfig{ - NetworkID: config.NetworkID, - OverlayAddr: common.FromHex(config.BzzKey), - HiveParams: config.HiveParams, - LightNode: config.LightNodeEnabled, - BootnodeMode: config.BootnodeMode, - } - - self.stateStore, err = state.NewDBStore(filepath.Join(config.Path, "state-store.db")) - if err != nil { - return - } - - // set up high level api - var resolver *api.MultiResolver - if len(config.EnsAPIs) > 0 { - opts := []api.MultiResolverOption{} - for _, c := range config.EnsAPIs { - tld, endpoint, addr := parseEnsAPIAddress(c) - r, err := newEnsClient(endpoint, addr, config, self.privateKey) - if err != nil { - return nil, err - } - opts = append(opts, api.MultiResolverOptionWithResolver(r, tld)) - - } - resolver = api.NewMultiResolver(opts...) - self.dns = resolver - } - // check that we are not in the old database schema - // if so - fail and exit - isLegacy := localstore.IsLegacyDatabase(config.ChunkDbPath) - - if isLegacy { - return nil, errors.New("Legacy database format detected! Please read the migration announcement at: https://github.com/ethersphere/go-ethereum/wiki/Swarm-v0.4-local-store-migration") - } - - var feedsHandler *feed.Handler - fhParams := &feed.HandlerParams{} - - feedsHandler = feed.NewHandler(fhParams) - - localStore, err := localstore.New(config.ChunkDbPath, config.BaseKey, &localstore.Options{ - MockStore: mockStore, - Capacity: config.DbCapacity, - }) - if err != nil { - return nil, err - } - lstore := chunk.NewValidatorStore( - localStore, - storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)), - feedsHandler, - ) - - self.netStore, err = storage.NewNetStore(lstore, nil) - if err != nil { - return nil, err - } - - to := network.NewKademlia( - common.FromHex(config.BzzKey), - network.NewKadParams(), - ) - delivery := stream.NewDelivery(to, self.netStore) - self.netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, config.DeliverySkipCheck).New - - feedsHandler.SetStore(self.netStore) - - if config.SwapEnabled { - balancesStore, err := state.NewDBStore(filepath.Join(config.Path, "balances.db")) - if err != nil { - return nil, err - } - self.swap = swap.New(balancesStore) - self.accountingMetrics = protocols.SetupAccountingMetrics(10*time.Second, filepath.Join(config.Path, "metrics.db")) - } - - nodeID := config.Enode.ID() - - syncing := stream.SyncingAutoSubscribe - if !config.SyncEnabled || config.LightNodeEnabled { - syncing = stream.SyncingDisabled - } - - registryOptions := &stream.RegistryOptions{ - SkipCheck: config.DeliverySkipCheck, - Syncing: syncing, - SyncUpdateDelay: config.SyncUpdateDelay, - MaxPeerServers: config.MaxStreamPeerServers, - } - self.streamer = stream.NewRegistry(nodeID, delivery, self.netStore, self.stateStore, registryOptions, self.swap) - tags := chunk.NewTags() //todo load from state store - - // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage - self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams, tags) - - log.Debug("Setup local storage") - - self.bzz = network.NewBzz(bzzconfig, to, self.stateStore, self.streamer.GetSpec(), self.streamer.Run) - - // Pss = postal service over swarm (devp2p over bzz) - self.ps, err = pss.NewPss(to, config.Pss) - if err != nil { - return nil, err - } - if pss.IsActiveHandshake { - pss.SetHandshakeController(self.ps, pss.NewHandshakeParams()) - } - - self.api = api.NewAPI(self.fileStore, self.dns, feedsHandler, self.privateKey, tags) - - self.sfs = fuse.NewSwarmFS(self.api) - log.Debug("Initialized FUSE filesystem") - - return self, nil -} - -// parseEnsAPIAddress parses string according to format -// [tld:][contract-addr@]url and returns ENSClientConfig structure -// with endpoint, contract address and TLD. -func parseEnsAPIAddress(s string) (tld, endpoint string, addr common.Address) { - isAllLetterString := func(s string) bool { - for _, r := range s { - if !unicode.IsLetter(r) { - return false - } - } - return true - } - endpoint = s - if i := strings.Index(endpoint, ":"); i > 0 { - if isAllLetterString(endpoint[:i]) && len(endpoint) > i+2 && endpoint[i+1:i+3] != "//" { - tld = endpoint[:i] - endpoint = endpoint[i+1:] - } - } - if i := strings.Index(endpoint, "@"); i > 0 { - addr = common.HexToAddress(endpoint[:i]) - endpoint = endpoint[i+1:] - } - return -} - -// ensClient provides functionality for api.ResolveValidator -type ensClient struct { - *ens.ENS - *ethclient.Client -} - -// newEnsClient creates a new ENS client for that is a consumer of -// a ENS API on a specific endpoint. It is used as a helper function -// for creating multiple resolvers in NewSwarm function. -func newEnsClient(endpoint string, addr common.Address, config *api.Config, privkey *ecdsa.PrivateKey) (*ensClient, error) { - log.Info("connecting to ENS API", "url", endpoint) - client, err := rpc.Dial(endpoint) - if err != nil { - return nil, fmt.Errorf("error connecting to ENS API %s: %s", endpoint, err) - } - ethClient := ethclient.NewClient(client) - - ensRoot := config.EnsRoot - if addr != (common.Address{}) { - ensRoot = addr - } else { - a, err := detectEnsAddr(client) - if err == nil { - ensRoot = a - } else { - log.Warn(fmt.Sprintf("could not determine ENS contract address, using default %s", ensRoot), "err", err) - } - } - transactOpts := bind.NewKeyedTransactor(privkey) - dns, err := ens.NewENS(transactOpts, ensRoot, ethClient) - if err != nil { - return nil, err - } - log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar %v @ address %v", endpoint, ensRoot.Hex())) - return &ensClient{ - ENS: dns, - Client: ethClient, - }, err -} - -// detectEnsAddr determines the ENS contract address by getting both the -// version and genesis hash using the client and matching them to either -// mainnet or testnet addresses -func detectEnsAddr(client *rpc.Client) (common.Address, error) { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - var version string - if err := client.CallContext(ctx, &version, "net_version"); err != nil { - return common.Address{}, err - } - - block, err := ethclient.NewClient(client).BlockByNumber(ctx, big.NewInt(0)) - if err != nil { - return common.Address{}, err - } - - switch { - - case version == "1" && block.Hash() == params.MainnetGenesisHash: - log.Info("using Mainnet ENS contract address", "addr", ens.MainNetAddress) - return ens.MainNetAddress, nil - - case version == "3" && block.Hash() == params.TestnetGenesisHash: - log.Info("using Testnet ENS contract address", "addr", ens.TestNetAddress) - return ens.TestNetAddress, nil - - default: - return common.Address{}, fmt.Errorf("unknown version and genesis hash: %s %s", version, block.Hash()) - } -} - -/* -Start is called when the stack is started -* starts the network kademlia hive peer management -* (starts netStore level 0 api) -* starts DPA level 1 api (chunking -> store/retrieve requests) -* (starts level 2 api) -* starts http proxy server -* registers url scheme handlers for bzz, etc -* TODO: start subservices like sword, swear, swarmdns -*/ -// implements the node.Service interface -func (s *Swarm) Start(srv *p2p.Server) error { - startTime := time.Now() - - s.tracerClose = tracing.Closer - - // update uaddr to correct enode - newaddr := s.bzz.UpdateLocalAddr([]byte(srv.Self().String())) - log.Info("Updated bzz local addr", "oaddr", fmt.Sprintf("%x", newaddr.OAddr), "uaddr", fmt.Sprintf("%s", newaddr.UAddr)) - // set chequebook - //TODO: Currently if swap is enabled and no chequebook (or inexistent) contract is provided, the node would crash. - //Once we integrate back the contracts, this check MUST be revisited - if s.config.SwapEnabled && s.config.SwapAPI != "" { - ctx := context.Background() // The initial setup has no deadline. - err := s.SetChequebook(ctx) - if err != nil { - return fmt.Errorf("Unable to set chequebook for SWAP: %v", err) - } - log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", s.config.Swap.Chequebook())) - } else { - log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set")) - } - - log.Info("Starting bzz service") - - err := s.bzz.Start(srv) - if err != nil { - log.Error("bzz failed", "err", err) - return err - } - log.Info("Swarm network started", "bzzaddr", fmt.Sprintf("%x", s.bzz.Hive.BaseAddr())) - - if s.ps != nil { - s.ps.Start(srv) - } - - // start swarm http proxy server - if s.config.Port != "" { - addr := net.JoinHostPort(s.config.ListenAddr, s.config.Port) - server := httpapi.NewServer(s.api, s.config.Cors) - - if s.config.Cors != "" { - log.Debug("Swarm HTTP proxy CORS headers", "allowedOrigins", s.config.Cors) - } - - log.Debug("Starting Swarm HTTP proxy", "port", s.config.Port) - go func() { - err := server.ListenAndServe(addr) - if err != nil { - log.Error("Could not start Swarm HTTP proxy", "err", err.Error()) - } - }() - } - - doneC := make(chan struct{}) - - s.cleanupFuncs = append(s.cleanupFuncs, func() error { - close(doneC) - return nil - }) - - go func(time.Time) { - for { - select { - case <-time.After(updateGaugesPeriod): - uptimeGauge.Update(time.Since(startTime).Nanoseconds()) - requestsCacheGauge.Update(int64(s.netStore.RequestsCacheLen())) - case <-doneC: - return - } - } - }(startTime) - - startCounter.Inc(1) - s.streamer.Start(srv) - return nil -} - -// implements the node.Service interface -// stops all component services. -func (s *Swarm) Stop() error { - if s.tracerClose != nil { - err := s.tracerClose.Close() - tracing.FinishSpans() - if err != nil { - return err - } - } - - if s.ps != nil { - s.ps.Stop() - } - if ch := s.config.Swap.Chequebook(); ch != nil { - ch.Stop() - ch.Save() - } - if s.swap != nil { - s.swap.Close() - } - if s.accountingMetrics != nil { - s.accountingMetrics.Close() - } - if s.netStore != nil { - s.netStore.Close() - } - s.sfs.Stop() - stopCounter.Inc(1) - s.streamer.Stop() - - err := s.bzz.Stop() - if s.stateStore != nil { - s.stateStore.Close() - } - - for _, cleanF := range s.cleanupFuncs { - err = cleanF() - if err != nil { - log.Error("encountered an error while running cleanup function", "err", err) - break - } - } - return err -} - -// Protocols implements the node.Service interface -func (s *Swarm) Protocols() (protos []p2p.Protocol) { - if s.config.BootnodeMode { - protos = append(protos, s.bzz.Protocols()...) - } else { - protos = append(protos, s.bzz.Protocols()...) - - if s.ps != nil { - protos = append(protos, s.ps.Protocols()...) - } - } - return -} - -// implements node.Service -// APIs returns the RPC API descriptors the Swarm implementation offers -func (s *Swarm) APIs() []rpc.API { - - apis := []rpc.API{ - // public APIs - { - Namespace: "bzz", - Version: "3.0", - Service: &Info{s.config, chequebook.ContractParams}, - Public: true, - }, - // admin APIs - { - Namespace: "bzz", - Version: "3.0", - Service: api.NewInspector(s.api, s.bzz.Hive, s.netStore), - Public: false, - }, - { - Namespace: "chequebook", - Version: chequebook.Version, - Service: chequebook.NewAPI(s.config.Swap.Chequebook), - Public: false, - }, - { - Namespace: "swarmfs", - Version: fuse.SwarmFSVersion, - Service: s.sfs, - Public: false, - }, - { - Namespace: "accounting", - Version: protocols.AccountingVersion, - Service: protocols.NewAccountingApi(s.accountingMetrics), - Public: false, - }, - } - - apis = append(apis, s.bzz.APIs()...) - - apis = append(apis, s.streamer.APIs()...) - - if s.ps != nil { - apis = append(apis, s.ps.APIs()...) - } - - return apis -} - -// SetChequebook ensures that the local checquebook is set up on chain. -func (s *Swarm) SetChequebook(ctx context.Context) error { - err := s.config.Swap.SetChequebook(ctx, s.backend, s.config.Path) - if err != nil { - return err - } - log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", s.config.Swap.Contract.Hex())) - return nil -} - -// RegisterPssProtocol adds a devp2p protocol to the swarm node's Pss instance -func (s *Swarm) RegisterPssProtocol(topic *pss.Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol, options *pss.ProtocolParams) (*pss.Protocol, error) { - return pss.RegisterProtocol(s.ps, topic, spec, targetprotocol, options) -} - -// serialisable info about swarm -type Info struct { - *api.Config - *chequebook.Params -} - -func (s *Info) Info() *Info { - return s -} diff --git a/swarm/swarm_test.go b/swarm/swarm_test.go deleted file mode 100644 index cf2afaec9e..0000000000 --- a/swarm/swarm_test.go +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package swarm - -import ( - "context" - "encoding/hex" - "io/ioutil" - "math/rand" - "os" - "path" - "runtime" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/swarm/api" - "github.com/ethereum/go-ethereum/swarm/sctx" -) - -// TestNewSwarm validates Swarm fields in repsect to the provided configuration. -func TestNewSwarm(t *testing.T) { - dir, err := ioutil.TempDir("", "swarm") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - // a simple rpc endpoint for testing dialing - ipcEndpoint := path.Join(dir, "TestSwarm.ipc") - - // windows namedpipes are not on filesystem but on NPFS - if runtime.GOOS == "windows" { - b := make([]byte, 8) - rand.Read(b) - ipcEndpoint = `\\.\pipe\TestSwarm-` + hex.EncodeToString(b) - } - - _, server, err := rpc.StartIPCEndpoint(ipcEndpoint, nil) - if err != nil { - t.Error(err) - } - defer server.Stop() - - for _, tc := range []struct { - name string - configure func(*api.Config) - check func(*testing.T, *Swarm, *api.Config) - }{ - { - name: "defaults", - configure: nil, - check: func(t *testing.T, s *Swarm, config *api.Config) { - if s.config != config { - t.Error("config is not the same object") - } - if s.backend != nil { - t.Error("backend is not nil") - } - if s.privateKey == nil { - t.Error("private key is not set") - } - if !s.config.HiveParams.Discovery { - t.Error("config.HiveParams.Discovery is false, must be true regardless the configuration") - } - if s.dns != nil { - t.Error("dns initialized, but it should not be") - } - if s.netStore == nil { - t.Error("netStore not initialized") - } - if s.streamer == nil { - t.Error("streamer not initialized") - } - if s.fileStore == nil { - t.Error("fileStore not initialized") - } - if s.bzz == nil { - t.Error("bzz not initialized") - } - if s.ps == nil { - t.Error("pss not initialized") - } - if s.api == nil { - t.Error("api not initialized") - } - if s.sfs == nil { - t.Error("swarm filesystem not initialized") - } - }, - }, - { - name: "with swap", - configure: func(config *api.Config) { - config.SwapAPI = ipcEndpoint - config.SwapEnabled = true - }, - check: func(t *testing.T, s *Swarm, _ *api.Config) { - if s.backend == nil { - t.Error("backend is nil") - } - }, - }, - { - name: "with swap disabled", - configure: func(config *api.Config) { - config.SwapAPI = ipcEndpoint - config.SwapEnabled = false - }, - check: func(t *testing.T, s *Swarm, _ *api.Config) { - if s.backend != nil { - t.Error("backend is not nil") - } - }, - }, - { - name: "with swap enabled and api endpoint blank", - configure: func(config *api.Config) { - config.SwapAPI = "" - config.SwapEnabled = true - }, - check: func(t *testing.T, s *Swarm, _ *api.Config) { - if s.backend != nil { - t.Error("backend is not nil") - } - }, - }, - { - name: "ens", - configure: func(config *api.Config) { - config.EnsAPIs = []string{ - "http://127.0.0.1:8888", - } - }, - check: func(t *testing.T, s *Swarm, _ *api.Config) { - if s.dns == nil { - t.Error("dns is not initialized") - } - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - config := api.NewConfig() - - dir, err := ioutil.TempDir("", "swarm") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - config.Path = dir - - privkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - nodekey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - config.Init(privkey, nodekey) - - if tc.configure != nil { - tc.configure(config) - } - - s, err := NewSwarm(config, nil) - if err != nil { - t.Fatal(err) - } - - if tc.check != nil { - tc.check(t, s, config) - } - }) - } -} - -func TestParseEnsAPIAddress(t *testing.T) { - for _, x := range []struct { - description string - value string - tld string - endpoint string - addr common.Address - }{ - { - description: "IPC endpoint", - value: "/data/testnet/geth.ipc", - endpoint: "/data/testnet/geth.ipc", - }, - { - description: "HTTP endpoint", - value: "http://127.0.0.1:1234", - endpoint: "http://127.0.0.1:1234", - }, - { - description: "WS endpoint", - value: "ws://127.0.0.1:1234", - endpoint: "ws://127.0.0.1:1234", - }, - { - description: "IPC Endpoint and TLD", - value: "test:/data/testnet/geth.ipc", - endpoint: "/data/testnet/geth.ipc", - tld: "test", - }, - { - description: "HTTP endpoint and TLD", - value: "test:http://127.0.0.1:1234", - endpoint: "http://127.0.0.1:1234", - tld: "test", - }, - { - description: "WS endpoint and TLD", - value: "test:ws://127.0.0.1:1234", - endpoint: "ws://127.0.0.1:1234", - tld: "test", - }, - { - description: "IPC Endpoint and contract address", - value: "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", - endpoint: "/data/testnet/geth.ipc", - addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), - }, - { - description: "HTTP endpoint and contract address", - value: "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", - endpoint: "http://127.0.0.1:1234", - addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), - }, - { - description: "WS endpoint and contract address", - value: "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", - endpoint: "ws://127.0.0.1:1234", - addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), - }, - { - description: "IPC Endpoint, TLD and contract address", - value: "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", - endpoint: "/data/testnet/geth.ipc", - addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), - tld: "test", - }, - { - description: "HTTP endpoint, TLD and contract address", - value: "eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", - endpoint: "http://127.0.0.1:1234", - addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), - tld: "eth", - }, - { - description: "WS endpoint, TLD and contract address", - value: "eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", - endpoint: "ws://127.0.0.1:1234", - addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), - tld: "eth", - }, - } { - t.Run(x.description, func(t *testing.T) { - tld, endpoint, addr := parseEnsAPIAddress(x.value) - if endpoint != x.endpoint { - t.Errorf("expected Endpoint %q, got %q", x.endpoint, endpoint) - } - if addr != x.addr { - t.Errorf("expected ContractAddress %q, got %q", x.addr.String(), addr.String()) - } - if tld != x.tld { - t.Errorf("expected TLD %q, got %q", x.tld, tld) - } - }) - } -} - -// TestLocalStoreAndRetrieve runs multiple tests where different size files are uploaded -// to a single Swarm instance using API Store and checked against the content returned -// by API Retrieve function. -// -// This test is intended to validate functionality of chunker store and join functions -// and their intergartion into Swarm, without comparing results with ones produced by -// another chunker implementation, as it is done in swarm/storage tests. -func TestLocalStoreAndRetrieve(t *testing.T) { - config := api.NewConfig() - - dir, err := ioutil.TempDir("", "node") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - config.Path = dir - - privkey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - nodekey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - config.Init(privkey, nodekey) - - swarm, err := NewSwarm(config, nil) - if err != nil { - t.Fatal(err) - } - - // by default, test only the lonely chunk cases - sizes := []int{1, 60, 4097, 524288 + 1, 7*524288 + 1} - - if *longrunning { - // test broader set of cases if -longruning flag is set - sizes = append(sizes, 83, 179, 253, 1024, 4095, 4096, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678, 67298391, 524288, 524288+4096, 524288+4097, 7*524288, 7*524288+4096, 7*524288+4097, 128*524288+1, 128*524288, 128*524288+4096, 128*524288+4097, 816778334) - } - for _, n := range sizes { - testLocalStoreAndRetrieve(t, swarm, n, true) - testLocalStoreAndRetrieve(t, swarm, n, false) - } -} - -// testLocalStoreAndRetrieve is using a single Swarm instance, to upload -// a file of length n with optional random data using API Store function, -// and checks the output of API Retrieve function on the same instance. -// This is a regression test for issue -// https://github.com/ethersphere/go-ethereum/issues/639 -// where pyramid chunker did not split correctly files with lengths that -// are edge cases for chunk and tree parameters, depending whether there -// is a tree chunk with only one data chunk and how the compress functionality -// changed the tree. -func testLocalStoreAndRetrieve(t *testing.T, swarm *Swarm, n int, randomData bool) { - slice := make([]byte, n) - if randomData { - rand.Seed(time.Now().UnixNano()) - rand.Read(slice) - } - dataPut := string(slice) - tag, err := swarm.api.Tags.New("test-local-store-and-retrieve", 0) - if err != nil { - t.Fatal(err) - } - ctx := sctx.SetTag(context.Background(), tag.Uid) - k, wait, err := swarm.api.Store(ctx, strings.NewReader(dataPut), int64(len(dataPut)), false) - if err != nil { - t.Fatal(err) - } - if wait != nil { - err = wait(ctx) - if err != nil { - t.Fatal(err) - } - } - - r, _ := swarm.api.Retrieve(context.TODO(), k) - - d, err := ioutil.ReadAll(r) - if err != nil { - t.Fatal(err) - } - dataGet := string(d) - - if len(dataPut) != len(dataGet) { - t.Fatalf("data not matched: length expected %v, got %v", len(dataPut), len(dataGet)) - } else { - if dataPut != dataGet { - t.Fatal("data not matched") - } - } -} diff --git a/swarm/testutil/file.go b/swarm/testutil/file.go deleted file mode 100644 index 70732aa92e..0000000000 --- a/swarm/testutil/file.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package testutil - -import ( - "bytes" - "io" - "io/ioutil" - "math/rand" - "os" - "strings" - "testing" -) - -// TempFileWithContent is a helper function that creates a temp file that contains the following string content then closes the file handle -// it returns the complete file path -func TempFileWithContent(t *testing.T, content string) string { - tempFile, err := ioutil.TempFile("", "swarm-temp-file") - if err != nil { - t.Fatal(err) - } - - _, err = io.Copy(tempFile, strings.NewReader(content)) - if err != nil { - os.RemoveAll(tempFile.Name()) - t.Fatal(err) - } - if err = tempFile.Close(); err != nil { - t.Fatal(err) - } - return tempFile.Name() -} - -// RandomBytes returns pseudo-random deterministic result -// because test fails must be reproducible -func RandomBytes(seed, length int) []byte { - b := make([]byte, length) - reader := rand.New(rand.NewSource(int64(seed))) - for n := 0; n < length; { - read, err := reader.Read(b[n:]) - if err != nil { - panic(err) - } - n += read - } - return b -} - -func RandomReader(seed, length int) *bytes.Reader { - return bytes.NewReader(RandomBytes(seed, length)) -} diff --git a/swarm/testutil/norace.go b/swarm/testutil/norace.go deleted file mode 100644 index bc652184bb..0000000000 --- a/swarm/testutil/norace.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build !race - -package testutil - -// RaceEnabled is true when -race flag is provided to the go tool. This const -// might be used in tests to skip some cases as the race detector may increase -// memory usage 5-10x and execution time by 2-20x. That might causes problems -// on Travis. Please, use this flag sparingly and keep your unit tests -// as light on resources as possible. -const RaceEnabled = false diff --git a/swarm/testutil/race.go b/swarm/testutil/race.go deleted file mode 100644 index 08aa279ae3..0000000000 --- a/swarm/testutil/race.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// +build race - -package testutil - -// RaceEnabled is true when -race flag is provided to the go tool. -// See norace.go for more. -const RaceEnabled = true diff --git a/swarm/testutil/tag.go b/swarm/testutil/tag.go deleted file mode 100644 index d9908f11bd..0000000000 --- a/swarm/testutil/tag.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package testutil - -import ( - "testing" - - "github.com/ethereum/go-ethereum/swarm/chunk" -) - -// CheckTag checks the first tag in the api struct to be in a certain state -func CheckTag(t *testing.T, tag *chunk.Tag, split, stored, seen, total int64) { - t.Helper() - if tag == nil { - t.Fatal("no tag found") - } - - tSplit := tag.Get(chunk.StateSplit) - if tSplit != split { - t.Fatalf("should have had split chunks, got %d want %d", tSplit, split) - } - - tSeen := tag.Get(chunk.StateSeen) - if tSeen != seen { - t.Fatalf("should have had seen chunks, got %d want %d", tSeen, seen) - } - - tStored := tag.Get(chunk.StateStored) - if tStored != stored { - t.Fatalf("mismatch stored chunks, got %d want %d", tStored, stored) - } - - tTotal := tag.Total() - if tTotal != total { - t.Fatalf("mismatch total chunks, got %d want %d", tTotal, total) - } -} diff --git a/swarm/tracing/tracing.go b/swarm/tracing/tracing.go deleted file mode 100644 index 55875464b9..0000000000 --- a/swarm/tracing/tracing.go +++ /dev/null @@ -1,173 +0,0 @@ -package tracing - -import ( - "context" - "io" - "os" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/swarm/spancontext" - - opentracing "github.com/opentracing/opentracing-go" - jaeger "github.com/uber/jaeger-client-go" - jaegercfg "github.com/uber/jaeger-client-go/config" - cli "gopkg.in/urfave/cli.v1" -) - -var ( - // Enabled turns tracing on for the current swarm instance - Enabled bool = false - store = spanStore{} -) - -const ( - // TracingEnabledFlag is the CLI flag name to use to enable trace collections. - TracingEnabledFlag = "tracing" - - // StoreLabelId is the context value key of the name of the span to be saved - StoreLabelId = "span_save_id" - - // StoreLabelMeta is the context value key that together with StoreLabelId constitutes the retrieval key for saved spans in the span store - // StartSaveSpan and ShiftSpanByKey - StoreLabelMeta = "span_save_meta" -) - -var ( - Closer io.Closer -) - -var ( - TracingFlag = cli.BoolFlag{ - Name: TracingEnabledFlag, - Usage: "Enable tracing", - } - TracingEndpointFlag = cli.StringFlag{ - Name: "tracing.endpoint", - Usage: "Tracing endpoint", - Value: "0.0.0.0:6831", - } - TracingSvcFlag = cli.StringFlag{ - Name: "tracing.svc", - Usage: "Tracing service name", - Value: "swarm", - } -) - -// Flags holds all command-line flags required for tracing collection. -var Flags = []cli.Flag{ - TracingFlag, - TracingEndpointFlag, - TracingSvcFlag, -} - -// Init enables or disables the open tracing system. -func init() { - for _, arg := range os.Args { - if flag := strings.TrimLeft(arg, "-"); flag == TracingEnabledFlag { - Enabled = true - } - } -} - -func Setup(ctx *cli.Context) { - if Enabled { - log.Info("Enabling opentracing") - var ( - endpoint = ctx.GlobalString(TracingEndpointFlag.Name) - svc = ctx.GlobalString(TracingSvcFlag.Name) - ) - - Closer = initTracer(endpoint, svc) - } -} - -func initTracer(endpoint, svc string) (closer io.Closer) { - // Sample configuration for testing. Use constant sampling to sample every trace - // and enable LogSpan to log every span via configured Logger. - cfg := jaegercfg.Configuration{ - Sampler: &jaegercfg.SamplerConfig{ - Type: jaeger.SamplerTypeConst, - Param: 1, - }, - Reporter: &jaegercfg.ReporterConfig{ - LogSpans: true, - BufferFlushInterval: 1 * time.Second, - LocalAgentHostPort: endpoint, - }, - } - - // Example logger and metrics factory. Use github.com/uber/jaeger-client-go/log - // and github.com/uber/jaeger-lib/metrics respectively to bind to real logging and metrics - // frameworks. - //jLogger := jaegerlog.StdLogger - //jMetricsFactory := metrics.NullFactory - - // Initialize tracer with a logger and a metrics factory - closer, err := cfg.InitGlobalTracer( - svc, - //jaegercfg.Logger(jLogger), - //jaegercfg.Metrics(jMetricsFactory), - //jaegercfg.Observer(rpcmetrics.NewObserver(jMetricsFactory, rpcmetrics.DefaultNameNormalizer)), - ) - if err != nil { - log.Error("Could not initialize Jaeger tracer", "err", err) - } - - return closer -} - -// spanStore holds saved spans -type spanStore struct { - spans sync.Map -} - -// StartSaveSpan stores the span specified in the passed context for later retrieval -// The span object but be context value on the key StoreLabelId. -// It will be stored under the the following string key context.Value(StoreLabelId)|.|context.Value(StoreLabelMeta) -func StartSaveSpan(ctx context.Context) context.Context { - if !Enabled { - return ctx - } - traceId := ctx.Value(StoreLabelId) - - if traceId != nil { - traceStr := traceId.(string) - var sp opentracing.Span - ctx, sp = spancontext.StartSpan( - ctx, - traceStr, - ) - traceMeta := ctx.Value(StoreLabelMeta) - if traceMeta != nil { - traceStr = traceStr + "." + traceMeta.(string) - } - store.spans.Store(traceStr, sp) - } - return ctx -} - -// ShiftSpanByKey retrieves the span stored under the key of the string given as argument -// The span is then deleted from the store -func ShiftSpanByKey(k string) opentracing.Span { - if !Enabled { - return nil - } - span, spanOk := store.spans.Load(k) - if !spanOk { - return nil - } - store.spans.Delete(k) - return span.(opentracing.Span) -} - -// FinishSpans calls `Finish()` on all stored spans -// It should be called on instance shutdown -func FinishSpans() { - store.spans.Range(func(_, v interface{}) bool { - v.(opentracing.Span).Finish() - return true - }) -} diff --git a/swarm/version/version.go b/swarm/version/version.go deleted file mode 100644 index 271a9cede4..0000000000 --- a/swarm/version/version.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package version - -import ( - "fmt" -) - -const ( - VersionMajor = 0 // Major version component of the current release - VersionMinor = 4 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string -) - -// Version holds the textual version string. -var Version = func() string { - return fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch) -}() - -// VersionWithMeta holds the textual version string including the metadata. -var VersionWithMeta = func() string { - v := Version - if VersionMeta != "" { - v += "-" + VersionMeta - } - return v -}() - -// Git SHA1 commit hash of the release, will be set by main.init() function -var GitCommit string - -// ArchiveVersion holds the textual version string used for Swarm archives. -// e.g. "0.3.0-dea1ce05" for stable releases, or -// "0.3.1-unstable-21c059b6" for unstable releases -func ArchiveVersion(gitCommit string) string { - vsn := Version - if VersionMeta != "stable" { - vsn += "-" + VersionMeta - } - if len(gitCommit) >= 8 { - vsn += "-" + gitCommit[:8] - } - return vsn -} - -func VersionWithCommit(gitCommit string) string { - vsn := Version - if len(gitCommit) >= 8 { - vsn += "-" + gitCommit[:8] - } - return vsn -} From 5d68400cad8cda3b265d2bc9d45223b303349023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sat, 1 Jun 2019 17:19:47 +0300 Subject: [PATCH 32/47] accounts/usbwallet, vendor: switch from HID to generic USB lib --- accounts/usbwallet/hub.go | 26 +- accounts/usbwallet/trezor.go | 2 - accounts/usbwallet/wallet.go | 6 +- node/config.go | 10 +- signer/core/api.go | 14 +- vendor/github.com/karalabe/hid/LICENSE.md | 8 - vendor/github.com/karalabe/hid/README.md | 53 - vendor/github.com/karalabe/hid/generic.go | 54 - vendor/github.com/karalabe/hid/hid.go | 52 - .../github.com/karalabe/hid/hid_disabled.go | 76 - vendor/github.com/karalabe/hid/hid_enabled.go | 459 -- .../hid/libusb/libusb/os/poll_windows.c | 728 --- .../hid/libusb/libusb/os/threads_posix.h | 55 - .../hid/libusb/libusb/os/threads_windows.c | 259 - .../hid/libusb/libusb/os/windows_nt_common.h | 63 - .../hid/libusb/libusb/os/windows_winusb.c | 4290 ----------------- .../karalabe/hid/libusb/libusb/version_nano.h | 1 - vendor/github.com/karalabe/hid/usb.go | 53 - vendor/github.com/karalabe/usb/AUTHORS | 6 + vendor/github.com/karalabe/usb/LICENSE | 165 + vendor/github.com/karalabe/usb/README.md | 47 + .../karalabe/{hid => usb}/appveyor.yml | 6 +- vendor/github.com/karalabe/usb/demo.go | 76 + vendor/github.com/karalabe/usb/go.mod | 3 + .../github.com/karalabe/usb/hid_disabled.go | 42 + vendor/github.com/karalabe/usb/hid_enabled.go | 187 + .../karalabe/{hid => usb}/hidapi/AUTHORS.txt | 0 .../{hid => usb}/hidapi/LICENSE-bsd.txt | 0 .../{hid => usb}/hidapi/LICENSE-gpl3.txt | 0 .../{hid => usb}/hidapi/LICENSE-orig.txt | 0 .../karalabe/{hid => usb}/hidapi/LICENSE.txt | 0 .../karalabe/{hid => usb}/hidapi/README.txt | 0 .../{hid => usb}/hidapi/hidapi/hidapi.h | 0 .../karalabe/{hid => usb}/hidapi/libusb/hid.c | 0 .../karalabe/{hid => usb}/hidapi/mac/hid.c | 0 .../{hid => usb}/hidapi/windows/hid.c | 0 vendor/github.com/karalabe/usb/libs.go | 74 + .../karalabe/{hid => usb}/libusb/AUTHORS | 34 +- .../karalabe/{hid => usb}/libusb/COPYING | 0 .../{hid => usb}/libusb/libusb/config.h | 0 .../{hid => usb}/libusb/libusb/core.c | 352 +- .../{hid => usb}/libusb/libusb/descriptor.c | 21 +- .../{hid => usb}/libusb/libusb/hotplug.c | 123 +- .../{hid => usb}/libusb/libusb/hotplug.h | 59 +- .../karalabe/{hid => usb}/libusb/libusb/io.c | 73 +- .../{hid => usb}/libusb/libusb/libusb.h | 95 +- .../{hid => usb}/libusb/libusb/libusbi.h | 162 +- .../libusb/libusb/os/darwin_usb.c | 102 +- .../libusb/libusb/os/darwin_usb.h | 61 +- .../libusb/libusb/os/haiku_pollfs.cpp | 0 .../{hid => usb}/libusb/libusb/os/haiku_usb.h | 0 .../libusb/libusb/os/haiku_usb_backend.cpp | 0 .../libusb/libusb/os/haiku_usb_raw.cpp | 7 +- .../libusb/libusb/os/haiku_usb_raw.h | 0 .../libusb/libusb/os/linux_netlink.c | 65 +- .../libusb/libusb/os/linux_udev.c | 34 +- .../libusb/libusb/os/linux_usbfs.c | 266 +- .../libusb/libusb/os/linux_usbfs.h | 3 +- .../libusb/libusb/os/netbsd_usb.c | 6 +- .../libusb/libusb/os/openbsd_usb.c | 6 +- .../libusb/libusb/os/poll_posix.c | 41 +- .../libusb/libusb/os/poll_posix.h | 0 .../usb/libusb/libusb/os/poll_windows.c | 364 ++ .../libusb/libusb/os/poll_windows.h | 52 +- .../{hid => usb}/libusb/libusb/os/sunos_usb.c | 563 ++- .../{hid => usb}/libusb/libusb/os/sunos_usb.h | 6 + .../libusb/libusb/os/threads_posix.c | 11 +- .../usb/libusb/libusb/os/threads_posix.h | 102 + .../usb/libusb/libusb/os/threads_windows.c | 126 + .../libusb/libusb/os/threads_windows.h | 93 +- .../{hid => usb}/libusb/libusb/os/wince_usb.c | 67 +- .../{hid => usb}/libusb/libusb/os/wince_usb.h | 0 .../libusb/libusb/os/windows_common.h | 36 +- .../libusb/libusb/os/windows_nt_common.c | 699 ++- .../usb/libusb/libusb/os/windows_nt_common.h | 110 + .../libusb/os/windows_nt_shared_types.h | 138 + .../libusb/libusb/os/windows_usbdk.c | 423 +- .../libusb/libusb/os/windows_usbdk.h | 49 +- .../usb/libusb/libusb/os/windows_winusb.c | 3009 ++++++++++++ .../libusb/libusb/os/windows_winusb.h | 597 +-- .../{hid => usb}/libusb/libusb/strerror.c | 0 .../{hid => usb}/libusb/libusb/sync.c | 0 .../{hid => usb}/libusb/libusb/version.h | 2 +- .../karalabe/usb/libusb/libusb/version_nano.h | 1 + .../github.com/karalabe/usb/raw_disabled.go | 42 + vendor/github.com/karalabe/usb/raw_enabled.go | 253 + vendor/github.com/karalabe/usb/raw_errors.go | 74 + vendor/github.com/karalabe/usb/usb.go | 68 + .../github.com/karalabe/usb/usb_disabled.go | 46 + vendor/github.com/karalabe/usb/usb_enabled.go | 98 + .../github.com/karalabe/{hid => usb}/wchar.go | 2 +- vendor/vendor.json | 8 +- 92 files changed, 7522 insertions(+), 7842 deletions(-) delete mode 100644 vendor/github.com/karalabe/hid/LICENSE.md delete mode 100644 vendor/github.com/karalabe/hid/README.md delete mode 100644 vendor/github.com/karalabe/hid/generic.go delete mode 100644 vendor/github.com/karalabe/hid/hid.go delete mode 100644 vendor/github.com/karalabe/hid/hid_disabled.go delete mode 100644 vendor/github.com/karalabe/hid/hid_enabled.go delete mode 100644 vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c delete mode 100644 vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h delete mode 100644 vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c delete mode 100644 vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h delete mode 100644 vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c delete mode 100644 vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h delete mode 100644 vendor/github.com/karalabe/hid/usb.go create mode 100644 vendor/github.com/karalabe/usb/AUTHORS create mode 100644 vendor/github.com/karalabe/usb/LICENSE create mode 100644 vendor/github.com/karalabe/usb/README.md rename vendor/github.com/karalabe/{hid => usb}/appveyor.yml (81%) create mode 100644 vendor/github.com/karalabe/usb/demo.go create mode 100644 vendor/github.com/karalabe/usb/go.mod create mode 100644 vendor/github.com/karalabe/usb/hid_disabled.go create mode 100644 vendor/github.com/karalabe/usb/hid_enabled.go rename vendor/github.com/karalabe/{hid => usb}/hidapi/AUTHORS.txt (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/LICENSE-bsd.txt (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/LICENSE-gpl3.txt (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/LICENSE-orig.txt (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/LICENSE.txt (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/README.txt (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/hidapi/hidapi.h (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/libusb/hid.c (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/mac/hid.c (100%) rename vendor/github.com/karalabe/{hid => usb}/hidapi/windows/hid.c (100%) mode change 100755 => 100644 create mode 100644 vendor/github.com/karalabe/usb/libs.go rename vendor/github.com/karalabe/{hid => usb}/libusb/AUTHORS (76%) rename vendor/github.com/karalabe/{hid => usb}/libusb/COPYING (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/config.h (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/core.c (91%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/descriptor.c (98%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/hotplug.c (76%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/hotplug.h (65%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/io.c (98%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/libusb.h (96%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/libusbi.h (94%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/darwin_usb.c (96%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/darwin_usb.h (60%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/haiku_pollfs.cpp (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/haiku_usb.h (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/haiku_usb_backend.cpp (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/haiku_usb_raw.cpp (98%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/haiku_usb_raw.h (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/linux_netlink.c (89%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/linux_udev.c (90%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/linux_usbfs.c (93%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/linux_usbfs.h (99%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/netbsd_usb.c (98%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/openbsd_usb.c (99%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/poll_posix.c (56%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/poll_posix.h (100%) create mode 100644 vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/poll_windows.h (70%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/sunos_usb.c (71%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/sunos_usb.h (96%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/threads_posix.c (92%) create mode 100644 vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h create mode 100644 vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/threads_windows.h (53%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/wince_usb.c (94%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/wince_usb.h (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/windows_common.h (82%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/windows_nt_common.c (52%) create mode 100644 vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h create mode 100644 vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/windows_usbdk.c (70%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/windows_usbdk.h (64%) create mode 100644 vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/os/windows_winusb.h (54%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/strerror.c (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/sync.c (100%) rename vendor/github.com/karalabe/{hid => usb}/libusb/libusb/version.h (94%) create mode 100644 vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h create mode 100644 vendor/github.com/karalabe/usb/raw_disabled.go create mode 100644 vendor/github.com/karalabe/usb/raw_enabled.go create mode 100644 vendor/github.com/karalabe/usb/raw_errors.go create mode 100644 vendor/github.com/karalabe/usb/usb.go create mode 100644 vendor/github.com/karalabe/usb/usb_disabled.go create mode 100644 vendor/github.com/karalabe/usb/usb_enabled.go rename vendor/github.com/karalabe/{hid => usb}/wchar.go (99%) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index 35695dd1c5..8f34d63e8a 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -25,7 +25,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/karalabe/hid" + "github.com/karalabe/usb" ) // LedgerScheme is the protocol scheme prefixing account and wallet URLs. @@ -84,20 +84,20 @@ func NewLedgerHub() (*Hub, error) { }, 0xffa0, 0, newLedgerDriver) } -// NewTrezorHub creates a new hardware wallet manager for Trezor devices. -func NewTrezorHub() (*Hub, error) { - return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor 1 */}, 0xff00, 0, newTrezorDriver) +// NewTrezorHubWithHID creates a new hardware wallet manager for Trezor devices. +func NewTrezorHubWithHID() (*Hub, error) { + return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor HID */}, 0xff00, 0, newTrezorDriver) } -// NewWebUSBTrezorHub creates a new hardware wallet manager for Trezor devices with +// NewTrezorHubWithWebUSB creates a new hardware wallet manager for Trezor devices with // firmware version > 1.8.0 -func NewWebUSBTrezorHub() (*Hub, error) { - return newHub(TrezorScheme, 0x1209, []uint16{0x53c1 /* Trezor 1 WebUSB */}, 0, 0, newTrezorDriver) +func NewTrezorHubWithWebUSB() (*Hub, error) { + return newHub(TrezorScheme, 0x1209, []uint16{0x53c1 /* Trezor WebUSB */}, 0xffff /* No usage id on webusb, don't match unset (0) */, 0, newTrezorDriver) } // newHub creates a new hardware wallet manager for generic USB devices. func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) { - if !hid.Supported() { + if !usb.Supported() { return nil, errors.New("unsupported platform") } hub := &Hub{ @@ -139,7 +139,7 @@ func (hub *Hub) refreshWallets() { return } // Retrieve the current list of USB wallet devices - var devices []hid.DeviceInfo + var devices []usb.DeviceInfo if runtime.GOOS == "linux" { // hidapi on Linux opens the device during enumeration to retrieve some infos, @@ -154,7 +154,7 @@ func (hub *Hub) refreshWallets() { return } } - infos, err := hid.Enumerate(hub.vendorID, 0) + infos, err := usb.Enumerate(hub.vendorID, 0) if err != nil { if runtime.GOOS == "linux" { // See rationale before the enumeration why this is needed and only on Linux. @@ -165,8 +165,8 @@ func (hub *Hub) refreshWallets() { } for _, info := range infos { for _, id := range hub.productIDs { - _, pid, endpoint, _ /* FIXME usageID */ := info.IDs() - if pid == id && ( /* FIXME usageID == hub.usageID || */ endpoint == hub.endpointID) { + // Windows and Macos use UsageID matching, Linux uses Interface matching + if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { devices = append(devices, info) break } @@ -185,7 +185,7 @@ func (hub *Hub) refreshWallets() { ) for _, device := range devices { - url := accounts.URL{Scheme: hub.scheme, Path: device.GetPath()} + url := accounts.URL{Scheme: hub.scheme, Path: device.Path} // Drop wallets in front of the next device or those that failed for some reason for len(hub.wallets) > 0 { diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 34079c8812..1892097baf 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -36,8 +36,6 @@ import ( "github.com/golang/protobuf/proto" ) -var ErrInvalidDeviceType = errors.New("trezor: invalid device type") - // ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In // this case, the calling application should display a pinpad and send back the // encoded passphrase. diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index df38f953dd..ed786d9b42 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -31,7 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/karalabe/hid" + "github.com/karalabe/usb" ) // Maximum time between wallet health checks to detect USB unplugs. @@ -77,8 +77,8 @@ type wallet struct { driver driver // Hardware implementation of the low level device operations url *accounts.URL // Textual URL uniquely identifying this wallet - info hid.DeviceInfo // Known USB device infos about the wallet - device hid.Device // USB device advertising itself as a hardware wallet + info usb.DeviceInfo // Known USB device infos about the wallet + device usb.Device // USB device advertising itself as a hardware wallet accounts []accounts.Account // List of derive accounts pinned on the hardware wallet paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations diff --git a/node/config.go b/node/config.go index c864fea9c1..31d36f203f 100644 --- a/node/config.go +++ b/node/config.go @@ -501,15 +501,15 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { } else { backends = append(backends, ledgerhub) } - // Start a USB hub for Trezor hardware wallets - if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + // Start a USB hub for Trezor hardware wallets (HID version) + if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil { + log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err)) } else { backends = append(backends, trezorhub) } // Start a USB hub for Trezor hardware wallets (WebUSB version) - if trezorhub, err := usbwallet.NewWebUSBTrezorHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil { + log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err)) } else { backends = append(backends, trezorhub) } diff --git a/signer/core/api.go b/signer/core/api.go index 12bbd7bd3d..19b716d21a 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -144,19 +144,19 @@ func StartClefAccountManager(ksLocation string, nousb, lightKDF bool) *accounts. backends = append(backends, ledgerhub) log.Debug("Ledger support enabled") } - // Start a USB hub for Trezor hardware wallets - if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + // Start a USB hub for Trezor hardware wallets (HID version) + if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil { + log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err)) } else { backends = append(backends, trezorhub) - log.Debug("Trezor support enabled") + log.Debug("Trezor support enabled via HID") } // Start a USB hub for Trezor hardware wallets (WebUSB version) - if trezorhub, err := usbwallet.NewWebUSBTrezorHub(); err != nil { - log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil { + log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err)) } else { backends = append(backends, trezorhub) - log.Debug("Trezor support enabled") + log.Debug("Trezor support enabled via WebUSB") } } // Clef doesn't allow insecure http account unlock. diff --git a/vendor/github.com/karalabe/hid/LICENSE.md b/vendor/github.com/karalabe/hid/LICENSE.md deleted file mode 100644 index 230d1daeb6..0000000000 --- a/vendor/github.com/karalabe/hid/LICENSE.md +++ /dev/null @@ -1,8 +0,0 @@ -The components of `hid` are licensed as such: - - * `hidapi` is released under the [3-clause BSD](https://github.com/signal11/hidapi/blob/master/LICENSE-bsd.txt) license. - * `libusb` is released under the [GNU LGPL 2.1](https://github.com/libusb/libusb/blob/master/COPYING)license. - * `go.hid` is released under the [2-clause BSD](https://github.com/GeertJohan/go.hid/blob/master/LICENSE) license. - * `gowchar` is released under the [3-clause BSD](https://github.com/orofarne/gowchar/blob/master/LICENSE) license. - -Given the above, `hid` is licensed under GNU LGPL 2.1 or later on Linux and 3-clause BSD on other platforms. diff --git a/vendor/github.com/karalabe/hid/README.md b/vendor/github.com/karalabe/hid/README.md deleted file mode 100644 index 2851ffe420..0000000000 --- a/vendor/github.com/karalabe/hid/README.md +++ /dev/null @@ -1,53 +0,0 @@ -[![Travis][travisimg]][travisurl] -[![AppVeyor][appveyorimg]][appveyorurl] -[![GoDoc][docimg]][docurl] - -[travisimg]: https://travis-ci.org/karalabe/hid.svg?branch=master -[travisurl]: https://travis-ci.org/karalabe/hid -[appveyorimg]: https://ci.appveyor.com/api/projects/status/plroy54odykb0ch3/branch/master?svg=true -[appveyorurl]: https://ci.appveyor.com/project/karalabe/hid -[docimg]: https://godoc.org/github.com/karalabe/hid?status.svg -[docurl]: https://godoc.org/github.com/karalabe/hid - -# Gopher Interface Devices (USB HID) - -The `hid` package is a cross platform library for accessing and communicating with USB Human Interface -Devices (HID). It is an alternative package to [`gousb`](https://github.com/karalabe/gousb) for use -cases where devices support this ligher mode of operation (e.g. input devices, hardware crypto wallets). - -The package wraps [`hidapi`](https://github.com/signal11/hidapi) for accessing OS specific USB HID APIs -directly instead of using low level USB constructs, which might have permission issues on some platforms. -On Linux the package also wraps [`libusb`](https://github.com/libusb/libusb). Both of these dependencies -are vendored directly into the repository and wrapped using CGO, making the `hid` package self-contained -and go-gettable. - -Supported platforms at the moment are Linux, macOS and Windows (exclude constraints are also specified -for Android and iOS to allow smoother vendoring into cross platform projects). - -## Cross-compiling - -Using `go get` the embedded C library is compiled into the binary format of your host OS. Cross compiling to a different platform or architecture entails disabling CGO by default in Go, causing device enumeration `hid.Enumerate()` to yield no results. - -To cross compile a functional version of this library, you'll need to enable CGO during cross compilation via `CGO_ENABLED=1` and you'll need to install and set a cross compilation enabled C toolkit via `CC=your-cross-gcc`. - -## Acknowledgements - -Although the `hid` package is an implementation from scratch, it was heavily inspired by the existing -[`go.hid`](https://github.com/GeertJohan/go.hid) library, which seems abandoned since 2015; is incompatible -with Go 1.6+; and has various external dependencies. Given its inspirational roots, I thought it important -to give credit to the author of said package too. - -Wide character support in the `hid` package is done via the [`gowchar`](https://github.com/orofarne/gowchar) -library, unmaintained since 2013; non buildable with a modern Go release and failing `go vet` checks. As -such, `gowchar` was also vendored in inline (copyright headers and origins preserved). - -## License - -The components of `hid` are licensed as such: - - * `hidapi` is released under the [3-clause BSD](https://github.com/signal11/hidapi/blob/master/LICENSE-bsd.txt) license. - * `libusb` is released under the [GNU LGPL 2.1](https://github.com/libusb/libusb/blob/master/COPYING)license. - * `go.hid` is released under the [2-clause BSD](https://github.com/GeertJohan/go.hid/blob/master/LICENSE) license. - * `gowchar` is released under the [3-clause BSD](https://github.com/orofarne/gowchar/blob/master/LICENSE) license. - -Given the above, `hid` is licensed under GNU LGPL 2.1 or later on Linux and 3-clause BSD on other platforms. diff --git a/vendor/github.com/karalabe/hid/generic.go b/vendor/github.com/karalabe/hid/generic.go deleted file mode 100644 index 8de16fcbfc..0000000000 --- a/vendor/github.com/karalabe/hid/generic.go +++ /dev/null @@ -1,54 +0,0 @@ -// hid - Gopher Interface Devices (USB HID) -// Copyright (c) 2019 Péter Szilágyi, Guillaume Ballet. All rights reserved. - -package hid - -import ( - "C" -) - -type GenericEndpointDirection uint8 - -// List of endpoint direction types -const ( - GenericEndpointDirectionOut = 0x00 - GenericEndpointDirectionIn = 0x80 -) - -// List of endpoint attributes -const ( - GenericEndpointAttributeInterrupt = 3 -) - -// GenericEndpoint represents a USB endpoint -type GenericEndpoint struct { - Address uint8 - Direction GenericEndpointDirection - Attributes uint8 -} - -type GenericDeviceInfo struct { - Path string // Platform-specific device path - VendorID uint16 // Device Vendor ID - ProductID uint16 // Device Product ID - - device *GenericDevice - - Interface int - - Endpoints []GenericEndpoint -} - -func (gdi *GenericDeviceInfo) Type() DeviceType { - return DeviceTypeGeneric -} - -// Platform-specific device path -func (gdi *GenericDeviceInfo) GetPath() string { - return gdi.Path -} - -// IDs returns the vendor and product IDs for the device -func (gdi *GenericDeviceInfo) IDs() (uint16, uint16, int, uint16) { - return gdi.VendorID, gdi.ProductID, gdi.Interface, 0 -} diff --git a/vendor/github.com/karalabe/hid/hid.go b/vendor/github.com/karalabe/hid/hid.go deleted file mode 100644 index f929006d8b..0000000000 --- a/vendor/github.com/karalabe/hid/hid.go +++ /dev/null @@ -1,52 +0,0 @@ -// hid - Gopher Interface Devices (USB HID) -// Copyright (c) 2017 Péter Szilágyi. All rights reserved. -// -// This file is released under the 3-clause BSD license. Note however that Linux -// support depends on libusb, released under GNU LGPL 2.1 or later. - -// Package hid provides an interface for USB HID devices. -package hid - -import "errors" - -// ErrDeviceClosed is returned for operations where the device closed before or -// during the execution. -var ErrDeviceClosed = errors.New("hid: device closed") - -// ErrUnsupportedPlatform is returned for all operations where the underlying -// operating system is not supported by the library. -var ErrUnsupportedPlatform = errors.New("hid: unsupported platform") - -// HidDeviceInfo is a hidapi info structure. -type HidDeviceInfo struct { - Path string // Platform-specific device path - VendorID uint16 // Device Vendor ID - ProductID uint16 // Device Product ID - Release uint16 // Device Release Number in binary-coded decimal, also known as Device Version Number - Serial string // Serial Number - Manufacturer string // Manufacturer String - Product string // Product string - UsagePage uint16 // Usage Page for this Device/Interface (Windows/Mac only) - Usage uint16 // Usage for this Device/Interface (Windows/Mac only) - - // The USB interface which this logical device - // represents. Valid on both Linux implementations - // in all cases, and valid on the Windows implementation - // only if the device contains more than one interface. - Interface int -} - -// GetPath returns the system-dependent path to the device -func (hdi *HidDeviceInfo) GetPath() string { - return hdi.Path -} - -// IDs returns the vendor and product id of the device -func (hdi *HidDeviceInfo) IDs() (uint16, uint16, int, uint16) { - return hdi.VendorID, hdi.ProductID, hdi.Interface, hdi.UsagePage -} - -// Type returns the type of the device (HID or generic) -func (hdi *HidDeviceInfo) Type() DeviceType { - return DeviceTypeHID -} diff --git a/vendor/github.com/karalabe/hid/hid_disabled.go b/vendor/github.com/karalabe/hid/hid_disabled.go deleted file mode 100644 index ce98279531..0000000000 --- a/vendor/github.com/karalabe/hid/hid_disabled.go +++ /dev/null @@ -1,76 +0,0 @@ -// hid - Gopher Interface Devices (USB HID) -// Copyright (c) 2017 Péter Szilágyi. All rights reserved. -// -// This file is released under the 3-clause BSD license. Note however that Linux -// support depends on libusb, released under GNU LGPL 2.1 or later. - -// +build !freebsd,!linux,!darwin,!windows ios !cgo - -package hid - -// Supported returns whether this platform is supported by the HID library or not. -// The goal of this method is to allow programatically handling platforms that do -// not support USB HID and not having to fall back to build constraints. -func Supported() bool { - return false -} - -// Enumerate returns a list of all the HID devices attached to the system which -// match the vendor and product id. On platforms that this file implements the -// function is a noop and returns an empty list always. -func Enumerate(vendorID uint16, productID uint16) []DeviceInfo { - return nil -} - -// HidDevice is a live HID USB connected device handle. On platforms that this file -// implements the type lacks the actual HID device and all methods are noop. -type HidDevice struct { - HidDeviceInfo // Embed the infos for easier access -} - -// Open connects to an HID device by its path name. On platforms that this file -// implements the method just returns an error. -func (info HidDeviceInfo) Open() (*Device, error) { - return nil, ErrUnsupportedPlatform -} - -// Close releases the HID USB device handle. On platforms that this file implements -// the method is just a noop. -func (dev *HidDevice) Close() error { return ErrUnsupportedPlatform } - -// Write sends an output report to a HID device. On platforms that this file -// implements the method just returns an error. -func (dev *HidDevice) Write(b []byte) (int, error) { - return 0, ErrUnsupportedPlatform -} - -// Read retrieves an input report from a HID device. On platforms that this file -// implements the method just returns an error. -func (dev *HidDevice) Read(b []byte) (int, error) { - return 0, ErrUnsupportedPlatform -} - -// Open tries to open the USB device represented by the current DeviceInfo -func (gdi *GenericDeviceInfo) Open() (Device, error) { - return nil, ErrUnsupportedPlatform -} - -// GenericDevice represents a generic USB device -type GenericDevice struct { - *GenericDeviceInfo // Embed the infos for easier access -} - -// Write implements io.ReaderWriter -func (gd *GenericDevice) Write(b []byte) (int, error) { - return 0, ErrUnsupportedPlatform -} - -// Read implements io.ReaderWriter -func (gd *GenericDevice) Read(b []byte) (int, error) { - return 0, ErrUnsupportedPlatform -} - -// Close a previously opened generic USB device -func (gd *GenericDevice) Close() error { - return ErrUnsupportedPlatform -} diff --git a/vendor/github.com/karalabe/hid/hid_enabled.go b/vendor/github.com/karalabe/hid/hid_enabled.go deleted file mode 100644 index ee27ff98df..0000000000 --- a/vendor/github.com/karalabe/hid/hid_enabled.go +++ /dev/null @@ -1,459 +0,0 @@ -// hid - Gopher Interface Devices (USB HID) -// Copyright (c) 2017 Péter Szilágyi. All rights reserved. -// -// This file is released under the 3-clause BSD license. Note however that Linux -// support depends on libusb, released under LGNU GPL 2.1 or later. - -// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo - -package hid - -/* -#cgo CFLAGS: -I./hidapi/hidapi - -#cgo linux CFLAGS: -I./libusb/libusb -DDEFAULT_VISIBILITY="" -DOS_LINUX -D_GNU_SOURCE -DPOLL_NFDS_TYPE=int -#cgo linux,!android LDFLAGS: -lrt -#cgo darwin CFLAGS: -DOS_DARWIN -I./libusb/libusb -#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit -lusb-1.0.0 -#cgo windows CFLAGS: -DOS_WINDOWS -#cgo windows LDFLAGS: -lsetupapi -#cgo freebsd CFLAGS: -DOS_FREEBSD -#cgo freebsd LDFLAGS: -lusb - -#ifdef OS_LINUX - #include - #include "os/threads_posix.c" - #include "os/poll_posix.c" - - #include "os/linux_usbfs.c" - #include "os/linux_netlink.c" - - #include "core.c" - #include "descriptor.c" - #include "hotplug.c" - #include "io.c" - #include "strerror.c" - #include "sync.c" - - #include "hidapi/libusb/hid.c" -#elif OS_DARWIN - #include - #include "hidapi/mac/hid.c" -#elif OS_WINDOWS - #include "hidapi/windows/hid.c" -#elif OS_FREEBSD - #include - #include - #include "hidapi/libusb/hid.c" -#endif - -#if defined(OS_LINUX) || defined(OS_WINDOWS) - void copy_device_list_to_slice(struct libusb_device **data, struct libusb_device **list, int count) - { - int i; - struct libusb_device *current = *list; - for (i=0; ilist.next, struct libusb_device, list); - } - } -#elif defined(OS_DARWIN) || defined(OS_FREEBSD) - void copy_device_list_to_slice(struct libusb_device **data, struct libusb_device **list, int count) - { - int i; - // No memcopy because the struct size isn't available for a sizeof() - for (i=0; i "subsequent calls will cause the hid manager to release previously enumerated devices" -var enumerateLock sync.Mutex - -// Supported returns whether this platform is supported by the HID library or not. -// The goal of this method is to allow programatically handling platforms that do -// not support USB HID and not having to fall back to build constraints. -func Supported() bool { - return true -} - -// genericEnumerate performs generic USB device enumeration -func genericEnumerate(vendorID uint16, productID uint16) ([]DeviceInfo, error) { - var infos []DeviceInfo - var ctx *C.struct_libusb_context - errCode := int(C.libusb_init((**C.struct_libusb_context)(&ctx))) - if errCode < 0 { - return nil, fmt.Errorf("Error while initializing libusb: %d", errCode) - } - - var deviceListPtr **C.struct_libusb_device - count := C.libusb_get_device_list(ctx, (***C.struct_libusb_device)(&deviceListPtr)) - if count < 0 { - return nil, fmt.Errorf("Error code listing devices: %d", count) - } - defer C.libusb_free_device_list(deviceListPtr, C.int(count)) - - deviceList := make([]*C.struct_libusb_device, count) - dlhdr := (*reflect.SliceHeader)(unsafe.Pointer(&deviceList)) - C.copy_device_list_to_slice((**C.struct_libusb_device)(unsafe.Pointer(dlhdr.Data)), deviceListPtr, C.int(count)) - - for devnum, dev := range deviceList { - var desc C.struct_libusb_device_descriptor - errCode := int(C.libusb_get_device_descriptor(dev, &desc)) - if errCode < 0 { - return nil, fmt.Errorf("Error getting device descriptor for generic device %d: %d", devnum, errCode) - } - - // Start by checking the vendor id and the product id if necessary - if uint16(desc.idVendor) != vendorID || !(productID == 0 || uint16(desc.idProduct) == productID) { - continue - } - - // Skip HID devices, they will be handled later - switch desc.bDeviceClass { - case 0: - /* Device class is specified at interface level */ - for cfgnum := 0; cfgnum < int(desc.bNumConfigurations); cfgnum++ { - var cfgdesc *C.struct_libusb_config_descriptor - errCode = int(C.libusb_get_config_descriptor(dev, C.uint8_t(cfgnum), &cfgdesc)) - if errCode != 0 { - return nil, fmt.Errorf("Error getting device configuration #%d for generic device %d: %d", cfgnum, devnum, errCode) - } - - var ifs []C.struct_libusb_interface - ifshdr := (*reflect.SliceHeader)(unsafe.Pointer(&ifs)) - ifshdr.Cap = int(cfgdesc.bNumInterfaces) - ifshdr.Len = int(cfgdesc.bNumInterfaces) - ifshdr.Data = uintptr(unsafe.Pointer(cfgdesc._interface)) - - for ifnum, ifc := range ifs { - var ifdescs []C.struct_libusb_interface_descriptor - ifdshdr := (*reflect.SliceHeader)(unsafe.Pointer(&ifdescs)) - ifdshdr.Cap = int(ifc.num_altsetting) - ifdshdr.Len = int(ifc.num_altsetting) - ifdshdr.Data = uintptr(unsafe.Pointer(ifc.altsetting)) - - for _, alt := range ifdescs { - if alt.bInterfaceClass != 3 { - // Device isn't a HID interface, add them to the device list. - - var endps []C.struct_libusb_endpoint_descriptor - endpshdr := (*reflect.SliceHeader)(unsafe.Pointer(&endps)) - endpshdr.Cap = int(alt.bNumEndpoints) - endpshdr.Len = int(alt.bNumEndpoints) - endpshdr.Data = uintptr(unsafe.Pointer(alt.endpoint)) - - endpoints := make([]GenericEndpoint, alt.bNumEndpoints) - - for ne, endpoint := range endps { - endpoints[ne] = GenericEndpoint{ - Direction: GenericEndpointDirection(endpoint.bEndpointAddress) & GenericEndpointDirectionIn, - Address: uint8(endpoint.bEndpointAddress), - Attributes: uint8(endpoint.bmAttributes), - } - } - - info := &GenericDeviceInfo{ - Path: fmt.Sprintf("%x:%x:%d", vendorID, uint16(desc.idProduct), uint8(C.libusb_get_port_number(dev))), - VendorID: uint16(desc.idVendor), - ProductID: uint16(desc.idProduct), - device: &GenericDevice{ - device: dev, - }, - Endpoints: endpoints, - Interface: ifnum, - } - info.device.GenericDeviceInfo = info - infos = append(infos, info) - } - } - } - } - case 3: - // Device class is HID, skip it - continue - } - } - - return infos, nil -} - -// Enumerate returns a list of all the HID devices attached to the system which -// match the vendor and product id: -// - If the vendor id is set to 0 then any vendor matches. -// - If the product id is set to 0 then any product matches. -// - If the vendor and product id are both 0, all HID devices are returned. -func Enumerate(vendorID uint16, productID uint16) ([]DeviceInfo, error) { - enumerateLock.Lock() - defer enumerateLock.Unlock() - - infos, err := genericEnumerate(vendorID, productID) - - if err != nil { - return nil, err - } - - // Gather all device infos and ensure they are freed before returning - head := C.hid_enumerate(C.ushort(vendorID), C.ushort(productID)) - if head == nil { - return nil, nil - } - defer C.hid_free_enumeration(head) - - // Iterate the list and retrieve the device details - for ; head != nil; head = head.next { - info := &HidDeviceInfo{ - Path: C.GoString(head.path), - VendorID: uint16(head.vendor_id), - ProductID: uint16(head.product_id), - Release: uint16(head.release_number), - UsagePage: uint16(head.usage_page), - Usage: uint16(head.usage), - Interface: int(head.interface_number), - } - if head.serial_number != nil { - info.Serial, _ = wcharTToString(head.serial_number) - } - if head.product_string != nil { - info.Product, _ = wcharTToString(head.product_string) - } - if head.manufacturer_string != nil { - info.Manufacturer, _ = wcharTToString(head.manufacturer_string) - } - infos = append(infos, info) - } - return infos, nil -} - -// Open connects to an HID device by its path name. -func (info *HidDeviceInfo) Open() (Device, error) { - enumerateLock.Lock() - defer enumerateLock.Unlock() - - path := C.CString(info.Path) - defer C.free(unsafe.Pointer(path)) - - device := C.hid_open_path(path) - if device == nil { - return nil, errors.New("hidapi: failed to open device") - } - return &HidDevice{ - DeviceInfo: info, - device: device, - }, nil -} - -// HidDevice is a live HID USB connected device handle. -type HidDevice struct { - DeviceInfo // Embed the infos for easier access - - device *C.hid_device // Low level HID device to communicate through - lock sync.Mutex -} - -// Close releases the HID USB device handle. -func (dev *HidDevice) Close() error { - dev.lock.Lock() - defer dev.lock.Unlock() - - if dev.device != nil { - C.hid_close(dev.device) - dev.device = nil - } - return nil -} - -// Write sends an output report to a HID device. -// -// Write will send the data on the first OUT endpoint, if one exists. If it does -// not, it will send the data through the Control Endpoint (Endpoint 0). -func (dev *HidDevice) Write(b []byte) (int, error) { - // Abort if nothing to write - if len(b) == 0 { - return 0, nil - } - // Abort if device closed in between - dev.lock.Lock() - device := dev.device - dev.lock.Unlock() - - if device == nil { - return 0, ErrDeviceClosed - } - // Prepend a HID report ID on Windows, other OSes don't need it - var report []byte - if runtime.GOOS == "windows" { - report = append([]byte{0x00}, b...) - } else { - report = b - } - // Execute the write operation - written := int(C.hid_write(device, (*C.uchar)(&report[0]), C.size_t(len(report)))) - if written == -1 { - // If the write failed, verify if closed or other error - dev.lock.Lock() - device = dev.device - dev.lock.Unlock() - - if device == nil { - return 0, ErrDeviceClosed - } - // Device not closed, some other error occurred - message := C.hid_error(device) - if message == nil { - return 0, errors.New("hidapi: unknown failure") - } - failure, _ := wcharTToString(message) - return 0, errors.New("hidapi: " + failure) - } - return written, nil -} - -// Read retrieves an input report from a HID device. -func (dev *HidDevice) Read(b []byte) (int, error) { - // Aborth if nothing to read - if len(b) == 0 { - return 0, nil - } - // Abort if device closed in between - dev.lock.Lock() - device := dev.device - dev.lock.Unlock() - - if device == nil { - return 0, ErrDeviceClosed - } - // Execute the read operation - read := int(C.hid_read(device, (*C.uchar)(&b[0]), C.size_t(len(b)))) - if read == -1 { - // If the read failed, verify if closed or other error - dev.lock.Lock() - device = dev.device - dev.lock.Unlock() - - if device == nil { - return 0, ErrDeviceClosed - } - // Device not closed, some other error occurred - message := C.hid_error(device) - if message == nil { - return 0, errors.New("hidapi: unknown failure") - } - failure, _ := wcharTToString(message) - return 0, errors.New("hidapi: " + failure) - } - return read, nil -} - -// Type identify the device as a HID device -func (dev *HidDevice) Type() DeviceType { - return dev.DeviceInfo.Type() -} - -// Open tries to open the USB device represented by the current DeviceInfo -func (gdi *GenericDeviceInfo) Open() (Device, error) { - var handle *C.struct_libusb_device_handle - errCode := int(C.libusb_open(gdi.device.device, (**C.struct_libusb_device_handle)(&handle))) - if errCode < 0 { - return nil, fmt.Errorf("Error opening generic USB device %v, code %d", gdi.device.handle, errCode) - } - - gdi.device.handle = handle - // QUESTION: ai-je deja initialie le GDI ? - // GenericDeviceInfo: gdi, - // handle: handle, - // } - - for _, endpoint := range gdi.Endpoints { - switch { - case endpoint.Direction == GenericEndpointDirectionOut && endpoint.Attributes == GenericEndpointAttributeInterrupt: - gdi.device.WEndpoint = endpoint.Address - case endpoint.Direction == GenericEndpointDirectionIn && endpoint.Attributes == GenericEndpointAttributeInterrupt: - gdi.device.REndpoint = endpoint.Address - } - } - - if gdi.device.REndpoint == 0 || gdi.device.WEndpoint == 0 { - return nil, fmt.Errorf("Missing endpoint in device %#x:%#x:%d", gdi.VendorID, gdi.ProductID, gdi.Interface) - } - - return gdi.device, nil -} - -// GenericDevice represents a generic USB device -type GenericDevice struct { - *GenericDeviceInfo // Embed the infos for easier access - - REndpoint uint8 - WEndpoint uint8 - - device *C.struct_libusb_device - handle *C.struct_libusb_device_handle - lock sync.Mutex -} - -// Write implements io.ReaderWriter -func (gd *GenericDevice) Write(b []byte) (int, error) { - gd.lock.Lock() - defer gd.lock.Unlock() - - out, err := interruptTransfer(gd.handle, gd.WEndpoint, b) - return len(out), err -} - -// Read implements io.ReaderWriter -func (gd *GenericDevice) Read(b []byte) (int, error) { - gd.lock.Lock() - defer gd.lock.Unlock() - - out, err := interruptTransfer(gd.handle, gd.REndpoint, b) - return len(out), err -} - -// Close a previously opened generic USB device -func (gd *GenericDevice) Close() error { - gd.lock.Lock() - defer gd.lock.Unlock() - - if gd.handle != nil { - C.libusb_close(gd.handle) - gd.handle = nil - } - - return nil -} - -// interruptTransfer is a helpler function for libusb's interrupt transfer function -func interruptTransfer(handle *C.struct_libusb_device_handle, endpoint uint8, data []byte) ([]byte, error) { - var transferred C.int - errCode := int(C.libusb_interrupt_transfer(handle, (C.uchar)(endpoint), (*C.uchar)(&data[0]), (C.int)(len(data)), &transferred, (C.uint)(0))) - if errCode != 0 { - return nil, fmt.Errorf("Interrupt transfer error: %s", C.GoString(C.usb_strerror(C.int(errCode)))) - } - return data[:int(transferred)], nil -} diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c deleted file mode 100644 index 9825607512..0000000000 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * poll_windows: poll compatibility wrapper for Windows - * Copyright © 2012-2013 RealVNC Ltd. - * Copyright © 2009-2010 Pete Batard - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * poll() and pipe() Windows compatibility layer for libusb 1.0 - * - * The way this layer works is by using OVERLAPPED with async I/O transfers, as - * OVERLAPPED have an associated event which is flagged for I/O completion. - * - * For USB pollable async I/O, you would typically: - * - obtain a Windows HANDLE to a file or device that has been opened in - * OVERLAPPED mode - * - call usbi_create_fd with this handle to obtain a custom fd. - * Note that if you need simultaneous R/W access, you need to call create_fd - * twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate - * pollable fds - * - leave the core functions call the poll routine and flag POLLIN/POLLOUT - * - * The pipe pollable synchronous I/O works using the overlapped event associated - * with a fake pipe. The read/write functions are only meant to be used in that - * context. - */ -#include - -#include -#include -#include - -#include "libusbi.h" - -// Uncomment to debug the polling layer -//#define DEBUG_POLL_WINDOWS -#if defined(DEBUG_POLL_WINDOWS) -#define poll_dbg usbi_dbg -#else -// MSVC++ < 2005 cannot use a variadic argument and non MSVC -// compilers produce warnings if parenthesis are omitted. -#if defined(_MSC_VER) && (_MSC_VER < 1400) -#define poll_dbg -#else -#define poll_dbg(...) -#endif -#endif - -#if defined(_PREFAST_) -#pragma warning(disable:28719) -#endif - -#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) - -// public fd data -const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE}; -struct winfd poll_fd[MAX_FDS]; -// internal fd data -struct { - CRITICAL_SECTION mutex; // lock for fds - // Additional variables for XP CancelIoEx partial emulation - HANDLE original_handle; - DWORD thread_id; -} _poll_fd[MAX_FDS]; - -// globals -BOOLEAN is_polling_set = FALSE; -LONG pipe_number = 0; -static volatile LONG compat_spinlock = 0; - -#if !defined(_WIN32_WCE) -// CancelIoEx, available on Vista and later only, provides the ability to cancel -// a single transfer (OVERLAPPED) when used. As it may not be part of any of the -// platform headers, we hook into the Kernel32 system DLL directly to seek it. -static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; -#define Use_Duplicate_Handles (pCancelIoEx == NULL) - -static inline void setup_cancel_io(void) -{ - HMODULE hKernel32 = GetModuleHandleA("KERNEL32"); - if (hKernel32 != NULL) { - pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) - GetProcAddress(hKernel32, "CancelIoEx"); - } - usbi_dbg("Will use CancelIo%s for I/O cancellation", - Use_Duplicate_Handles?"":"Ex"); -} - -static inline BOOL cancel_io(int _index) -{ - if ((_index < 0) || (_index >= MAX_FDS)) { - return FALSE; - } - - if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) { - return TRUE; - } - if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) { - // Cancel outstanding transfer via the specific callback - (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer); - return TRUE; - } - if (pCancelIoEx != NULL) { - return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped); - } - if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { - return CancelIo(poll_fd[_index].handle); - } - usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); - return FALSE; -} -#else -#define Use_Duplicate_Handles FALSE - -static __inline void setup_cancel_io() -{ - // No setup needed on WinCE -} - -static __inline BOOL cancel_io(int _index) -{ - if ((_index < 0) || (_index >= MAX_FDS)) { - return FALSE; - } - if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) { - return TRUE; - } - if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) { - // Cancel outstanding transfer via the specific callback - (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer); - } - return TRUE; -} -#endif - -// Init -void init_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (!is_polling_set) { - setup_cancel_io(); - for (i=0; ihEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(overlapped->hEvent == NULL) { - free (overlapped); - return NULL; - } - return overlapped; -} - -static void free_overlapped(OVERLAPPED *overlapped) -{ - if (overlapped == NULL) - return; - - if ( (overlapped->hEvent != 0) - && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { - CloseHandle(overlapped->hEvent); - } - free(overlapped); -} - -void exit_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (is_polling_set) { - is_polling_set = FALSE; - - for (i=0; iInternal = STATUS_PENDING; - overlapped->InternalHigh = 0; - - for (i=0; i= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - - // Use index as the unique fd number - poll_fd[i].fd = i; - // Read end of the "pipe" - filedes[0] = poll_fd[i].fd; - // We can use the same handle for both ends - filedes[1] = filedes[0]; - - poll_fd[i].handle = DUMMY_HANDLE; - poll_fd[i].overlapped = overlapped; - // There's no polling on the write end, so we just use READ for our needs - poll_fd[i].rw = RW_READ; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - LeaveCriticalSection(&_poll_fd[i].mutex); - return 0; - } - } - free_overlapped(overlapped); - return -1; -} - -/* - * Create both an fd and an OVERLAPPED from an open Windows handle, so that - * it can be used with our polling function - * The handle MUST support overlapped transfers (usually requires CreateFile - * with FILE_FLAG_OVERLAPPED) - * Return a pollable file descriptor struct, or INVALID_WINFD on error - * - * Note that the fd returned by this function is a per-transfer fd, rather - * than a per-session fd and cannot be used for anything else but our - * custom functions (the fd itself points to the NUL: device) - * if you plan to do R/W on the same handle, you MUST create 2 fds: one for - * read and one for write. Using a single R/W fd is unsupported and will - * produce unexpected results - */ -struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn) -{ - int i; - struct winfd wfd = INVALID_WINFD; - OVERLAPPED* overlapped = NULL; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { - return INVALID_WINFD; - } - - wfd.itransfer = itransfer; - wfd.cancel_fn = cancel_fn; - - if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) { - usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported. " - "If you want to poll for R/W simultaneously, create multiple fds from the same handle."); - return INVALID_WINFD; - } - if (access_mode == RW_READ) { - wfd.rw = RW_READ; - } else { - wfd.rw = RW_WRITE; - } - - overlapped = create_overlapped(); - if(overlapped == NULL) { - return INVALID_WINFD; - } - - for (i=0; i= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - // Use index as the unique fd number - wfd.fd = i; - // Attempt to emulate some of the CancelIoEx behaviour on platforms - // that don't have it - if (Use_Duplicate_Handles) { - _poll_fd[i].thread_id = GetCurrentThreadId(); - if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), - &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { - usbi_dbg("could not duplicate handle for CancelIo - using original one"); - wfd.handle = handle; - // Make sure we won't close the original handle on fd deletion then - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - } else { - _poll_fd[i].original_handle = handle; - } - } else { - wfd.handle = handle; - } - wfd.overlapped = overlapped; - memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - free_overlapped(overlapped); - return INVALID_WINFD; -} - -static void _free_index(int _index) -{ - // Cancel any async IO (Don't care about the validity of our handles for this) - cancel_io(_index); - // close the duplicate handle (if we have an actual duplicate) - if (Use_Duplicate_Handles) { - if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[_index].handle); - } - _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[_index].thread_id = 0; - } - free_overlapped(poll_fd[_index].overlapped); - poll_fd[_index] = INVALID_WINFD; -} - -/* - * Release a pollable file descriptor. - * - * Note that the associated Windows handle is not closed by this call - */ -void usbi_free_fd(struct winfd *wfd) -{ - int _index; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(wfd->fd); - if (_index < 0) { - return; - } - _free_index(_index); - *wfd = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[_index].mutex); -} - -/* - * The functions below perform various conversions between fd, handle and OVERLAPPED - */ -struct winfd fd_to_winfd(int fd) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (fd < 0) - return INVALID_WINFD; - - for (i=0; i= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - usbi_warn(NULL, "invalid fd"); - triggered = -1; - goto poll_exit; - } - - // IN or OUT must match our fd direction - if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLIN on fd without READ access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - // The following macro only works if overlapped I/O was reported pending - if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) - || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { - poll_dbg(" completed"); - // checks above should ensure this works: - fds[i].revents = fds[i].events; - triggered++; - } else { - handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; - handle_to_index[nb_handles_to_wait_on] = i; - nb_handles_to_wait_on++; - } - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - - // If nothing was triggered, wait on all fds that require it - if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { - if (timeout < 0) { - poll_dbg("starting infinite wait for %u handles...", (unsigned int)nb_handles_to_wait_on); - } else { - poll_dbg("starting %d ms wait for %u handles...", timeout, (unsigned int)nb_handles_to_wait_on); - } - ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, - FALSE, (timeout<0)?INFINITE:(DWORD)timeout); - object_index = ret-WAIT_OBJECT_0; - if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { - poll_dbg(" completed after wait"); - i = handle_to_index[object_index]; - _index = _fd_to_index_and_lock(fds[i].fd); - fds[i].revents = fds[i].events; - triggered++; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - } else if (ret == WAIT_TIMEOUT) { - poll_dbg(" timed out"); - triggered = 0; // 0 = timeout - } else { - errno = EIO; - triggered = -1; // error - } - } - -poll_exit: - if (handles_to_wait_on != NULL) { - free(handles_to_wait_on); - } - if (handle_to_index != NULL) { - free(handle_to_index); - } - return triggered; -} - -/* - * close a fake pipe fd - */ -int usbi_close(int fd) -{ - int _index; - int r = -1; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; - } else { - free_overlapped(poll_fd[_index].overlapped); - poll_fd[_index] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - return r; -} - -/* - * synchronous write for fake "pipe" signaling - */ -ssize_t usbi_write(int fd, const void *buf, size_t count) -{ - int _index; - UNUSED(buf); - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - _index = _fd_to_index_and_lock(fd); - - if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { - errno = EBADF; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - return -1; - } - - poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId()); - SetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; - // If two threads write on the pipe at the same time, we need to - // process two separate reads => use the overlapped as a counter - poll_fd[_index].overlapped->InternalHigh++; - - LeaveCriticalSection(&_poll_fd[_index].mutex); - return sizeof(unsigned char); -} - -/* - * synchronous read for fake "pipe" signaling - */ -ssize_t usbi_read(int fd, void *buf, size_t count) -{ - int _index; - ssize_t r = -1; - UNUSED(buf); - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; - return -1; - } - - if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { - usbi_warn(NULL, "waiting for event failed: %u", (unsigned int)GetLastError()); - errno = EIO; - goto out; - } - - poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId()); - poll_fd[_index].overlapped->InternalHigh--; - // Don't reset unless we don't have any more events to process - if (poll_fd[_index].overlapped->InternalHigh <= 0) { - ResetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_PENDING; - } - - r = sizeof(unsigned char); - -out: - LeaveCriticalSection(&_poll_fd[_index].mutex); - return r; -} diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h deleted file mode 100644 index 4c1514ea61..0000000000 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * libusb synchronization using POSIX Threads - * - * Copyright © 2010 Peter Stuge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_THREADS_POSIX_H -#define LIBUSB_THREADS_POSIX_H - -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#define usbi_mutex_static_t pthread_mutex_t -#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define usbi_mutex_static_lock pthread_mutex_lock -#define usbi_mutex_static_unlock pthread_mutex_unlock - -#define usbi_mutex_t pthread_mutex_t -#define usbi_mutex_init(mutex) pthread_mutex_init((mutex), NULL) -#define usbi_mutex_lock pthread_mutex_lock -#define usbi_mutex_unlock pthread_mutex_unlock -#define usbi_mutex_trylock pthread_mutex_trylock -#define usbi_mutex_destroy pthread_mutex_destroy - -#define usbi_cond_t pthread_cond_t -#define usbi_cond_init(cond) pthread_cond_init((cond), NULL) -#define usbi_cond_wait pthread_cond_wait -#define usbi_cond_broadcast pthread_cond_broadcast -#define usbi_cond_destroy pthread_cond_destroy - -#define usbi_tls_key_t pthread_key_t -#define usbi_tls_key_create(key) pthread_key_create((key), NULL) -#define usbi_tls_key_get pthread_getspecific -#define usbi_tls_key_set pthread_setspecific -#define usbi_tls_key_delete pthread_key_delete - -int usbi_get_tid(void); - -#endif /* LIBUSB_THREADS_POSIX_H */ diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c deleted file mode 100644 index 7c2e52dba6..0000000000 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * libusb synchronization on Microsoft Windows - * - * Copyright © 2010 Michael Plante - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include -#include - -#include "libusbi.h" - -struct usbi_cond_perthread { - struct list_head list; - DWORD tid; - HANDLE event; -}; - -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) -{ - if (!mutex) - return EINVAL; - while (InterlockedExchange(mutex, 1) == 1) - SleepEx(0, TRUE); - return 0; -} - -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) -{ - if (!mutex) - return EINVAL; - InterlockedExchange(mutex, 0); - return 0; -} - -int usbi_mutex_init(usbi_mutex_t *mutex) -{ - if (!mutex) - return EINVAL; - *mutex = CreateMutex(NULL, FALSE, NULL); - if (!*mutex) - return ENOMEM; - return 0; -} - -int usbi_mutex_lock(usbi_mutex_t *mutex) -{ - DWORD result; - - if (!mutex) - return EINVAL; - result = WaitForSingleObject(*mutex, INFINITE); - if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - else - return EINVAL; // don't know how this would happen - // so don't know proper errno -} - -int usbi_mutex_unlock(usbi_mutex_t *mutex) -{ - if (!mutex) - return EINVAL; - if (ReleaseMutex(*mutex)) - return 0; - else - return EPERM; -} - -int usbi_mutex_trylock(usbi_mutex_t *mutex) -{ - DWORD result; - - if (!mutex) - return EINVAL; - result = WaitForSingleObject(*mutex, 0); - if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - else if (result == WAIT_TIMEOUT) - return EBUSY; - else - return EINVAL; // don't know how this would happen - // so don't know proper error -} - -int usbi_mutex_destroy(usbi_mutex_t *mutex) -{ - // It is not clear if CloseHandle failure is due to failure to unlock. - // If so, this should be errno=EBUSY. - if (!mutex || !CloseHandle(*mutex)) - return EINVAL; - *mutex = NULL; - return 0; -} - -int usbi_cond_init(usbi_cond_t *cond) -{ - if (!cond) - return EINVAL; - list_init(&cond->waiters); - list_init(&cond->not_waiting); - return 0; -} - -int usbi_cond_destroy(usbi_cond_t *cond) -{ - // This assumes no one is using this anymore. The check MAY NOT BE safe. - struct usbi_cond_perthread *pos, *next_pos; - - if(!cond) - return EINVAL; - if (!list_empty(&cond->waiters)) - return EBUSY; // (!see above!) - list_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - CloseHandle(pos->event); - list_del(&pos->list); - free(pos); - } - return 0; -} - -int usbi_cond_broadcast(usbi_cond_t *cond) -{ - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - int fail = 0; - struct usbi_cond_perthread *pos; - - if (!cond) - return EINVAL; - list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) { - if (!SetEvent(pos->event)) - fail = 1; - } - // The wait function will remove its respective item from the list. - return fail ? EINVAL : 0; -} - -__inline static int usbi_cond_intwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, DWORD timeout_ms) -{ - struct usbi_cond_perthread *pos; - int r, found = 0; - DWORD r2, tid = GetCurrentThreadId(); - - if (!cond || !mutex) - return EINVAL; - list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - if(tid == pos->tid) { - found = 1; - break; - } - } - - if (!found) { - pos = calloc(1, sizeof(struct usbi_cond_perthread)); - if (!pos) - return ENOMEM; // This errno is not POSIX-allowed. - pos->tid = tid; - pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset. - if (!pos->event) { - free(pos); - return ENOMEM; - } - list_add(&pos->list, &cond->not_waiting); - } - - list_del(&pos->list); // remove from not_waiting list. - list_add(&pos->list, &cond->waiters); - - r = usbi_mutex_unlock(mutex); - if (r) - return r; - - r2 = WaitForSingleObject(pos->event, timeout_ms); - r = usbi_mutex_lock(mutex); - if (r) - return r; - - list_del(&pos->list); - list_add(&pos->list, &cond->not_waiting); - - if (r2 == WAIT_OBJECT_0) - return 0; - else if (r2 == WAIT_TIMEOUT) - return ETIMEDOUT; - else - return EINVAL; -} -// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot! -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) -{ - return usbi_cond_intwait(cond, mutex, INFINITE); -} - -int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, const struct timeval *tv) -{ - DWORD millis; - - millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000); - /* round up to next millisecond */ - if (tv->tv_usec % 1000) - millis++; - return usbi_cond_intwait(cond, mutex, millis); -} - -int usbi_tls_key_create(usbi_tls_key_t *key) -{ - if (!key) - return EINVAL; - *key = TlsAlloc(); - if (*key == TLS_OUT_OF_INDEXES) - return ENOMEM; - else - return 0; -} - -void *usbi_tls_key_get(usbi_tls_key_t key) -{ - return TlsGetValue(key); -} - -int usbi_tls_key_set(usbi_tls_key_t key, void *value) -{ - if (TlsSetValue(key, value)) - return 0; - else - return EINVAL; -} - -int usbi_tls_key_delete(usbi_tls_key_t key) -{ - if (TlsFree(key)) - return 0; - else - return EINVAL; -} - -int usbi_get_tid(void) -{ - return (int)GetCurrentThreadId(); -} diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h deleted file mode 100644 index 52ea8708b0..0000000000 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Windows backend common header for libusb 1.0 - * - * This file brings together header code common between - * the desktop Windows backends. - * Copyright © 2012-2013 RealVNC Ltd. - * Copyright © 2009-2012 Pete Batard - * With contributions from Michael Plante, Orin Eman et al. - * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer - * Major code testing contribution by Xiaofan Chen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -// Missing from MinGW -#if !defined(FACILITY_SETUPAPI) -#define FACILITY_SETUPAPI 15 -#endif - -typedef struct USB_CONFIGURATION_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - USHORT wTotalLength; - UCHAR bNumInterfaces; - UCHAR bConfigurationValue; - UCHAR iConfiguration; - UCHAR bmAttributes; - UCHAR MaxPower; -} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; - -typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; - -int windows_common_init(struct libusb_context *ctx); -void windows_common_exit(void); - -unsigned long htab_hash(const char *str); -int windows_clock_gettime(int clk_id, struct timespec *tp); - -void windows_clear_transfer_priv(struct usbi_transfer *itransfer); -int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); -struct winfd *windows_get_fd(struct usbi_transfer *transfer); -void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size); - -void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size); -int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready); - -#if defined(ENABLE_LOGGING) -const char *windows_error_str(DWORD error_code); -#endif diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c deleted file mode 100644 index 0dce0ea6cb..0000000000 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c +++ /dev/null @@ -1,4290 +0,0 @@ -/* - * windows backend for libusb 1.0 - * Copyright © 2009-2012 Pete Batard - * With contributions from Michael Plante, Orin Eman et al. - * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer - * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software - * Hash table functions adapted from glibc, by Ulrich Drepper et al. - * Major code testing contribution by Xiaofan Chen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#if !defined(USE_USBDK) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libusbi.h" -#include "poll_windows.h" -#include "windows_winusb.h" - -#define HANDLE_VALID(h) (((h) != 0) && ((h) != INVALID_HANDLE_VALUE)) - -// The 2 macros below are used in conjunction with safe loops. -#define LOOP_CHECK(fcall) \ - { \ - r = fcall; \ - if (r != LIBUSB_SUCCESS) \ - continue; \ - } -#define LOOP_BREAK(err) \ - { \ - r = err; \ - continue; \ - } - -// WinUSB-like API prototypes -static int winusbx_init(int sub_api, struct libusb_context *ctx); -static int winusbx_exit(int sub_api); -static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle); -static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle); -static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); -// HID API prototypes -static int hid_init(int sub_api, struct libusb_context *ctx); -static int hid_exit(int sub_api); -static int hid_open(int sub_api, struct libusb_device_handle *dev_handle); -static void hid_close(int sub_api, struct libusb_device_handle *dev_handle); -static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); -static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); -static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); -// Composite API prototypes -static int composite_init(int sub_api, struct libusb_context *ctx); -static int composite_exit(int sub_api); -static int composite_open(int sub_api, struct libusb_device_handle *dev_handle); -static void composite_close(int sub_api, struct libusb_device_handle *dev_handle); -static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); -static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); -static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); -static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer); -static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); - - -// Global variables -int windows_version = WINDOWS_UNDEFINED; -static char windows_version_str[128] = "Undefined"; -// Concurrency -static int concurrent_usage = -1; -static usbi_mutex_t autoclaim_lock; -// API globals -#define CHECK_WINUSBX_AVAILABLE(sub_api) \ - do { \ - if (sub_api == SUB_API_NOTSET) \ - sub_api = priv->sub_api; \ - if (!WinUSBX[sub_api].initialized) \ - return LIBUSB_ERROR_ACCESS; \ - } while(0) - -static HMODULE WinUSBX_handle = NULL; -static struct winusb_interface WinUSBX[SUB_API_MAX]; -static const char *sub_api_name[SUB_API_MAX] = WINUSBX_DRV_NAMES; - -static bool api_hid_available = false; -#define CHECK_HID_AVAILABLE \ - do { \ - if (!api_hid_available) \ - return LIBUSB_ERROR_ACCESS; \ - } while (0) - -static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2) -{ - if ((guid1 != NULL) && (guid2 != NULL)) - return (memcmp(guid1, guid2, sizeof(GUID)) == 0); - - return false; -} - -#if defined(ENABLE_LOGGING) -static char *guid_to_string(const GUID *guid) -{ - static char guid_string[MAX_GUID_STRING_LENGTH]; - - if (guid == NULL) - return NULL; - - sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - (unsigned int)guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); - - return guid_string; -} -#endif - -/* - * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes. - * Return an allocated sanitized string or NULL on error. - */ -static char *sanitize_path(const char *path) -{ - const char root_prefix[] = { '\\', '\\', '.', '\\' }; - size_t j, size; - char *ret_path; - size_t add_root = 0; - - if (path == NULL) - return NULL; - - size = strlen(path) + 1; - - // Microsoft indiscriminately uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes. - if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\')) - || ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) { - add_root = sizeof(root_prefix); - size += add_root; - } - - ret_path = malloc(size); - if (ret_path == NULL) - return NULL; - - strcpy(&ret_path[add_root], path); - - // Ensure consistency with root prefix - memcpy(ret_path, root_prefix, sizeof(root_prefix)); - - // Same goes for '\' and '#' after the root prefix. Ensure '#' is used - for (j = sizeof(root_prefix); j < size; j++) { - ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too - if (ret_path[j] == '\\') - ret_path[j] = '#'; - } - - return ret_path; -} - -/* - * Cfgmgr32, OLE32 and SetupAPI DLL functions - */ -static int init_dlls(void) -{ - DLL_GET_HANDLE(Cfgmgr32); - DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE); - DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE); - DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Sibling, TRUE); - DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Device_IDA, TRUE); - - // Prefixed to avoid conflict with header files - DLL_GET_HANDLE(AdvAPI32); - DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE); - DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE); - - DLL_GET_HANDLE(Kernel32); - DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE); - - DLL_GET_HANDLE(OLE32); - DLL_LOAD_FUNC_PREFIXED(OLE32, p, CLSIDFromString, TRUE); - - DLL_GET_HANDLE(SetupAPI); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE); - DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE); - - return LIBUSB_SUCCESS; -} - -static void exit_dlls(void) -{ - DLL_FREE_HANDLE(Cfgmgr32); - DLL_FREE_HANDLE(AdvAPI32); - DLL_FREE_HANDLE(Kernel32); - DLL_FREE_HANDLE(OLE32); - DLL_FREE_HANDLE(SetupAPI); -} - -/* - * enumerate interfaces for the whole USB class - * - * Parameters: - * dev_info: a pointer to a dev_info list - * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) - * usb_class: the generic USB class for which to retrieve interface details - * index: zero based index of the interface in the device info list - * - * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and call this function repeatedly using the same guid (with an - * incremented index starting at zero) until all interfaces have been returned. - */ -static bool get_devinfo_data(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char *usb_class, unsigned _index) -{ - if (_index <= 0) { - *dev_info = pSetupDiGetClassDevsA(NULL, usb_class, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); - if (*dev_info == INVALID_HANDLE_VALUE) - return false; - } - - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return false; - } - return true; -} - -/* - * enumerate interfaces for a specific GUID - * - * Parameters: - * dev_info: a pointer to a dev_info list - * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) - * guid: the GUID for which to retrieve interface details - * index: zero based index of the interface in the device info list - * - * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and call this function repeatedly using the same guid (with an - * incremented index starting at zero) until all interfaces have been returned. - */ -static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index) -{ - SP_DEVICE_INTERFACE_DATA dev_interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details; - DWORD size; - - if (_index <= 0) - *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - - if (dev_info_data != NULL) { - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - } - - dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) - usbi_err(ctx, "Could not obtain interface data for index %u: %s", - _index, windows_error_str(0)); - - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - - // Read interface data (dummy + actual) to access the device path - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { - // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", - _index, windows_error_str(0)); - goto err_exit; - } - } else { - usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); - goto err_exit; - } - - dev_interface_details = calloc(1, size); - if (dev_interface_details == NULL) { - usbi_err(ctx, "could not allocate interface data for index %u.", _index); - goto err_exit; - } - - dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, - dev_interface_details, size, &size, NULL)) { - usbi_err(ctx, "could not access interface data (actual) for index %u: %s", - _index, windows_error_str(0)); - } - - return dev_interface_details; - -err_exit: - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; -} - -/* For libusb0 filter */ -static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index, char *filter_path) -{ - SP_DEVICE_INTERFACE_DATA dev_interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details; - DWORD size; - - if (_index <= 0) - *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - - if (dev_info_data != NULL) { - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - } - - dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) - usbi_err(ctx, "Could not obtain interface data for index %u: %s", - _index, windows_error_str(0)); - - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - - // Read interface data (dummy + actual) to access the device path - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { - // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", - _index, windows_error_str(0)); - goto err_exit; - } - } else { - usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); - goto err_exit; - } - - dev_interface_details = calloc(1, size); - if (dev_interface_details == NULL) { - usbi_err(ctx, "could not allocate interface data for index %u.", _index); - goto err_exit; - } - - dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, dev_interface_details, size, &size, NULL)) - usbi_err(ctx, "could not access interface data (actual) for index %u: %s", - _index, windows_error_str(0)); - - // [trobinso] lookup the libusb0 symbolic index. - if (dev_interface_details) { - HKEY hkey_device_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ); - if (hkey_device_interface != INVALID_HANDLE_VALUE) { - DWORD libusb0_symboliclink_index = 0; - DWORD value_length = sizeof(DWORD); - DWORD value_type = 0; - LONG status; - - status = pRegQueryValueExW(hkey_device_interface, L"LUsb0", NULL, &value_type, - (LPBYTE)&libusb0_symboliclink_index, &value_length); - if (status == ERROR_SUCCESS) { - if (libusb0_symboliclink_index < 256) { - // libusb0.sys is connected to this device instance. - // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter. - sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index); - usbi_dbg("assigned libusb0 symbolic link %s", filter_path); - } else { - // libusb0.sys was connected to this device instance at one time; but not anymore. - } - } - pRegCloseKey(hkey_device_interface); - } - } - - return dev_interface_details; - -err_exit: - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; -} - -/* - * Returns the session ID of a device's nth level ancestor - * If there's no device at the nth level, return 0 - */ -static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level) -{ - DWORD parent_devinst; - unsigned long session_id; - char *sanitized_path; - char path[MAX_PATH_LENGTH]; - unsigned i; - - if (level < 1) - return 0; - - for (i = 0; i < level; i++) { - if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS) - return 0; - devinst = parent_devinst; - } - - if (CM_Get_Device_IDA(devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) - return 0; - - // TODO: (post hotplug): try without sanitizing - sanitized_path = sanitize_path(path); - if (sanitized_path == NULL) - return 0; - - session_id = htab_hash(sanitized_path); - free(sanitized_path); - return session_id; -} - -/* - * Determine which interface the given endpoint address belongs to - */ -static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep) -{ - const struct libusb_interface *intf; - const struct libusb_interface_descriptor *intf_desc; - int i, j, k; - - for (i = 0; i < conf_desc->bNumInterfaces; i++) { - intf = &conf_desc->interface[i]; - for (j = 0; j < intf->num_altsetting; j++) { - intf_desc = &intf->altsetting[j]; - for (k = 0; k < intf_desc->bNumEndpoints; k++) { - if (intf_desc->endpoint[k].bEndpointAddress == ep) { - usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i); - return intf_desc->bInterfaceNumber; - } - } - } - } - - usbi_dbg("endpoint %02X not found on any interface", ep); - return LIBUSB_ERROR_NOT_FOUND; -} - -/* - * Populate the endpoints addresses of the device_priv interface helper structs - */ -static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - int i, r; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct libusb_config_descriptor *conf_desc; - const struct libusb_interface_descriptor *if_desc; - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc); - if (r != LIBUSB_SUCCESS) { - usbi_warn(ctx, "could not read config descriptor: error %d", r); - return r; - } - - if_desc = &conf_desc->interface[iface].altsetting[altsetting]; - safe_free(priv->usb_interface[iface].endpoint); - - if (if_desc->bNumEndpoints == 0) { - usbi_dbg("no endpoints found for interface %d", iface); - libusb_free_config_descriptor(conf_desc); - return LIBUSB_SUCCESS; - } - - priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints); - if (priv->usb_interface[iface].endpoint == NULL) { - libusb_free_config_descriptor(conf_desc); - return LIBUSB_ERROR_NO_MEM; - } - - priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints; - for (i = 0; i < if_desc->bNumEndpoints; i++) { - priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress; - usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface); - } - libusb_free_config_descriptor(conf_desc); - - // Extra init may be required to configure endpoints - return priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface); -} - -// Lookup for a match in the list of API driver names -// return -1 if not found, driver match number otherwise -static int get_sub_api(char *driver, int api) -{ - int i; - const char sep_str[2] = {LIST_SEPARATOR, 0}; - char *tok, *tmp_str; - size_t len = strlen(driver); - - if (len == 0) - return SUB_API_NOTSET; - - tmp_str = _strdup(driver); - if (tmp_str == NULL) - return SUB_API_NOTSET; - - tok = strtok(tmp_str, sep_str); - while (tok != NULL) { - for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) { - if (_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) { - free(tmp_str); - return i; - } - } - tok = strtok(NULL, sep_str); - } - - free(tmp_str); - return SUB_API_NOTSET; -} - -/* - * auto-claiming and auto-release helper functions - */ -static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) -{ - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv( - transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface = *interface_number; - int r = LIBUSB_SUCCESS; - - switch(api_type) { - case USB_API_WINUSBX: - case USB_API_HID: - break; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } - - usbi_mutex_lock(&autoclaim_lock); - if (current_interface < 0) { // No serviceable interface was found - for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) { - // Must claim an interface of the same API type - if ((priv->usb_interface[current_interface].apib->id == api_type) - && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) { - usbi_dbg("auto-claimed interface %d for control request", current_interface); - if (handle_priv->autoclaim_count[current_interface] != 0) - usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero"); - handle_priv->autoclaim_count[current_interface]++; - break; - } - } - if (current_interface == USB_MAXINTERFACES) { - usbi_err(ctx, "could not auto-claim any interface"); - r = LIBUSB_ERROR_NOT_FOUND; - } - } else { - // If we have a valid interface that was autoclaimed, we must increment - // its autoclaim count so that we can prevent an early release. - if (handle_priv->autoclaim_count[current_interface] != 0) - handle_priv->autoclaim_count[current_interface]++; - } - usbi_mutex_unlock(&autoclaim_lock); - - *interface_number = current_interface; - return r; -} - -static void auto_release(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - libusb_device_handle *dev_handle = transfer->dev_handle; - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - int r; - - usbi_mutex_lock(&autoclaim_lock); - if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) { - handle_priv->autoclaim_count[transfer_priv->interface_number]--; - if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) { - r = libusb_release_interface(dev_handle, transfer_priv->interface_number); - if (r == LIBUSB_SUCCESS) - usbi_dbg("auto-released interface %d", transfer_priv->interface_number); - else - usbi_dbg("failed to auto-release interface %d (%s)", - transfer_priv->interface_number, libusb_error_name((enum libusb_error)r)); - } - } - usbi_mutex_unlock(&autoclaim_lock); -} - -/* Windows version dtection */ -static BOOL is_x64(void) -{ - BOOL ret = FALSE; - - // Detect if we're running a 32 or 64 bit system - if (sizeof(uintptr_t) < 8) { - if (pIsWow64Process != NULL) - pIsWow64Process(GetCurrentProcess(), &ret); - } else { - ret = TRUE; - } - - return ret; -} - -static void get_windows_version(void) -{ - OSVERSIONINFOEXA vi, vi2; - const char *arch, *w = NULL; - unsigned major, minor; - ULONGLONG major_equal, minor_equal; - BOOL ws; - - memset(&vi, 0, sizeof(vi)); - vi.dwOSVersionInfoSize = sizeof(vi); - if (!GetVersionExA((OSVERSIONINFOA *)&vi)) { - memset(&vi, 0, sizeof(vi)); - vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - if (!GetVersionExA((OSVERSIONINFOA *)&vi)) - return; - } - - if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) { - if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) { - // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version - // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx - - major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); - for (major = vi.dwMajorVersion; major <= 9; major++) { - memset(&vi2, 0, sizeof(vi2)); - vi2.dwOSVersionInfoSize = sizeof(vi2); - vi2.dwMajorVersion = major; - if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal)) - continue; - - if (vi.dwMajorVersion < major) { - vi.dwMajorVersion = major; - vi.dwMinorVersion = 0; - } - - minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL); - for (minor = vi.dwMinorVersion; minor <= 9; minor++) { - memset(&vi2, 0, sizeof(vi2)); - vi2.dwOSVersionInfoSize = sizeof(vi2); - vi2.dwMinorVersion = minor; - if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal)) - continue; - - vi.dwMinorVersion = minor; - break; - } - - break; - } - } - - if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) { - ws = (vi.wProductType <= VER_NT_WORKSTATION); - windows_version = vi.dwMajorVersion << 4 | vi.dwMinorVersion; - switch (windows_version) { - case 0x50: w = "2000"; break; - case 0x51: w = "XP"; break; - case 0x52: w = "2003"; break; - case 0x60: w = (ws ? "Vista" : "2008"); break; - case 0x61: w = (ws ? "7" : "2008_R2"); break; - case 0x62: w = (ws ? "8" : "2012"); break; - case 0x63: w = (ws ? "8.1" : "2012_R2"); break; - case 0x64: w = (ws ? "10" : "2015"); break; - default: - if (windows_version < 0x50) - windows_version = WINDOWS_UNSUPPORTED; - else - w = "11 or later"; - break; - } - } - } - - arch = is_x64() ? "64-bit" : "32-bit"; - - if (w == NULL) - snprintf(windows_version_str, sizeof(windows_version_str), "%s %u.%u %s", - (vi.dwPlatformId == VER_PLATFORM_WIN32_NT ? "NT" : "??"), - (unsigned int)vi.dwMajorVersion, (unsigned int)vi.dwMinorVersion, arch); - else if (vi.wServicePackMinor) - snprintf(windows_version_str, sizeof(windows_version_str), "%s SP%u.%u %s", - w, vi.wServicePackMajor, vi.wServicePackMinor, arch); - else if (vi.wServicePackMajor) - snprintf(windows_version_str, sizeof(windows_version_str), "%s SP%u %s", - w, vi.wServicePackMajor, arch); - else - snprintf(windows_version_str, sizeof(windows_version_str), "%s %s", - w, arch); -} - -/* - * init: libusb backend init function - * - * This function enumerates the HCDs (Host Controller Drivers) and populates our private HCD list - * In our implementation, we equate Windows' "HCD" to libusb's "bus". Note that bus is zero indexed. - * HCDs are not expected to change after init (might not hold true for hot pluggable USB PCI card?) - */ -static int windows_init(struct libusb_context *ctx) -{ - int i, r = LIBUSB_ERROR_OTHER; - HANDLE semaphore; - char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' - - sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_MEM; - } - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore's release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); - CloseHandle(semaphore); - return LIBUSB_ERROR_NO_MEM; - } - - // NB: concurrent usage supposes that init calls are equally balanced with - // exit calls. If init is called more than exit, we will not exit properly - if (++concurrent_usage == 0) { // First init? - get_windows_version(); - usbi_dbg("Windows %s", windows_version_str); - - if (windows_version == WINDOWS_UNSUPPORTED) { - usbi_err(ctx, "This version of Windows is NOT supported"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - goto init_exit; - } - - // We need a lock for proper auto-release - usbi_mutex_init(&autoclaim_lock); - - // Initialize pollable file descriptors - init_polling(); - - // Load DLL imports - if (init_dlls() != LIBUSB_SUCCESS) { - usbi_err(ctx, "could not resolve DLL functions"); - goto init_exit; - } - - // Initialize the low level APIs (we don't care about errors at this stage) - for (i = 0; i < USB_API_MAX; i++) - usb_api_backend[i].init(SUB_API_NOTSET, ctx); - - r = windows_common_init(ctx); - if (r) - goto init_exit; - } - // At this stage, either we went through full init successfully, or didn't need to - r = LIBUSB_SUCCESS; - -init_exit: // Holds semaphore here. - if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? - for (i = 0; i < USB_API_MAX; i++) - usb_api_backend[i].exit(SUB_API_NOTSET); - exit_dlls(); - exit_polling(); - windows_common_exit(); - usbi_mutex_destroy(&autoclaim_lock); - } - - if (r != LIBUSB_SUCCESS) - --concurrent_usage; // Not expected to call libusb_exit if we failed. - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); - return r; -} - -/* - * HCD (root) hubs need to have their device descriptor manually populated - * - * Note that, like Microsoft does in the device manager, we populate the - * Vendor and Device ID for HCD hubs with the ones from the PCI HCD device. - */ -static int force_hcd_device_descriptor(struct libusb_device *dev) -{ - struct windows_device_priv *parent_priv, *priv = _device_priv(dev); - struct libusb_context *ctx = DEVICE_CTX(dev); - int vid, pid; - - dev->num_configurations = 1; - priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR); - priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; - priv->dev_descriptor.bNumConfigurations = 1; - priv->active_config = 1; - - if (dev->parent_dev == NULL) { - usbi_err(ctx, "program assertion failed - HCD hub has no parent"); - return LIBUSB_ERROR_NO_DEVICE; - } - - parent_priv = _device_priv(dev->parent_dev); - if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) { - priv->dev_descriptor.idVendor = (uint16_t)vid; - priv->dev_descriptor.idProduct = (uint16_t)pid; - } else { - usbi_warn(ctx, "could not infer VID/PID of HCD hub from '%s'", parent_priv->path); - priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub - priv->dev_descriptor.idProduct = 1; - } - - return LIBUSB_SUCCESS; -} - -/* - * fetch and cache all the config descriptors through I/O - */ -static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle, char *device_id) -{ - DWORD size, ret_size; - struct libusb_context *ctx = DEVICE_CTX(dev); - struct windows_device_priv *priv = _device_priv(dev); - int r; - uint8_t i; - - USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request - PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request - PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL; - - if (dev->num_configurations == 0) - return LIBUSB_ERROR_INVALID_PARAM; - - priv->config_descriptor = calloc(dev->num_configurations, sizeof(unsigned char *)); - if (priv->config_descriptor == NULL) - return LIBUSB_ERROR_NO_MEM; - - for (i = 0; i < dev->num_configurations; i++) - priv->config_descriptor[i] = NULL; - - for (i = 0, r = LIBUSB_SUCCESS; ; i++) { - // safe loop: release all dynamic resources - safe_free(cd_buf_actual); - - // safe loop: end of loop condition - if ((i >= dev->num_configurations) || (r != LIBUSB_SUCCESS)) - break; - - size = sizeof(USB_CONFIGURATION_DESCRIPTOR_SHORT); - memset(&cd_buf_short, 0, size); - - cd_buf_short.req.ConnectionIndex = (ULONG)priv->port; - cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_short.req.SetupPacket.wIndex = 0; - cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - // Dummy call to get the required data size. Initial failures are reported as info rather - // than error as they can occur for non-penalizing situations, such as with some hubs. - // coverity[tainted_data_argument] - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size, - &cd_buf_short, size, &ret_size, NULL)) { - usbi_info(ctx, "could not access configuration descriptor (dummy) for '%s': %s", device_id, windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if ((ret_size != size) || (cd_buf_short.data.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) { - usbi_info(ctx, "unexpected configuration descriptor size (dummy) for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.data.wTotalLength; - cd_buf_actual = calloc(1, size); - if (cd_buf_actual == NULL) { - usbi_err(ctx, "could not allocate configuration descriptor buffer for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - - // Actual call - cd_buf_actual->ConnectionIndex = (ULONG)priv->port; - cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_actual->SetupPacket.wIndex = 0; - cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size, - cd_buf_actual, size, &ret_size, NULL)) { - usbi_err(ctx, "could not access configuration descriptor (actual) for '%s': %s", device_id, windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST)); - - if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.data.wTotalLength)) { - usbi_err(ctx, "unexpected configuration descriptor size (actual) for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) { - usbi_err(ctx, "not a configuration descriptor for '%s'", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - usbi_dbg("cached config descriptor %d (bConfigurationValue=%u, %u bytes)", - i, cd_data->bConfigurationValue, cd_data->wTotalLength); - - // Cache the descriptor - priv->config_descriptor[i] = malloc(cd_data->wTotalLength); - if (priv->config_descriptor[i] == NULL) - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength); - } - return LIBUSB_SUCCESS; -} - -/* - * Populate a libusb device structure - */ -static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev, - uint8_t port_number, char *device_id, DWORD devinst) -{ - HANDLE handle; - DWORD size; - USB_NODE_CONNECTION_INFORMATION_EX conn_info; - USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2; - struct windows_device_priv *priv, *parent_priv; - struct libusb_context *ctx; - struct libusb_device *tmp_dev; - unsigned long tmp_id; - unsigned i; - - if ((dev == NULL) || (parent_dev == NULL)) - return LIBUSB_ERROR_NOT_FOUND; - - ctx = DEVICE_CTX(dev); - priv = _device_priv(dev); - parent_priv = _device_priv(parent_dev); - if (parent_priv->apib->id != USB_API_HUB) { - usbi_warn(ctx, "parent for device '%s' is not a hub", device_id); - return LIBUSB_ERROR_NOT_FOUND; - } - - // It is possible for the parent hub not to have been initialized yet - // If that's the case, lookup the ancestors to set the bus number - if (parent_dev->bus_number == 0) { - for (i = 2; ; i++) { - tmp_id = get_ancestor_session_id(devinst, i); - if (tmp_id == 0) - break; - - tmp_dev = usbi_get_device_by_session_id(ctx, tmp_id); - if (tmp_dev == NULL) - continue; - - if (tmp_dev->bus_number != 0) { - usbi_dbg("got bus number from ancestor #%u", i); - parent_dev->bus_number = tmp_dev->bus_number; - libusb_unref_device(tmp_dev); - break; - } - - libusb_unref_device(tmp_dev); - } - } - - if (parent_dev->bus_number == 0) { - usbi_err(ctx, "program assertion failed: unable to find ancestor bus number for '%s'", device_id); - return LIBUSB_ERROR_NOT_FOUND; - } - - dev->bus_number = parent_dev->bus_number; - priv->port = port_number; - dev->port_number = port_number; - priv->depth = parent_priv->depth + 1; - dev->parent_dev = parent_dev; - - // If the device address is already set, we can stop here - if (dev->device_address != 0) - return LIBUSB_SUCCESS; - - memset(&conn_info, 0, sizeof(conn_info)); - if (priv->depth != 0) { // Not a HCD hub - handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - if (handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - - size = sizeof(conn_info); - conn_info.ConnectionIndex = (ULONG)port_number; - // coverity[tainted_data_argument] - if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, size, - &conn_info, size, &size, NULL)) { - usbi_warn(ctx, "could not get node connection information for device '%s': %s", - device_id, windows_error_str(0)); - CloseHandle(handle); - return LIBUSB_ERROR_NO_DEVICE; - } - - if (conn_info.ConnectionStatus == NoDeviceConnected) { - usbi_err(ctx, "device '%s' is no longer connected!", device_id); - CloseHandle(handle); - return LIBUSB_ERROR_NO_DEVICE; - } - - memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); - dev->num_configurations = priv->dev_descriptor.bNumConfigurations; - priv->active_config = conn_info.CurrentConfigurationValue; - usbi_dbg("found %u configurations (active conf: %u)", dev->num_configurations, priv->active_config); - - // If we can't read the config descriptors, just set the number of confs to zero - if (cache_config_descriptors(dev, handle, device_id) != LIBUSB_SUCCESS) { - dev->num_configurations = 0; - priv->dev_descriptor.bNumConfigurations = 0; - } - - // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8 - if (windows_version >= WINDOWS_8) { - memset(&conn_info_v2, 0, sizeof(conn_info_v2)); - size = sizeof(conn_info_v2); - conn_info_v2.ConnectionIndex = (ULONG)port_number; - conn_info_v2.Length = size; - conn_info_v2.SupportedUsbProtocols.Usb300 = 1; - if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, - &conn_info_v2, size, &conn_info_v2, size, &size, NULL)) { - usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s", - device_id, windows_error_str(0)); - } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) { - conn_info.Speed = 3; - } - } - - CloseHandle(handle); - - if (conn_info.DeviceAddress > UINT8_MAX) - usbi_err(ctx, "program assertion failed: device address overflow"); - - dev->device_address = (uint8_t)conn_info.DeviceAddress + 1; - if (dev->device_address == 1) - usbi_err(ctx, "program assertion failed: device address collision with root hub"); - - switch (conn_info.Speed) { - case 0: dev->speed = LIBUSB_SPEED_LOW; break; - case 1: dev->speed = LIBUSB_SPEED_FULL; break; - case 2: dev->speed = LIBUSB_SPEED_HIGH; break; - case 3: dev->speed = LIBUSB_SPEED_SUPER; break; - default: - usbi_warn(ctx, "Got unknown device speed %u", conn_info.Speed); - break; - } - } else { - dev->device_address = 1; // root hubs are set to use device number 1 - force_hcd_device_descriptor(dev); - } - - usbi_sanitize_device(dev); - - usbi_dbg("(bus: %u, addr: %u, depth: %u, port: %u): '%s'", - dev->bus_number, dev->device_address, priv->depth, priv->port, device_id); - - return LIBUSB_SUCCESS; -} - -// Returns the api type, or 0 if not found/unsupported -static void get_api_type(struct libusb_context *ctx, HDEVINFO *dev_info, - SP_DEVINFO_DATA *dev_info_data, int *api, int *sub_api) -{ - // Precedence for filter drivers vs driver is in the order of this array - struct driver_lookup lookup[3] = { - {"\0\0", SPDRP_SERVICE, "driver"}, - {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"}, - {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"} - }; - DWORD size, reg_type; - unsigned k, l; - int i, j; - - *api = USB_API_UNSUPPORTED; - *sub_api = SUB_API_NOTSET; - - // Check the service & filter names to know the API we should use - for (k = 0; k < 3; k++) { - if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop, - ®_type, (BYTE *)lookup[k].list, MAX_KEY_LENGTH, &size)) { - // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ - if (lookup[k].reg_prop == SPDRP_SERVICE) - // our buffers are MAX_KEY_LENGTH + 1 so we can overflow if needed - lookup[k].list[strlen(lookup[k].list) + 1] = 0; - - // MULTI_SZ is a pain to work with. Turn it into something much more manageable - // NB: none of the driver names we check against contain LIST_SEPARATOR, - // (currently ';'), so even if an unsuported one does, it's not an issue - for (l = 0; (lookup[k].list[l] != 0) || (lookup[k].list[l + 1] != 0); l++) { - if (lookup[k].list[l] == 0) - lookup[k].list[l] = LIST_SEPARATOR; - } - usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); - } else { - if (GetLastError() != ERROR_INVALID_DATA) - usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); - lookup[k].list[0] = 0; - } - } - - for (i = 1; i < USB_API_MAX; i++) { - for (k = 0; k < 3; k++) { - j = get_sub_api(lookup[k].list, i); - if (j >= 0) { - usbi_dbg("matched %s name against %s", lookup[k].designation, - (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : sub_api_name[j]); - *api = i; - *sub_api = j; - return; - } - } - } -} - -static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev, - char *dev_interface_path, char *device_id, int api, int sub_api) -{ - unsigned i; - struct windows_device_priv *priv = _device_priv(dev); - int interface_number; - - if (priv->apib->id != USB_API_COMPOSITE) { - usbi_err(ctx, "program assertion failed: '%s' is not composite", device_id); - return LIBUSB_ERROR_NO_DEVICE; - } - - // Because MI_## are not necessarily in sequential order (some composite - // devices will have only MI_00 & MI_03 for instance), we retrieve the actual - // interface number from the path's MI value - interface_number = 0; - for (i = 0; device_id[i] != 0; ) { - if ((device_id[i++] == 'M') && (device_id[i++] == 'I') - && (device_id[i++] == '_')) { - interface_number = (device_id[i++] - '0') * 10; - interface_number += device_id[i] - '0'; - break; - } - } - - if (device_id[i] == 0) - usbi_warn(ctx, "failure to read interface number for %s. Using default value %d", - device_id, interface_number); - - if (priv->usb_interface[interface_number].path != NULL) { - if (api == USB_API_HID) { - // HID devices can have multiple collections (COL##) for each MI_## interface - usbi_dbg("interface[%d] already set - ignoring HID collection: %s", - interface_number, device_id); - return LIBUSB_ERROR_ACCESS; - } - // In other cases, just use the latest data - safe_free(priv->usb_interface[interface_number].path); - } - - usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path); - priv->usb_interface[interface_number].path = dev_interface_path; - priv->usb_interface[interface_number].apib = &usb_api_backend[api]; - priv->usb_interface[interface_number].sub_api = sub_api; - if ((api == USB_API_HID) && (priv->hid == NULL)) { - priv->hid = calloc(1, sizeof(struct hid_device_priv)); - if (priv->hid == NULL) - return LIBUSB_ERROR_NO_MEM; - } - - return LIBUSB_SUCCESS; -} - -static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev, - char *dev_interface_path) -{ - int i; - struct windows_device_priv *priv = _device_priv(dev); - - if (priv->hid == NULL) { - usbi_err(ctx, "program assertion failed: parent is not HID"); - return LIBUSB_ERROR_NO_DEVICE; - } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) { - usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device"); - return LIBUSB_ERROR_NO_DEVICE; - } - - for (i = 0; i < priv->hid->nb_interfaces; i++) { - if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) { - usbi_dbg("interface[%d] already set to %s", i, dev_interface_path); - return LIBUSB_ERROR_ACCESS; - } - } - - priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path; - priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID]; - usbi_dbg("interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path); - priv->hid->nb_interfaces++; - return LIBUSB_SUCCESS; -} - -/* - * get_device_list: libusb backend device enumeration function - */ -static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) -{ - struct discovered_devs *discdevs; - HDEVINFO dev_info = { 0 }; - const char *usb_class[] = {"USB", "NUSB3", "IUSB3", "IARUSB3"}; - SP_DEVINFO_DATA dev_info_data = { 0 }; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; - GUID hid_guid; -#define MAX_ENUM_GUIDS 64 - const GUID *guid[MAX_ENUM_GUIDS]; -#define HCD_PASS 0 -#define HUB_PASS 1 -#define GEN_PASS 2 -#define DEV_PASS 3 -#define HID_PASS 4 - int r = LIBUSB_SUCCESS; - int api, sub_api; - size_t class_index = 0; - unsigned int nb_guids, pass, i, j, ancestor; - char path[MAX_PATH_LENGTH]; - char strbuf[MAX_PATH_LENGTH]; - struct libusb_device *dev, *parent_dev; - struct windows_device_priv *priv, *parent_priv; - char *dev_interface_path = NULL; - char *dev_id_path = NULL; - unsigned long session_id; - DWORD size, reg_type, port_nr, install_state; - HKEY key; - WCHAR guid_string_w[MAX_GUID_STRING_LENGTH]; - GUID *if_guid; - LONG s; - // Keep a list of newly allocated devs to unref - libusb_device **unref_list, **new_unref_list; - unsigned int unref_size = 64; - unsigned int unref_cur = 0; - - // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug) - // PASS 2 : (re)enumerate HUBS - // PASS 3 : (re)enumerate generic USB devices (including driverless) - // and list additional USB device interface GUIDs to explore - // PASS 4 : (re)enumerate master USB devices that have a device interface - // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and - // set the device interfaces. - - // Init the GUID table - guid[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER; - guid[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB; - guid[GEN_PASS] = NULL; - guid[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE; - HidD_GetHidGuid(&hid_guid); - guid[HID_PASS] = &hid_guid; - nb_guids = HID_PASS + 1; - - unref_list = calloc(unref_size, sizeof(libusb_device *)); - if (unref_list == NULL) - return LIBUSB_ERROR_NO_MEM; - - for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) { -//#define ENUM_DEBUG -#if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG) - const char *passname[] = { "HCD", "HUB", "GEN", "DEV", "HID", "EXT" }; - usbi_dbg("#### PROCESSING %ss %s", passname[(pass <= HID_PASS) ? pass : (HID_PASS + 1)], - (pass != GEN_PASS) ? guid_to_string(guid[pass]) : ""); -#endif - for (i = 0; ; i++) { - // safe loop: free up any (unprotected) dynamic resource - // NB: this is always executed before breaking the loop - safe_free(dev_interface_details); - safe_free(dev_interface_path); - safe_free(dev_id_path); - priv = parent_priv = NULL; - dev = parent_dev = NULL; - - // Safe loop: end of loop conditions - if (r != LIBUSB_SUCCESS) - break; - - if ((pass == HCD_PASS) && (i == UINT8_MAX)) { - usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", UINT8_MAX); - break; - } - - if (pass != GEN_PASS) { - // Except for GEN, all passes deal with device interfaces - dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid[pass], i); - if (dev_interface_details == NULL) - break; - - dev_interface_path = sanitize_path(dev_interface_details->DevicePath); - if (dev_interface_path == NULL) { - usbi_warn(ctx, "could not sanitize device interface path for '%s'", dev_interface_details->DevicePath); - continue; - } - } else { - // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are - // being listed under the "NUSB3" PnP Symbolic Name rather than "USB". - // The Intel USB 3.0 driver behaves similar, but uses "IUSB3" - // The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3" - for (; class_index < ARRAYSIZE(usb_class); class_index++) { - if (get_devinfo_data(ctx, &dev_info, &dev_info_data, usb_class[class_index], i)) - break; - i = 0; - } - if (class_index >= ARRAYSIZE(usb_class)) - break; - } - - // Read the Device ID path. This is what we'll use as UID - // Note that if the device is plugged in a different port or hub, the Device ID changes - if (CM_Get_Device_IDA(dev_info_data.DevInst, path, sizeof(path), 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not read the device id path for devinst %X, skipping", - (unsigned int)dev_info_data.DevInst); - continue; - } - - dev_id_path = sanitize_path(path); - if (dev_id_path == NULL) { - usbi_warn(ctx, "could not sanitize device id path for devinst %X, skipping", - (unsigned int)dev_info_data.DevInst); - continue; - } -#ifdef ENUM_DEBUG - usbi_dbg("PRO: %s", dev_id_path); -#endif - - // The SPDRP_ADDRESS for USB devices is the device port number on the hub - port_nr = 0; - if ((pass >= HUB_PASS) && (pass <= GEN_PASS)) { - if ((!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ADDRESS, - ®_type, (BYTE *)&port_nr, 4, &size)) || (size != 4)) { - usbi_warn(ctx, "could not retrieve port number for device '%s', skipping: %s", - dev_id_path, windows_error_str(0)); - continue; - } - } - - // Set API to use or get additional data from generic pass - api = USB_API_UNSUPPORTED; - sub_api = SUB_API_NOTSET; - switch (pass) { - case HCD_PASS: - break; - case GEN_PASS: - // We use the GEN pass to detect driverless devices... - size = sizeof(strbuf); - if (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER, - ®_type, (BYTE *)strbuf, size, &size)) { - usbi_info(ctx, "The following device has no driver: '%s'", dev_id_path); - usbi_info(ctx, "libusb will not be able to access it."); - } - // ...and to add the additional device interface GUIDs - key = pSetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); - if (key != INVALID_HANDLE_VALUE) { - size = sizeof(guid_string_w); - s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, ®_type, - (BYTE *)guid_string_w, &size); - pRegCloseKey(key); - if (s == ERROR_SUCCESS) { - if (nb_guids >= MAX_ENUM_GUIDS) { - // If this assert is ever reported, grow a GUID table dynamically - usbi_err(ctx, "program assertion failed: too many GUIDs"); - LOOP_BREAK(LIBUSB_ERROR_OVERFLOW); - } - if_guid = calloc(1, sizeof(GUID)); - if (if_guid == NULL) { - usbi_err(ctx, "could not calloc for if_guid: not enough memory"); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - pCLSIDFromString(guid_string_w, if_guid); - guid[nb_guids++] = if_guid; - usbi_dbg("extra GUID: %s", guid_to_string(if_guid)); - } - } - break; - case HID_PASS: - api = USB_API_HID; - break; - default: - // Get the API type (after checking that the driver installation is OK) - if ((!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE, - ®_type, (BYTE *)&install_state, 4, &size)) || (size != 4)) { - usbi_warn(ctx, "could not detect installation state of driver for '%s': %s", - dev_id_path, windows_error_str(0)); - } else if (install_state != 0) { - usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %u) - skipping", - dev_id_path, (unsigned int)install_state); - continue; - } - get_api_type(ctx, &dev_info, &dev_info_data, &api, &sub_api); - break; - } - - // Find parent device (for the passes that need it) - switch (pass) { - case HCD_PASS: - case DEV_PASS: - case HUB_PASS: - break; - default: - // Go through the ancestors until we see a face we recognize - parent_dev = NULL; - for (ancestor = 1; parent_dev == NULL; ancestor++) { - session_id = get_ancestor_session_id(dev_info_data.DevInst, ancestor); - if (session_id == 0) - break; - - parent_dev = usbi_get_device_by_session_id(ctx, session_id); - } - - if (parent_dev == NULL) { - usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id_path); - continue; - } - - parent_priv = _device_priv(parent_dev); - // virtual USB devices are also listed during GEN - don't process these yet - if ((pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB)) { - libusb_unref_device(parent_dev); - continue; - } - - break; - } - - // Create new or match existing device, using the (hashed) device_id as session id - if (pass <= DEV_PASS) { // For subsequent passes, we'll lookup the parent - // These are the passes that create "new" devices - session_id = htab_hash(dev_id_path); - dev = usbi_get_device_by_session_id(ctx, session_id); - if (dev == NULL) { - if (pass == DEV_PASS) { - // This can occur if the OS only reports a newly plugged device after we started enum - usbi_warn(ctx, "'%s' was only detected in late pass (newly connected device?)" - " - ignoring", dev_id_path); - continue; - } - - usbi_dbg("allocating new device for session [%lX]", session_id); - dev = usbi_alloc_device(ctx, session_id); - if (dev == NULL) - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - - priv = windows_device_priv_init(dev); - } else { - usbi_dbg("found existing device for session [%lX] (%u.%u)", - session_id, dev->bus_number, dev->device_address); - - priv = _device_priv(dev); - if ((parent_dev != NULL) && (dev->parent_dev != NULL)) { - if (dev->parent_dev != parent_dev) { - // It is possible for the actual parent device to not have existed at the - // time of enumeration, so the currently assigned parent may in fact be a - // grandparent. If the devices differ, we assume the "new" parent device - // is in fact closer to the device. - usbi_dbg("updating parent device [session %lX -> %lX]", - dev->parent_dev->session_data, parent_dev->session_data); - libusb_unref_device(dev->parent_dev); - dev->parent_dev = parent_dev; - } else { - // We hold a reference to parent_dev instance, but this device already - // has a parent_dev reference (only one per child) - libusb_unref_device(parent_dev); - } - } - } - - // Keep track of devices that need unref - unref_list[unref_cur++] = dev; - if (unref_cur >= unref_size) { - unref_size += 64; - new_unref_list = usbi_reallocf(unref_list, unref_size * sizeof(libusb_device *)); - if (new_unref_list == NULL) { - usbi_err(ctx, "could not realloc list for unref - aborting."); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } else { - unref_list = new_unref_list; - } - } - } - - // Setup device - switch (pass) { - case HCD_PASS: - // If the hcd has already been setup, don't do it again - if (priv->path != NULL) - break; - dev->bus_number = (uint8_t)(i + 1); // bus 0 is reserved for disconnected - dev->device_address = 0; - dev->num_configurations = 0; - priv->apib = &usb_api_backend[USB_API_HUB]; - priv->sub_api = SUB_API_NOTSET; - priv->depth = UINT8_MAX; // Overflow to 0 for HCD Hubs - priv->path = dev_interface_path; - dev_interface_path = NULL; - break; - case HUB_PASS: - case DEV_PASS: - // If the device has already been setup, don't do it again - if (priv->path != NULL) - break; - // Take care of API initialization - priv->path = dev_interface_path; - dev_interface_path = NULL; - priv->apib = &usb_api_backend[api]; - priv->sub_api = sub_api; - switch(api) { - case USB_API_COMPOSITE: - case USB_API_HUB: - break; - case USB_API_HID: - priv->hid = calloc(1, sizeof(struct hid_device_priv)); - if (priv->hid == NULL) - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - - priv->hid->nb_interfaces = 0; - break; - default: - // For other devices, the first interface is the same as the device - priv->usb_interface[0].path = _strdup(priv->path); - if (priv->usb_interface[0].path == NULL) - usbi_warn(ctx, "could not duplicate interface path '%s'", priv->path); - // The following is needed if we want API calls to work for both simple - // and composite devices. - for (j = 0; j < USB_MAXINTERFACES; j++) - priv->usb_interface[j].apib = &usb_api_backend[api]; - - break; - } - break; - case GEN_PASS: - r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_id_path, dev_info_data.DevInst); - if (r == LIBUSB_SUCCESS) { - // Append device to the list of discovered devices - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - - *_discdevs = discdevs; - } else if (r == LIBUSB_ERROR_NO_DEVICE) { - // This can occur if the device was disconnected but Windows hasn't - // refreshed its enumeration yet - in that case, we ignore the device - r = LIBUSB_SUCCESS; - } - break; - default: // HID_PASS and later - if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) { - if (parent_priv->apib->id == USB_API_HID) { - usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data); - r = set_hid_interface(ctx, parent_dev, dev_interface_path); - } else { - usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data); - r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api, sub_api); - } - switch (r) { - case LIBUSB_SUCCESS: - dev_interface_path = NULL; - break; - case LIBUSB_ERROR_ACCESS: - // interface has already been set => make sure dev_interface_path is freed then - r = LIBUSB_SUCCESS; - break; - default: - LOOP_BREAK(r); - break; - } - } - libusb_unref_device(parent_dev); - break; - } - } - } - - // Free any additional GUIDs - for (pass = HID_PASS + 1; pass < nb_guids; pass++) - free((void *)guid[pass]); - - // Unref newly allocated devs - for (i = 0; i < unref_cur; i++) - libusb_unref_device(unref_list[i]); - free(unref_list); - - return r; -} - -/* - * exit: libusb backend deinitialization function - */ -static void windows_exit(void) -{ - int i; - HANDLE semaphore; - char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' - - sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) - return; - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - CloseHandle(semaphore); - return; - } - - // Only works if exits and inits are balanced exactly - if (--concurrent_usage < 0) { // Last exit - for (i = 0; i < USB_API_MAX; i++) - usb_api_backend[i].exit(SUB_API_NOTSET); - exit_dlls(); - exit_polling(); - windows_common_exit(); - usbi_mutex_destroy(&autoclaim_lock); - } - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); -} - -static int windows_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - - memcpy(buffer, &priv->dev_descriptor, DEVICE_DESC_LENGTH); - *host_endian = 0; - - return LIBUSB_SUCCESS; -} - -static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - PUSB_CONFIGURATION_DESCRIPTOR config_header; - size_t size; - - // config index is zero based - if (config_index >= dev->num_configurations) - return LIBUSB_ERROR_INVALID_PARAM; - - if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL)) - return LIBUSB_ERROR_NOT_FOUND; - - config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index]; - - size = MIN(config_header->wTotalLength, len); - memcpy(buffer, priv->config_descriptor[config_index], size); - *host_endian = 0; - - return (int)size; -} - -static int windows_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue, - unsigned char **buffer, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - PUSB_CONFIGURATION_DESCRIPTOR config_header; - uint8_t index; - - *buffer = NULL; - *host_endian = 0; - - if (priv->config_descriptor == NULL) - return LIBUSB_ERROR_NOT_FOUND; - - for (index = 0; index < dev->num_configurations; index++) { - config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[index]; - if (config_header->bConfigurationValue == bConfigurationValue) { - *buffer = priv->config_descriptor[index]; - return (int)config_header->wTotalLength; - } - } - - return LIBUSB_ERROR_NOT_FOUND; -} - -/* - * return the cached copy of the active config descriptor - */ -static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - unsigned char *config_desc; - int r; - - if (priv->active_config == 0) - return LIBUSB_ERROR_NOT_FOUND; - - r = windows_get_config_descriptor_by_value(dev, priv->active_config, &config_desc, host_endian); - if (r < 0) - return r; - - len = MIN((size_t)r, len); - memcpy(buffer, config_desc, len); - return (int)len; -} - -static int windows_open(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - if (priv->apib == NULL) { - usbi_err(ctx, "program assertion failed - device is not initialized"); - return LIBUSB_ERROR_NO_DEVICE; - } - - return priv->apib->open(SUB_API_NOTSET, dev_handle); -} - -static void windows_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - priv->apib->close(SUB_API_NOTSET, dev_handle); -} - -static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - if (priv->active_config == 0) { - *config = 0; - return LIBUSB_ERROR_NOT_FOUND; - } - - *config = priv->active_config; - return LIBUSB_SUCCESS; -} - -/* - * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver - * does not currently expose a service that allows higher-level drivers to set - * the configuration." - */ -static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int r = LIBUSB_SUCCESS; - - if (config >= USB_MAXCONFIG) - return LIBUSB_ERROR_INVALID_PARAM; - - r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | - LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config, - 0, NULL, 0, 1000); - - if (r == LIBUSB_SUCCESS) - priv->active_config = (uint8_t)config; - - return r; -} - -static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints = 0; - - r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface); - - if (r == LIBUSB_SUCCESS) - r = windows_assign_endpoints(dev_handle, iface, 0); - - return r; -} - -static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints = 0; - - r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting); - - if (r == LIBUSB_SUCCESS) - r = windows_assign_endpoints(dev_handle, iface, altsetting); - - return r; -} - -static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface); -} - -static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint); -} - -static int windows_reset_device(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->apib->reset_device(SUB_API_NOTSET, dev_handle); -} - -// The 3 functions below are unlikely to ever get supported on Windows -static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static void windows_destroy_device(struct libusb_device *dev) -{ - windows_device_priv_release(dev); -} - -void windows_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - - usbi_free_fd(&transfer_priv->pollable_fd); - safe_free(transfer_priv->hid_buffer); - // When auto claim is in use, attempt to release the auto-claimed interface - auto_release(itransfer); -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_bulk_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) - return r; - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); - - return LIBUSB_SUCCESS; -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_iso_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) - return r; - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); - - return LIBUSB_SUCCESS; -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_control_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) - return r; - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); - - return LIBUSB_SUCCESS; -} - -static int windows_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) - return LIBUSB_ERROR_NOT_SUPPORTED; - return submit_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK_STREAM: - return LIBUSB_ERROR_NOT_SUPPORTED; - default: - usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int windows_abort_control(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_control(SUB_API_NOTSET, itransfer); -} - -static int windows_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer); -} - -static int windows_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return windows_abort_control(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return windows_abort_transfers(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK_STREAM: - return LIBUSB_ERROR_NOT_SUPPORTED; - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size); -} - -struct winfd *windows_get_fd(struct usbi_transfer *transfer) -{ - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(transfer); - return &transfer_priv->pollable_fd; -} - -void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size) -{ - if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) { - *io_result = NO_ERROR; - *io_size = (DWORD)pollable_fd->overlapped->InternalHigh; - } else if (GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { - // Regular async overlapped - *io_result = NO_ERROR; - } else { - *io_result = GetLastError(); - } -} - -// NB: MSVC6 does not support named initializers. -const struct usbi_os_backend windows_backend = { - "Windows", - USBI_CAP_HAS_HID_ACCESS, - windows_init, - windows_exit, - - windows_get_device_list, - NULL, /* hotplug_poll */ - windows_open, - windows_close, - - windows_get_device_descriptor, - windows_get_active_config_descriptor, - windows_get_config_descriptor, - windows_get_config_descriptor_by_value, - - windows_get_configuration, - windows_set_configuration, - windows_claim_interface, - windows_release_interface, - - windows_set_interface_altsetting, - windows_clear_halt, - windows_reset_device, - - NULL, /* alloc_streams */ - NULL, /* free_streams */ - - NULL, /* dev_mem_alloc */ - NULL, /* dev_mem_free */ - - windows_kernel_driver_active, - windows_detach_kernel_driver, - windows_attach_kernel_driver, - - windows_destroy_device, - - windows_submit_transfer, - windows_cancel_transfer, - windows_clear_transfer_priv, - - windows_handle_events, - NULL, - - windows_clock_gettime, -#if defined(USBI_TIMERFD_AVAILABLE) - NULL, -#endif - sizeof(struct windows_device_priv), - sizeof(struct windows_device_handle_priv), - sizeof(struct windows_transfer_priv), -}; - - -/* - * USB API backends - */ -static int unsupported_init(int sub_api, struct libusb_context *ctx) -{ - return LIBUSB_SUCCESS; -} - -static int unsupported_exit(int sub_api) -{ - return LIBUSB_SUCCESS; -} - -static int unsupported_open(int sub_api, struct libusb_device_handle *dev_handle) -{ - PRINT_UNSUPPORTED_API(open); -} - -static void unsupported_close(int sub_api, struct libusb_device_handle *dev_handle) -{ - usbi_dbg("unsupported API call for 'close'"); -} - -static int unsupported_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - PRINT_UNSUPPORTED_API(configure_endpoints); -} - -static int unsupported_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - PRINT_UNSUPPORTED_API(claim_interface); -} - -static int unsupported_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - PRINT_UNSUPPORTED_API(set_interface_altsetting); -} - -static int unsupported_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - PRINT_UNSUPPORTED_API(release_interface); -} - -static int unsupported_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - PRINT_UNSUPPORTED_API(clear_halt); -} - -static int unsupported_reset_device(int sub_api, struct libusb_device_handle *dev_handle) -{ - PRINT_UNSUPPORTED_API(reset_device); -} - -static int unsupported_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - PRINT_UNSUPPORTED_API(submit_bulk_transfer); -} - -static int unsupported_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - PRINT_UNSUPPORTED_API(submit_iso_transfer); -} - -static int unsupported_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - PRINT_UNSUPPORTED_API(submit_control_transfer); -} - -static int unsupported_abort_control(int sub_api, struct usbi_transfer *itransfer) -{ - PRINT_UNSUPPORTED_API(abort_control); -} - -static int unsupported_abort_transfers(int sub_api, struct usbi_transfer *itransfer) -{ - PRINT_UNSUPPORTED_API(abort_transfers); -} - -static int unsupported_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) -{ - PRINT_UNSUPPORTED_API(copy_transfer_data); -} - -static int common_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_SUCCESS; -} - -// These names must be uppercase -static const char *hub_driver_names[] = {"USBHUB", "USBHUB3", "USB3HUB", "NUSB3HUB", "RUSB3HUB", "FLXHCIH", "TIHUB3", "ETRONHUB3", "VIAHUB3", "ASMTHUB3", "IUSB3HUB", "VUSB3HUB", "AMDHUB30", "VHHUB", "AUSB3HUB"}; -static const char *composite_driver_names[] = {"USBCCGP"}; -static const char *winusbx_driver_names[] = WINUSBX_DRV_NAMES; -static const char *hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"}; -const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { - { - USB_API_UNSUPPORTED, - "Unsupported API", - NULL, - 0, - unsupported_init, - unsupported_exit, - unsupported_open, - unsupported_close, - unsupported_configure_endpoints, - unsupported_claim_interface, - unsupported_set_interface_altsetting, - unsupported_release_interface, - unsupported_clear_halt, - unsupported_reset_device, - unsupported_submit_bulk_transfer, - unsupported_submit_iso_transfer, - unsupported_submit_control_transfer, - unsupported_abort_control, - unsupported_abort_transfers, - unsupported_copy_transfer_data, - }, - { - USB_API_HUB, - "HUB API", - hub_driver_names, - ARRAYSIZE(hub_driver_names), - unsupported_init, - unsupported_exit, - unsupported_open, - unsupported_close, - unsupported_configure_endpoints, - unsupported_claim_interface, - unsupported_set_interface_altsetting, - unsupported_release_interface, - unsupported_clear_halt, - unsupported_reset_device, - unsupported_submit_bulk_transfer, - unsupported_submit_iso_transfer, - unsupported_submit_control_transfer, - unsupported_abort_control, - unsupported_abort_transfers, - unsupported_copy_transfer_data, - }, - { - USB_API_COMPOSITE, - "Composite API", - composite_driver_names, - ARRAYSIZE(composite_driver_names), - composite_init, - composite_exit, - composite_open, - composite_close, - common_configure_endpoints, - composite_claim_interface, - composite_set_interface_altsetting, - composite_release_interface, - composite_clear_halt, - composite_reset_device, - composite_submit_bulk_transfer, - composite_submit_iso_transfer, - composite_submit_control_transfer, - composite_abort_control, - composite_abort_transfers, - composite_copy_transfer_data, - }, - { - USB_API_WINUSBX, - "WinUSB-like APIs", - winusbx_driver_names, - ARRAYSIZE(winusbx_driver_names), - winusbx_init, - winusbx_exit, - winusbx_open, - winusbx_close, - winusbx_configure_endpoints, - winusbx_claim_interface, - winusbx_set_interface_altsetting, - winusbx_release_interface, - winusbx_clear_halt, - winusbx_reset_device, - winusbx_submit_bulk_transfer, - unsupported_submit_iso_transfer, - winusbx_submit_control_transfer, - winusbx_abort_control, - winusbx_abort_transfers, - winusbx_copy_transfer_data, - }, - { - USB_API_HID, - "HID API", - hid_driver_names, - ARRAYSIZE(hid_driver_names), - hid_init, - hid_exit, - hid_open, - hid_close, - common_configure_endpoints, - hid_claim_interface, - hid_set_interface_altsetting, - hid_release_interface, - hid_clear_halt, - hid_reset_device, - hid_submit_bulk_transfer, - unsupported_submit_iso_transfer, - hid_submit_control_transfer, - hid_abort_transfers, - hid_abort_transfers, - hid_copy_transfer_data, - }, -}; - - -/* - * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions - */ -#define WinUSBX_Set(fn) \ - do { \ - if (native_winusb) \ - WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \ - else \ - pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn); \ - } while (0) - -static int winusbx_init(int sub_api, struct libusb_context *ctx) -{ - HMODULE h; - bool native_winusb; - int i; - KLIB_VERSION LibK_Version; - LibK_GetProcAddress_t pLibK_GetProcAddress = NULL; - LibK_GetVersion_t pLibK_GetVersion; - - h = LoadLibraryA("libusbK"); - - if (h == NULL) { - usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB"); - h = LoadLibraryA("WinUSB"); - - if (h == NULL) { - usbi_warn(ctx, "WinUSB DLL is not available either, " - "you will not be able to access devices outside of enumeration"); - return LIBUSB_ERROR_NOT_FOUND; - } - } else { - usbi_dbg("using libusbK DLL for universal access"); - pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion"); - if (pLibK_GetVersion != NULL) { - pLibK_GetVersion(&LibK_Version); - usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, - LibK_Version.Micro, LibK_Version.Nano); - } - pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress"); - if (pLibK_GetProcAddress == NULL) { - usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL"); - FreeLibrary(h); - return LIBUSB_ERROR_NOT_FOUND; - } - } - - native_winusb = (pLibK_GetProcAddress == NULL); - for (i = SUB_API_LIBUSBK; i < SUB_API_MAX; i++) { - WinUSBX_Set(AbortPipe); - WinUSBX_Set(ControlTransfer); - WinUSBX_Set(FlushPipe); - WinUSBX_Set(Free); - WinUSBX_Set(GetAssociatedInterface); - WinUSBX_Set(GetCurrentAlternateSetting); - WinUSBX_Set(GetDescriptor); - WinUSBX_Set(GetOverlappedResult); - WinUSBX_Set(GetPipePolicy); - WinUSBX_Set(GetPowerPolicy); - WinUSBX_Set(Initialize); - WinUSBX_Set(QueryDeviceInformation); - WinUSBX_Set(QueryInterfaceSettings); - WinUSBX_Set(QueryPipe); - WinUSBX_Set(ReadPipe); - WinUSBX_Set(ResetPipe); - WinUSBX_Set(SetCurrentAlternateSetting); - WinUSBX_Set(SetPipePolicy); - WinUSBX_Set(SetPowerPolicy); - WinUSBX_Set(WritePipe); - if (!native_winusb) - WinUSBX_Set(ResetDevice); - - if (WinUSBX[i].Initialize != NULL) { - WinUSBX[i].initialized = true; - usbi_dbg("initalized sub API %s", sub_api_name[i]); - } else { - usbi_warn(ctx, "Failed to initalize sub API %s", sub_api_name[i]); - WinUSBX[i].initialized = false; - } - } - - WinUSBX_handle = h; - return LIBUSB_SUCCESS; -} - -static int winusbx_exit(int sub_api) -{ - if (WinUSBX_handle != NULL) { - FreeLibrary(WinUSBX_handle); - WinUSBX_handle = NULL; - - /* Reset the WinUSBX API structures */ - memset(&WinUSBX, 0, sizeof(WinUSBX)); - } - - return LIBUSB_SUCCESS; -} - -// NB: open and close must ensure that they only handle interface of -// the right API type, as these functions can be called wholesale from -// composite_open(), with interfaces belonging to different APIs -static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - - HANDLE file_handle; - int i; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // WinUSB requires a separate handle for each interface - for (i = 0; i < USB_MAXINTERFACES; i++) { - if ((priv->usb_interface[i].path != NULL) - && (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) { - file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (file_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); - switch(GetLastError()) { - case ERROR_FILE_NOT_FOUND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ACCESS_DENIED: - return LIBUSB_ERROR_ACCESS; - default: - return LIBUSB_ERROR_IO; - } - } - handle_priv->interface_handle[i].dev_handle = file_handle; - } - } - - return LIBUSB_SUCCESS; -} - -static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE handle; - int i; - - if (sub_api == SUB_API_NOTSET) - sub_api = priv->sub_api; - - if (!WinUSBX[sub_api].initialized) - return; - - if (priv->apib->id == USB_API_COMPOSITE) { - // If this is a composite device, just free and close all WinUSB-like - // interfaces directly (each is independent and not associated with another) - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) { - handle = handle_priv->interface_handle[i].api_handle; - if (HANDLE_VALID(handle)) - WinUSBX[sub_api].Free(handle); - - handle = handle_priv->interface_handle[i].dev_handle; - if (HANDLE_VALID(handle)) - CloseHandle(handle); - } - } - } else { - // If this is a WinUSB device, free all interfaces above interface 0, - // then free and close interface 0 last - for (i = 1; i < USB_MAXINTERFACES; i++) { - handle = handle_priv->interface_handle[i].api_handle; - if (HANDLE_VALID(handle)) - WinUSBX[sub_api].Free(handle); - } - handle = handle_priv->interface_handle[0].api_handle; - if (HANDLE_VALID(handle)) - WinUSBX[sub_api].Free(handle); - - handle = handle_priv->interface_handle[0].dev_handle; - if (HANDLE_VALID(handle)) - CloseHandle(handle); - } -} - -static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle; - UCHAR policy; - ULONG timeout = 0; - uint8_t endpoint_address; - int i; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // With handle and enpoints set (in parent), we can setup the default pipe properties - // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx - for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) { - endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i]; - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) - usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address); - - if ((i == -1) || (sub_api == SUB_API_LIBUSB0)) - continue; // Other policies don't apply to control endpoint or libusb0 - - policy = false; - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) - usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); - - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) - usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); - - policy = true; - /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See: - https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */ - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) - usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); - - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) - usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); - } - - return LIBUSB_SUCCESS; -} - -static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE); - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; - HDEVINFO dev_info = INVALID_HANDLE_VALUE; - SP_DEVINFO_DATA dev_info_data; - char *dev_path_no_guid = NULL; - char filter_path[] = "\\\\.\\libusb0-0000"; - bool found_filter = false; - HANDLE file_handle, winusb_handle; - DWORD err; - int i; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // If the device is composite, but using the default Windows composite parent driver (usbccgp) - // or if it's the first WinUSB-like interface, we get a handle through Initialize(). - if ((is_using_usbccgp) || (iface == 0)) { - // composite device (independent interfaces) or interface 0 - file_handle = handle_priv->interface_handle[iface].dev_handle; - if (!HANDLE_VALID(file_handle)) - return LIBUSB_ERROR_NOT_FOUND; - - if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - err = GetLastError(); - switch(err) { - case ERROR_BAD_COMMAND: - // The device was disconnected - usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - default: - // it may be that we're using the libusb0 filter driver. - // TODO: can we move this whole business into the K/0 DLL? - for (i = 0; ; i++) { - safe_free(dev_interface_details); - safe_free(dev_path_no_guid); - - dev_interface_details = get_interface_details_filter(ctx, &dev_info, &dev_info_data, &GUID_DEVINTERFACE_LIBUSB0_FILTER, i, filter_path); - if ((found_filter) || (dev_interface_details == NULL)) - break; - - // ignore GUID part - dev_path_no_guid = sanitize_path(strtok(dev_interface_details->DevicePath, "{")); - if (dev_path_no_guid == NULL) - continue; - - if (strncmp(dev_path_no_guid, priv->usb_interface[iface].path, strlen(dev_path_no_guid)) == 0) { - file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (file_handle != INVALID_HANDLE_VALUE) { - if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { - // Replace the existing file handle with the working one - CloseHandle(handle_priv->interface_handle[iface].dev_handle); - handle_priv->interface_handle[iface].dev_handle = file_handle; - found_filter = true; - } else { - usbi_err(ctx, "could not initialize filter driver for %s", filter_path); - CloseHandle(file_handle); - } - } else { - usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0)); - } - } - } - free(dev_interface_details); - if (!found_filter) { - usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(err)); - return LIBUSB_ERROR_ACCESS; - } - } - } - handle_priv->interface_handle[iface].api_handle = winusb_handle; - } else { - // For all other interfaces, use GetAssociatedInterface() - winusb_handle = handle_priv->interface_handle[0].api_handle; - // It is a requirement for multiple interface devices on Windows that, to you - // must first claim the first interface before you claim the others - if (!HANDLE_VALID(winusb_handle)) { - file_handle = handle_priv->interface_handle[0].dev_handle; - if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { - handle_priv->interface_handle[0].api_handle = winusb_handle; - usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface); - } else { - usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB): %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1), - &handle_priv->interface_handle[iface].api_handle)) { - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - switch(GetLastError()) { - case ERROR_NO_MORE_ITEMS: // invalid iface - return LIBUSB_ERROR_NOT_FOUND; - case ERROR_BAD_COMMAND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ALREADY_EXISTS: // already claimed - return LIBUSB_ERROR_BUSY; - default: - usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - } - usbi_dbg("claimed interface %d", iface); - handle_priv->active_interface = iface; - - return LIBUSB_SUCCESS; -} - -static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if (!HANDLE_VALID(winusb_handle)) - return LIBUSB_ERROR_NOT_FOUND; - - WinUSBX[sub_api].Free(winusb_handle); - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - - return LIBUSB_SUCCESS; -} - -/* - * Return the first valid interface (of the same API type), for control transfers - */ -static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int i; - - if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) { - usbi_dbg("unsupported API ID"); - return -1; - } - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle) - && HANDLE_VALID(handle_priv->interface_handle[i].api_handle) - && (priv->usb_interface[i].apib->id == api_id)) - return i; - } - - return -1; -} - -/* - * Lookup interface by endpoint address. -1 if not found - */ -static int interface_by_endpoint(struct windows_device_priv *priv, - struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address) -{ - int i, j; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle)) - continue; - if (priv->usb_interface[i].endpoint == NULL) - continue; - for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { - if (priv->usb_interface[i].endpoint[j] == endpoint_address) - return i; - } - } - - return -1; -} - -static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; - ULONG size; - HANDLE winusb_handle; - int current_interface; - struct winfd wfd; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - transfer_priv->pollable_fd = INVALID_WINFD; - size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; - - // Windows places upper limits on the control transfer size - // See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538112.aspx - if (size > MAX_CTRL_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - - current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX); - if (current_interface < 0) { - if (auto_claim(transfer, ¤t_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS) - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("will use interface %d", current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - wfd = usbi_create_fd(winusb_handle, RW_READ, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; - - // Sending of set configuration control requests from WinUSB creates issues - if (((setup->request_type & (0x03 << 5)) == LIBUSB_REQUEST_TYPE_STANDARD) - && (setup->request == LIBUSB_REQUEST_SET_CONFIGURATION)) { - if (setup->value != priv->active_config) { - usbi_warn(ctx, "cannot set configuration other than the default one"); - usbi_free_fd(&wfd); - return LIBUSB_ERROR_INVALID_PARAM; - } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = 0; - } else { - if (!WinUSBX[sub_api].ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); - return LIBUSB_ERROR_IO; - } - } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)size; - } - } - - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return LIBUSB_SUCCESS; -} - -static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - if (altsetting > 255) - return LIBUSB_ERROR_INVALID_PARAM; - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if (!HANDLE_VALID(winusb_handle)) { - usbi_err(ctx, "interface must be claimed first"); - return LIBUSB_ERROR_NOT_FOUND; - } - - if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) { - usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_IO; - } - - return LIBUSB_SUCCESS; -} - -static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - HANDLE winusb_handle; - bool ret; - int current_interface; - struct winfd wfd; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - transfer_priv->pollable_fd = INVALID_WINFD; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; - - if (IS_XFERIN(transfer)) { - usbi_dbg("reading %d bytes", transfer->length); - ret = WinUSBX[sub_api].ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); - } else { - usbi_dbg("writing %d bytes", transfer->length); - ret = WinUSBX[sub_api].WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); - } - - if (!ret) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); - return LIBUSB_ERROR_IO; - } - } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)transfer->length; - } - - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return LIBUSB_SUCCESS; -} - -static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) { - usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed - * through testing as well): - * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel - * the control transfer using CancelIo" - */ -static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer) -{ - // Cancelling of the I/O is done in the parent - return LIBUSB_SUCCESS; -} - -static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - current_interface = transfer_priv->interface_number; - if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { - usbi_err(ctx, "program assertion failed: invalid interface_number"); - return LIBUSB_ERROR_NOT_FOUND; - } - usbi_dbg("will use interface %d", current_interface); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUSBX[sub_api].AbortPipe(winusb_handle, transfer->endpoint)) { - usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper - * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx): - * "WinUSB does not support host-initiated reset port and cycle port operations" and - * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the - * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is - * cycle the pipes (and even then, the control pipe can not be reset using WinUSB) - */ -// TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?) -static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct winfd wfd; - HANDLE winusb_handle; - int i, j; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // Reset any available pipe (except control) - for (i = 0; i < USB_MAXINTERFACES; i++) { - winusb_handle = handle_priv->interface_handle[i].api_handle; - for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0; ) { - // Cancel any pollable I/O - usbi_remove_pollfd(ctx, wfd.fd); - usbi_free_fd(&wfd); - wfd = handle_to_winfd(winusb_handle); - } - - if (HANDLE_VALID(winusb_handle)) { - for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { - usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); - if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) - usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - - // FlushPipe seems to fail on OUT pipes - if (IS_EPIN(priv->usb_interface[i].endpoint[j]) - && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))) - usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - - if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) - usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - } - } - - // libusbK & libusb0 have the ability to issue an actual device reset - if (WinUSBX[sub_api].ResetDevice != NULL) { - winusb_handle = handle_priv->interface_handle[0].api_handle; - if (HANDLE_VALID(winusb_handle)) - WinUSBX[sub_api].ResetDevice(winusb_handle); - } - - return LIBUSB_SUCCESS; -} - -static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) -{ - itransfer->transferred += io_size; - return LIBUSB_TRANSFER_COMPLETED; -} - -/* - * Internal HID Support functions (from libusb-win32) - * Note that functions that complete data transfer synchronously must return - * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS - */ -static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size); -static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size); - -static int _hid_wcslen(WCHAR *str) -{ - int i = 0; - - while (str[i] && (str[i] != 0x409)) - i++; - - return i; -} - -static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, size_t *size) -{ - struct libusb_device_descriptor d; - - d.bLength = LIBUSB_DT_DEVICE_SIZE; - d.bDescriptorType = LIBUSB_DT_DEVICE; - d.bcdUSB = 0x0200; /* 2.00 */ - d.bDeviceClass = 0; - d.bDeviceSubClass = 0; - d.bDeviceProtocol = 0; - d.bMaxPacketSize0 = 64; /* fix this! */ - d.idVendor = (uint16_t)dev->vid; - d.idProduct = (uint16_t)dev->pid; - d.bcdDevice = 0x0100; - d.iManufacturer = dev->string_index[0]; - d.iProduct = dev->string_index[1]; - d.iSerialNumber = dev->string_index[2]; - d.bNumConfigurations = 1; - - if (*size > LIBUSB_DT_DEVICE_SIZE) - *size = LIBUSB_DT_DEVICE_SIZE; - memcpy(data, &d, *size); - - return LIBUSB_COMPLETED; -} - -static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, size_t *size) -{ - char num_endpoints = 0; - size_t config_total_len = 0; - char tmp[HID_MAX_CONFIG_DESC_SIZE]; - struct libusb_config_descriptor *cd; - struct libusb_interface_descriptor *id; - struct libusb_hid_descriptor *hd; - struct libusb_endpoint_descriptor *ed; - size_t tmp_size; - - if (dev->input_report_size) - num_endpoints++; - if (dev->output_report_size) - num_endpoints++; - - config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE - + LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE; - - cd = (struct libusb_config_descriptor *)tmp; - id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE); - hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE - + LIBUSB_DT_INTERFACE_SIZE); - ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE - + LIBUSB_DT_INTERFACE_SIZE - + LIBUSB_DT_HID_SIZE); - - cd->bLength = LIBUSB_DT_CONFIG_SIZE; - cd->bDescriptorType = LIBUSB_DT_CONFIG; - cd->wTotalLength = (uint16_t)config_total_len; - cd->bNumInterfaces = 1; - cd->bConfigurationValue = 1; - cd->iConfiguration = 0; - cd->bmAttributes = 1 << 7; /* bus powered */ - cd->MaxPower = 50; - - id->bLength = LIBUSB_DT_INTERFACE_SIZE; - id->bDescriptorType = LIBUSB_DT_INTERFACE; - id->bInterfaceNumber = 0; - id->bAlternateSetting = 0; - id->bNumEndpoints = num_endpoints; - id->bInterfaceClass = 3; - id->bInterfaceSubClass = 0; - id->bInterfaceProtocol = 0; - id->iInterface = 0; - - tmp_size = LIBUSB_DT_HID_SIZE; - _hid_get_hid_descriptor(dev, hd, &tmp_size); - - if (dev->input_report_size) { - ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; - ed->bDescriptorType = LIBUSB_DT_ENDPOINT; - ed->bEndpointAddress = HID_IN_EP; - ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->input_report_size - 1; - ed->bInterval = 10; - ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE); - } - - if (dev->output_report_size) { - ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; - ed->bDescriptorType = LIBUSB_DT_ENDPOINT; - ed->bEndpointAddress = HID_OUT_EP; - ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->output_report_size - 1; - ed->bInterval = 10; - } - - if (*size > config_total_len) - *size = config_total_len; - memcpy(data, tmp, *size); - - return LIBUSB_COMPLETED; -} - -static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index, - void *data, size_t *size) -{ - void *tmp = NULL; - size_t tmp_size = 0; - int i; - - /* language ID, EN-US */ - char string_langid[] = {0x09, 0x04}; - - if ((*size < 2) || (*size > 255)) - return LIBUSB_ERROR_OVERFLOW; - - if (_index == 0) { - tmp = string_langid; - tmp_size = sizeof(string_langid) + 2; - } else { - for (i = 0; i < 3; i++) { - if (_index == (dev->string_index[i])) { - tmp = dev->string[i]; - tmp_size = (_hid_wcslen(dev->string[i]) + 1) * sizeof(WCHAR); - break; - } - } - - if (i == 3) // not found - return LIBUSB_ERROR_INVALID_PARAM; - } - - if (!tmp_size) - return LIBUSB_ERROR_INVALID_PARAM; - - if (tmp_size < *size) - *size = tmp_size; - - // 2 byte header - ((uint8_t *)data)[0] = (uint8_t)*size; - ((uint8_t *)data)[1] = LIBUSB_DT_STRING; - memcpy((uint8_t *)data + 2, tmp, *size - 2); - - return LIBUSB_COMPLETED; -} - -static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size) -{ - struct libusb_hid_descriptor d; - uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE]; - size_t report_len = MAX_HID_DESCRIPTOR_SIZE; - - _hid_get_report_descriptor(dev, tmp, &report_len); - - d.bLength = LIBUSB_DT_HID_SIZE; - d.bDescriptorType = LIBUSB_DT_HID; - d.bcdHID = 0x0110; /* 1.10 */ - d.bCountryCode = 0; - d.bNumDescriptors = 1; - d.bClassDescriptorType = LIBUSB_DT_REPORT; - d.wClassDescriptorLength = (uint16_t)report_len; - - if (*size > LIBUSB_DT_HID_SIZE) - *size = LIBUSB_DT_HID_SIZE; - memcpy(data, &d, *size); - - return LIBUSB_COMPLETED; -} - -static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size) -{ - uint8_t d[MAX_HID_DESCRIPTOR_SIZE]; - size_t i = 0; - - /* usage page (0xFFA0 == vendor defined) */ - d[i++] = 0x06; d[i++] = 0xA0; d[i++] = 0xFF; - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x01; - /* start collection (application) */ - d[i++] = 0xA1; d[i++] = 0x01; - /* input report */ - if (dev->input_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x01; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1; - /* input (data, variable, absolute) */ - d[i++] = 0x81; d[i++] = 0x00; - } - /* output report */ - if (dev->output_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x02; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1; - /* output (data, variable, absolute) */ - d[i++] = 0x91; d[i++] = 0x00; - } - /* feature report */ - if (dev->feature_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x03; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1; - /* feature (data, variable, absolute) */ - d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01; - } - - /* end collection */ - d[i++] = 0xC0; - - if (*size > i) - *size = i; - memcpy(data, d, *size); - - return LIBUSB_COMPLETED; -} - -static int _hid_get_descriptor(struct hid_device_priv *dev, HANDLE hid_handle, int recipient, - int type, int _index, void *data, size_t *size) -{ - switch(type) { - case LIBUSB_DT_DEVICE: - usbi_dbg("LIBUSB_DT_DEVICE"); - return _hid_get_device_descriptor(dev, data, size); - case LIBUSB_DT_CONFIG: - usbi_dbg("LIBUSB_DT_CONFIG"); - if (!_index) - return _hid_get_config_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_STRING: - usbi_dbg("LIBUSB_DT_STRING"); - return _hid_get_string_descriptor(dev, _index, data, size); - case LIBUSB_DT_HID: - usbi_dbg("LIBUSB_DT_HID"); - if (!_index) - return _hid_get_hid_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_REPORT: - usbi_dbg("LIBUSB_DT_REPORT"); - if (!_index) - return _hid_get_report_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_PHYSICAL: - usbi_dbg("LIBUSB_DT_PHYSICAL"); - if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size)) - return LIBUSB_COMPLETED; - return LIBUSB_ERROR_OTHER; - } - - usbi_dbg("unsupported"); - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data, - struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type) -{ - uint8_t *buf; - DWORD ioctl_code, read_size, expected_size = (DWORD)*size; - int r = LIBUSB_SUCCESS; - - if (tp->hid_buffer != NULL) - usbi_dbg("program assertion failed: hid_buffer is not NULL"); - - if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { - usbi_dbg("invalid size (%u)", *size); - return LIBUSB_ERROR_INVALID_PARAM; - } - - switch (report_type) { - case HID_REPORT_TYPE_INPUT: - ioctl_code = IOCTL_HID_GET_INPUT_REPORT; - break; - case HID_REPORT_TYPE_FEATURE: - ioctl_code = IOCTL_HID_GET_FEATURE; - break; - default: - usbi_dbg("unknown HID report type %d", report_type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - // Add a trailing byte to detect overflows - buf = calloc(1, expected_size + 1); - if (buf == NULL) - return LIBUSB_ERROR_NO_MEM; - - buf[0] = (uint8_t)id; // Must be set always - usbi_dbg("report ID: 0x%02X", buf[0]); - - tp->hid_expected_size = expected_size; - read_size = expected_size; - - // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) - if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1, - buf, expected_size + 1, &read_size, overlapped)) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0)); - free(buf); - return LIBUSB_ERROR_IO; - } - // Asynchronous wait - tp->hid_buffer = buf; - tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer - return LIBUSB_SUCCESS; - } - - // Transfer completed synchronously => copy and discard extra buffer - if (read_size == 0) { - usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read"); - *size = 0; - } else { - if (buf[0] != id) - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); - - if ((size_t)read_size > expected_size) { - r = LIBUSB_ERROR_OVERFLOW; - usbi_dbg("OVERFLOW!"); - } else { - r = LIBUSB_COMPLETED; - } - - *size = MIN((size_t)read_size, *size); - if (id == 0) - memcpy(data, buf + 1, *size); // Discard report ID - else - memcpy(data, buf, *size); - } - - free(buf); - return r; -} - -static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data, - struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type) -{ - uint8_t *buf = NULL; - DWORD ioctl_code, write_size = (DWORD)*size; - - if (tp->hid_buffer != NULL) - usbi_dbg("program assertion failed: hid_buffer is not NULL"); - - if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { - usbi_dbg("invalid size (%u)", *size); - return LIBUSB_ERROR_INVALID_PARAM; - } - - switch (report_type) { - case HID_REPORT_TYPE_OUTPUT: - ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT; - break; - case HID_REPORT_TYPE_FEATURE: - ioctl_code = IOCTL_HID_SET_FEATURE; - break; - default: - usbi_dbg("unknown HID report type %d", report_type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - usbi_dbg("report ID: 0x%02X", id); - // When report IDs are not used (i.e. when id == 0), we must add - // a null report ID. Otherwise, we just use original data buffer - if (id == 0) - write_size++; - - buf = malloc(write_size); - if (buf == NULL) - return LIBUSB_ERROR_NO_MEM; - - if (id == 0) { - buf[0] = 0; - memcpy(buf + 1, data, *size); - } else { - // This seems like a waste, but if we don't duplicate the - // data, we'll get issues when freeing hid_buffer - memcpy(buf, data, *size); - if (buf[0] != id) - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); - } - - // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) - if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size, - buf, write_size, &write_size, overlapped)) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0)); - free(buf); - return LIBUSB_ERROR_IO; - } - tp->hid_buffer = buf; - tp->hid_dest = NULL; - return LIBUSB_SUCCESS; - } - - // Transfer completed synchronously - *size = write_size; - if (write_size == 0) - usbi_dbg("program assertion failed - write completed synchronously, but no data was written"); - - free(buf); - return LIBUSB_COMPLETED; -} - -static int _hid_class_request(struct hid_device_priv *dev, HANDLE hid_handle, int request_type, - int request, int value, int _index, void *data, struct windows_transfer_priv *tp, - size_t *size, OVERLAPPED *overlapped) -{ - int report_type = (value >> 8) & 0xFF; - int report_id = value & 0xFF; - - if ((LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE) - && (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE)) - return LIBUSB_ERROR_INVALID_PARAM; - - if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT) - return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); - - if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT) - return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); - - return LIBUSB_ERROR_INVALID_PARAM; -} - - -/* - * HID API functions - */ -static int hid_init(int sub_api, struct libusb_context *ctx) -{ - DLL_GET_HANDLE(hid); - DLL_LOAD_FUNC(hid, HidD_GetAttributes, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetHidGuid, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, TRUE); - DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetProductString, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, TRUE); - DLL_LOAD_FUNC(hid, HidP_GetCaps, TRUE); - DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, TRUE); - DLL_LOAD_FUNC(hid, HidD_SetFeature, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetFeature, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, TRUE); - DLL_LOAD_FUNC(hid, HidD_GetInputReport, FALSE); - DLL_LOAD_FUNC(hid, HidD_SetOutputReport, FALSE); - DLL_LOAD_FUNC(hid, HidD_FlushQueue, TRUE); - DLL_LOAD_FUNC(hid, HidP_GetValueCaps, TRUE); - - api_hid_available = true; - return LIBUSB_SUCCESS; -} - -static int hid_exit(int sub_api) -{ - DLL_FREE_HANDLE(hid); - - return LIBUSB_SUCCESS; -} - -// NB: open and close must ensure that they only handle interface of -// the right API type, as these functions can be called wholesale from -// composite_open(), with interfaces belonging to different APIs -static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - HIDD_ATTRIBUTES hid_attributes; - PHIDP_PREPARSED_DATA preparsed_data = NULL; - HIDP_CAPS capabilities; - HIDP_VALUE_CAPS *value_caps; - HANDLE hid_handle = INVALID_HANDLE_VALUE; - int i, j; - // report IDs handling - ULONG size[3]; - int nb_ids[2]; // zero and nonzero report IDs -#if defined(ENABLE_LOGGING) - const char *type[3] = {"input", "output", "feature"}; -#endif - - CHECK_HID_AVAILABLE; - - if (priv->hid == NULL) { - usbi_err(ctx, "program assertion failed - private HID structure is unitialized"); - return LIBUSB_ERROR_NOT_FOUND; - } - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if ((priv->usb_interface[i].path != NULL) - && (priv->usb_interface[i].apib->id == USB_API_HID)) { - hid_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - /* - * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID? - * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system - * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not - * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and - * HidD_GetFeature (if the device supports Feature reports)." - */ - if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without"); - hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0)); - switch(GetLastError()) { - case ERROR_FILE_NOT_FOUND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ACCESS_DENIED: - return LIBUSB_ERROR_ACCESS; - default: - return LIBUSB_ERROR_IO; - } - } - priv->usb_interface[i].restricted_functionality = true; - } - handle_priv->interface_handle[i].api_handle = hid_handle; - } - } - - hid_attributes.Size = sizeof(hid_attributes); - do { - if (!HidD_GetAttributes(hid_handle, &hid_attributes)) { - usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)"); - break; - } - - priv->hid->vid = hid_attributes.VendorID; - priv->hid->pid = hid_attributes.ProductID; - - // Set the maximum available input buffer size - for (i = 32; HidD_SetNumInputBuffers(hid_handle, i); i *= 2); - usbi_dbg("set maximum input buffer size to %d", i / 2); - - // Get the maximum input and output report size - if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) { - usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)"); - break; - } - if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) { - usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)"); - break; - } - - // Find out if interrupt will need report IDs - size[0] = capabilities.NumberInputValueCaps; - size[1] = capabilities.NumberOutputValueCaps; - size[2] = capabilities.NumberFeatureValueCaps; - for (j = HidP_Input; j <= HidP_Feature; j++) { - usbi_dbg("%u HID %s report value(s) found", (unsigned int)size[j], type[j]); - priv->hid->uses_report_ids[j] = false; - if (size[j] > 0) { - value_caps = calloc(size[j], sizeof(HIDP_VALUE_CAPS)); - if ((value_caps != NULL) - && (HidP_GetValueCaps((HIDP_REPORT_TYPE)j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS) - && (size[j] >= 1)) { - nb_ids[0] = 0; - nb_ids[1] = 0; - for (i = 0; i < (int)size[j]; i++) { - usbi_dbg(" Report ID: 0x%02X", value_caps[i].ReportID); - if (value_caps[i].ReportID != 0) - nb_ids[1]++; - else - nb_ids[0]++; - } - if (nb_ids[1] != 0) { - if (nb_ids[0] != 0) - usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s", - type[j]); - priv->hid->uses_report_ids[j] = true; - } - } else { - usbi_warn(ctx, " could not process %s report IDs", type[j]); - } - free(value_caps); - } - } - - // Set the report sizes - priv->hid->input_report_size = capabilities.InputReportByteLength; - priv->hid->output_report_size = capabilities.OutputReportByteLength; - priv->hid->feature_report_size = capabilities.FeatureReportByteLength; - - // Fetch string descriptors - priv->hid->string_index[0] = priv->dev_descriptor.iManufacturer; - if (priv->hid->string_index[0] != 0) - HidD_GetManufacturerString(hid_handle, priv->hid->string[0], sizeof(priv->hid->string[0])); - else - priv->hid->string[0][0] = 0; - - priv->hid->string_index[1] = priv->dev_descriptor.iProduct; - if (priv->hid->string_index[1] != 0) - HidD_GetProductString(hid_handle, priv->hid->string[1], sizeof(priv->hid->string[1])); - else - priv->hid->string[1][0] = 0; - - priv->hid->string_index[2] = priv->dev_descriptor.iSerialNumber; - if (priv->hid->string_index[2] != 0) - HidD_GetSerialNumberString(hid_handle, priv->hid->string[2], sizeof(priv->hid->string[2])); - else - priv->hid->string[2][0] = 0; - } while(0); - - if (preparsed_data) - HidD_FreePreparsedData(preparsed_data); - - return LIBUSB_SUCCESS; -} - -static void hid_close(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - HANDLE file_handle; - int i; - - if (!api_hid_available) - return; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].apib->id == USB_API_HID) { - file_handle = handle_priv->interface_handle[i].api_handle; - if (HANDLE_VALID(file_handle)) - CloseHandle(file_handle); - } - } -} - -static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - // NB: Disconnection detection is not possible in this function - if (priv->usb_interface[iface].path == NULL) - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - - // We use dev_handle as a flag for interface claimed - if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED) - return LIBUSB_ERROR_BUSY; // already claimed - - - handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED; - - usbi_dbg("claimed interface %d", iface); - handle_priv->active_interface = iface; - - return LIBUSB_SUCCESS; -} - -static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - if (priv->usb_interface[iface].path == NULL) - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - - if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED) - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - - handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE; - - return LIBUSB_SUCCESS; -} - -static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - if (altsetting > 255) - return LIBUSB_ERROR_INVALID_PARAM; - - if (altsetting != 0) { - usbi_err(ctx, "set interface altsetting not supported for altsetting >0"); - return LIBUSB_ERROR_NOT_SUPPORTED; - } - - return LIBUSB_SUCCESS; -} - -static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; - HANDLE hid_handle; - struct winfd wfd; - int current_interface, config; - size_t size; - int r = LIBUSB_ERROR_INVALID_PARAM; - - CHECK_HID_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - safe_free(transfer_priv->hid_buffer); - transfer_priv->hid_dest = NULL; - size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; - - if (size > MAX_CTRL_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - - current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID); - if (current_interface < 0) { - if (auto_claim(transfer, ¤t_interface, USB_API_HID) != LIBUSB_SUCCESS) - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("will use interface %d", current_interface); - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - // Always use the handle returned from usbi_create_fd (wfd.handle) - wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL); - if (wfd.fd < 0) - return LIBUSB_ERROR_NOT_FOUND; - - switch(LIBUSB_REQ_TYPE(setup->request_type)) { - case LIBUSB_REQUEST_TYPE_STANDARD: - switch(setup->request) { - case LIBUSB_REQUEST_GET_DESCRIPTOR: - r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type), - (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size); - break; - case LIBUSB_REQUEST_GET_CONFIGURATION: - r = windows_get_configuration(transfer->dev_handle, &config); - if (r == LIBUSB_SUCCESS) { - size = 1; - ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config; - r = LIBUSB_COMPLETED; - } - break; - case LIBUSB_REQUEST_SET_CONFIGURATION: - if (setup->value == priv->active_config) { - r = LIBUSB_COMPLETED; - } else { - usbi_warn(ctx, "cannot set configuration other than the default one"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - } - break; - case LIBUSB_REQUEST_GET_INTERFACE: - size = 1; - ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0; - r = LIBUSB_COMPLETED; - break; - case LIBUSB_REQUEST_SET_INTERFACE: - r = hid_set_interface_altsetting(0, transfer->dev_handle, setup->index, setup->value); - if (r == LIBUSB_SUCCESS) - r = LIBUSB_COMPLETED; - break; - default: - usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - break; - } - break; - case LIBUSB_REQUEST_TYPE_CLASS: - r = _hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value, - setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv, - &size, wfd.overlapped); - break; - default: - usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - break; - } - - if (r == LIBUSB_COMPLETED) { - // Force request to be completed synchronously. Transferred size has been set by previous call - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx - // set InternalHigh to the number of bytes transferred - wfd.overlapped->InternalHigh = (DWORD)size; - r = LIBUSB_SUCCESS; - } - - if (r == LIBUSB_SUCCESS) { - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - } else { - usbi_free_fd(&wfd); - } - - return r; -} - -static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct winfd wfd; - HANDLE hid_handle; - bool direction_in, ret; - int current_interface, length; - DWORD size; - int r = LIBUSB_SUCCESS; - - CHECK_HID_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - transfer_priv->hid_dest = NULL; - safe_free(transfer_priv->hid_buffer); - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - wfd = usbi_create_fd(hid_handle, direction_in?RW_READ:RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; - - // If report IDs are not in use, an extra prefix byte must be added - if (((direction_in) && (!priv->hid->uses_report_ids[0])) - || ((!direction_in) && (!priv->hid->uses_report_ids[1]))) - length = transfer->length + 1; - else - length = transfer->length; - - // Add a trailing byte to detect overflows on input - transfer_priv->hid_buffer = calloc(1, length + 1); - if (transfer_priv->hid_buffer == NULL) - return LIBUSB_ERROR_NO_MEM; - - transfer_priv->hid_expected_size = length; - - if (direction_in) { - transfer_priv->hid_dest = transfer->buffer; - usbi_dbg("reading %d bytes (report ID: 0x00)", length); - ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length + 1, &size, wfd.overlapped); - } else { - if (!priv->hid->uses_report_ids[1]) - memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length); - else - // We could actually do without the calloc and memcpy in this case - memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length); - - usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]); - ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped); - } - - if (!ret) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); - safe_free(transfer_priv->hid_buffer); - return LIBUSB_ERROR_IO; - } - } else { - // Only write operations that completed synchronously need to free up - // hid_buffer. For reads, copy_transfer_data() handles that process. - if (!direction_in) - safe_free(transfer_priv->hid_buffer); - - if (size == 0) { - usbi_err(ctx, "program assertion failed - no data was transferred"); - size = 1; - } - if (size > (size_t)length) { - usbi_err(ctx, "OVERFLOW!"); - r = LIBUSB_ERROR_OVERFLOW; - } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = size; - } - - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return r; -} - -static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - current_interface = transfer_priv->interface_number; - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - CancelIo(hid_handle); - - return LIBUSB_SUCCESS; -} - -static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - // Flushing the queues on all interfaces is the best we can achieve - for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) { - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - if (HANDLE_VALID(hid_handle)) - HidD_FlushQueue(hid_handle); - } - - return LIBUSB_SUCCESS; -} - -static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - - // No endpoint selection with Microsoft's implementation, so we try to flush the - // whole interface. Should be OK for most case scenarios - if (!HidD_FlushQueue(hid_handle)) { - usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0)); - // Device was probably disconnected - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -// This extra function is only needed for HID -static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - int r = LIBUSB_TRANSFER_COMPLETED; - uint32_t corrected_size = io_size; - - if (transfer_priv->hid_buffer != NULL) { - // If we have a valid hid_buffer, it means the transfer was async - if (transfer_priv->hid_dest != NULL) { // Data readout - if (corrected_size > 0) { - // First, check for overflow - if (corrected_size > transfer_priv->hid_expected_size) { - usbi_err(ctx, "OVERFLOW!"); - corrected_size = (uint32_t)transfer_priv->hid_expected_size; - r = LIBUSB_TRANSFER_OVERFLOW; - } - - if (transfer_priv->hid_buffer[0] == 0) { - // Discard the 1 byte report ID prefix - corrected_size--; - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, corrected_size); - } else { - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size); - } - } - transfer_priv->hid_dest = NULL; - } - // For write, we just need to free the hid buffer - safe_free(transfer_priv->hid_buffer); - } - - itransfer->transferred += corrected_size; - return r; -} - - -/* - * Composite API functions - */ -static int composite_init(int sub_api, struct libusb_context *ctx) -{ - return LIBUSB_SUCCESS; -} - -static int composite_exit(int sub_api) -{ - return LIBUSB_SUCCESS; -} - -static int composite_open(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int r = LIBUSB_ERROR_NOT_FOUND; - uint8_t i; - // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID - bool available[SUB_API_MAX + 1] = { 0 }; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - switch (priv->usb_interface[i].apib->id) { - case USB_API_WINUSBX: - if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) - available[priv->usb_interface[i].sub_api] = true; - break; - case USB_API_HID: - available[SUB_API_MAX] = true; - break; - default: - break; - } - } - - for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers - if (available[i]) { - r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle); - if (r != LIBUSB_SUCCESS) - return r; - } - } - - if (available[SUB_API_MAX]) // HID driver - r = hid_open(SUB_API_NOTSET, dev_handle); - - return r; -} - -static void composite_close(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - uint8_t i; - // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID - bool available[SUB_API_MAX + 1] = { 0 }; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - switch (priv->usb_interface[i].apib->id) { - case USB_API_WINUSBX: - if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) - available[priv->usb_interface[i].sub_api] = true; - break; - case USB_API_HID: - available[SUB_API_MAX] = true; - break; - default: - break; - } - } - - for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers - if (available[i]) - usb_api_backend[USB_API_WINUSBX].close(i, dev_handle); - } - - if (available[SUB_API_MAX]) // HID driver - hid_close(SUB_API_NOTSET, dev_handle); -} - -static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - return priv->usb_interface[iface].apib-> - claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); -} - -static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - return priv->usb_interface[iface].apib-> - set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting); -} - -static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - return priv->usb_interface[iface].apib-> - release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); -} - -static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct libusb_config_descriptor *conf_desc; - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; - int iface, pass, r; - - // Interface shouldn't matter for control, but it does in practice, with Windows' - // restrictions with regards to accessing HID keyboards and mice. Try to target - // a specific interface first, if possible. - switch (LIBUSB_REQ_RECIPIENT(setup->request_type)) { - case LIBUSB_RECIPIENT_INTERFACE: - iface = setup->index & 0xFF; - break; - case LIBUSB_RECIPIENT_ENDPOINT: - r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc); - if (r == LIBUSB_SUCCESS) { - iface = get_interface_by_endpoint(conf_desc, (setup->index & 0xFF)); - libusb_free_config_descriptor(conf_desc); - break; - } - // Fall through if not able to determine interface - default: - iface = -1; - break; - } - - // Try and target a specific interface if the control setup indicates such - if ((iface >= 0) && (iface < USB_MAXINTERFACES)) { - usbi_dbg("attempting control transfer targeted to interface %d", iface); - if (priv->usb_interface[iface].path != NULL) { - r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); - if (r == LIBUSB_SUCCESS) - return r; - } - } - - // Either not targeted to a specific interface or no luck in doing so. - // Try a 2 pass approach with all interfaces. - for (pass = 0; pass < 2; pass++) { - for (iface = 0; iface < USB_MAXINTERFACES; iface++) { - if (priv->usb_interface[iface].path != NULL) { - if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) { - usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface); - continue; - } - usbi_dbg("using interface %d", iface); - r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); - // If not supported on this API, it may be supported on another, so don't give up yet!! - if (r == LIBUSB_ERROR_NOT_SUPPORTED) - continue; - return r; - } - } - } - - usbi_err(ctx, "no libusb supported interfaces to complete request"); - return LIBUSB_ERROR_NOT_FOUND; -} - -static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib-> - submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer); -} - -static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib-> - submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer); -} - -static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib-> - clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint); -} - -static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib-> - abort_control(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer); -} - -static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib-> - abort_transfers(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer); -} - -static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int r; - uint8_t i; - bool available[SUB_API_MAX]; - - for (i = 0; i < SUB_API_MAX; i++) - available[i] = false; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX) - && (priv->usb_interface[i].sub_api != SUB_API_NOTSET)) - available[priv->usb_interface[i].sub_api] = true; - } - - for (i = 0; i < SUB_API_MAX; i++) { - if (available[i]) { - r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle); - if (r != LIBUSB_SUCCESS) - return r; - } - } - - return LIBUSB_SUCCESS; -} - -static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib-> - copy_transfer_data(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer, io_size); -} - -#endif /* !USE_USBDK */ diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h b/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h deleted file mode 100644 index 0a5d1c9926..0000000000 --- a/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h +++ /dev/null @@ -1 +0,0 @@ -#define LIBUSB_NANO 11182 diff --git a/vendor/github.com/karalabe/hid/usb.go b/vendor/github.com/karalabe/hid/usb.go deleted file mode 100644 index 5e87682149..0000000000 --- a/vendor/github.com/karalabe/hid/usb.go +++ /dev/null @@ -1,53 +0,0 @@ -// hid - Gopher Interface Devices (USB HID) -// Copyright (c) 2019 Péter Szilágyi, Guillaume Ballet. All rights reserved. -// -// This file is released under the 3-clause BSD license. Note however that Linux -// support depends on libusb, released under GNU LGPL 2.1 or later. - -// Package usb provide interfaces for generic USB devices. -package hid - -// DeviceType represents the type of a USB device (generic or HID) -type DeviceType int - -// List of supported device types -const ( - DeviceTypeGeneric DeviceType = 0 - DeviceTypeHID DeviceType = 1 -) - -// Enumerate returns a list of all the HID devices attached to the system which -// match the vendor and product id: -// - If the vendor id is set to 0 then any vendor matches. -// - If the product id is set to 0 then any product matches. -// - If the vendor and product id are both 0, all HID devices are returned. -// func Enumerate(vendorID uint16, productID uint16) []DeviceInfo { -// } - -// DeviceInfo is a generic libusb info interface -type DeviceInfo interface { - // Type returns the type of the device (generic or HID) - Type() DeviceType - - // Platform-specific device path - GetPath() string - - // IDs returns the vendor and product IDs for the device, - // as well as the endpoint id and the usage page. - IDs() (uint16, uint16, int, uint16) - - // Open tries to open the USB device represented by the current DeviceInfo - Open() (Device, error) -} - -// Device is a generic libusb device interface -type Device interface { - Close() error - - Write(b []byte) (int, error) - - Read(b []byte) (int, error) - - // Type returns the type of the device (generic or HID) - Type() DeviceType -} diff --git a/vendor/github.com/karalabe/usb/AUTHORS b/vendor/github.com/karalabe/usb/AUTHORS new file mode 100644 index 0000000000..4112a92f33 --- /dev/null +++ b/vendor/github.com/karalabe/usb/AUTHORS @@ -0,0 +1,6 @@ +Felix Lange +Guillaume Ballet +Jakob Weisblat +Mateusz Mikołajczyk +Péter Szilágyi +Rosen Penev diff --git a/vendor/github.com/karalabe/usb/LICENSE b/vendor/github.com/karalabe/usb/LICENSE new file mode 100644 index 0000000000..65c5ca88a6 --- /dev/null +++ b/vendor/github.com/karalabe/usb/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/vendor/github.com/karalabe/usb/README.md b/vendor/github.com/karalabe/usb/README.md new file mode 100644 index 0000000000..b6920f51a1 --- /dev/null +++ b/vendor/github.com/karalabe/usb/README.md @@ -0,0 +1,47 @@ +[![Travis][travisimg]][travisurl] +[![AppVeyor][appveyorimg]][appveyorurl] +[![GoDoc][docimg]][docurl] + +[travisimg]: https://travis-ci.org/karalabe/usb.svg?branch=master +[travisurl]: https://travis-ci.org/karalabe/usb +[appveyorimg]: https://ci.appveyor.com/api/projects/status/u96eq262bj2itprh/branch/master?svg=true +[appveyorurl]: https://ci.appveyor.com/project/karalabe/usb +[docimg]: https://godoc.org/github.com/karalabe/usb?status.svg +[docurl]: https://godoc.org/github.com/karalabe/usb + +# Yet another USB library for Go + +The `usb` package is a cross platform, fully self-contained library for accessing and communicating with USB devices **either via HID or low level interrupts**. The goal of the library was to create a simple way to find-, attach to- and read/write form USB devices. + +There are multiple already existing USB libraries: + + * The original `gousb` package [created by @kylelemons](https://github.com/kylelemons/gousb) and nowadays [maintained by @google](https://github.com/google/gousb) is a CGO wrapper around `libusb`. It is the most advanced USB library for Go out there. + * Unfortunately, `gousb` requires the `libusb` C library to be installed both during build as well as during runtime on the host operating system. This breaks binary portability and also adds unnecessary hurdles on Windows. + * Furthermore, whilst HID devices are supported by `libusb`, the OS on Macos and Windows explicitly takes over these devices, so only native system calls can be used on recent versions (i.e. you **cannot** use `libusb` for HID). + * There is a fork of `gousb` [created by @karalabe](https://github.com/karalabe/gousb) that statically linked `libusb` during build, but with the lack of HID access, that work was abandoned. + * For HID-only devices, a previous self-contained package was created at [`github.com/karalabe/hid`](https://github.com/karalabe/hid), which worked well for hardware wallet uses cases in [`go-ethereum`](https://github.com/ethereum/go-ethereum). It's a simple package that does it's thing well. + * Unfortunately, `hid` is not capable of talking to generic USB devices. When multiple different devices are needed, eventually some will not support the HID spec (e.g. WebUSB). Pulling in both `hid` and `gousb` will break down due to both depending internally on different versions of `libusb` on Linux. + +This `usb` package is a proper integration of `hidapi` and `libusb` so that communication with HID devices is done via system calls, whereas communication with lower level USB devices is done via interrupts. All this detail is hidden away behind a tiny interface. + +The package supports Linux, macOS, Windows and FreeBSD. Exclude constraints are also specified for Android and iOS to allow smoother vendoring into cross platform projects. + +## Cross-compiling + +Using `go get`, the embedded C library is compiled into the binary format of your host OS. Cross compiling to a different platform or architecture entails disabling CGO by default in Go, causing device enumeration `hid.Enumerate()` to yield no results. + +To cross compile a functional version of this library, you'll need to enable CGO during cross compilation via `CGO_ENABLED=1` and you'll need to install and set a cross compilation enabled C toolkit via `CC=your-cross-gcc`. + +## Acknowledgements + +Although the `usb` package is an implementation from scratch, HID support was heavily inspired by the existing [`go.hid`](https://github.com/GeertJohan/go.hid) library, which seems abandoned since 2015; is incompatible with Go 1.6+; and has various external dependencies. + +Wide character support in the HID support is done via the [`gowchar`](https://github.com/orofarne/gowchar) library, unmaintained since 2013; non buildable with a modern Go release and failing `go vet` checks. As such, `gowchar` was also vendored in inline. + +Error handling for the `libusb` integration originates from the [`gousb`](https://github.com/google/gousb) library. + +## License + +This USB library is licensed under the [GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html) (dictated by libusb). + +If you are only interested in Human Interface devices, a less restrictive package can be found at [`github.com/karalabe/hid`](https://github.com/karalabe/hid). diff --git a/vendor/github.com/karalabe/hid/appveyor.yml b/vendor/github.com/karalabe/usb/appveyor.yml similarity index 81% rename from vendor/github.com/karalabe/hid/appveyor.yml rename to vendor/github.com/karalabe/usb/appveyor.yml index 84b3c95ff7..8d2d3da55c 100644 --- a/vendor/github.com/karalabe/hid/appveyor.yml +++ b/vendor/github.com/karalabe/usb/appveyor.yml @@ -1,7 +1,7 @@ os: Visual Studio 2015 # Clone directly into GOPATH. -clone_folder: C:\gopath\src\github.com\karalabe\hid +clone_folder: C:\gopath\src\github.com\karalabe\usb clone_depth: 1 version: "{branch}.{build}" environment: @@ -22,8 +22,8 @@ environment: install: - rmdir C:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.1.windows-%GOARCH%.zip - - 7z x go1.10.1.windows-%GOARCH%.zip -y -oC:\ > NUL + - appveyor DownloadFile https://storage.googleapis.com/golang/go1.12.5.windows-%GOARCH%.zip + - 7z x go1.12.5.windows-%GOARCH%.zip -y -oC:\ > NUL - go version - gcc --version diff --git a/vendor/github.com/karalabe/usb/demo.go b/vendor/github.com/karalabe/usb/demo.go new file mode 100644 index 0000000000..229faaf5f8 --- /dev/null +++ b/vendor/github.com/karalabe/usb/demo.go @@ -0,0 +1,76 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2019 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build none + +package main + +import ( + "fmt" + "strings" + + "github.com/karalabe/usb" +) + +func main() { + // Enumerate all the HID devices in alphabetical path order + hids, err := usb.EnumerateHid(0, 0) + if err != nil { + panic(err) + } + for i := 0; i < len(hids); i++ { + for j := i + 1; j < len(hids); j++ { + if hids[i].Path > hids[j].Path { + hids[i], hids[j] = hids[j], hids[i] + } + } + } + for i, hid := range hids { + fmt.Println(strings.Repeat("-", 128)) + fmt.Printf("HID #%d\n", i) + fmt.Printf(" OS Path: %s\n", hid.Path) + fmt.Printf(" Vendor ID: %#04x\n", hid.VendorID) + fmt.Printf(" Product ID: %#04x\n", hid.ProductID) + fmt.Printf(" Release: %d\n", hid.Release) + fmt.Printf(" Serial: %s\n", hid.Serial) + fmt.Printf(" Manufacturer: %s\n", hid.Manufacturer) + fmt.Printf(" Product: %s\n", hid.Product) + fmt.Printf(" Usage Page: %d\n", hid.UsagePage) + fmt.Printf(" Usage: %d\n", hid.Usage) + fmt.Printf(" Interface: %d\n", hid.Interface) + } + fmt.Println(strings.Repeat("=", 128)) + + // Enumerate all the non-HID devices in alphabetical path order + raws, err := usb.EnumerateRaw(0, 0) + if err != nil { + panic(err) + } + for i := 0; i < len(raws); i++ { + for j := i + 1; j < len(raws); j++ { + if raws[i].Path > raws[j].Path { + raws[i], raws[j] = raws[j], raws[i] + } + } + } + for i, raw := range raws { + fmt.Printf("RAW #%d\n", i) + fmt.Printf(" OS Path: %s\n", raw.Path) + fmt.Printf(" Vendor ID: %#04x\n", raw.VendorID) + fmt.Printf(" Product ID: %#04x\n", raw.ProductID) + fmt.Printf(" Interface: %d\n", raw.Interface) + fmt.Println(strings.Repeat("-", 128)) + } +} diff --git a/vendor/github.com/karalabe/usb/go.mod b/vendor/github.com/karalabe/usb/go.mod new file mode 100644 index 0000000000..ef549d28f5 --- /dev/null +++ b/vendor/github.com/karalabe/usb/go.mod @@ -0,0 +1,3 @@ +module github.com/karalabe/usb + +go 1.12 diff --git a/vendor/github.com/karalabe/usb/hid_disabled.go b/vendor/github.com/karalabe/usb/hid_disabled.go new file mode 100644 index 0000000000..a85964bf35 --- /dev/null +++ b/vendor/github.com/karalabe/usb/hid_disabled.go @@ -0,0 +1,42 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2017 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build !freebsd,!linux,!darwin,!windows ios !cgo + +package usb + +// HidDevice is a live HID USB connected device handle. On platforms that this file +// implements, the type lacks the actual HID device and all methods are noop. +type HidDevice struct { + DeviceInfo // Embed the infos for easier access +} + +// Close releases the HID USB device handle. On platforms that this file implements, +// the method is just a noop. +func (dev *HidDevice) Close() error { + return ErrUnsupportedPlatform +} + +// Write sends an output report to a HID device. On platforms that this file +// implements, the method just returns an error. +func (dev *HidDevice) Write(b []byte) (int, error) { + return 0, ErrUnsupportedPlatform +} + +// Read retrieves an input report from a HID device. On platforms that this file +// implements, the method just returns an error. +func (dev *HidDevice) Read(b []byte) (int, error) { + return 0, ErrUnsupportedPlatform +} diff --git a/vendor/github.com/karalabe/usb/hid_enabled.go b/vendor/github.com/karalabe/usb/hid_enabled.go new file mode 100644 index 0000000000..c2b3720989 --- /dev/null +++ b/vendor/github.com/karalabe/usb/hid_enabled.go @@ -0,0 +1,187 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2017 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo + +package usb + +/* +#include +#include "./hidapi/hidapi/hidapi.h" +*/ +import "C" + +import ( + "errors" + "runtime" + "sync" + "unsafe" +) + +// enumerateHid returns a list of all the HID devices attached to the system which +// match the vendor and product id: +// - If the vendor id is set to 0 then any vendor matches. +// - If the product id is set to 0 then any product matches. +// - If the vendor and product id are both 0, all HID devices are returned. +func enumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + // Gather all device infos and ensure they are freed before returning + head := C.hid_enumerate(C.ushort(vendorID), C.ushort(productID)) + if head == nil { + return nil, nil + } + defer C.hid_free_enumeration(head) + + // Iterate the list and retrieve the device details + var infos []DeviceInfo + for ; head != nil; head = head.next { + info := DeviceInfo{ + Path: C.GoString(head.path), + VendorID: uint16(head.vendor_id), + ProductID: uint16(head.product_id), + Release: uint16(head.release_number), + UsagePage: uint16(head.usage_page), + Usage: uint16(head.usage), + Interface: int(head.interface_number), + } + if head.serial_number != nil { + info.Serial, _ = wcharTToString(head.serial_number) + } + if head.product_string != nil { + info.Product, _ = wcharTToString(head.product_string) + } + if head.manufacturer_string != nil { + info.Manufacturer, _ = wcharTToString(head.manufacturer_string) + } + infos = append(infos, info) + } + return infos, nil +} + +// openHid connects to an HID device by its path name. +func openHid(info DeviceInfo) (*hidDevice, error) { + path := C.CString(info.Path) + defer C.free(unsafe.Pointer(path)) + + device := C.hid_open_path(path) + if device == nil { + return nil, errors.New("hidapi: failed to open device") + } + return &hidDevice{ + DeviceInfo: info, + device: device, + }, nil +} + +// hidDevice is a live HID USB connected device handle. +type hidDevice struct { + DeviceInfo // Embed the infos for easier access + + device *C.hid_device // Low level HID device to communicate through + lock sync.Mutex +} + +// Close releases the HID USB device handle. +func (dev *hidDevice) Close() error { + dev.lock.Lock() + defer dev.lock.Unlock() + + if dev.device != nil { + C.hid_close(dev.device) + dev.device = nil + } + return nil +} + +// Write sends an output report to a HID device. +// +// Write will send the data on the first OUT endpoint, if one exists. If it does +// not, it will send the data through the Control Endpoint (Endpoint 0). +func (dev *hidDevice) Write(b []byte) (int, error) { + // Abort if nothing to write + if len(b) == 0 { + return 0, nil + } + // Abort if device closed in between + dev.lock.Lock() + device := dev.device + dev.lock.Unlock() + + if device == nil { + return 0, ErrDeviceClosed + } + // Prepend a HID report ID on Windows, other OSes don't need it + var report []byte + if runtime.GOOS == "windows" { + report = append([]byte{0x00}, b...) + } else { + report = b + } + // Execute the write operation + written := int(C.hid_write(device, (*C.uchar)(&report[0]), C.size_t(len(report)))) + if written == -1 { + // If the write failed, verify if closed or other error + dev.lock.Lock() + device = dev.device + dev.lock.Unlock() + + if device == nil { + return 0, ErrDeviceClosed + } + // Device not closed, some other error occurred + message := C.hid_error(device) + if message == nil { + return 0, errors.New("hidapi: unknown failure") + } + failure, _ := wcharTToString(message) + return 0, errors.New("hidapi: " + failure) + } + return written, nil +} + +// Read retrieves an input report from a HID device. +func (dev *hidDevice) Read(b []byte) (int, error) { + // Aborth if nothing to read + if len(b) == 0 { + return 0, nil + } + // Abort if device closed in between + dev.lock.Lock() + device := dev.device + dev.lock.Unlock() + + if device == nil { + return 0, ErrDeviceClosed + } + // Execute the read operation + read := int(C.hid_read(device, (*C.uchar)(&b[0]), C.size_t(len(b)))) + if read == -1 { + // If the read failed, verify if closed or other error + dev.lock.Lock() + device = dev.device + dev.lock.Unlock() + + if device == nil { + return 0, ErrDeviceClosed + } + // Device not closed, some other error occurred + message := C.hid_error(device) + if message == nil { + return 0, errors.New("hidapi: unknown failure") + } + failure, _ := wcharTToString(message) + return 0, errors.New("hidapi: " + failure) + } + return read, nil +} diff --git a/vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt b/vendor/github.com/karalabe/usb/hidapi/AUTHORS.txt similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt rename to vendor/github.com/karalabe/usb/hidapi/AUTHORS.txt diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE-bsd.txt similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt rename to vendor/github.com/karalabe/usb/hidapi/LICENSE-bsd.txt diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE-gpl3.txt similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt rename to vendor/github.com/karalabe/usb/hidapi/LICENSE-gpl3.txt diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE-orig.txt similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt rename to vendor/github.com/karalabe/usb/hidapi/LICENSE-orig.txt diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE.txt similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/LICENSE.txt rename to vendor/github.com/karalabe/usb/hidapi/LICENSE.txt diff --git a/vendor/github.com/karalabe/hid/hidapi/README.txt b/vendor/github.com/karalabe/usb/hidapi/README.txt similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/README.txt rename to vendor/github.com/karalabe/usb/hidapi/README.txt diff --git a/vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h b/vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h rename to vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h diff --git a/vendor/github.com/karalabe/hid/hidapi/libusb/hid.c b/vendor/github.com/karalabe/usb/hidapi/libusb/hid.c similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/libusb/hid.c rename to vendor/github.com/karalabe/usb/hidapi/libusb/hid.c diff --git a/vendor/github.com/karalabe/hid/hidapi/mac/hid.c b/vendor/github.com/karalabe/usb/hidapi/mac/hid.c similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/mac/hid.c rename to vendor/github.com/karalabe/usb/hidapi/mac/hid.c diff --git a/vendor/github.com/karalabe/hid/hidapi/windows/hid.c b/vendor/github.com/karalabe/usb/hidapi/windows/hid.c old mode 100755 new mode 100644 similarity index 100% rename from vendor/github.com/karalabe/hid/hidapi/windows/hid.c rename to vendor/github.com/karalabe/usb/hidapi/windows/hid.c diff --git a/vendor/github.com/karalabe/usb/libs.go b/vendor/github.com/karalabe/usb/libs.go new file mode 100644 index 0000000000..94720fbd46 --- /dev/null +++ b/vendor/github.com/karalabe/usb/libs.go @@ -0,0 +1,74 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2019 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo + +package usb + +/* +#cgo CFLAGS: -I./hidapi/hidapi +#cgo CFLAGS: -I./libusb/libusb +#cgo CFLAGS: -DDEFAULT_VISIBILITY="" +#cgo CFLAGS: -DPOLL_NFDS_TYPE=int + +#cgo linux CFLAGS: -DOS_LINUX -D_GNU_SOURCE +#cgo linux,!android LDFLAGS: -lrt +#cgo darwin CFLAGS: -DOS_DARWIN -DHAVE_SYS_TIME_H +#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit -lobjc +#cgo windows CFLAGS: -DOS_WINDOWS +#cgo windows LDFLAGS: -lsetupapi +#cgo freebsd CFLAGS: -DOS_FREEBSD +#cgo freebsd LDFLAGS: -lusb +#cgo openbsd CFLAGS: -DOS_OPENBSD + +#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(DOS_FREEBSD) || defined(OS_OPENBSD) + #include + #include "os/threads_posix.c" + #include "os/poll_posix.c" +#elif defined(OS_WINDOWS) + #include "os/poll_windows.c" + #include "os/threads_windows.c" +#endif + +#ifdef OS_LINUX + #include "os/linux_usbfs.c" + #include "os/linux_netlink.c" + #include "hidapi/libusb/hid.c" +#elif OS_DARWIN + #include "os/darwin_usb.c" + #include "hidapi/mac/hid.c" +#elif OS_WINDOWS + #include "os/windows_nt_common.c" + #include "os/windows_usbdk.c" + #include "os/windows_winusb.c" + #include "hidapi/windows/hid.c" +#elif OS_FREEBSD + #include + #include "hidapi/libusb/hid.c" +#elif DOS_OPENBSD + #include "os/openbsd_usb.c" + #include "hidapi/libusb/hid.c" +#endif + +#ifndef OS_FREEBSD + #include "core.c" + #include "descriptor.c" + #include "hotplug.c" + #include "io.c" + #include "strerror.c" + #include "sync.c" +#endif +*/ +import "C" diff --git a/vendor/github.com/karalabe/hid/libusb/AUTHORS b/vendor/github.com/karalabe/usb/libusb/AUTHORS similarity index 76% rename from vendor/github.com/karalabe/hid/libusb/AUTHORS rename to vendor/github.com/karalabe/usb/libusb/AUTHORS index 70d407bd19..e90ad9bb2a 100644 --- a/vendor/github.com/karalabe/hid/libusb/AUTHORS +++ b/vendor/github.com/karalabe/usb/libusb/AUTHORS @@ -8,14 +8,19 @@ Copyright © 2010-2012 Michael Plante Copyright © 2011-2013 Hans de Goede Copyright © 2012-2013 Martin Pieuchot Copyright © 2012-2013 Toby Gray -Copyright © 2013-2015 Chris Dickens +Copyright © 2013-2018 Chris Dickens Other contributors: +Adrian Bunk Akshay Jaggi Alan Ott Alan Stern Alex Vatchenko Andrew Fernandes +Andy Chunyu +Andy McFadden +Angus Gratton +Anil Nair Anthony Clay Antonio Ospite Artem Egorkine @@ -23,12 +28,17 @@ Aurelien Jarno Bastien Nocera Bei Zhang Benjamin Dobell +Brent Rector Carl Karsten +Christophe Zeitouny Colin Walters Dave Camarillo David Engraf David Moore Davidlohr Bueso +Dmitry Fleytman +Doug Johnston +Evan Hunter Federico Manzan Felipe Balbi Florian Albrechtskirchinger @@ -41,23 +51,34 @@ Hans Ulrich Niedermann Hector Martin Hoi-Ho Chan Ilya Konstantinov +Jakub Klama James Hanko +Jeffrey Nichols +Johann Richard John Sheu +Jonathon Jongsma +Joost Muller +Josh Gao Joshua Blake Justin Bischoff +KIMURA Masaru Karsten Koenig Konrad Rzepecki Kuangye Guo Lars Kanis Lars Wirzenius +Lei Chen Luca Longinotti Marcus Meissner Markus Heidelberg Martin Ettl Martin Koegler +Matthew Stapleton Matthias Bolte +Michel Zou Mike Frysinger Mikhail Gusarov +Morgan Leborgne Moritz Fischer Ларионов Даниил Nicholas Corgan @@ -66,10 +87,17 @@ Orin Eman Paul Fertser Pekka Nikander Rob Walker +Romain Vimont +Roman Kalashnikov +Sameeh Jubran Sean McBride Sebastian Pipping +Sergey Serb Simon Haggett Simon Newton +Stefan Agner +Stefan Tauner +Steinar H. Gunderson Thomas Röfer Tim Hutt Tim Roberts @@ -81,9 +109,11 @@ Uri Lublin Vasily Khoruzhick Vegard Storheil Eriksen Venkatesh Shukla +Vianney le Clément de Saint-Marcq +Victor Toso Vitali Lovich +William Skellenger Xiaofan Chen Zoltán Kovács Роман Донченко parafin -xantares diff --git a/vendor/github.com/karalabe/hid/libusb/COPYING b/vendor/github.com/karalabe/usb/libusb/COPYING similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/COPYING rename to vendor/github.com/karalabe/usb/libusb/COPYING diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/config.h b/vendor/github.com/karalabe/usb/libusb/libusb/config.h similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/config.h rename to vendor/github.com/karalabe/usb/libusb/libusb/config.h diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/core.c b/vendor/github.com/karalabe/usb/libusb/libusb/core.c similarity index 91% rename from vendor/github.com/karalabe/hid/libusb/libusb/core.c rename to vendor/github.com/karalabe/usb/libusb/libusb/core.c index d45bfe177e..50f92f6b1b 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/core.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/core.c @@ -44,32 +44,6 @@ #include "libusbi.h" #include "hotplug.h" -#if defined(OS_LINUX) -const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend; -#elif defined(OS_DARWIN) -const struct usbi_os_backend * const usbi_backend = &darwin_backend; -#elif defined(OS_OPENBSD) -const struct usbi_os_backend * const usbi_backend = &openbsd_backend; -#elif defined(OS_NETBSD) -const struct usbi_os_backend * const usbi_backend = &netbsd_backend; -#elif defined(OS_WINDOWS) - -#if defined(USE_USBDK) -const struct usbi_os_backend * const usbi_backend = &usbdk_backend; -#else -const struct usbi_os_backend * const usbi_backend = &windows_backend; -#endif - -#elif defined(OS_WINCE) -const struct usbi_os_backend * const usbi_backend = &wince_backend; -#elif defined(OS_HAIKU) -const struct usbi_os_backend * const usbi_backend = &haiku_usb_raw_backend; -#elif defined (OS_SUNOS) -const struct usbi_os_backend * const usbi_backend = &sunos_backend; -#else -#error "Unsupported OS" -#endif - struct libusb_context *usbi_default_context = NULL; static const struct libusb_version libusb_version_internal = { LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO, @@ -142,15 +116,17 @@ struct list_head active_contexts_list; * libusb uses stderr for all logging. By default, logging is set to NONE, * which means that no output will be produced. However, unless the library * has been compiled with logging disabled, then any application calls to - * libusb_set_debug(), or the setting of the environmental variable - * LIBUSB_DEBUG outside of the application, can result in logging being - * produced. Your application should therefore not close stderr, but instead - * direct it to the null device if its output is undesirable. + * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level), or the setting of the + * environmental variable LIBUSB_DEBUG outside of the application, can result + * in logging being produced. Your application should therefore not close + * stderr, but instead direct it to the null device if its output is + * undesirable. * - * The libusb_set_debug() function can be used to enable logging of certain - * messages. Under standard configuration, libusb doesn't really log much - * so you are advised to use this function to enable all error/warning/ - * informational messages. It will help debug problems with your software. + * The libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) function can be + * used to enable logging of certain messages. Under standard configuration, + * libusb doesn't really log much so you are advised to use this function + * to enable all error/warning/ informational messages. It will help debug + * problems with your software. * * The logged messages are unstructured. There is no one-to-one correspondence * between messages being logged and success or failure return codes from @@ -165,18 +141,20 @@ struct list_head active_contexts_list; * * The LIBUSB_DEBUG environment variable can be used to enable message logging * at run-time. This environment variable should be set to a log level number, - * which is interpreted the same as the libusb_set_debug() parameter. When this + * which is interpreted the same as the + * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) parameter. When this * environment variable is set, the message logging verbosity level is fixed - * and libusb_set_debug() effectively does nothing. + * and libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) effectively does + * nothing. * * libusb can be compiled without any logging functions, useful for embedded - * systems. In this case, libusb_set_debug() and the LIBUSB_DEBUG environment - * variable have no effects. + * systems. In this case, libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) + * and the LIBUSB_DEBUG environment variable have no effects. * * libusb can also be compiled with verbose debugging messages always. When * the library is compiled in this way, all messages of all verbosities are - * always logged. libusb_set_debug() and the LIBUSB_DEBUG environment variable - * have no effects. + * always logged. libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) and + * the LIBUSB_DEBUG environment variable have no effects. * * \section remarks Other remarks * @@ -187,6 +165,20 @@ struct list_head active_contexts_list; /** * \page libusb_caveats Caveats * + * \section fork Fork considerations + * + * libusb is not designed to work across fork() calls. Depending on + * the platform, there may be resources in the parent process that are not + * available to the child (e.g. the hotplug monitor thread on Linux). In + * addition, since the parent and child will share libusb's internal file + * descriptors, using libusb in any way from the child could cause the parent + * process's \ref libusb_context to get into an inconsistent state. + * + * On Linux, libusb's file descriptors will be marked as CLOEXEC, which means + * that it is safe to fork() and exec() without worrying about the child + * process needing to clean up state or having access to these file descriptors. + * Other platforms may not be so forgiving, so consider yourself warned! + * * \section devresets Device resets * * The libusb_reset_device() function allows you to reset a device. If your @@ -291,7 +283,6 @@ if (cfg != desired) * information about the end of the short packet, and the user probably wanted * that surplus data to arrive in the next logical transfer. * - * * \section zlp Zero length packets * * - libusb is able to send a packet of zero length to an endpoint simply by @@ -310,7 +301,7 @@ if (cfg != desired) * developed modules may both use libusb. * * libusb is written to allow for these multiple user scenarios. The two - * "instances" of libusb will not interfere: libusb_set_debug() calls + * "instances" of libusb will not interfere: libusb_set_option() calls * from one user will not affect the same settings for other users, other * users can continue using libusb after one of them calls libusb_exit(), etc. * @@ -435,6 +426,7 @@ if (cfg != desired) * - libusb_set_debug() * - libusb_set_interface_alt_setting() * - libusb_set_iso_packet_lengths() + * - libusb_set_option() * - libusb_setlocale() * - libusb_set_pollfd_notifiers() * - libusb_strerror() @@ -478,6 +470,7 @@ if (cfg != desired) * - \ref libusb_iso_sync_type * - \ref libusb_iso_usage_type * - \ref libusb_log_level + * - \ref libusb_option * - \ref libusb_request_recipient * - \ref libusb_request_type * - \ref libusb_speed @@ -680,7 +673,7 @@ struct discovered_devs *discovered_devs_append( struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, unsigned long session_id) { - size_t priv_size = usbi_backend->device_priv_size; + size_t priv_size = usbi_backend.device_priv_size; struct libusb_device *dev = calloc(1, sizeof(*dev) + priv_size); int r; @@ -824,8 +817,8 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, /* backend provides hotplug support */ struct libusb_device *dev; - if (usbi_backend->hotplug_poll) - usbi_backend->hotplug_poll(); + if (usbi_backend.hotplug_poll) + usbi_backend.hotplug_poll(); usbi_mutex_lock(&ctx->usb_devs_lock); list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) { @@ -839,7 +832,7 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, usbi_mutex_unlock(&ctx->usb_devs_lock); } else { /* backend does not provide hotplug support */ - r = usbi_backend->get_device_list(ctx, &discdevs); + r = usbi_backend.get_device_list(ctx, &discdevs); } if (r < 0) { @@ -1167,8 +1160,8 @@ void API_EXPORTED libusb_unref_device(libusb_device *dev) libusb_unref_device(dev->parent_dev); - if (usbi_backend->destroy_device) - usbi_backend->destroy_device(dev); + if (usbi_backend.destroy_device) + usbi_backend.destroy_device(dev); if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { /* backend does not support hotplug */ @@ -1242,7 +1235,7 @@ int API_EXPORTED libusb_open(libusb_device *dev, { struct libusb_context *ctx = DEVICE_CTX(dev); struct libusb_device_handle *_dev_handle; - size_t priv_size = usbi_backend->device_handle_priv_size; + size_t priv_size = usbi_backend.device_handle_priv_size; int r; usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); @@ -1265,7 +1258,7 @@ int API_EXPORTED libusb_open(libusb_device *dev, _dev_handle->claimed_interfaces = 0; memset(&_dev_handle->os_priv, 0, priv_size); - r = usbi_backend->open(_dev_handle); + r = usbi_backend.open(_dev_handle); if (r < 0) { usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r); libusb_unref_device(dev); @@ -1382,7 +1375,7 @@ static void do_close(struct libusb_context *ctx, list_del(&dev_handle->list); usbi_mutex_unlock(&ctx->open_devs_lock); - usbi_backend->close(dev_handle); + usbi_backend.close(dev_handle); libusb_unref_device(dev_handle->dev); usbi_mutex_destroy(&dev_handle->lock); free(dev_handle); @@ -1491,8 +1484,8 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle, int r = LIBUSB_ERROR_NOT_SUPPORTED; usbi_dbg(""); - if (usbi_backend->get_configuration) - r = usbi_backend->get_configuration(dev_handle, config); + if (usbi_backend.get_configuration) + r = usbi_backend.get_configuration(dev_handle, config); if (r == LIBUSB_ERROR_NOT_SUPPORTED) { uint8_t tmp = 0; @@ -1567,7 +1560,7 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev_handle, int configuration) { usbi_dbg("configuration %d", configuration); - return usbi_backend->set_configuration(dev_handle, configuration); + return usbi_backend.set_configuration(dev_handle, configuration); } /** \ingroup libusb_dev @@ -1614,7 +1607,7 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle, if (dev_handle->claimed_interfaces & (1 << interface_number)) goto out; - r = usbi_backend->claim_interface(dev_handle, interface_number); + r = usbi_backend.claim_interface(dev_handle, interface_number); if (r == 0) dev_handle->claimed_interfaces |= 1 << interface_number; @@ -1657,7 +1650,7 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle, goto out; } - r = usbi_backend->release_interface(dev_handle, interface_number); + r = usbi_backend.release_interface(dev_handle, interface_number); if (r == 0) dev_handle->claimed_interfaces &= ~(1 << interface_number); @@ -1707,7 +1700,7 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_hand } usbi_mutex_unlock(&dev_handle->lock); - return usbi_backend->set_interface_altsetting(dev_handle, interface_number, + return usbi_backend.set_interface_altsetting(dev_handle, interface_number, alternate_setting); } @@ -1734,7 +1727,7 @@ int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev_handle, if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - return usbi_backend->clear_halt(dev_handle, endpoint); + return usbi_backend.clear_halt(dev_handle, endpoint); } /** \ingroup libusb_dev @@ -1762,7 +1755,7 @@ int API_EXPORTED libusb_reset_device(libusb_device_handle *dev_handle) if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - return usbi_backend->reset_device(dev_handle); + return usbi_backend.reset_device(dev_handle); } /** \ingroup libusb_asyncio @@ -1794,8 +1787,8 @@ int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev_handle, if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - if (usbi_backend->alloc_streams) - return usbi_backend->alloc_streams(dev_handle, num_streams, endpoints, + if (usbi_backend.alloc_streams) + return usbi_backend.alloc_streams(dev_handle, num_streams, endpoints, num_endpoints); else return LIBUSB_ERROR_NOT_SUPPORTED; @@ -1821,8 +1814,8 @@ int API_EXPORTED libusb_free_streams(libusb_device_handle *dev_handle, if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - if (usbi_backend->free_streams) - return usbi_backend->free_streams(dev_handle, endpoints, + if (usbi_backend.free_streams) + return usbi_backend.free_streams(dev_handle, endpoints, num_endpoints); else return LIBUSB_ERROR_NOT_SUPPORTED; @@ -1859,8 +1852,8 @@ unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handl if (!dev_handle->dev->attached) return NULL; - if (usbi_backend->dev_mem_alloc) - return usbi_backend->dev_mem_alloc(dev_handle, length); + if (usbi_backend.dev_mem_alloc) + return usbi_backend.dev_mem_alloc(dev_handle, length); else return NULL; } @@ -1876,8 +1869,8 @@ unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handl int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev_handle, unsigned char *buffer, size_t length) { - if (usbi_backend->dev_mem_free) - return usbi_backend->dev_mem_free(dev_handle, buffer, length); + if (usbi_backend.dev_mem_free) + return usbi_backend.dev_mem_free(dev_handle, buffer, length); else return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -1907,8 +1900,8 @@ int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev_handle, if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - if (usbi_backend->kernel_driver_active) - return usbi_backend->kernel_driver_active(dev_handle, interface_number); + if (usbi_backend.kernel_driver_active) + return usbi_backend.kernel_driver_active(dev_handle, interface_number); else return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -1942,8 +1935,8 @@ int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev_handle, if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - if (usbi_backend->detach_kernel_driver) - return usbi_backend->detach_kernel_driver(dev_handle, interface_number); + if (usbi_backend.detach_kernel_driver) + return usbi_backend.detach_kernel_driver(dev_handle, interface_number); else return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -1976,8 +1969,8 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev_handle, if (!dev_handle->dev->attached) return LIBUSB_ERROR_NO_DEVICE; - if (usbi_backend->attach_kernel_driver) - return usbi_backend->attach_kernel_driver(dev_handle, interface_number); + if (usbi_backend.attach_kernel_driver) + return usbi_backend.attach_kernel_driver(dev_handle, interface_number); else return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -2007,7 +2000,7 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev_handle, int API_EXPORTED libusb_set_auto_detach_kernel_driver( libusb_device_handle *dev_handle, int enable) { - if (!(usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)) + if (!(usbi_backend.caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)) return LIBUSB_ERROR_NOT_SUPPORTED; dev_handle->auto_detach_kernel_driver = enable; @@ -2015,37 +2008,100 @@ int API_EXPORTED libusb_set_auto_detach_kernel_driver( } /** \ingroup libusb_lib - * Set log message verbosity. - * - * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever - * printed. If you choose to increase the message verbosity level, ensure - * that your application does not close the stdout/stderr file descriptors. - * - * You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative - * with its message logging and most of the time, will only log messages that - * explain error conditions and other oddities. This will help you debug - * your software. - * - * If the LIBUSB_DEBUG environment variable was set when libusb was - * initialized, this function does nothing: the message verbosity is fixed - * to the value in the environment variable. - * - * If libusb was compiled without any message logging, this function does - * nothing: you'll never get any messages. - * - * If libusb was compiled with verbose debug message logging, this function - * does nothing: you'll always get messages from all levels. - * - * \param ctx the context to operate on, or NULL for the default context - * \param level debug level to set + * \deprecated Use libusb_set_option() instead using the + * \ref LIBUSB_OPTION_LOG_LEVEL option. */ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) { +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) USBI_GET_CONTEXT(ctx); - if (!ctx->debug_fixed) - ctx->debug = level; + if (!ctx->debug_fixed) { + level = CLAMP(level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG); + ctx->debug = (enum libusb_log_level)level; + } +#else + UNUSED(ctx); + UNUSED(level); +#endif } +/** \ingroup libusb_lib + * Set an option in the library. + * + * Use this function to configure a specific option within the library. + * + * Some options require one or more arguments to be provided. Consult each + * option's documentation for specific requirements. + * + * Since version 1.0.22, \ref LIBUSB_API_VERSION >= 0x01000106 + * + * \param ctx context on which to operate + * \param option which option to set + * \param ... any required arguments for the specified option + * + * \returns LIBUSB_SUCCESS on success + * \returns LIBUSB_ERROR_INVALID_PARAM if the option or arguments are invalid + * \returns LIBUSB_ERROR_NOT_SUPPORTED if the option is valid but not supported + * on this platform + */ +int API_EXPORTED libusb_set_option(libusb_context *ctx, + enum libusb_option option, ...) +{ + int arg, r = LIBUSB_SUCCESS; + va_list ap; + + USBI_GET_CONTEXT(ctx); + + va_start(ap, option); + switch (option) { + case LIBUSB_OPTION_LOG_LEVEL: + arg = va_arg(ap, int); + if (arg < LIBUSB_LOG_LEVEL_NONE || arg > LIBUSB_LOG_LEVEL_DEBUG) { + r = LIBUSB_ERROR_INVALID_PARAM; + break; + } +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) + if (!ctx->debug_fixed) + ctx->debug = (enum libusb_log_level)arg; +#endif + break; + + /* Handle all backend-specific options here */ + case LIBUSB_OPTION_USE_USBDK: + if (usbi_backend.set_option) + r = usbi_backend.set_option(ctx, option, ap); + else + r = LIBUSB_ERROR_NOT_SUPPORTED; + break; + + default: + r = LIBUSB_ERROR_INVALID_PARAM; + } + va_end(ap); + + return r; +} + +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) +/* returns the log level as defined in the LIBUSB_DEBUG environment variable. + * if LIBUSB_DEBUG is not present or not a number, returns LIBUSB_LOG_LEVEL_NONE. + * value is clamped to ensure it is within the valid range of possibilities. + */ +static enum libusb_log_level get_env_debug_level(void) +{ + const char *dbg = getenv("LIBUSB_DEBUG"); + enum libusb_log_level level; + if (dbg) { + int dbg_level = atoi(dbg); + dbg_level = CLAMP(dbg_level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG); + level = (enum libusb_log_level)dbg_level; + } else { + level = LIBUSB_LOG_LEVEL_NONE; + } + return level; +} +#endif + /** \ingroup libusb_lib * Initialize libusb. This function must be called before calling any other * libusb function. @@ -2062,7 +2118,7 @@ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) int API_EXPORTED libusb_init(libusb_context **context) { struct libusb_device *dev, *next; - char *dbg = getenv("LIBUSB_DEBUG"); + size_t priv_size = usbi_backend.context_priv_size; struct libusb_context *ctx; static int first_init = 1; int r = 0; @@ -2070,7 +2126,7 @@ int API_EXPORTED libusb_init(libusb_context **context) usbi_mutex_static_lock(&default_context_lock); if (!timestamp_origin.tv_sec) { - usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, ×tamp_origin); + usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, ×tamp_origin); } if (!context && usbi_default_context) { @@ -2080,22 +2136,18 @@ int API_EXPORTED libusb_init(libusb_context **context) return 0; } - ctx = calloc(1, sizeof(*ctx)); + ctx = calloc(1, sizeof(*ctx) + priv_size); if (!ctx) { r = LIBUSB_ERROR_NO_MEM; goto err_unlock; } -#ifdef ENABLE_DEBUG_LOGGING - ctx->debug = LIBUSB_LOG_LEVEL_DEBUG; +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) + ctx->debug = get_env_debug_level(); + if (ctx->debug != LIBUSB_LOG_LEVEL_NONE) + ctx->debug_fixed = 1; #endif - if (dbg) { - ctx->debug = atoi(dbg); - if (ctx->debug) - ctx->debug_fixed = 1; - } - /* default context should be initialized before calling usbi_dbg */ if (!usbi_default_context) { usbi_default_context = ctx; @@ -2112,6 +2164,7 @@ int API_EXPORTED libusb_init(libusb_context **context) list_init(&ctx->usb_devs); list_init(&ctx->open_devs); list_init(&ctx->hotplug_cbs); + ctx->next_hotplug_cb_handle = 1; usbi_mutex_static_lock(&active_contexts_lock); if (first_init) { @@ -2121,8 +2174,8 @@ int API_EXPORTED libusb_init(libusb_context **context) list_add (&ctx->list, &active_contexts_list); usbi_mutex_static_unlock(&active_contexts_lock); - if (usbi_backend->init) { - r = usbi_backend->init(ctx); + if (usbi_backend.init) { + r = usbi_backend.init(ctx); if (r) goto err_free_ctx; } @@ -2139,8 +2192,8 @@ int API_EXPORTED libusb_init(libusb_context **context) return 0; err_backend_exit: - if (usbi_backend->exit) - usbi_backend->exit(); + if (usbi_backend.exit) + usbi_backend.exit(ctx); err_free_ctx: if (ctx == usbi_default_context) { usbi_default_context = NULL; @@ -2200,7 +2253,7 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx) usbi_mutex_static_unlock(&active_contexts_lock); if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { - usbi_hotplug_deregister_all(ctx); + usbi_hotplug_deregister(ctx, 1); /* * Ensure any pending unplug events are read from the hotplug @@ -2230,8 +2283,8 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx) usbi_warn(ctx, "application left some devices open"); usbi_io_exit(ctx); - if (usbi_backend->exit) - usbi_backend->exit(); + if (usbi_backend.exit) + usbi_backend.exit(ctx); usbi_mutex_destroy(&ctx->open_devs_lock); usbi_mutex_destroy(&ctx->usb_devs_lock); @@ -2253,15 +2306,17 @@ int API_EXPORTED libusb_has_capability(uint32_t capability) case LIBUSB_CAP_HAS_CAPABILITY: return 1; case LIBUSB_CAP_HAS_HOTPLUG: - return !(usbi_backend->get_device_list); + return !(usbi_backend.get_device_list); case LIBUSB_CAP_HAS_HID_ACCESS: - return (usbi_backend->caps & USBI_CAP_HAS_HID_ACCESS); + return (usbi_backend.caps & USBI_CAP_HAS_HID_ACCESS); case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER: - return (usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER); + return (usbi_backend.caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER); } return 0; } +#ifdef ENABLE_LOGGING + /* this is defined in libusbi.h if needed */ #ifdef LIBUSB_PRINTF_WIN32 /* @@ -2301,10 +2356,9 @@ int usbi_vsnprintf(char *str, size_t size, const char *format, va_list ap) return ret; } -#endif +#endif /* LIBUSB_PRINTF_WIN32 */ -static void usbi_log_str(struct libusb_context *ctx, - enum libusb_log_level level, const char * str) +static void usbi_log_str(enum libusb_log_level level, const char *str) { #if defined(USE_SYSTEM_LOGGING_FACILITY) #if defined(OS_WINDOWS) @@ -2317,18 +2371,20 @@ static void usbi_log_str(struct libusb_context *ctx, #elif defined(__ANDROID__) int priority = ANDROID_LOG_UNKNOWN; switch (level) { - case LIBUSB_LOG_LEVEL_INFO: priority = ANDROID_LOG_INFO; break; - case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; break; + case LIBUSB_LOG_LEVEL_NONE: return; case LIBUSB_LOG_LEVEL_ERROR: priority = ANDROID_LOG_ERROR; break; + case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; break; + case LIBUSB_LOG_LEVEL_INFO: priority = ANDROID_LOG_INFO; break; case LIBUSB_LOG_LEVEL_DEBUG: priority = ANDROID_LOG_DEBUG; break; } __android_log_write(priority, "libusb", str); #elif defined(HAVE_SYSLOG_FUNC) int syslog_level = LOG_INFO; switch (level) { - case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break; - case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break; + case LIBUSB_LOG_LEVEL_NONE: return; case LIBUSB_LOG_LEVEL_ERROR: syslog_level = LOG_ERR; break; + case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break; + case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break; case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break; } syslog(syslog_level, "%s", str); @@ -2339,14 +2395,13 @@ static void usbi_log_str(struct libusb_context *ctx, #else fputs(str, stderr); #endif /* USE_SYSTEM_LOGGING_FACILITY */ - UNUSED(ctx); UNUSED(level); } void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, const char *function, const char *format, va_list args) { - const char *prefix = ""; + const char *prefix; char buf[USBI_MAX_LOG_LEN]; struct timespec now; int global_debug, header_len, text_len; @@ -2356,18 +2411,15 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, global_debug = 1; UNUSED(ctx); #else - int ctx_level = 0; + enum libusb_log_level ctx_level = LIBUSB_LOG_LEVEL_NONE; USBI_GET_CONTEXT(ctx); - if (ctx) { + if (ctx) ctx_level = ctx->debug; - } else { - char *dbg = getenv("LIBUSB_DEBUG"); - if (dbg) - ctx_level = atoi(dbg); - } - global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG); - if (!ctx_level) + else + ctx_level = get_env_debug_level(); + + if (ctx_level == LIBUSB_LOG_LEVEL_NONE) return; if (level == LIBUSB_LOG_LEVEL_WARNING && ctx_level < LIBUSB_LOG_LEVEL_WARNING) return; @@ -2375,13 +2427,15 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, return; if (level == LIBUSB_LOG_LEVEL_DEBUG && ctx_level < LIBUSB_LOG_LEVEL_DEBUG) return; + + global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG); #endif - usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &now); + usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &now); if ((global_debug) && (!has_debug_header_been_displayed)) { has_debug_header_been_displayed = 1; - usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] " USBI_LOG_LINE_END); - usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END); + usbi_log_str(LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] " USBI_LOG_LINE_END); + usbi_log_str(LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END); } if (now.tv_nsec < timestamp_origin.tv_nsec) { now.tv_sec--; @@ -2391,20 +2445,20 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, now.tv_nsec -= timestamp_origin.tv_nsec; switch (level) { - case LIBUSB_LOG_LEVEL_INFO: - prefix = "info"; + case LIBUSB_LOG_LEVEL_NONE: + return; + case LIBUSB_LOG_LEVEL_ERROR: + prefix = "error"; break; case LIBUSB_LOG_LEVEL_WARNING: prefix = "warning"; break; - case LIBUSB_LOG_LEVEL_ERROR: - prefix = "error"; + case LIBUSB_LOG_LEVEL_INFO: + prefix = "info"; break; case LIBUSB_LOG_LEVEL_DEBUG: prefix = "debug"; break; - case LIBUSB_LOG_LEVEL_NONE: - return; default: prefix = "unknown"; break; @@ -2439,7 +2493,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, } strcpy(buf + header_len + text_len, USBI_LOG_LINE_END); - usbi_log_str(ctx, level, buf); + usbi_log_str(level, buf); } void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, @@ -2452,6 +2506,8 @@ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, va_end (args); } +#endif /* ENABLE_LOGGING */ + /** \ingroup libusb_misc * Returns a constant NULL-terminated string with the ASCII name of a libusb * error or transfer status code. The caller must not free() the returned diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c b/vendor/github.com/karalabe/usb/libusb/libusb/descriptor.c similarity index 98% rename from vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c rename to vendor/github.com/karalabe/usb/libusb/libusb/descriptor.c index 4c9435fffe..74d6de557e 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/descriptor.c @@ -333,7 +333,7 @@ static int parse_interface(libusb_context *ctx, goto err; if (r == 0) { ifp->bNumEndpoints = (uint8_t)i; - break;; + break; } buffer += r; @@ -513,7 +513,7 @@ int usbi_device_cache_descriptor(libusb_device *dev) { int r, host_endian = 0; - r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor, + r = usbi_backend.get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor, &host_endian); if (r < 0) return r; @@ -572,7 +572,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, int host_endian = 0; int r; - r = usbi_backend->get_active_config_descriptor(dev, tmp, + r = usbi_backend.get_active_config_descriptor(dev, tmp, LIBUSB_DT_CONFIG_SIZE, &host_endian); if (r < 0) return r; @@ -587,7 +587,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, if (!buf) return LIBUSB_ERROR_NO_MEM; - r = usbi_backend->get_active_config_descriptor(dev, buf, + r = usbi_backend.get_active_config_descriptor(dev, buf, _config.wTotalLength, &host_endian); if (r >= 0) r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config); @@ -625,7 +625,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, if (config_index >= dev->num_configurations) return LIBUSB_ERROR_NOT_FOUND; - r = usbi_backend->get_config_descriptor(dev, config_index, tmp, + r = usbi_backend.get_config_descriptor(dev, config_index, tmp, LIBUSB_DT_CONFIG_SIZE, &host_endian); if (r < 0) return r; @@ -640,7 +640,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, if (!buf) return LIBUSB_ERROR_NO_MEM; - r = usbi_backend->get_config_descriptor(dev, config_index, buf, + r = usbi_backend.get_config_descriptor(dev, config_index, buf, _config.wTotalLength, &host_endian); if (r >= 0) r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config); @@ -663,7 +663,7 @@ int usbi_get_config_index_by_value(struct libusb_device *dev, for (i = 0; i < dev->num_configurations; i++) { unsigned char tmp[6]; int host_endian; - int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp), + int r = usbi_backend.get_config_descriptor(dev, i, tmp, sizeof(tmp), &host_endian); if (r < 0) { *idx = -1; @@ -702,8 +702,8 @@ int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, int r, idx, host_endian; unsigned char *buf = NULL; - if (usbi_backend->get_config_descriptor_by_value) { - r = usbi_backend->get_config_descriptor_by_value(dev, + if (usbi_backend.get_config_descriptor_by_value) { + r = usbi_backend.get_config_descriptor_by_value(dev, bConfigurationValue, &buf, &host_endian); if (r < 0) return r; @@ -1176,7 +1176,8 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha if (tbuf[0] > r) return LIBUSB_ERROR_IO; - for (di = 0, si = 2; si < tbuf[0]; si += 2) { + di = 0; + for (si = 2; si < tbuf[0]; si += 2) { if (di >= (length - 1)) break; diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.c similarity index 76% rename from vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c rename to vendor/github.com/karalabe/usb/libusb/libusb/hotplug.c index bbfd6e79a1..a4320bc42e 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.c @@ -154,36 +154,30 @@ int main (void) { \endcode */ -static int usbi_hotplug_match_cb (struct libusb_context *ctx, +static int usbi_hotplug_match_cb(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, struct libusb_hotplug_callback *hotplug_cb) { - /* Handle lazy deregistration of callback */ - if (hotplug_cb->needs_free) { - /* Free callback */ - return 1; - } - - if (!(hotplug_cb->events & event)) { + if (!(hotplug_cb->flags & event)) { return 0; } - if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id && + if ((hotplug_cb->flags & USBI_HOTPLUG_VENDOR_ID_VALID) && hotplug_cb->vendor_id != dev->device_descriptor.idVendor) { return 0; } - if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id && + if ((hotplug_cb->flags & USBI_HOTPLUG_PRODUCT_ID_VALID) && hotplug_cb->product_id != dev->device_descriptor.idProduct) { return 0; } - if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class && + if ((hotplug_cb->flags & USBI_HOTPLUG_DEV_CLASS_VALID) && hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) { return 0; } - return hotplug_cb->cb (ctx, dev, event, hotplug_cb->user_data); + return hotplug_cb->cb(ctx, dev, event, hotplug_cb->user_data); } void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, @@ -195,8 +189,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, usbi_mutex_lock(&ctx->hotplug_cbs_lock); list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { + if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) { + /* process deregistration in usbi_hotplug_deregister() */ + continue; + } + usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - ret = usbi_hotplug_match_cb (ctx, dev, event, hotplug_cb); + ret = usbi_hotplug_match_cb(ctx, dev, event, hotplug_cb); usbi_mutex_lock(&ctx->hotplug_cbs_lock); if (ret) { @@ -206,15 +205,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, } usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - - /* the backend is expected to call the callback for each active transfer */ } void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event) { int pending_events; - libusb_hotplug_message *message = calloc(1, sizeof(*message)); + struct libusb_hotplug_message *message = calloc(1, sizeof(*message)); if (!message) { usbi_err(ctx, "error allocating hotplug message"); @@ -240,59 +237,70 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *callback_handle) { - libusb_hotplug_callback *new_callback; - static int handle_id = 1; - - /* check for hotplug support */ - if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { - return LIBUSB_ERROR_NOT_SUPPORTED; - } + struct libusb_hotplug_callback *new_callback; /* check for sane values */ - if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) || + if ((!events || (~(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) & events)) || + (flags && (~LIBUSB_HOTPLUG_ENUMERATE & flags)) || + (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) || (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) || (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) || !cb_fn) { return LIBUSB_ERROR_INVALID_PARAM; } + /* check for hotplug support */ + if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { + return LIBUSB_ERROR_NOT_SUPPORTED; + } + USBI_GET_CONTEXT(ctx); - new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback)); + new_callback = calloc(1, sizeof(*new_callback)); if (!new_callback) { return LIBUSB_ERROR_NO_MEM; } - new_callback->ctx = ctx; - new_callback->vendor_id = vendor_id; - new_callback->product_id = product_id; - new_callback->dev_class = dev_class; - new_callback->flags = flags; - new_callback->events = events; + new_callback->flags = (uint8_t)events; + if (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id) { + new_callback->flags |= USBI_HOTPLUG_VENDOR_ID_VALID; + new_callback->vendor_id = (uint16_t)vendor_id; + } + if (LIBUSB_HOTPLUG_MATCH_ANY != product_id) { + new_callback->flags |= USBI_HOTPLUG_PRODUCT_ID_VALID; + new_callback->product_id = (uint16_t)product_id; + } + if (LIBUSB_HOTPLUG_MATCH_ANY != dev_class) { + new_callback->flags |= USBI_HOTPLUG_DEV_CLASS_VALID; + new_callback->dev_class = (uint8_t)dev_class; + } new_callback->cb = cb_fn; new_callback->user_data = user_data; - new_callback->needs_free = 0; usbi_mutex_lock(&ctx->hotplug_cbs_lock); - /* protect the handle by the context hotplug lock. it doesn't matter if the same handle - * is used for different contexts only that the handle is unique for this context */ - new_callback->handle = handle_id++; + /* protect the handle by the context hotplug lock */ + new_callback->handle = ctx->next_hotplug_cb_handle++; + + /* handle the unlikely case of overflow */ + if (ctx->next_hotplug_cb_handle < 0) + ctx->next_hotplug_cb_handle = 1; list_add(&new_callback->list, &ctx->hotplug_cbs); usbi_mutex_unlock(&ctx->hotplug_cbs_lock); + usbi_dbg("new hotplug cb %p with handle %d", new_callback, new_callback->handle); - if (flags & LIBUSB_HOTPLUG_ENUMERATE) { - int i, len; + if ((flags & LIBUSB_HOTPLUG_ENUMERATE) && (events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)) { + ssize_t i, len; struct libusb_device **devs; - len = (int) libusb_get_device_list(ctx, &devs); + len = libusb_get_device_list(ctx, &devs); if (len < 0) { libusb_hotplug_deregister_callback(ctx, new_callback->handle); - return len; + return (int)len; } for (i = 0; i < len; i++) { @@ -311,10 +319,11 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, return LIBUSB_SUCCESS; } -void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx, +void API_EXPORTED libusb_hotplug_deregister_callback(struct libusb_context *ctx, libusb_hotplug_callback_handle callback_handle) { struct libusb_hotplug_callback *hotplug_cb; + int deregistered = 0; /* check for hotplug support */ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { @@ -323,28 +332,42 @@ void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx USBI_GET_CONTEXT(ctx); + usbi_dbg("deregister hotplug cb %d", callback_handle); + usbi_mutex_lock(&ctx->hotplug_cbs_lock); - list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, - struct libusb_hotplug_callback) { + list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { if (callback_handle == hotplug_cb->handle) { /* Mark this callback for deregistration */ - hotplug_cb->needs_free = 1; + hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE; + deregistered = 1; } } usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - usbi_hotplug_notification(ctx, NULL, 0); + if (deregistered) { + int pending_events; + + usbi_mutex_lock(&ctx->event_data_lock); + pending_events = usbi_pending_events(ctx); + ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED; + if (!pending_events) + usbi_signal_event(ctx); + usbi_mutex_unlock(&ctx->event_data_lock); + } } -void usbi_hotplug_deregister_all(struct libusb_context *ctx) { +void usbi_hotplug_deregister(struct libusb_context *ctx, int forced) +{ struct libusb_hotplug_callback *hotplug_cb, *next; usbi_mutex_lock(&ctx->hotplug_cbs_lock); - list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, - struct libusb_hotplug_callback) { - list_del(&hotplug_cb->list); - free(hotplug_cb); + list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { + if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) { + usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb, + hotplug_cb->handle); + list_del(&hotplug_cb->list); + free(hotplug_cb); + } } - usbi_mutex_unlock(&ctx->hotplug_cbs_lock); } diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.h similarity index 65% rename from vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h rename to vendor/github.com/karalabe/usb/libusb/libusb/hotplug.h index 2bec81b06c..dbadbcb93d 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.h @@ -19,12 +19,34 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#if !defined(USBI_HOTPLUG_H) +#ifndef USBI_HOTPLUG_H #define USBI_HOTPLUG_H -#ifndef LIBUSBI_H #include "libusbi.h" -#endif + +enum usbi_hotplug_flags { + /* This callback is interested in device arrivals */ + USBI_HOTPLUG_DEVICE_ARRIVED = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, + + /* This callback is interested in device removals */ + USBI_HOTPLUG_DEVICE_LEFT = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, + + /* IMPORTANT: The values for the below entries must start *after* + * the highest value of the above entries!!! + */ + + /* The vendor_id field is valid for matching */ + USBI_HOTPLUG_VENDOR_ID_VALID = (1 << 3), + + /* The product_id field is valid for matching */ + USBI_HOTPLUG_PRODUCT_ID_VALID = (1 << 4), + + /* The dev_class field is valid for matching */ + USBI_HOTPLUG_DEV_CLASS_VALID = (1 << 5), + + /* This callback has been unregistered and needs to be freed */ + USBI_HOTPLUG_NEEDS_FREE = (1 << 6), +}; /** \ingroup hotplug * The hotplug callback structure. The user populates this structure with @@ -32,23 +54,17 @@ * to receive notification of hotplug events. */ struct libusb_hotplug_callback { - /** Context this callback is associated with */ - struct libusb_context *ctx; + /** Flags that control how this callback behaves */ + uint8_t flags; - /** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */ - int vendor_id; + /** Vendor ID to match (if flags says this is valid) */ + uint16_t vendor_id; - /** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */ - int product_id; + /** Product ID to match (if flags says this is valid) */ + uint16_t product_id; - /** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */ - int dev_class; - - /** Hotplug callback flags */ - libusb_hotplug_flag flags; - - /** Event(s) that will trigger this callback */ - libusb_hotplug_event events; + /** Device class to match (if flags says this is valid) */ + uint8_t dev_class; /** Callback function to invoke for matching event/device */ libusb_hotplug_callback_fn cb; @@ -59,15 +75,10 @@ struct libusb_hotplug_callback { /** User data that will be passed to the callback function */ void *user_data; - /** Callback is marked for deletion */ - int needs_free; - /** List this callback is registered in (ctx->hotplug_cbs) */ struct list_head list; }; -typedef struct libusb_hotplug_callback libusb_hotplug_callback; - struct libusb_hotplug_message { /** The hotplug event that occurred */ libusb_hotplug_event event; @@ -79,9 +90,7 @@ struct libusb_hotplug_message { struct list_head list; }; -typedef struct libusb_hotplug_message libusb_hotplug_message; - -void usbi_hotplug_deregister_all(struct libusb_context *ctx); +void usbi_hotplug_deregister(struct libusb_context *ctx, int forced); void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event); void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev, diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/io.c b/vendor/github.com/karalabe/usb/libusb/libusb/io.c similarity index 98% rename from vendor/github.com/karalabe/hid/libusb/libusb/io.c rename to vendor/github.com/karalabe/usb/libusb/libusb/io.c index eb1eabf1cb..a03bfaae1a 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/io.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/io.c @@ -1144,8 +1144,8 @@ int usbi_io_init(struct libusb_context *ctx) goto err_close_pipe; #ifdef USBI_TIMERFD_AVAILABLE - ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(), - TFD_NONBLOCK); + ctx->timerfd = timerfd_create(usbi_backend.get_timerfd_clockid(), + TFD_NONBLOCK | TFD_CLOEXEC); if (ctx->timerfd >= 0) { usbi_dbg("using timerfd for timeouts"); r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN); @@ -1205,10 +1205,12 @@ static int calculate_timeout(struct usbi_transfer *transfer) unsigned int timeout = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout; - if (!timeout) + if (!timeout) { + timerclear(&transfer->timeout); return 0; + } - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, ¤t_time); + r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, ¤t_time); if (r < 0) { usbi_err(ITRANSFER_CTX(transfer), "failed to read monotonic clock, errno=%d", errno); @@ -1255,7 +1257,7 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( int iso_packets) { struct libusb_transfer *transfer; - size_t os_alloc_size = usbi_backend->transfer_priv_size; + size_t os_alloc_size = usbi_backend.transfer_priv_size; size_t alloc_size = sizeof(struct usbi_transfer) + sizeof(struct libusb_transfer) + (sizeof(struct libusb_iso_packet_descriptor) * iso_packets) @@ -1526,7 +1528,7 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) */ usbi_mutex_unlock(&ctx->flying_transfers_lock); - r = usbi_backend->submit_transfer(itransfer); + r = usbi_backend.submit_transfer(itransfer); if (r == LIBUSB_SUCCESS) { itransfer->state_flags |= USBI_TRANSFER_IN_FLIGHT; /* keep a reference to this device */ @@ -1567,7 +1569,7 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) r = LIBUSB_ERROR_NOT_FOUND; goto out; } - r = usbi_backend->cancel_transfer(itransfer); + r = usbi_backend.cancel_transfer(itransfer); if (r < 0) { if (r != LIBUSB_ERROR_NOT_FOUND && r != LIBUSB_ERROR_NO_DEVICE) @@ -2004,7 +2006,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx) return 0; /* get current time */ - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts); + r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts); if (r < 0) return r; @@ -2077,7 +2079,6 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) struct pollfd *fds = NULL; int i = -1; int timeout_ms; - int special_event; /* prevent attempts to recursively handle events (e.g. calling into * libusb_handle_events() from within a hotplug or transfer callback) */ @@ -2146,32 +2147,30 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv) if (tv->tv_usec % 1000) timeout_ms++; -redo_poll: usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms); r = usbi_poll(fds, nfds, timeout_ms); usbi_dbg("poll() returned %d", r); if (r == 0) { r = handle_timeouts(ctx); goto done; - } - else if (r == -1 && errno == EINTR) { + } else if (r == -1 && errno == EINTR) { r = LIBUSB_ERROR_INTERRUPTED; goto done; - } - else if (r < 0) { + } else if (r < 0) { usbi_err(ctx, "poll failed %d err=%d", r, errno); r = LIBUSB_ERROR_IO; goto done; } - special_event = 0; - /* fds[0] is always the event pipe */ if (fds[0].revents) { - libusb_hotplug_message *message = NULL; + struct list_head hotplug_msgs; struct usbi_transfer *itransfer; + int hotplug_cb_deregistered = 0; int ret = 0; + list_init(&hotplug_msgs); + usbi_dbg("caught a fish on the event pipe"); /* take the the event data lock while processing events */ @@ -2186,6 +2185,12 @@ redo_poll: ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT; } + if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) { + usbi_dbg("someone unregistered a hotplug cb"); + ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED; + hotplug_cb_deregistered = 1; + } + /* check if someone is closing a device */ if (ctx->device_close) usbi_dbg("someone is closing a device"); @@ -2193,9 +2198,7 @@ redo_poll: /* check for any pending hotplug messages */ if (!list_empty(&ctx->hotplug_msgs)) { usbi_dbg("hotplug message received"); - special_event = 1; - message = list_first_entry(&ctx->hotplug_msgs, libusb_hotplug_message, list); - list_del(&message->list); + list_cut(&hotplug_msgs, &ctx->hotplug_msgs); } /* complete any pending transfers */ @@ -2203,7 +2206,7 @@ redo_poll: itransfer = list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list); list_del(&itransfer->completed_list); usbi_mutex_unlock(&ctx->event_data_lock); - ret = usbi_backend->handle_transfer_completion(itransfer); + ret = usbi_backend.handle_transfer_completion(itransfer); if (ret) usbi_err(ctx, "backend handle_transfer_completion failed with error %d", ret); usbi_mutex_lock(&ctx->event_data_lock); @@ -2215,14 +2218,21 @@ redo_poll: usbi_mutex_unlock(&ctx->event_data_lock); - /* process the hotplug message, if any */ - if (message) { + if (hotplug_cb_deregistered) + usbi_hotplug_deregister(ctx, 0); + + /* process the hotplug messages, if any */ + while (!list_empty(&hotplug_msgs)) { + struct libusb_hotplug_message *message = + list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list); + usbi_hotplug_match(ctx, message->device, message->event); /* the device left, dereference the device */ if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event) libusb_unref_device(message->device); + list_del(&message->list); free(message); } @@ -2233,7 +2243,7 @@ redo_poll: } if (0 == --r) - goto handled; + goto done; } #ifdef USBI_TIMERFD_AVAILABLE @@ -2242,7 +2252,6 @@ redo_poll: /* timerfd indicates that a timeout has expired */ int ret; usbi_dbg("timerfd triggered"); - special_event = 1; ret = handle_timerfd_trigger(ctx); if (ret < 0) { @@ -2252,20 +2261,14 @@ redo_poll: } if (0 == --r) - goto handled; + goto done; } #endif - r = usbi_backend->handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r); + r = usbi_backend.handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r); if (r) usbi_err(ctx, "backend handle_events failed with error %d", r); -handled: - if (r == 0 && special_event) { - timeout_ms = 0; - goto redo_poll; - } - done: usbi_end_event_handling(ctx); return r; @@ -2583,7 +2586,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, return 0; } - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts); + r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts); if (r < 0) { usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno); return 0; @@ -2811,7 +2814,7 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle) USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel)); usbi_mutex_lock(&to_cancel->lock); - usbi_backend->clear_transfer_priv(to_cancel); + usbi_backend.clear_transfer_priv(to_cancel); usbi_mutex_unlock(&to_cancel->lock); usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE); } diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/libusb.h b/vendor/github.com/karalabe/usb/libusb/libusb/libusb.h similarity index 96% rename from vendor/github.com/karalabe/hid/libusb/libusb/libusb.h rename to vendor/github.com/karalabe/usb/libusb/libusb/libusb.h index c562690f9a..430136b2e2 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/libusb.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/libusb.h @@ -54,13 +54,19 @@ typedef unsigned __int32 uint32_t; #include #endif -#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__) +#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__) #include #endif #include #include +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define ZERO_SIZED_ARRAY /* [] - valid C99 code */ +#else +#define ZERO_SIZED_ARRAY 0 /* [0] - non-standard, but usually working code */ +#endif + /* 'interface' might be defined as a macro on Windows, so we need to * undefine it so as not to break the current libusb API, because * libusb_config_descriptor has an 'interface' member @@ -79,6 +85,8 @@ typedef unsigned __int32 uint32_t; #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define LIBUSB_DEPRECATED_FOR(f) \ __attribute__((deprecated("Use " #f " instead"))) +#elif __GNUC__ >= 3 +#define LIBUSB_DEPRECATED_FOR(f) __attribute__((deprecated)) #else #define LIBUSB_DEPRECATED_FOR(f) #endif /* __GNUC__ */ @@ -141,7 +149,7 @@ typedef unsigned __int32 uint32_t; * Internally, LIBUSB_API_VERSION is defined as follows: * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental) */ -#define LIBUSB_API_VERSION 0x01000105 +#define LIBUSB_API_VERSION 0x01000106 /* The following is kept for compatibility, but will be deprecated in the future */ #define LIBUSBX_API_VERSION LIBUSB_API_VERSION @@ -729,13 +737,7 @@ struct libusb_bos_dev_capability_descriptor { /** Device Capability type */ uint8_t bDevCapabilityType; /** Device Capability data (bLength - 3 bytes) */ - uint8_t dev_capability_data -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; + uint8_t dev_capability_data[ZERO_SIZED_ARRAY]; }; /** \ingroup libusb_desc @@ -760,13 +762,7 @@ struct libusb_bos_descriptor { uint8_t bNumDeviceCaps; /** bNumDeviceCap Device Capability Descriptors */ - struct libusb_bos_dev_capability_descriptor *dev_capability -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; + struct libusb_bos_dev_capability_descriptor *dev_capability[ZERO_SIZED_ARRAY]; }; /** \ingroup libusb_desc @@ -927,7 +923,7 @@ struct libusb_version { * sessions allows for your program to use two libraries (or dynamically * load two modules) which both independently use libusb. This will prevent * interference between the individual libusb users - for example - * libusb_set_debug() will not affect the other user of the library, and + * libusb_set_option() will not affect the other user of the library, and * libusb_exit() will not destroy resources that the other user is still * using. * @@ -987,6 +983,9 @@ enum libusb_speed { /** The device is operating at super speed (5000MBit/s). */ LIBUSB_SPEED_SUPER = 4, + + /** The device is operating at super speed plus (10000MBit/s). */ + LIBUSB_SPEED_SUPER_PLUS = 5, }; /** \ingroup libusb_dev @@ -1256,13 +1255,7 @@ struct libusb_transfer { int num_iso_packets; /** Isochronous packet descriptors, for isochronous transfers only. */ - struct libusb_iso_packet_descriptor iso_packet_desc -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; + struct libusb_iso_packet_descriptor iso_packet_desc[ZERO_SIZED_ARRAY]; }; /** \ingroup libusb_misc @@ -1290,21 +1283,20 @@ enum libusb_capability { * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default) * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr - * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning - * and error messages are printed to stderr - * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout, - * warnings and errors to stderr + * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stderr + * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stderr */ enum libusb_log_level { LIBUSB_LOG_LEVEL_NONE = 0, - LIBUSB_LOG_LEVEL_ERROR, - LIBUSB_LOG_LEVEL_WARNING, - LIBUSB_LOG_LEVEL_INFO, - LIBUSB_LOG_LEVEL_DEBUG, + LIBUSB_LOG_LEVEL_ERROR = 1, + LIBUSB_LOG_LEVEL_WARNING = 2, + LIBUSB_LOG_LEVEL_INFO = 3, + LIBUSB_LOG_LEVEL_DEBUG = 4, }; int LIBUSB_CALL libusb_init(libusb_context **ctx); void LIBUSB_CALL libusb_exit(libusb_context *ctx); +LIBUSB_DEPRECATED_FOR(libusb_set_option) void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); const struct libusb_version * LIBUSB_CALL libusb_get_version(void); int LIBUSB_CALL libusb_has_capability(uint32_t capability); @@ -2001,6 +1993,45 @@ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle callback_handle); +/** \ingroup libusb_lib + * Available option values for libusb_set_option(). + */ +enum libusb_option { + /** Set the log message verbosity. + * + * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever + * printed. If you choose to increase the message verbosity level, ensure + * that your application does not close the stderr file descriptor. + * + * You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative + * with its message logging and most of the time, will only log messages that + * explain error conditions and other oddities. This will help you debug + * your software. + * + * If the LIBUSB_DEBUG environment variable was set when libusb was + * initialized, this function does nothing: the message verbosity is fixed + * to the value in the environment variable. + * + * If libusb was compiled without any message logging, this function does + * nothing: you'll never get any messages. + * + * If libusb was compiled with verbose debug message logging, this function + * does nothing: you'll always get messages from all levels. + */ + LIBUSB_OPTION_LOG_LEVEL, + + /** Use the UsbDk backend for a specific context, if available. + * + * This option should be set immediately after calling libusb_init(), otherwise + * unspecified behavior may occur. + * + * Only valid on Windows. + */ + LIBUSB_OPTION_USE_USBDK, +}; + +int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...); + #ifdef __cplusplus } #endif diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h b/vendor/github.com/karalabe/usb/libusb/libusb/libusbi.h similarity index 94% rename from vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h rename to vendor/github.com/karalabe/usb/libusb/libusb/libusbi.h index 752e398878..31d6ce98d4 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/libusbi.h @@ -39,6 +39,20 @@ #include "libusb.h" #include "version.h" +/* Attribute to ensure that a structure member is aligned to a natural + * pointer alignment. Used for os_priv member. */ +#if defined(_MSC_VER) +#if defined(_WIN64) +#define PTR_ALIGNED __declspec(align(8)) +#else +#define PTR_ALIGNED __declspec(align(4)) +#endif +#elif defined(__GNUC__) +#define PTR_ALIGNED __attribute__((aligned(sizeof(void *)))) +#else +#define PTR_ALIGNED +#endif + /* Inside the libusb code, mark all public functions as follows: * return_type API_EXPORTED function_name(params) { ... } * But if the function returns a pointer, mark it as follows: @@ -139,6 +153,19 @@ static inline void list_del(struct list_head *entry) entry->next = entry->prev = NULL; } +static inline void list_cut(struct list_head *list, struct list_head *head) +{ + if (list_empty(head)) + return; + + list->next = head->next; + list->next->prev = list; + list->prev = head->prev; + list->prev->next = list; + + list_init(head); +} + static inline void *usbi_reallocf(void *ptr, size_t size) { void *ret = realloc(ptr, size); @@ -151,6 +178,9 @@ static inline void *usbi_reallocf(void *ptr, size_t size) const typeof( ((type *)0)->member ) *mptr = (ptr); \ (type *)( (char *)mptr - offsetof(type,member) );}) +#ifndef CLAMP +#define CLAMP(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? (max) : (val))) +#endif #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif @@ -175,29 +205,33 @@ static inline void *usbi_reallocf(void *ptr, size_t size) } while (0) #endif +#ifdef ENABLE_LOGGING + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf usbi_snprintf +#define vsnprintf usbi_vsnprintf +int usbi_snprintf(char *dst, size_t size, const char *format, ...); +int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap); +#define LIBUSB_PRINTF_WIN32 +#endif /* defined(_MSC_VER) && (_MSC_VER < 1900) */ + void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, const char *function, const char *format, ...); void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, const char *function, const char *format, va_list args); -#if !defined(_MSC_VER) || _MSC_VER >= 1400 +#if !defined(_MSC_VER) || (_MSC_VER >= 1400) -#ifdef ENABLE_LOGGING #define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__) -#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__) -#else -#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0) -#define usbi_dbg(...) do {} while(0) -#endif -#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__) -#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__) #define usbi_err(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_ERROR, __VA_ARGS__) +#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__) +#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__) +#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__) -#else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ +#else /* !defined(_MSC_VER) || (_MSC_VER >= 1400) */ -#ifdef ENABLE_LOGGING #define LOG_BODY(ctxt, level) \ { \ va_list args; \ @@ -205,24 +239,26 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, usbi_log_v(ctxt, level, "", format, args); \ va_end(args); \ } -#else -#define LOG_BODY(ctxt, level) \ -{ \ - (void)(ctxt); \ -} -#endif -static inline void usbi_info(struct libusb_context *ctx, const char *format, ...) - LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO) -static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...) - LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING) static inline void usbi_err(struct libusb_context *ctx, const char *format, ...) LOG_BODY(ctx, LIBUSB_LOG_LEVEL_ERROR) - +static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...) + LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING) +static inline void usbi_info(struct libusb_context *ctx, const char *format, ...) + LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO) static inline void usbi_dbg(const char *format, ...) LOG_BODY(NULL, LIBUSB_LOG_LEVEL_DEBUG) -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ +#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1400) */ + +#else /* ENABLE_LOGGING */ + +#define usbi_err(ctx, ...) do { (void)ctx; } while (0) +#define usbi_warn(ctx, ...) do { (void)ctx; } while (0) +#define usbi_info(ctx, ...) do { (void)ctx; } while (0) +#define usbi_dbg(...) do {} while (0) + +#endif /* ENABLE_LOGGING */ #define USBI_GET_CONTEXT(ctx) \ do { \ @@ -254,8 +290,10 @@ extern struct libusb_context *usbi_default_context; struct pollfd; struct libusb_context { - int debug; +#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING) + enum libusb_log_level debug; int debug_fixed; +#endif /* internal event pipe, used for signalling occurrence of an internal event. */ int event_pipe[2]; @@ -270,6 +308,7 @@ struct libusb_context { /* A list of registered hotplug callbacks */ struct list_head hotplug_cbs; + libusb_hotplug_callback_handle next_hotplug_cb_handle; usbi_mutex_t hotplug_cbs_lock; /* this is a list of in-flight transfer handles, sorted by timeout @@ -331,6 +370,8 @@ struct libusb_context { #endif struct list_head list; + + PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY]; }; enum usbi_event_flags { @@ -339,6 +380,9 @@ enum usbi_event_flags { /* The user has interrupted the event handler */ USBI_EVENT_USER_INTERRUPT = 1 << 1, + + /* A hotplug callback deregistration is pending */ + USBI_EVENT_HOTPLUG_CB_DEREGISTERED = 1 << 2, }; /* Macros for managing event handling state */ @@ -383,17 +427,7 @@ struct libusb_device { struct libusb_device_descriptor device_descriptor; int attached; - unsigned char os_priv -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif -#if defined(OS_SUNOS) - __attribute__ ((aligned (8))); -#else - ; -#endif + PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY]; }; struct libusb_device_handle { @@ -404,17 +438,8 @@ struct libusb_device_handle { struct list_head list; struct libusb_device *dev; int auto_detach_kernel_driver; - unsigned char os_priv -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif -#if defined(OS_SUNOS) - __attribute__ ((aligned (8))); -#else - ; -#endif + + PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY]; }; enum { @@ -540,14 +565,6 @@ int usbi_clear_event(struct libusb_context *ctx); #include "os/poll_windows.h" #endif -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define snprintf usbi_snprintf -#define vsnprintf usbi_vsnprintf -int usbi_snprintf(char *dst, size_t size, const char *format, ...); -int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap); -#define LIBUSB_PRINTF_WIN32 -#endif - struct usbi_pollfd { /* must come first */ struct libusb_pollfd pollfd; @@ -568,13 +585,7 @@ void usbi_remove_pollfd(struct libusb_context *ctx, int fd); struct discovered_devs { size_t len; size_t capacity; - struct libusb_device *devices -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; + struct libusb_device *devices[ZERO_SIZED_ARRAY]; }; struct discovered_devs *discovered_devs_append( @@ -607,7 +618,17 @@ struct usbi_os_backend { * * This function is called when the user deinitializes the library. */ - void (*exit)(void); + void (*exit)(struct libusb_context *ctx); + + /* Set a backend-specific option. Optional. + * + * This function is called when the user calls libusb_set_option() and + * the option is not handled by the core library. + * + * Return 0 on success, or a LIBUSB_ERROR code on failure. + */ + int (*set_option)(struct libusb_context *ctx, enum libusb_option option, + va_list args); /* Enumerate all the USB devices on the system, returning them in a list * of discovered devices. @@ -1110,6 +1131,11 @@ struct usbi_os_backend { clockid_t (*get_timerfd_clockid)(void); #endif + /* Number of bytes to reserve for per-context private backend data. + * This private data area is accessible through the "os_priv" field of + * struct libusb_context. */ + size_t context_priv_size; + /* Number of bytes to reserve for per-device private backend data. * This private data area is accessible through the "os_priv" field of * struct libusb_device. */ @@ -1127,17 +1153,7 @@ struct usbi_os_backend { size_t transfer_priv_size; }; -extern const struct usbi_os_backend * const usbi_backend; - -extern const struct usbi_os_backend linux_usbfs_backend; -extern const struct usbi_os_backend darwin_backend; -extern const struct usbi_os_backend openbsd_backend; -extern const struct usbi_os_backend netbsd_backend; -extern const struct usbi_os_backend windows_backend; -extern const struct usbi_os_backend usbdk_backend; -extern const struct usbi_os_backend wince_backend; -extern const struct usbi_os_backend haiku_usb_raw_backend; -extern const struct usbi_os_backend sunos_backend; +extern const struct usbi_os_backend usbi_backend; extern struct list_head active_contexts_list; extern usbi_mutex_static_t active_contexts_lock; diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.c similarity index 96% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.c index b0219d1b05..35ea1c321e 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode:nil -*- */ /* * darwin backend for libusb 1.0 - * Copyright © 2008-2016 Nathan Hjelm + * Copyright © 2008-2017 Nathan Hjelm * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -36,6 +36,10 @@ #include #include +/* Suppress warnings about the use of the deprecated objc_registerThreadWithCollector + * function. Its use is also conditionalized to only older deployment targets. */ +#define OBJC_SILENCE_GC_DEPRECATIONS 1 + #include #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200 #include @@ -55,6 +59,14 @@ _Atomic int32_t initCount = ATOMIC_VAR_INIT(0); #define libusb_darwin_atomic_fetch_add(x, y) (OSAtomicAdd32Barrier(y, x) - y) static volatile int32_t initCount = 0; + +#endif + +/* On 10.12 and later, use newly available clock_*() functions */ +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 +#define OSX_USE_CLOCK_GETTIME 1 +#else +#define OSX_USE_CLOCK_GETTIME 0 #endif #include "darwin_usb.h" @@ -65,15 +77,17 @@ static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER; static pthread_once_t darwin_init_once = PTHREAD_ONCE_INIT; +#if !OSX_USE_CLOCK_GETTIME static clock_serv_t clock_realtime; static clock_serv_t clock_monotonic; +#endif static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */ static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */ static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER; static struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices}; -static char *darwin_device_class = kIOUSBDeviceClassName; +static const char *darwin_device_class = kIOUSBDeviceClassName; #define DARWIN_CACHED_DEVICE(a) ((struct darwin_cached_device *) (((struct darwin_device_priv *)((a)->os_priv))->dev)) @@ -219,20 +233,21 @@ static int usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 loca &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (propertyMatchDict) { - /* there are no unsigned CFNumber types so treat the value as signed. the os seems to do this - internally (CFNumberType of locationID is 3) */ - CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location); + /* there are no unsigned CFNumber types so treat the value as signed. the OS seems to do this + internally (CFNumberType of locationID is kCFNumberSInt32Type) */ + CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location); + if (propertyMatchDict && locationCF) { CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF); - /* release our reference to the CFNumber (CFDictionarySetValue retains it) */ - CFRelease (locationCF); - CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict); - /* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */ - CFRelease (propertyMatchDict); } /* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */ + + /* release our references as per the Create Rule */ + if (propertyMatchDict) + CFRelease (propertyMatchDict); + if (locationCF) + CFRelease (locationCF); } return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, deviceIterator); @@ -300,6 +315,7 @@ static usb_device_t **darwin_device_from_service (io_service_t service) } static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) { + UNUSED(ptr); struct libusb_context *ctx; io_service_t service; @@ -308,7 +324,7 @@ static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) { while ((service = IOIteratorNext(add_devices))) { /* add this device to each active context's device list */ list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { - process_new_device (ctx, service);; + process_new_device (ctx, service); } IOObjectRelease(service); @@ -318,6 +334,7 @@ static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) { } static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { + UNUSED(ptr); struct libusb_device *dev = NULL; struct libusb_context *ctx; struct darwin_cached_device *old_device; @@ -516,7 +533,6 @@ static void darwin_check_version (void) { } static int darwin_init(struct libusb_context *ctx) { - host_name_port_t host_self; int rc; rc = pthread_once (&darwin_init_once, darwin_check_version); @@ -530,12 +546,15 @@ static int darwin_init(struct libusb_context *ctx) { } if (libusb_darwin_atomic_fetch_add (&initCount, 1) == 0) { - /* create the clocks that will be used */ +#if !OSX_USE_CLOCK_GETTIME + /* create the clocks that will be used if clock_gettime() is not available */ + host_name_port_t host_self; host_self = mach_host_self(); host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime); host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic); mach_port_deallocate(mach_task_self(), host_self); +#endif pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, ctx); @@ -548,10 +567,13 @@ static int darwin_init(struct libusb_context *ctx) { return rc; } -static void darwin_exit (void) { +static void darwin_exit (struct libusb_context *ctx) { + UNUSED(ctx); if (libusb_darwin_atomic_fetch_add (&initCount, -1) == 1) { +#if !OSX_USE_CLOCK_GETTIME mach_port_deallocate(mach_task_self(), clock_realtime); mach_port_deallocate(mach_task_self(), clock_monotonic); +#endif /* stop the event runloop and wait for the thread to terminate. */ CFRunLoopSourceSignal(libusb_darwin_acfls); @@ -866,14 +888,29 @@ static int get_device_port (io_service_t service, UInt8 *port) { return ret; } +static int get_device_parent_sessionID(io_service_t service, UInt64 *parent_sessionID) { + kern_return_t result; + io_service_t parent; + + /* Walk up the tree in the IOService plane until we find a parent that has a sessionID */ + parent = service; + while((result = IORegistryEntryGetParentEntry (parent, kIOServicePlane, &parent)) == kIOReturnSuccess) { + if (get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, parent_sessionID)) { + /* Success */ + return 1; + } + } + + /* We ran out of parents */ + return 0; +} + static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service, struct darwin_cached_device **cached_out) { struct darwin_cached_device *new_device; UInt64 sessionID = 0, parent_sessionID = 0; int ret = LIBUSB_SUCCESS; usb_device_t **device; - io_service_t parent; - kern_return_t result; UInt8 port = 0; /* get some info from the io registry */ @@ -884,11 +921,8 @@ static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t ser usbi_dbg("finding cached device for sessionID 0x%" PRIx64, sessionID); - result = IORegistryEntryGetParentEntry (service, kIOUSBPlane, &parent); - - if (kIOReturnSuccess == result) { - (void) get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, &parent_sessionID); - IOObjectRelease(parent); + if (get_device_parent_sessionID(service, &parent_sessionID)) { + usbi_dbg("parent sessionID: 0x%" PRIx64, parent_sessionID); } usbi_mutex_lock(&darwin_cached_devices_lock); @@ -1005,8 +1039,11 @@ static int process_new_device (struct libusb_context *ctx, io_service_t service) case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break; case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break; case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break; -#if DeviceVersion >= 500 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break; +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 + case kUSBDeviceSpeedSuperPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; #endif default: usbi_warn (ctx, "Got unknown device speed %d", devSpeed); @@ -1216,9 +1253,9 @@ static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) { kern_return_t kresult; - u_int8_t numep, direction, number; - u_int8_t dont_care1, dont_care3; - u_int16_t dont_care2; + UInt8 numep, direction, number; + UInt8 dont_care1, dont_care3; + UInt16 dont_care2; int rc; usbi_dbg ("building table of endpoints."); @@ -1965,6 +2002,7 @@ static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) { } static int darwin_clock_gettime(int clk_id, struct timespec *tp) { +#if !OSX_USE_CLOCK_GETTIME mach_timespec_t sys_time; clock_serv_t clock_ref; @@ -1987,6 +2025,16 @@ static int darwin_clock_gettime(int clk_id, struct timespec *tp) { tp->tv_nsec = sys_time.tv_nsec; return 0; +#else + switch (clk_id) { + case USBI_CLOCK_MONOTONIC: + return clock_gettime(CLOCK_MONOTONIC, tp); + case USBI_CLOCK_REALTIME: + return clock_gettime(CLOCK_REALTIME, tp); + default: + return LIBUSB_ERROR_INVALID_PARAM; + } +#endif } #if InterfaceVersion >= 550 @@ -2047,7 +2095,7 @@ static int darwin_free_streams (struct libusb_device_handle *dev_handle, unsigne } #endif -const struct usbi_os_backend darwin_backend = { +const struct usbi_os_backend usbi_backend = { .name = "Darwin", .caps = 0, .init = darwin_init, diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.h similarity index 60% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.h index 118043421a..474567f6ac 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.h @@ -28,37 +28,58 @@ #include /* IOUSBInterfaceInferface */ -#if defined (kIOUSBInterfaceInterfaceID700) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 + +/* New in OS 10.12.0. */ +#if defined (kIOUSBInterfaceInterfaceID800) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + +#define usb_interface_t IOUSBInterfaceInterface800 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID800 +#define InterfaceVersion 800 + +/* New in OS 10.10.0. */ +#elif defined (kIOUSBInterfaceInterfaceID700) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101000) #define usb_interface_t IOUSBInterfaceInterface700 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID700 #define InterfaceVersion 700 -#elif defined (kIOUSBInterfaceInterfaceID550) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 +/* New in OS 10.9.0. */ +#elif defined (kIOUSBInterfaceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) + +#define usb_interface_t IOUSBInterfaceInterface650 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID650 +#define InterfaceVersion 650 + +/* New in OS 10.8.2 but can't test deployment target to that granularity, so round up. */ +#elif defined (kIOUSBInterfaceInterfaceID550) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) #define usb_interface_t IOUSBInterfaceInterface550 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550 #define InterfaceVersion 550 -#elif defined (kIOUSBInterfaceInterfaceID500) +/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */ +#elif defined (kIOUSBInterfaceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) #define usb_interface_t IOUSBInterfaceInterface500 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID500 #define InterfaceVersion 500 -#elif defined (kIOUSBInterfaceInterfaceID300) +/* New in OS 10.5.0. */ +#elif defined (kIOUSBInterfaceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) #define usb_interface_t IOUSBInterfaceInterface300 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300 #define InterfaceVersion 300 -#elif defined (kIOUSBInterfaceInterfaceID245) +/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */ +#elif defined (kIOUSBInterfaceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) #define usb_interface_t IOUSBInterfaceInterface245 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245 #define InterfaceVersion 245 -#elif defined (kIOUSBInterfaceInterfaceID220) +/* New in OS 10.4.0. */ +#elif defined (kIOUSBInterfaceInterfaceID220) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1040) #define usb_interface_t IOUSBInterfaceInterface220 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 @@ -66,43 +87,57 @@ #else -#error "IOUSBFamily is too old. Please upgrade your OS" +#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target" #endif /* IOUSBDeviceInterface */ -#if defined (kIOUSBDeviceInterfaceID500) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 + +/* New in OS 10.9.0. */ +#if defined (kIOUSBDeviceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) + +#define usb_device_t IOUSBDeviceInterface650 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID650 +#define DeviceVersion 650 + +/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */ +#elif defined (kIOUSBDeviceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) #define usb_device_t IOUSBDeviceInterface500 #define DeviceInterfaceID kIOUSBDeviceInterfaceID500 #define DeviceVersion 500 -#elif defined (kIOUSBDeviceInterfaceID320) +/* New in OS 10.5.4 but can't test deployment target to that granularity, so round up. */ +#elif defined (kIOUSBDeviceInterfaceID320) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) #define usb_device_t IOUSBDeviceInterface320 #define DeviceInterfaceID kIOUSBDeviceInterfaceID320 #define DeviceVersion 320 -#elif defined (kIOUSBDeviceInterfaceID300) +/* New in OS 10.5.0. */ +#elif defined (kIOUSBDeviceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) #define usb_device_t IOUSBDeviceInterface300 #define DeviceInterfaceID kIOUSBDeviceInterfaceID300 #define DeviceVersion 300 -#elif defined (kIOUSBDeviceInterfaceID245) +/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */ +#elif defined (kIOUSBDeviceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) #define usb_device_t IOUSBDeviceInterface245 #define DeviceInterfaceID kIOUSBDeviceInterfaceID245 #define DeviceVersion 245 -#elif defined (kIOUSBDeviceInterfaceID220) +/* New in OS 10.2.3 but can't test deployment target to that granularity, so round up. */ +#elif defined (kIOUSBDeviceInterfaceID197) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1030) + #define usb_device_t IOUSBDeviceInterface197 #define DeviceInterfaceID kIOUSBDeviceInterfaceID197 #define DeviceVersion 197 #else -#error "IOUSBFamily is too old. Please upgrade your OS" +#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target" #endif diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_pollfs.cpp similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp rename to vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_pollfs.cpp diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb.h similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb.h diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_backend.cpp similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp rename to vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_backend.cpp diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.cpp similarity index 98% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp rename to vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.cpp index 77adbd1e60..c701e34421 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.cpp @@ -38,8 +38,9 @@ haiku_init(struct libusb_context *ctx) } static void -haiku_exit(void) +haiku_exit(struct libusb_context *ctx) { + UNUSED(ctx); if (atomic_add(&gInitCount, -1) == 1) gUsbRoster.Stop(); } @@ -195,11 +196,12 @@ haiku_clock_gettime(int clkid, struct timespec *tp) return LIBUSB_ERROR_INVALID_PARAM; } -const struct usbi_os_backend haiku_usb_raw_backend = { +const struct usbi_os_backend usbi_backend = { /*.name =*/ "Haiku usbfs", /*.caps =*/ 0, /*.init =*/ haiku_init, /*.exit =*/ haiku_exit, + /*.set_option =*/ NULL, /*.get_device_list =*/ NULL, /*.hotplug_poll =*/ NULL, /*.open =*/ haiku_open, @@ -244,6 +246,7 @@ const struct usbi_os_backend haiku_usb_raw_backend = { /*.get_timerfd_clockid =*/ NULL, #endif + /*.context_priv_size=*/ 0, /*.device_priv_size =*/ sizeof(USBDevice *), /*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *), /*.transfer_priv_size =*/ sizeof(USBTransfer *), diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.h similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.h diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_netlink.c similarity index 89% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/linux_netlink.c index 60cf3ad1bd..c1ad1ec51f 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_netlink.c @@ -45,24 +45,33 @@ #define NL_GROUP_KERNEL 1 +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + +#ifndef SOCK_NONBLOCK +#define SOCK_NONBLOCK 0 +#endif + static int linux_netlink_socket = -1; static int netlink_control_pipe[2] = { -1, -1 }; static pthread_t libusb_linux_event_thread; static void *linux_netlink_event_thread_main(void *arg); -static int set_fd_cloexec_nb(int fd) +static int set_fd_cloexec_nb(int fd, int socktype) { int flags; #if defined(FD_CLOEXEC) - flags = fcntl(fd, F_GETFD); - if (flags == -1) { - usbi_err(NULL, "failed to get netlink fd flags (%d)", errno); - return -1; - } + /* Make sure the netlink socket file descriptor is marked as CLOEXEC */ + if (!(socktype & SOCK_CLOEXEC)) { + flags = fcntl(fd, F_GETFD); + if (flags == -1) { + usbi_err(NULL, "failed to get netlink fd flags (%d)", errno); + return -1; + } - if (!(flags & FD_CLOEXEC)) { if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { usbi_err(NULL, "failed to set netlink fd flags (%d)", errno); return -1; @@ -70,13 +79,14 @@ static int set_fd_cloexec_nb(int fd) } #endif - flags = fcntl(fd, F_GETFL); - if (flags == -1) { - usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno); - return -1; - } + /* Make sure the netlink socket is non-blocking */ + if (!(socktype & SOCK_NONBLOCK)) { + flags = fcntl(fd, F_GETFL); + if (flags == -1) { + usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno); + return -1; + } - if (!(flags & O_NONBLOCK)) { if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno); return -1; @@ -89,21 +99,15 @@ static int set_fd_cloexec_nb(int fd) int linux_netlink_start_event_monitor(void) { struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL }; - int socktype = SOCK_RAW; + int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC; int opt = 1; int ret; -#if defined(SOCK_CLOEXEC) - socktype |= SOCK_CLOEXEC; -#endif -#if defined(SOCK_NONBLOCK) - socktype |= SOCK_NONBLOCK; -#endif - linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT); if (linux_netlink_socket == -1 && errno == EINVAL) { usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype); - linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); + socktype = SOCK_RAW; + linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT); } if (linux_netlink_socket == -1) { @@ -111,7 +115,7 @@ int linux_netlink_start_event_monitor(void) goto err; } - ret = set_fd_cloexec_nb(linux_netlink_socket); + ret = set_fd_cloexec_nb(linux_netlink_socket, socktype); if (ret == -1) goto err_close_socket; @@ -162,7 +166,7 @@ int linux_netlink_stop_event_monitor(void) /* Write some dummy data to the control pipe and * wait for the thread to exit */ - r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy)); + r = write(netlink_control_pipe[1], &dummy, sizeof(dummy)); if (r <= 0) usbi_warn(NULL, "netlink control pipe signal failed"); @@ -356,7 +360,8 @@ static int linux_netlink_read_message(void) static void *linux_netlink_event_thread_main(void *arg) { char dummy; - ssize_t r; + int r; + ssize_t nb; struct pollfd fds[] = { { .fd = netlink_control_pipe[0], .events = POLLIN }, @@ -368,11 +373,15 @@ static void *linux_netlink_event_thread_main(void *arg) usbi_dbg("netlink event thread entering"); - while (poll(fds, 2, -1) >= 0) { + while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) { + if (r < 0) { + /* temporary failure */ + continue; + } if (fds[0].revents & POLLIN) { /* activity on control pipe, read the byte and exit */ - r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) + nb = read(netlink_control_pipe[0], &dummy, sizeof(dummy)); + if (nb <= 0) usbi_warn(NULL, "netlink control pipe read failed"); break; } diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_udev.c similarity index 90% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/linux_udev.c index 61d953d8c2..c97806ba6b 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_udev.c @@ -82,17 +82,33 @@ int linux_udev_start_event_monitor(void) udev_monitor_fd = udev_monitor_get_fd(udev_monitor); +#if defined(FD_CLOEXEC) + /* Make sure the udev file descriptor is marked as CLOEXEC */ + r = fcntl(udev_monitor_fd, F_GETFD); + if (r == -1) { + usbi_err(NULL, "geting udev monitor fd flags (%d)", errno); + goto err_free_monitor; + } + if (!(r & FD_CLOEXEC)) { + if (fcntl(udev_monitor_fd, F_SETFD, r | FD_CLOEXEC) == -1) { + usbi_err(NULL, "setting udev monitor fd flags (%d)", errno); + goto err_free_monitor; + } + } +#endif + /* Some older versions of udev are not non-blocking by default, * so make sure this is set */ r = fcntl(udev_monitor_fd, F_GETFL); if (r == -1) { - usbi_err(NULL, "getting udev monitor fd flags (%d)", errno); + usbi_err(NULL, "getting udev monitor fd status flags (%d)", errno); goto err_free_monitor; } - r = fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK); - if (r) { - usbi_err(NULL, "setting udev monitor fd flags (%d)", errno); - goto err_free_monitor; + if (!(r & O_NONBLOCK)) { + if (fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK) == -1) { + usbi_err(NULL, "setting udev monitor fd status flags (%d)", errno); + goto err_free_monitor; + } } r = usbi_pipe(udev_control_pipe); @@ -134,7 +150,7 @@ int linux_udev_stop_event_monitor(void) /* Write some dummy data to the control pipe and * wait for the thread to exit */ - r = usbi_write(udev_control_pipe[1], &dummy, sizeof(dummy)); + r = write(udev_control_pipe[1], &dummy, sizeof(dummy)); if (r <= 0) { usbi_warn(NULL, "udev control pipe signal failed"); } @@ -162,6 +178,7 @@ static void *linux_udev_event_thread_main(void *arg) { char dummy; int r; + ssize_t nb; struct udev_device* udev_dev; struct pollfd fds[] = { {.fd = udev_control_pipe[0], @@ -179,8 +196,8 @@ static void *linux_udev_event_thread_main(void *arg) } if (fds[0].revents & POLLIN) { /* activity on control pipe, read the byte and exit */ - r = usbi_read(udev_control_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) { + nb = read(udev_control_pipe[0], &dummy, sizeof(dummy)); + if (nb <= 0) { usbi_warn(NULL, "udev control pipe read failed"); } break; @@ -274,6 +291,7 @@ int linux_udev_scan_devices(struct libusb_context *ctx) udev_enumerate_scan_devices(enumerator); devices = udev_enumerate_get_list_entry(enumerator); + entry = NULL; udev_list_entry_foreach(entry, devices) { const char *path = udev_list_entry_get_name(entry); uint8_t busnum = 0, devaddr = 0; diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.c similarity index 93% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.c index 6b89ba2889..768e7d5a64 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.c @@ -81,6 +81,19 @@ static const char *usbfs_path = NULL; /* use usbdev*.* device names in /dev instead of the usbfs bus directories */ static int usbdev_names = 0; +/* Linux has changed the maximum length of an individual isochronous packet + * over time. Initially this limit was 1,023 bytes, but Linux 2.6.18 + * (commit 3612242e527eb47ee4756b5350f8bdf791aa5ede) increased this value to + * 8,192 bytes to support higher bandwidth devices. Linux 3.10 + * (commit e2e2f0ea1c935edcf53feb4c4c8fdb4f86d57dd9) further increased this + * value to 49,152 bytes to support super speed devices. + */ +static unsigned int max_iso_packet_len = 0; + +/* Linux 2.6.23 adds support for O_CLOEXEC when opening files, which marks the + * close-on-exec flag in the underlying file descriptor. */ +static int supports_flag_cloexec = -1; + /* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically * allows us to mark URBs as being part of a specific logical transfer when * we submit them to the kernel. then, on any error except a cancellation, all @@ -136,6 +149,12 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *, int); static int linux_default_scan_devices (struct libusb_context *ctx); #endif +struct kernel_version { + int major; + int minor; + int sublevel; +}; + struct linux_device_priv { char *sysfs_dir; unsigned char *descriptors; @@ -180,6 +199,16 @@ struct linux_transfer_priv { int iso_packet_offset; }; +static int _open(const char *path, int flags) +{ +#if defined(O_CLOEXEC) + if (supports_flag_cloexec) + return open(path, flags | O_CLOEXEC); + else +#endif + return open(path, flags); +} + static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) { struct libusb_context *ctx = DEVICE_CTX(dev); @@ -194,7 +223,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, dev->bus_number, dev->device_address); - fd = open(path, mode); + fd = _open(path, mode); if (fd != -1) return fd; /* Success */ @@ -205,7 +234,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) /* Wait 10ms for USB device path creation.*/ nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL); - fd = open(path, mode); + fd = _open(path, mode); if (fd != -1) return fd; /* Success */ } @@ -342,39 +371,59 @@ static clockid_t find_monotonic_clock(void) return CLOCK_REALTIME; } -static int kernel_version_ge(int major, int minor, int sublevel) +static int get_kernel_version(struct libusb_context *ctx, + struct kernel_version *ver) { struct utsname uts; - int atoms, kmajor, kminor, ksublevel; + int atoms; - if (uname(&uts) < 0) - return -1; - atoms = sscanf(uts.release, "%d.%d.%d", &kmajor, &kminor, &ksublevel); - if (atoms < 1) + if (uname(&uts) < 0) { + usbi_err(ctx, "uname failed, errno %d", errno); return -1; + } - if (kmajor > major) + atoms = sscanf(uts.release, "%d.%d.%d", &ver->major, &ver->minor, &ver->sublevel); + if (atoms < 1) { + usbi_err(ctx, "failed to parse uname release '%s'", uts.release); + return -1; + } + + if (atoms < 2) + ver->minor = -1; + if (atoms < 3) + ver->sublevel = -1; + + usbi_dbg("reported kernel version is %s", uts.release); + + return 0; +} + +static int kernel_version_ge(const struct kernel_version *ver, + int major, int minor, int sublevel) +{ + if (ver->major > major) return 1; - if (kmajor < major) + else if (ver->major < major) return 0; /* kmajor == major */ - if (atoms < 2) + if (ver->minor == -1 && ver->sublevel == -1) return 0 == minor && 0 == sublevel; - if (kminor > minor) + else if (ver->minor > minor) return 1; - if (kminor < minor) + else if (ver->minor < minor) return 0; /* kminor == minor */ - if (atoms < 3) + if (ver->sublevel == -1) return 0 == sublevel; - return ksublevel >= sublevel; + return ver->sublevel >= sublevel; } static int op_init(struct libusb_context *ctx) { + struct kernel_version kversion; struct stat statbuf; int r; @@ -387,13 +436,17 @@ static int op_init(struct libusb_context *ctx) if (monotonic_clkid == -1) monotonic_clkid = find_monotonic_clock(); + if (get_kernel_version(ctx, &kversion) < 0) + return LIBUSB_ERROR_OTHER; + + if (supports_flag_cloexec == -1) { + /* O_CLOEXEC flag available from Linux 2.6.23 */ + supports_flag_cloexec = kernel_version_ge(&kversion,2,6,23); + } + if (supports_flag_bulk_continuation == -1) { /* bulk continuation URB flag available from Linux 2.6.32 */ - supports_flag_bulk_continuation = kernel_version_ge(2,6,32); - if (supports_flag_bulk_continuation == -1) { - usbi_err(ctx, "error checking for bulk continuation support"); - return LIBUSB_ERROR_OTHER; - } + supports_flag_bulk_continuation = kernel_version_ge(&kversion,2,6,32); } if (supports_flag_bulk_continuation) @@ -401,32 +454,31 @@ static int op_init(struct libusb_context *ctx) if (-1 == supports_flag_zero_packet) { /* zero length packet URB flag fixed since Linux 2.6.31 */ - supports_flag_zero_packet = kernel_version_ge(2,6,31); - if (-1 == supports_flag_zero_packet) { - usbi_err(ctx, "error checking for zero length packet support"); - return LIBUSB_ERROR_OTHER; - } + supports_flag_zero_packet = kernel_version_ge(&kversion,2,6,31); } if (supports_flag_zero_packet) usbi_dbg("zero length packet flag supported"); + if (!max_iso_packet_len) { + if (kernel_version_ge(&kversion,3,10,0)) + max_iso_packet_len = 49152; + else if (kernel_version_ge(&kversion,2,6,18)) + max_iso_packet_len = 8192; + else + max_iso_packet_len = 1023; + } + + usbi_dbg("max iso packet length is (likely) %u bytes", max_iso_packet_len); + if (-1 == sysfs_has_descriptors) { /* sysfs descriptors has all descriptors since Linux 2.6.26 */ - sysfs_has_descriptors = kernel_version_ge(2,6,26); - if (-1 == sysfs_has_descriptors) { - usbi_err(ctx, "error checking for sysfs descriptors"); - return LIBUSB_ERROR_OTHER; - } + sysfs_has_descriptors = kernel_version_ge(&kversion,2,6,26); } if (-1 == sysfs_can_relate_devices) { /* sysfs has busnum since Linux 2.6.22 */ - sysfs_can_relate_devices = kernel_version_ge(2,6,22); - if (-1 == sysfs_can_relate_devices) { - usbi_err(ctx, "error checking for sysfs busnum"); - return LIBUSB_ERROR_OTHER; - } + sysfs_can_relate_devices = kernel_version_ge(&kversion,2,6,22); } if (sysfs_can_relate_devices || sysfs_has_descriptors) { @@ -463,8 +515,9 @@ static int op_init(struct libusb_context *ctx) return r; } -static void op_exit(void) +static void op_exit(struct libusb_context *ctx) { + UNUSED(ctx); usbi_mutex_static_lock(&linux_hotplug_startstop_lock); assert(init_count != 0); if (!--init_count) { @@ -526,7 +579,7 @@ static int _open_sysfs_attr(struct libusb_device *dev, const char *attr) snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, priv->sysfs_dir, attr); - fd = open(filename, O_RDONLY); + fd = _open(filename, O_RDONLY); if (fd < 0) { usbi_err(DEVICE_CTX(dev), "open %s failed ret=%d errno=%d", filename, fd, errno); @@ -542,12 +595,12 @@ static int __read_sysfs_attr(struct libusb_context *ctx, { char filename[PATH_MAX]; FILE *f; - int r, value; + int fd, r, value; snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, devname, attr); - f = fopen(filename, "r"); - if (f == NULL) { + fd = _open(filename, O_RDONLY); + if (fd == -1) { if (errno == ENOENT) { /* File doesn't exist. Assume the device has been disconnected (see trac ticket #70). */ @@ -557,6 +610,13 @@ static int __read_sysfs_attr(struct libusb_context *ctx, return LIBUSB_ERROR_IO; } + f = fdopen(fd, "r"); + if (f == NULL) { + usbi_err(ctx, "fdopen %s failed errno=%d", filename, errno); + close(fd); + return LIBUSB_ERROR_OTHER; + } + r = fscanf(f, "%d", &value); fclose(f); if (r != 1) { @@ -806,7 +866,7 @@ static int op_get_active_config_descriptor(struct libusb_device *dev, if (r < 0) return r; - len = MIN(len, r); + len = MIN(len, (size_t)r); memcpy(buffer, config_desc, len); return len; } @@ -836,7 +896,7 @@ static int op_get_config_descriptor(struct libusb_device *dev, descriptors += r; } - len = MIN(len, r); + len = MIN(len, (size_t)r); memcpy(buffer, descriptors, len); return len; } @@ -911,6 +971,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, case 12: dev->speed = LIBUSB_SPEED_FULL; break; case 480: dev->speed = LIBUSB_SPEED_HIGH; break; case 5000: dev->speed = LIBUSB_SPEED_SUPER; break; + case 10000: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break; default: usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed); } @@ -1239,11 +1300,12 @@ static int sysfs_get_device_list(struct libusb_context *ctx) { DIR *devices = opendir(SYSFS_DEVICE_PATH); struct dirent *entry; - int r = LIBUSB_ERROR_IO; + int num_devices = 0; + int num_enumerated = 0; if (!devices) { usbi_err(ctx, "opendir devices failed errno=%d", errno); - return r; + return LIBUSB_ERROR_IO; } while ((entry = readdir(devices))) { @@ -1251,16 +1313,23 @@ static int sysfs_get_device_list(struct libusb_context *ctx) || strchr(entry->d_name, ':')) continue; + num_devices++; + if (sysfs_scan_device(ctx, entry->d_name)) { usbi_dbg("failed to enumerate dir entry %s", entry->d_name); continue; } - r = 0; + num_enumerated++; } closedir(devices); - return r; + + /* successful if at least one device was enumerated or no devices were found */ + if (num_enumerated || !num_devices) + return LIBUSB_SUCCESS; + else + return LIBUSB_ERROR_IO; } static int linux_default_scan_devices (struct libusb_context *ctx) @@ -1685,10 +1754,7 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle, strcpy(dc.driver, "usbfs"); dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER; r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc); - if (r == 0 || (r != 0 && errno != ENOTTY)) { - if (r == 0) - return 0; - + if (r != 0 && errno != ENOTTY) { switch (errno) { case EBUSY: return LIBUSB_ERROR_BUSY; @@ -1700,7 +1766,8 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle, usbi_err(HANDLE_CTX(handle), "disconnect-and-claim failed errno %d", errno); return LIBUSB_ERROR_OTHER; - } + } else if (r == 0) + return 0; /* Fallback code for kernels which don't support the disconnect-and-claim ioctl */ @@ -1973,38 +2040,43 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) struct linux_device_handle_priv *dpriv = _device_handle_priv(transfer->dev_handle); struct usbfs_urb **urbs; - size_t alloc_size; int num_packets = transfer->num_iso_packets; - int i; - int this_urb_len = 0; - int num_urbs = 1; - int packet_offset = 0; + int num_packets_remaining; + int i, j; + int num_urbs; unsigned int packet_len; + unsigned int total_len = 0; unsigned char *urb_buffer = transfer->buffer; - /* usbfs places arbitrary limits on iso URBs. this limit has changed - * at least three times, and it's difficult to accurately detect which - * limit this running kernel might impose. so we attempt to submit - * whatever the user has provided. if the kernel rejects the request - * due to its size, we return an error indicating such to the user. - */ + if (num_packets < 1) + return LIBUSB_ERROR_INVALID_PARAM; - /* calculate how many URBs we need */ + /* usbfs places arbitrary limits on iso URBs. this limit has changed + * at least three times, but we attempt to detect this limit during + * init and check it here. if the kernel rejects the request due to + * its size, we return an error indicating such to the user. + */ for (i = 0; i < num_packets; i++) { - unsigned int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len; packet_len = transfer->iso_packet_desc[i].length; - if (packet_len > space_remaining) { - num_urbs++; - this_urb_len = packet_len; - /* check that we can actually support this packet length */ - if (this_urb_len > MAX_ISO_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - } else { - this_urb_len += packet_len; + if (packet_len > max_iso_packet_len) { + usbi_warn(TRANSFER_CTX(transfer), + "iso packet length of %u bytes exceeds maximum of %u bytes", + packet_len, max_iso_packet_len); + return LIBUSB_ERROR_INVALID_PARAM; } + + total_len += packet_len; } - usbi_dbg("need %d %dk URBs for transfer", num_urbs, MAX_ISO_BUFFER_LENGTH / 1024); + + if (transfer->length < (int)total_len) + return LIBUSB_ERROR_INVALID_PARAM; + + /* usbfs limits the number of iso packets per URB */ + num_urbs = (num_packets + (MAX_ISO_PACKETS_PER_URB - 1)) / MAX_ISO_PACKETS_PER_URB; + + usbi_dbg("need %d urbs for new transfer with length %d", num_urbs, + transfer->length); urbs = calloc(num_urbs, sizeof(*urbs)); if (!urbs) @@ -2017,31 +2089,15 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) tpriv->iso_packet_offset = 0; /* allocate + initialize each URB with the correct number of packets */ - for (i = 0; i < num_urbs; i++) { + num_packets_remaining = num_packets; + for (i = 0, j = 0; i < num_urbs; i++) { + int num_packets_in_urb = MIN(num_packets_remaining, MAX_ISO_PACKETS_PER_URB); struct usbfs_urb *urb; - unsigned int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH; - int urb_packet_offset = 0; - unsigned char *urb_buffer_orig = urb_buffer; - int j; + size_t alloc_size; int k; - /* swallow up all the packets we can fit into this URB */ - while (packet_offset < transfer->num_iso_packets) { - packet_len = transfer->iso_packet_desc[packet_offset].length; - if (packet_len <= space_remaining_in_urb) { - /* throw it in */ - urb_packet_offset++; - packet_offset++; - space_remaining_in_urb -= packet_len; - urb_buffer += packet_len; - } else { - /* it can't fit, save it for the next URB */ - break; - } - } - alloc_size = sizeof(*urb) - + (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc)); + + (num_packets_in_urb * sizeof(struct usbfs_iso_packet_desc)); urb = calloc(1, alloc_size); if (!urb) { free_iso_urbs(tpriv); @@ -2050,10 +2106,10 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) urbs[i] = urb; /* populate packet lengths */ - for (j = 0, k = packet_offset - urb_packet_offset; - k < packet_offset; k++, j++) { - packet_len = transfer->iso_packet_desc[k].length; - urb->iso_frame_desc[j].length = packet_len; + for (k = 0; k < num_packets_in_urb; j++, k++) { + packet_len = transfer->iso_packet_desc[j].length; + urb->buffer_length += packet_len; + urb->iso_frame_desc[k].length = packet_len; } urb->usercontext = itransfer; @@ -2061,8 +2117,11 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) /* FIXME: interface for non-ASAP data? */ urb->flags = USBFS_URB_ISO_ASAP; urb->endpoint = transfer->endpoint; - urb->number_of_packets = urb_packet_offset; - urb->buffer = urb_buffer_orig; + urb->number_of_packets = num_packets_in_urb; + urb->buffer = urb_buffer; + + urb_buffer += urb->buffer_length; + num_packets_remaining -= num_packets_in_urb; } /* submit URBs */ @@ -2075,6 +2134,10 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) usbi_warn(TRANSFER_CTX(transfer), "submiturb failed, transfer too large"); r = LIBUSB_ERROR_INVALID_PARAM; + } else if (errno == EMSGSIZE) { + usbi_warn(TRANSFER_CTX(transfer), + "submiturb failed, iso packet length too large"); + r = LIBUSB_ERROR_INVALID_PARAM; } else { usbi_err(TRANSFER_CTX(transfer), "submiturb failed error %d errno=%d", r, errno); @@ -2213,7 +2276,6 @@ static void op_clear_transfer_priv(struct usbi_transfer *itransfer) USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - /* urbs can be freed also in submit_transfer so lock mutex first */ switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: case LIBUSB_TRANSFER_TYPE_BULK: @@ -2685,7 +2747,7 @@ static clockid_t op_get_timerfd_clockid(void) } #endif -const struct usbi_os_backend linux_usbfs_backend = { +const struct usbi_os_backend usbi_backend = { .name = "Linux usbfs", .caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER, .init = op_init, diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.h similarity index 99% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.h index 8bd3ebcb16..24496325f6 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.h @@ -81,10 +81,11 @@ struct usbfs_iso_packet_desc { unsigned int status; }; -#define MAX_ISO_BUFFER_LENGTH 49152 * 128 #define MAX_BULK_BUFFER_LENGTH 16384 #define MAX_CTRL_BUFFER_LENGTH 4096 +#define MAX_ISO_PACKETS_PER_URB 128 + struct usbfs_urb { unsigned char type; unsigned char endpoint; diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/netbsd_usb.c similarity index 98% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/netbsd_usb.c index ad1ede73e1..d9c059a776 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/netbsd_usb.c @@ -86,11 +86,12 @@ static int _sync_control_transfer(struct usbi_transfer *); static int _sync_gen_transfer(struct usbi_transfer *); static int _access_endpoint(struct libusb_transfer *); -const struct usbi_os_backend netbsd_backend = { +const struct usbi_os_backend usbi_backend = { "Synchronous NetBSD backend", 0, NULL, /* init() */ NULL, /* exit() */ + NULL, /* set_option() */ netbsd_get_device_list, NULL, /* hotplug_poll */ netbsd_open, @@ -131,6 +132,7 @@ const struct usbi_os_backend netbsd_backend = { netbsd_handle_transfer_completion, netbsd_clock_gettime, + 0, /* context_priv_size */ sizeof(struct device_priv), sizeof(struct handle_priv), 0, /* transfer_priv_size */ @@ -212,7 +214,6 @@ error: int netbsd_open(struct libusb_device_handle *handle) { - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; dpriv->fd = open(dpriv->devnode, O_RDWR); @@ -230,7 +231,6 @@ netbsd_open(struct libusb_device_handle *handle) void netbsd_close(struct libusb_device_handle *handle) { - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; usbi_dbg("close: fd %d", dpriv->fd); diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/openbsd_usb.c similarity index 99% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/openbsd_usb.c index c660257114..f174e496c4 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/openbsd_usb.c @@ -89,11 +89,12 @@ static int _access_endpoint(struct libusb_transfer *); static int _bus_open(int); -const struct usbi_os_backend openbsd_backend = { +const struct usbi_os_backend usbi_backend = { "Synchronous OpenBSD backend", 0, NULL, /* init() */ NULL, /* exit() */ + NULL, /* set_option() */ obsd_get_device_list, NULL, /* hotplug_poll */ obsd_open, @@ -134,6 +135,7 @@ const struct usbi_os_backend openbsd_backend = { obsd_handle_transfer_completion, obsd_clock_gettime, + 0, /* context_priv_size */ sizeof(struct device_priv), sizeof(struct handle_priv), 0, /* transfer_priv_size */ @@ -246,7 +248,6 @@ obsd_get_device_list(struct libusb_context * ctx, int obsd_open(struct libusb_device_handle *handle) { - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; char devnode[16]; @@ -270,7 +271,6 @@ obsd_open(struct libusb_device_handle *handle) void obsd_close(struct libusb_device_handle *handle) { - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; if (dpriv->devname) { diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.c similarity index 56% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.c index e2f55a57a1..337714aa6b 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.c @@ -29,25 +29,56 @@ int usbi_pipe(int pipefd[2]) { +#if defined(HAVE_PIPE2) + int ret = pipe2(pipefd, O_CLOEXEC); +#else int ret = pipe(pipefd); +#endif + if (ret != 0) { + usbi_err(NULL, "failed to create pipe (%d)", errno); return ret; } + +#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC) + ret = fcntl(pipefd[0], F_GETFD); + if (ret == -1) { + usbi_err(NULL, "failed to get pipe fd flags (%d)", errno); + goto err_close_pipe; + } + ret = fcntl(pipefd[0], F_SETFD, ret | FD_CLOEXEC); + if (ret == -1) { + usbi_err(NULL, "failed to set pipe fd flags (%d)", errno); + goto err_close_pipe; + } + + ret = fcntl(pipefd[1], F_GETFD); + if (ret == -1) { + usbi_err(NULL, "failed to get pipe fd flags (%d)", errno); + goto err_close_pipe; + } + ret = fcntl(pipefd[1], F_SETFD, ret | FD_CLOEXEC); + if (ret == -1) { + usbi_err(NULL, "failed to set pipe fd flags (%d)", errno); + goto err_close_pipe; + } +#endif + ret = fcntl(pipefd[1], F_GETFL); if (ret == -1) { - usbi_dbg("Failed to get pipe fd flags: %d", errno); + usbi_err(NULL, "failed to get pipe fd status flags (%d)", errno); goto err_close_pipe; } ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK); - if (ret != 0) { - usbi_dbg("Failed to set non-blocking on new pipe: %d", errno); + if (ret == -1) { + usbi_err(NULL, "failed to set pipe fd status flags (%d)", errno); goto err_close_pipe; } return 0; err_close_pipe: - usbi_close(pipefd[0]); - usbi_close(pipefd[1]); + close(pipefd[0]); + close(pipefd[1]); return ret; } diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.h similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.h diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c new file mode 100644 index 0000000000..4d283333d1 --- /dev/null +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c @@ -0,0 +1,364 @@ +/* + * poll_windows: poll compatibility wrapper for Windows + * Copyright © 2017 Chris Dickens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* + * poll() and pipe() Windows compatibility layer for libusb 1.0 + * + * The way this layer works is by using OVERLAPPED with async I/O transfers, as + * OVERLAPPED have an associated event which is flagged for I/O completion. + * + * For USB pollable async I/O, you would typically: + * - obtain a Windows HANDLE to a file or device that has been opened in + * OVERLAPPED mode + * - call usbi_create_fd with this handle to obtain a custom fd. + * - leave the core functions call the poll routine and flag POLLIN/POLLOUT + * + * The pipe pollable synchronous I/O works using the overlapped event associated + * with a fake pipe. The read/write functions are only meant to be used in that + * context. + */ +#include + +#include +#include +#include + +#include "libusbi.h" +#include "windows_common.h" + +// public fd data +const struct winfd INVALID_WINFD = { -1, NULL }; + +// private data +struct file_descriptor { + enum fd_type { FD_TYPE_PIPE, FD_TYPE_TRANSFER } type; + OVERLAPPED overlapped; +}; + +static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER; +static struct file_descriptor *fd_table[MAX_FDS]; + +static struct file_descriptor *create_fd(enum fd_type type) +{ + struct file_descriptor *fd = calloc(1, sizeof(*fd)); + if (fd == NULL) + return NULL; + fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (fd->overlapped.hEvent == NULL) { + free(fd); + return NULL; + } + fd->type = type; + return fd; +} + +static void free_fd(struct file_descriptor *fd) +{ + CloseHandle(fd->overlapped.hEvent); + free(fd); +} + +/* + * Create both an fd and an OVERLAPPED, so that it can be used with our + * polling function + * The handle MUST support overlapped transfers (usually requires CreateFile + * with FILE_FLAG_OVERLAPPED) + * Return a pollable file descriptor struct, or INVALID_WINFD on error + * + * Note that the fd returned by this function is a per-transfer fd, rather + * than a per-session fd and cannot be used for anything else but our + * custom functions. + * if you plan to do R/W on the same handle, you MUST create 2 fds: one for + * read and one for write. Using a single R/W fd is unsupported and will + * produce unexpected results + */ +struct winfd usbi_create_fd(void) +{ + struct file_descriptor *fd; + struct winfd wfd; + + fd = create_fd(FD_TYPE_TRANSFER); + if (fd == NULL) + return INVALID_WINFD; + + usbi_mutex_static_lock(&fd_table_lock); + for (wfd.fd = 0; wfd.fd < MAX_FDS; wfd.fd++) { + if (fd_table[wfd.fd] != NULL) + continue; + fd_table[wfd.fd] = fd; + break; + } + usbi_mutex_static_unlock(&fd_table_lock); + + if (wfd.fd == MAX_FDS) { + free_fd(fd); + return INVALID_WINFD; + } + + wfd.overlapped = &fd->overlapped; + + return wfd; +} + +static int check_pollfds(struct pollfd *fds, unsigned int nfds, + HANDLE *wait_handles, DWORD *nb_wait_handles) +{ + struct file_descriptor *fd; + unsigned int n; + int nready = 0; + + usbi_mutex_static_lock(&fd_table_lock); + + for (n = 0; n < nfds; ++n) { + fds[n].revents = 0; + + // Keep it simple - only allow either POLLIN *or* POLLOUT + assert((fds[n].events == POLLIN) || (fds[n].events == POLLOUT)); + if ((fds[n].events != POLLIN) && (fds[n].events != POLLOUT)) { + fds[n].revents = POLLNVAL; + nready++; + continue; + } + + if ((fds[n].fd >= 0) && (fds[n].fd < MAX_FDS)) + fd = fd_table[fds[n].fd]; + else + fd = NULL; + + assert(fd != NULL); + if (fd == NULL) { + fds[n].revents = POLLNVAL; + nready++; + continue; + } + + if (HasOverlappedIoCompleted(&fd->overlapped) + && (WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) { + fds[n].revents = fds[n].events; + nready++; + } else if (wait_handles != NULL) { + if (*nb_wait_handles == MAXIMUM_WAIT_OBJECTS) { + usbi_warn(NULL, "too many HANDLEs to wait on"); + continue; + } + wait_handles[*nb_wait_handles] = fd->overlapped.hEvent; + (*nb_wait_handles)++; + } + } + + usbi_mutex_static_unlock(&fd_table_lock); + + return nready; +} +/* + * POSIX poll equivalent, using Windows OVERLAPPED + * Currently, this function only accepts one of POLLIN or POLLOUT per fd + * (but you can create multiple fds from the same handle for read and write) + */ +int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) +{ + HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS]; + DWORD nb_wait_handles = 0; + DWORD ret; + int nready; + + nready = check_pollfds(fds, nfds, wait_handles, &nb_wait_handles); + + // If nothing was triggered, wait on all fds that require it + if ((nready == 0) && (nb_wait_handles != 0) && (timeout != 0)) { + ret = WaitForMultipleObjects(nb_wait_handles, wait_handles, + FALSE, (timeout < 0) ? INFINITE : (DWORD)timeout); + if (ret < (WAIT_OBJECT_0 + nb_wait_handles)) { + nready = check_pollfds(fds, nfds, NULL, NULL); + } else if (ret != WAIT_TIMEOUT) { + if (ret == WAIT_FAILED) + usbi_err(NULL, "WaitForMultipleObjects failed: %u", (unsigned int)GetLastError()); + nready = -1; + } + } + + return nready; +} + +/* + * close a fake file descriptor + */ +int usbi_close(int _fd) +{ + struct file_descriptor *fd; + + if (_fd < 0 || _fd >= MAX_FDS) + goto err_badfd; + + usbi_mutex_static_lock(&fd_table_lock); + fd = fd_table[_fd]; + fd_table[_fd] = NULL; + usbi_mutex_static_unlock(&fd_table_lock); + + if (fd == NULL) + goto err_badfd; + + if (fd->type == FD_TYPE_PIPE) { + // InternalHigh is our reference count + fd->overlapped.InternalHigh--; + if (fd->overlapped.InternalHigh == 0) + free_fd(fd); + } else { + free_fd(fd); + } + + return 0; + +err_badfd: + errno = EBADF; + return -1; +} + +/* +* Create a fake pipe. +* As libusb only uses pipes for signaling, all we need from a pipe is an +* event. To that extent, we create a single wfd and overlapped as a means +* to access that event. +*/ +int usbi_pipe(int filedes[2]) +{ + struct file_descriptor *fd; + int r_fd = -1, w_fd = -1; + int i; + + fd = create_fd(FD_TYPE_PIPE); + if (fd == NULL) { + errno = ENOMEM; + return -1; + } + + // Use InternalHigh as a reference count + fd->overlapped.Internal = STATUS_PENDING; + fd->overlapped.InternalHigh = 2; + + usbi_mutex_static_lock(&fd_table_lock); + do { + for (i = 0; i < MAX_FDS; i++) { + if (fd_table[i] != NULL) + continue; + if (r_fd == -1) { + r_fd = i; + } else if (w_fd == -1) { + w_fd = i; + break; + } + } + + if (i == MAX_FDS) + break; + + fd_table[r_fd] = fd; + fd_table[w_fd] = fd; + + } while (0); + usbi_mutex_static_unlock(&fd_table_lock); + + if (i == MAX_FDS) { + free_fd(fd); + errno = EMFILE; + return -1; + } + + filedes[0] = r_fd; + filedes[1] = w_fd; + + return 0; +} + +/* + * synchronous write for fake "pipe" signaling + */ +ssize_t usbi_write(int fd, const void *buf, size_t count) +{ + int error = EBADF; + + UNUSED(buf); + + if (fd < 0 || fd >= MAX_FDS) + goto err_out; + + if (count != sizeof(unsigned char)) { + usbi_err(NULL, "this function should only used for signaling"); + error = EINVAL; + goto err_out; + } + + usbi_mutex_static_lock(&fd_table_lock); + if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) { + assert(fd_table[fd]->overlapped.Internal == STATUS_PENDING); + assert(fd_table[fd]->overlapped.InternalHigh == 2); + fd_table[fd]->overlapped.Internal = STATUS_WAIT_0; + SetEvent(fd_table[fd]->overlapped.hEvent); + error = 0; + } + usbi_mutex_static_unlock(&fd_table_lock); + + if (error) + goto err_out; + + return sizeof(unsigned char); + +err_out: + errno = error; + return -1; +} + +/* + * synchronous read for fake "pipe" signaling + */ +ssize_t usbi_read(int fd, void *buf, size_t count) +{ + int error = EBADF; + + UNUSED(buf); + + if (fd < 0 || fd >= MAX_FDS) + goto err_out; + + if (count != sizeof(unsigned char)) { + usbi_err(NULL, "this function should only used for signaling"); + error = EINVAL; + goto err_out; + } + + usbi_mutex_static_lock(&fd_table_lock); + if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) { + assert(fd_table[fd]->overlapped.Internal == STATUS_WAIT_0); + assert(fd_table[fd]->overlapped.InternalHigh == 2); + fd_table[fd]->overlapped.Internal = STATUS_PENDING; + ResetEvent(fd_table[fd]->overlapped.hEvent); + error = 0; + } + usbi_mutex_static_unlock(&fd_table_lock); + + if (error) + goto err_out; + + return sizeof(unsigned char); + +err_out: + errno = error; + return -1; +} diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.h similarity index 70% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.h index aa4c985dae..bd22c7f623 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.h @@ -2,6 +2,7 @@ * Windows compat: POSIX compatibility wrapper * Copyright © 2012-2013 RealVNC Ltd. * Copyright © 2009-2010 Pete Batard + * Copyright © 2016-2018 Chris Dickens * With contributions from Michael Plante, Orin Eman et al. * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. * @@ -40,21 +41,6 @@ #define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) -/* Windows versions */ -enum windows_version { - WINDOWS_CE = -2, - WINDOWS_UNDEFINED = -1, - WINDOWS_UNSUPPORTED = 0, - WINDOWS_XP = 0x51, - WINDOWS_2003 = 0x52, // Also XP x64 - WINDOWS_VISTA = 0x60, - WINDOWS_7 = 0x61, - WINDOWS_8 = 0x62, - WINDOWS_8_1_OR_LATER = 0x63, - WINDOWS_MAX -}; -extern int windows_version; - #define MAX_FDS 256 #define POLLIN 0x0001 /* There is data to read */ @@ -65,46 +51,26 @@ extern int windows_version; #define POLLNVAL 0x0020 /* Invalid request: fd not open */ struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ }; -// access modes -enum rw_type { - RW_NONE, - RW_READ, - RW_WRITE, -}; - -// fd struct that can be used for polling on Windows -typedef int cancel_transfer(struct usbi_transfer *itransfer); - struct winfd { - int fd; // what's exposed to libusb core - HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it - OVERLAPPED* overlapped; // what will report our I/O status - struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed - cancel_transfer *cancel_fn; // Function pointer to cancel transfer API - enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH) + int fd; // what's exposed to libusb core + OVERLAPPED *overlapped; // what will report our I/O status }; + extern const struct winfd INVALID_WINFD; +struct winfd usbi_create_fd(void); + int usbi_pipe(int pipefd[2]); int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout); ssize_t usbi_write(int fd, const void *buf, size_t count); ssize_t usbi_read(int fd, void *buf, size_t count); int usbi_close(int fd); -void init_polling(void); -void exit_polling(void); -struct winfd usbi_create_fd(HANDLE handle, int access_mode, - struct usbi_transfer *transfer, cancel_transfer *cancel_fn); -void usbi_free_fd(struct winfd* winfd); -struct winfd fd_to_winfd(int fd); -struct winfd handle_to_winfd(HANDLE handle); -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped); - /* * Timeval operations */ diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.c similarity index 71% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.c index cb608976b6..7150a3e9d9 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -28,21 +29,34 @@ #include #include #include +#include #include #include #include +#include +#include #include +#include #include #include #include "libusbi.h" #include "sunos_usb.h" +#define UPDATEDRV_PATH "/usr/sbin/update_drv" +#define UPDATEDRV "update_drv" + +typedef list_t string_list_t; +typedef struct string_node { + char *string; + list_node_t link; +} string_node_t; + /* * Backend functions */ static int sunos_init(struct libusb_context *); -static void sunos_exit(void); +static void sunos_exit(struct libusb_context *); static int sunos_get_device_list(struct libusb_context *, struct discovered_devs **); static int sunos_open(struct libusb_device_handle *); @@ -67,6 +81,162 @@ static int sunos_cancel_transfer(struct usbi_transfer *); static void sunos_clear_transfer_priv(struct usbi_transfer *); static int sunos_handle_transfer_completion(struct usbi_transfer *); static int sunos_clock_gettime(int, struct timespec *); +static int sunos_kernel_driver_active(struct libusb_device_handle *, int interface); +static int sunos_detach_kernel_driver (struct libusb_device_handle *dev, int interface_number); +static int sunos_attach_kernel_driver (struct libusb_device_handle *dev, int interface_number); +static int sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv); +static int sunos_usb_ioctl(struct libusb_device *dev, int cmd); + +static struct devctl_iocdata iocdata; +static int sunos_get_link(di_devlink_t devlink, void *arg) +{ + walk_link_t *larg = (walk_link_t *)arg; + const char *p; + const char *q; + + if (larg->path) { + char *content = (char *)di_devlink_content(devlink); + char *start = strstr(content, "/devices/"); + start += strlen("/devices"); + usbi_dbg("%s", start); + + /* line content must have minor node */ + if (start == NULL || + strncmp(start, larg->path, larg->len) != 0 || + start[larg->len] != ':') + return (DI_WALK_CONTINUE); + } + + p = di_devlink_path(devlink); + q = strrchr(p, '/'); + usbi_dbg("%s", q); + + *(larg->linkpp) = strndup(p, strlen(p) - strlen(q)); + + return (DI_WALK_TERMINATE); +} + + +static int sunos_physpath_to_devlink( + const char *node_path, const char *match, char **link_path) +{ + walk_link_t larg; + di_devlink_handle_t hdl; + + *link_path = NULL; + larg.linkpp = link_path; + if ((hdl = di_devlink_init(NULL, 0)) == NULL) { + usbi_dbg("di_devlink_init failure"); + return (-1); + } + + larg.len = strlen(node_path); + larg.path = (char *)node_path; + + (void) di_devlink_walk(hdl, match, NULL, DI_PRIMARY_LINK, + (void *)&larg, sunos_get_link); + + (void) di_devlink_fini(&hdl); + + if (*link_path == NULL) { + usbi_dbg("there is no devlink for this path"); + return (-1); + } + + return 0; +} + +static int +sunos_usb_ioctl(struct libusb_device *dev, int cmd) +{ + int fd; + nvlist_t *nvlist; + char *end; + char *phypath; + char *hubpath; + char path_arg[PATH_MAX]; + sunos_dev_priv_t *dpriv; + devctl_ap_state_t devctl_ap_state; + + dpriv = (sunos_dev_priv_t *)dev->os_priv; + phypath = dpriv->phypath; + + end = strrchr(phypath, '/'); + if (end == NULL) + return (-1); + hubpath = strndup(phypath, end - phypath); + if (hubpath == NULL) + return (-1); + + end = strrchr(hubpath, '@'); + if (end == NULL) { + free(hubpath); + return (-1); + } + end++; + usbi_dbg("unitaddr: %s", end); + + nvlist_alloc(&nvlist, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP); + nvlist_add_int32(nvlist, "port", dev->port_number); + //find the hub path + snprintf(path_arg, sizeof(path_arg), "/devices%s:hubd", hubpath); + usbi_dbg("ioctl hub path: %s", path_arg); + + fd = open(path_arg, O_RDONLY); + if (fd < 0) { + usbi_err(DEVICE_CTX(dev), "open failed: %d (%s)", errno, strerror(errno)); + nvlist_free(nvlist); + free(hubpath); + return (-1); + } + + memset(&iocdata, 0, sizeof(iocdata)); + memset(&devctl_ap_state, 0, sizeof(devctl_ap_state)); + + nvlist_pack(nvlist, (char **)&iocdata.nvl_user, &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0); + + iocdata.cmd = DEVCTL_AP_GETSTATE; + iocdata.flags = 0; + iocdata.c_nodename = "hub"; + iocdata.c_unitaddr = end; + iocdata.cpyout_buf = &devctl_ap_state; + usbi_dbg("%p, %d", iocdata.nvl_user, iocdata.nvl_usersz); + + errno = 0; + if (ioctl(fd, DEVCTL_AP_GETSTATE, &iocdata) == -1) { + usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)", + fd, DEVCTL_AP_GETSTATE, errno, strerror(errno)); + } else { + usbi_dbg("dev rstate: %d", devctl_ap_state.ap_rstate); + usbi_dbg("dev ostate: %d", devctl_ap_state.ap_ostate); + } + + errno = 0; + iocdata.cmd = cmd; + if (ioctl(fd, (int)cmd, &iocdata) != 0) { + usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)", + fd, cmd, errno, strerror(errno)); + sleep(2); + } + + close(fd); + free(iocdata.nvl_user); + nvlist_free(nvlist); + free(hubpath); + + return (-errno); +} + +static int +sunos_kernel_driver_active(struct libusb_device_handle *dev, int interface) +{ + sunos_dev_priv_t *dpriv; + dpriv = (sunos_dev_priv_t *)dev->dev->os_priv; + + usbi_dbg("%s", dpriv->ugenpath); + + return (dpriv->ugenpath == NULL); +} /* * Private functions @@ -79,11 +249,229 @@ static int sunos_init(struct libusb_context *ctx) return (LIBUSB_SUCCESS); } -static void sunos_exit(void) +static void sunos_exit(struct libusb_context *ctx) { usbi_dbg(""); } +static string_list_t * +sunos_new_string_list(void) +{ + string_list_t *list; + + list = calloc(1, sizeof(*list)); + if (list != NULL) + list_create(list, sizeof(string_node_t), + offsetof(string_node_t, link)); + + return (list); +} + +static int +sunos_append_to_string_list(string_list_t *list, const char *arg) +{ + string_node_t *np; + + np = calloc(1, sizeof(*np)); + if (!np) + return (-1); + + np->string = strdup(arg); + if (!np->string) { + free(np); + return (-1); + } + + list_insert_tail(list, np); + + return (0); +} + +static void +sunos_free_string_list(string_list_t *list) +{ + string_node_t *np; + + while ((np = list_remove_head(list)) != NULL) { + free(np->string); + free(np); + } + + free(list); +} + +static char ** +sunos_build_argv_list(string_list_t *list) +{ + char **argv_list; + string_node_t *np; + int n; + + n = 1; /* Start at 1 for NULL terminator */ + for (np = list_head(list); np != NULL; np = list_next(list, np)) + n++; + + argv_list = calloc(n, sizeof(char *)); + if (argv_list == NULL) + return NULL; + + n = 0; + for (np = list_head(list); np != NULL; np = list_next(list, np)) + argv_list[n++] = np->string; + + return (argv_list); +} + + +static int +sunos_exec_command(struct libusb_context *ctx, const char *path, + string_list_t *list) +{ + pid_t pid; + int status; + int waitstat; + int exit_status; + char **argv_list; + + argv_list = sunos_build_argv_list(list); + if (argv_list == NULL) + return (-1); + + pid = fork(); + if (pid == 0) { + /* child */ + execv(path, argv_list); + _exit(127); + } else if (pid > 0) { + /* parent */ + do { + waitstat = waitpid(pid, &status, 0); + } while ((waitstat == -1 && errno == EINTR) || + (waitstat == 0 && !WIFEXITED(status) && !WIFSIGNALED(status))); + + if (waitstat == 0) { + if (WIFEXITED(status)) + exit_status = WEXITSTATUS(status); + else + exit_status = WTERMSIG(status); + } else { + usbi_err(ctx, "waitpid failed: errno %d (%s)", errno, strerror(errno)); + exit_status = -1; + } + } else { + /* fork failed */ + usbi_err(ctx, "fork failed: errno %d (%s)", errno, strerror(errno)); + exit_status = -1; + } + + free(argv_list); + + return (exit_status); +} + +static int +sunos_detach_kernel_driver(struct libusb_device_handle *dev_handle, + int interface_number) +{ + struct libusb_context *ctx = HANDLE_CTX(dev_handle); + string_list_t *list; + char path_arg[PATH_MAX]; + sunos_dev_priv_t *dpriv; + int r; + + dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv; + snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath); + usbi_dbg("%s", path_arg); + + list = sunos_new_string_list(); + if (list == NULL) + return (LIBUSB_ERROR_NO_MEM); + + /* attach ugen driver */ + r = 0; + r |= sunos_append_to_string_list(list, UPDATEDRV); + r |= sunos_append_to_string_list(list, "-a"); /* add rule */ + r |= sunos_append_to_string_list(list, "-i"); /* specific device */ + r |= sunos_append_to_string_list(list, path_arg); /* physical path */ + r |= sunos_append_to_string_list(list, "ugen"); + if (r) { + sunos_free_string_list(list); + return (LIBUSB_ERROR_NO_MEM); + } + + r = sunos_exec_command(ctx, UPDATEDRV_PATH, list); + sunos_free_string_list(list); + if (r < 0) + return (LIBUSB_ERROR_OTHER); + + /* reconfigure the driver node */ + r = 0; + r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT); + r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE); + if (r) + usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed"); + + snprintf(path_arg, sizeof(path_arg), "^usb/%x.%x", dpriv->dev_descr.idVendor, + dpriv->dev_descr.idProduct); + sunos_physpath_to_devlink(dpriv->phypath, path_arg, &dpriv->ugenpath); + + if (access(dpriv->ugenpath, F_OK) == -1) { + usbi_err(HANDLE_CTX(dev_handle), "fail to detach kernel driver"); + return (LIBUSB_ERROR_IO); + } + + return sunos_usb_open_ep0((sunos_dev_handle_priv_t *)dev_handle->os_priv, dpriv); +} + +static int +sunos_attach_kernel_driver(struct libusb_device_handle *dev_handle, + int interface_number) +{ + struct libusb_context *ctx = HANDLE_CTX(dev_handle); + string_list_t *list; + char path_arg[PATH_MAX]; + sunos_dev_priv_t *dpriv; + int r; + + /* we open the dev in detach driver, so we need close it first. */ + sunos_close(dev_handle); + + dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv; + snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath); + usbi_dbg("%s", path_arg); + + list = sunos_new_string_list(); + if (list == NULL) + return (LIBUSB_ERROR_NO_MEM); + + /* detach ugen driver */ + r = 0; + r |= sunos_append_to_string_list(list, UPDATEDRV); + r |= sunos_append_to_string_list(list, "-d"); /* add rule */ + r |= sunos_append_to_string_list(list, "-i"); /* specific device */ + r |= sunos_append_to_string_list(list, path_arg); /* physical path */ + r |= sunos_append_to_string_list(list, "ugen"); + if (r) { + sunos_free_string_list(list); + return (LIBUSB_ERROR_NO_MEM); + } + + r = sunos_exec_command(ctx, UPDATEDRV_PATH, list); + sunos_free_string_list(list); + if (r < 0) + return (LIBUSB_ERROR_OTHER); + + /* reconfigure the driver node */ + r = 0; + r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE); + r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT); + r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE); + if (r) + usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed"); + + return 0; +} + static int sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev) { @@ -93,6 +481,7 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev) uint8_t *rdata; struct libusb_device_descriptor *descr; sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv; + char match_str[PATH_MAX]; /* Device descriptors */ proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, @@ -137,7 +526,11 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev) phypath = di_devfs_path(node); if (phypath) { dpriv->phypath = strdup(phypath); + snprintf(match_str, sizeof(match_str), "^usb/%x.%x", dpriv->dev_descr.idVendor, dpriv->dev_descr.idProduct); + usbi_dbg("match is %s", match_str); + sunos_physpath_to_devlink(dpriv->phypath, match_str, &dpriv->ugenpath); di_devfs_path_free(phypath); + } else { free(dpriv->raw_cfgdescr); @@ -170,111 +563,98 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev) return (LIBUSB_SUCCESS); } - static int sunos_add_devices(di_devlink_t link, void *arg) { struct devlink_cbarg *largs = (struct devlink_cbarg *)arg; struct node_args *nargs; - di_node_t myself, pnode; + di_node_t myself, dn; uint64_t session_id = 0; - uint16_t bdf = 0; + uint64_t sid = 0; + uint64_t bdf = 0; struct libusb_device *dev; sunos_dev_priv_t *devpriv; - const char *path, *newpath; - int n, i; + int n; + int i = 0; int *addr_prop; uint8_t bus_number = 0; + uint32_t * regbuf = NULL; + uint32_t reg; nargs = (struct node_args *)largs->nargs; myself = largs->myself; - if (nargs->last_ugenpath) { - /* the same node's links */ - return (DI_WALK_CONTINUE); - } /* * Construct session ID. - * session ID = ...parent hub addr|hub addr|dev addr. + * session ID = dev_addr | hub addr |parent hub addr|...|root hub bdf + * 8 bits 8bits 8 bits 16bits */ - pnode = myself; - i = 0; - while (pnode != DI_NODE_NIL) { - if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) { - /* walk to root */ - uint32_t *regbuf = NULL; - uint32_t reg; + if (myself == DI_NODE_NIL) + return (DI_WALK_CONTINUE); - n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg", - (int **)®buf); - reg = regbuf[0]; - bdf = (PCI_REG_BUS_G(reg) << 8) | - (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); - session_id |= (bdf << i * 8); + dn = myself; + /* find the root hub */ + while (di_prop_exists(DDI_DEV_T_ANY, dn, "root-hub") != 1) { + usbi_dbg("find_root_hub:%s", di_devfs_path(dn)); + n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, + "assigned-address", &addr_prop); + session_id |= ((addr_prop[0] & 0xff) << i++ * 8); + dn = di_parent_node(dn); + } - /* same as 'unit-address' property */ - bus_number = - (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); + /* dn is the root hub node */ + n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", (int **)®buf); + reg = regbuf[0]; + bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); + /* bdf must larger than i*8 bits */ + session_id |= (bdf << i * 8); + bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); - usbi_dbg("device bus address=%s:%x", - di_bus_addr(pnode), bus_number); - - break; - } + usbi_dbg("device bus address=%s:%x, name:%s", + di_bus_addr(myself), bus_number, di_node_name(dn)); + usbi_dbg("session id org:%lx", session_id); + /* dn is the usb device */ + for (dn = di_child_node(myself); dn != DI_NODE_NIL; dn = di_sibling_node(dn)) { + usbi_dbg("device path:%s", di_devfs_path(dn)); + /* skip hub devices, because its driver can not been unload */ + if (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "usb-port-count", &addr_prop) != -1) + continue; /* usb_addr */ - n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, + n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "assigned-address", &addr_prop); if ((n != 1) || (addr_prop[0] == 0)) { usbi_dbg("cannot get valid usb_addr"); - - return (DI_WALK_CONTINUE); + continue; } - session_id |= ((addr_prop[0] & 0xff) << i * 8); - if (++i > 7) - break; + sid = (session_id << 8) | (addr_prop[0] & 0xff) ; + usbi_dbg("session id %lx", sid); - pnode = di_parent_node(pnode); - } - - path = di_devlink_path(link); - dev = usbi_get_device_by_session_id(nargs->ctx, session_id); - if (dev == NULL) { - dev = usbi_alloc_device(nargs->ctx, session_id); + dev = usbi_get_device_by_session_id(nargs->ctx, sid); if (dev == NULL) { - usbi_dbg("can't alloc device"); + dev = usbi_alloc_device(nargs->ctx, sid); + if (dev == NULL) { + usbi_dbg("can't alloc device"); + continue; + } + devpriv = (sunos_dev_priv_t *)dev->os_priv; + dev->bus_number = bus_number; - return (DI_WALK_TERMINATE); + if (sunos_fill_in_dev_info(dn, dev) != LIBUSB_SUCCESS) { + libusb_unref_device(dev); + usbi_dbg("get infomation fail"); + continue; + } + if (usbi_sanitize_device(dev) < 0) { + libusb_unref_device(dev); + usbi_dbg("sanatize failed: "); + return (DI_WALK_TERMINATE); + } + } else { + devpriv = (sunos_dev_priv_t *)dev->os_priv; + usbi_dbg("Dev %s exists", devpriv->ugenpath); } - devpriv = (sunos_dev_priv_t *)dev->os_priv; - if ((newpath = strrchr(path, '/')) == NULL) { - libusb_unref_device(dev); - - return (DI_WALK_TERMINATE); - } - devpriv->ugenpath = strndup(path, strlen(path) - - strlen(newpath)); - dev->bus_number = bus_number; - - if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) { - libusb_unref_device(dev); - - return (DI_WALK_TERMINATE); - } - if (usbi_sanitize_device(dev) < 0) { - libusb_unref_device(dev); - usbi_dbg("sanatize failed: "); - return (DI_WALK_TERMINATE); - } - } else { - usbi_dbg("Dev %s exists", path); - } - - devpriv = (sunos_dev_priv_t *)dev->os_priv; - if (nargs->last_ugenpath == NULL) { - /* first device */ - nargs->last_ugenpath = devpriv->ugenpath; if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) { usbi_dbg("cannot append device"); @@ -285,11 +665,11 @@ sunos_add_devices(di_devlink_t link, void *arg) * hereafter. Front end or app should take care of their ref. */ libusb_unref_device(dev); - } - usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x", - devpriv->ugenpath, path, (uint64_t)session_id, - (*nargs->discdevs)->len, bdf); + usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x", + devpriv->ugenpath, di_devfs_path(dn), (uint64_t)sid, + (*nargs->discdevs)->len, bdf); + } return (DI_WALK_CONTINUE); } @@ -303,14 +683,14 @@ sunos_walk_minor_node_link(di_node_t node, void *args) struct node_args *nargs = (struct node_args *)args; di_devlink_handle_t devlink_hdl = nargs->dlink_hdl; - /* walk each minor to find ugen devices */ + /* walk each minor to find usb devices */ while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { minor_path = di_devfs_minor_path(minor); arg.nargs = args; arg.myself = node; arg.minor = minor; (void) di_devlink_walk(devlink_hdl, - "^usb/[0-9a-f]+[.][0-9a-f]+", minor_path, + "^usb/hub[0-9]+", minor_path, DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices); di_devfs_path_free(minor_path); } @@ -496,7 +876,7 @@ sunos_check_device_and_status_open(struct libusb_device_handle *hdl, usbi_dbg("can't find interface for endpoint 0x%02x", ep_addr); - return (LIBUSB_ERROR_ACCESS); + return (EACCES); } /* create filename */ @@ -603,6 +983,11 @@ sunos_open(struct libusb_device_handle *handle) hpriv->eps[i].statfd = -1; } + if (sunos_kernel_driver_active(handle, 0)) { + /* pretend we can open the device */ + return (LIBUSB_SUCCESS); + } + if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) { usbi_dbg("fail: %d", ret); return (ret); @@ -1010,9 +1395,7 @@ void sunos_destroy_device(struct libusb_device *dev) { sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv; - - usbi_dbg(""); - + usbi_dbg("destroy everyting"); free(dpriv->raw_cfgdescr); free(dpriv->ugenpath); free(dpriv->phypath); @@ -1254,7 +1637,7 @@ sunos_usb_get_status(int fd) return (status); } -const struct usbi_os_backend sunos_backend = { +const struct usbi_os_backend usbi_backend = { .name = "Solaris", .caps = 0, .init = sunos_init, @@ -1276,9 +1659,9 @@ const struct usbi_os_backend sunos_backend = { .reset_device = sunos_reset_device, /* TODO */ .alloc_streams = NULL, .free_streams = NULL, - .kernel_driver_active = NULL, - .detach_kernel_driver = NULL, - .attach_kernel_driver = NULL, + .kernel_driver_active = sunos_kernel_driver_active, + .detach_kernel_driver = sunos_detach_kernel_driver, + .attach_kernel_driver = sunos_attach_kernel_driver, .destroy_device = sunos_destroy_device, .submit_transfer = sunos_submit_transfer, .cancel_transfer = sunos_cancel_transfer, diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.h similarity index 96% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.h index 5741660319..52bb3d33a0 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.h @@ -65,6 +65,12 @@ struct devlink_cbarg { di_minor_t minor; }; +typedef struct walk_link { + char *path; + int len; + char **linkpp; +} walk_link_t; + /* AIO callback args */ struct aio_callback_args{ struct libusb_transfer *transfer; diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.c similarity index 92% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.c index a4f270bbe5..16a7578b81 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.c @@ -29,7 +29,7 @@ # include # include #elif defined(__APPLE__) -# include +# include #elif defined(__CYGWIN__) # include #endif @@ -43,7 +43,7 @@ int usbi_cond_timedwait(pthread_cond_t *cond, struct timespec timeout; int r; - r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout); + r = usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &timeout); if (r < 0) return r; @@ -59,7 +59,7 @@ int usbi_cond_timedwait(pthread_cond_t *cond, int usbi_get_tid(void) { - int ret = -1; + int ret; #if defined(__ANDROID__) ret = gettid(); #elif defined(__linux__) @@ -69,10 +69,11 @@ int usbi_get_tid(void) real thread support. For 5.1 and earlier, -1 is returned. */ ret = syscall(SYS_getthrid); #elif defined(__APPLE__) - ret = mach_thread_self(); - mach_port_deallocate(mach_task_self(), ret); + ret = (int)pthread_mach_thread_np(pthread_self()); #elif defined(__CYGWIN__) ret = GetCurrentThreadId(); +#else + ret = -1; #endif /* TODO: NetBSD thread ID support */ return ret; diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h new file mode 100644 index 0000000000..9f1ef94bc7 --- /dev/null +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h @@ -0,0 +1,102 @@ +/* + * libusb synchronization using POSIX Threads + * + * Copyright © 2010 Peter Stuge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_THREADS_POSIX_H +#define LIBUSB_THREADS_POSIX_H + +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +typedef pthread_mutex_t usbi_mutex_static_t; +static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex) +{ + (void)pthread_mutex_lock(mutex); +} +static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) +{ + (void)pthread_mutex_unlock(mutex); +} + +typedef pthread_mutex_t usbi_mutex_t; +static inline int usbi_mutex_init(usbi_mutex_t *mutex) +{ + return pthread_mutex_init(mutex, NULL); +} +static inline void usbi_mutex_lock(usbi_mutex_t *mutex) +{ + (void)pthread_mutex_lock(mutex); +} +static inline void usbi_mutex_unlock(usbi_mutex_t *mutex) +{ + (void)pthread_mutex_unlock(mutex); +} +static inline int usbi_mutex_trylock(usbi_mutex_t *mutex) +{ + return pthread_mutex_trylock(mutex); +} +static inline void usbi_mutex_destroy(usbi_mutex_t *mutex) +{ + (void)pthread_mutex_destroy(mutex); +} + +typedef pthread_cond_t usbi_cond_t; +static inline void usbi_cond_init(pthread_cond_t *cond) +{ + (void)pthread_cond_init(cond, NULL); +} +static inline int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) +{ + return pthread_cond_wait(cond, mutex); +} +int usbi_cond_timedwait(usbi_cond_t *cond, + usbi_mutex_t *mutex, const struct timeval *tv); +static inline void usbi_cond_broadcast(usbi_cond_t *cond) +{ + (void)pthread_cond_broadcast(cond); +} +static inline void usbi_cond_destroy(usbi_cond_t *cond) +{ + (void)pthread_cond_destroy(cond); +} + +typedef pthread_key_t usbi_tls_key_t; +static inline void usbi_tls_key_create(usbi_tls_key_t *key) +{ + (void)pthread_key_create(key, NULL); +} +static inline void *usbi_tls_key_get(usbi_tls_key_t key) +{ + return pthread_getspecific(key); +} +static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr) +{ + (void)pthread_setspecific(key, ptr); +} +static inline void usbi_tls_key_delete(usbi_tls_key_t key) +{ + (void)pthread_key_delete(key); +} + +int usbi_get_tid(void); + +#endif /* LIBUSB_THREADS_POSIX_H */ diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c new file mode 100644 index 0000000000..409c490553 --- /dev/null +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c @@ -0,0 +1,126 @@ +/* + * libusb synchronization on Microsoft Windows + * + * Copyright © 2010 Michael Plante + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include + +#include "libusbi.h" + +struct usbi_cond_perthread { + struct list_head list; + HANDLE event; +}; + +void usbi_mutex_static_lock(usbi_mutex_static_t *mutex) +{ + while (InterlockedExchange(mutex, 1L) == 1L) + SleepEx(0, TRUE); +} + +void usbi_cond_init(usbi_cond_t *cond) +{ + list_init(&cond->waiters); + list_init(&cond->not_waiting); +} + +static int usbi_cond_intwait(usbi_cond_t *cond, + usbi_mutex_t *mutex, DWORD timeout_ms) +{ + struct usbi_cond_perthread *pos; + DWORD r; + + // Same assumption as usbi_cond_broadcast() holds + if (list_empty(&cond->not_waiting)) { + pos = malloc(sizeof(*pos)); + if (pos == NULL) + return ENOMEM; // This errno is not POSIX-allowed. + pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset. + if (pos->event == NULL) { + free(pos); + return ENOMEM; + } + } else { + pos = list_first_entry(&cond->not_waiting, struct usbi_cond_perthread, list); + list_del(&pos->list); // remove from not_waiting list. + // Ensure the event is clear before waiting + WaitForSingleObject(pos->event, 0); + } + + list_add(&pos->list, &cond->waiters); + + LeaveCriticalSection(mutex); + r = WaitForSingleObject(pos->event, timeout_ms); + EnterCriticalSection(mutex); + + list_del(&pos->list); + list_add(&pos->list, &cond->not_waiting); + + if (r == WAIT_OBJECT_0) + return 0; + else if (r == WAIT_TIMEOUT) + return ETIMEDOUT; + else + return EINVAL; +} + +// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot! +int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) +{ + return usbi_cond_intwait(cond, mutex, INFINITE); +} + +int usbi_cond_timedwait(usbi_cond_t *cond, + usbi_mutex_t *mutex, const struct timeval *tv) +{ + DWORD millis; + + millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000); + /* round up to next millisecond */ + if (tv->tv_usec % 1000) + millis++; + return usbi_cond_intwait(cond, mutex, millis); +} + +void usbi_cond_broadcast(usbi_cond_t *cond) +{ + // Assumes mutex is locked; this is not in keeping with POSIX spec, but + // libusb does this anyway, so we simplify by not adding more sync + // primitives to the CV definition! + struct usbi_cond_perthread *pos; + + list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) + SetEvent(pos->event); + // The wait function will remove its respective item from the list. +} + +void usbi_cond_destroy(usbi_cond_t *cond) +{ + // This assumes no one is using this anymore. The check MAY NOT BE safe. + struct usbi_cond_perthread *pos, *next; + + if (!list_empty(&cond->waiters)) + return; // (!see above!) + list_for_each_entry_safe(pos, next, &cond->not_waiting, list, struct usbi_cond_perthread) { + CloseHandle(pos->event); + list_del(&pos->list); + free(pos); + } +} diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.h similarity index 53% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.h index e97ee78757..409de2d0e2 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.h @@ -21,17 +21,40 @@ #ifndef LIBUSB_THREADS_WINDOWS_H #define LIBUSB_THREADS_WINDOWS_H -#define usbi_mutex_static_t volatile LONG -#define USBI_MUTEX_INITIALIZER 0 +#define USBI_MUTEX_INITIALIZER 0L +#ifdef _WIN32_WCE +typedef LONG usbi_mutex_static_t; +#else +typedef volatile LONG usbi_mutex_static_t; +#endif +void usbi_mutex_static_lock(usbi_mutex_static_t *mutex); +static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) +{ + InterlockedExchange(mutex, 0L); +} -#define usbi_mutex_t HANDLE - -typedef struct usbi_cond { - // Every time a thread touches the CV, it winds up in one of these lists. - // It stays there until the CV is destroyed, even if the thread terminates. - struct list_head waiters; - struct list_head not_waiting; -} usbi_cond_t; +typedef CRITICAL_SECTION usbi_mutex_t; +static inline int usbi_mutex_init(usbi_mutex_t *mutex) +{ + InitializeCriticalSection(mutex); + return 0; +} +static inline void usbi_mutex_lock(usbi_mutex_t *mutex) +{ + EnterCriticalSection(mutex); +} +static inline void usbi_mutex_unlock(usbi_mutex_t *mutex) +{ + LeaveCriticalSection(mutex); +} +static inline int usbi_mutex_trylock(usbi_mutex_t *mutex) +{ + return !TryEnterCriticalSection(mutex); +} +static inline void usbi_mutex_destroy(usbi_mutex_t *mutex) +{ + DeleteCriticalSection(mutex); +} // We *were* getting timespec from pthread.h: #if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)) @@ -45,32 +68,44 @@ struct timespec { // We *were* getting ETIMEDOUT from pthread.h: #ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#define ETIMEDOUT 10060 /* This is the value in winsock.h. */ #endif -#define usbi_tls_key_t DWORD +typedef struct usbi_cond { + // Every time a thread touches the CV, it winds up in one of these lists. + // It stays there until the CV is destroyed, even if the thread terminates. + struct list_head waiters; + struct list_head not_waiting; +} usbi_cond_t; -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex); -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex); - -int usbi_mutex_init(usbi_mutex_t *mutex); -int usbi_mutex_lock(usbi_mutex_t *mutex); -int usbi_mutex_unlock(usbi_mutex_t *mutex); -int usbi_mutex_trylock(usbi_mutex_t *mutex); -int usbi_mutex_destroy(usbi_mutex_t *mutex); - -int usbi_cond_init(usbi_cond_t *cond); +void usbi_cond_init(usbi_cond_t *cond); int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex); int usbi_cond_timedwait(usbi_cond_t *cond, usbi_mutex_t *mutex, const struct timeval *tv); -int usbi_cond_broadcast(usbi_cond_t *cond); -int usbi_cond_destroy(usbi_cond_t *cond); +void usbi_cond_broadcast(usbi_cond_t *cond); +void usbi_cond_destroy(usbi_cond_t *cond); -int usbi_tls_key_create(usbi_tls_key_t *key); -void *usbi_tls_key_get(usbi_tls_key_t key); -int usbi_tls_key_set(usbi_tls_key_t key, void *value); -int usbi_tls_key_delete(usbi_tls_key_t key); +typedef DWORD usbi_tls_key_t; +static inline void usbi_tls_key_create(usbi_tls_key_t *key) +{ + *key = TlsAlloc(); +} +static inline void *usbi_tls_key_get(usbi_tls_key_t key) +{ + return TlsGetValue(key); +} +static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr) +{ + (void)TlsSetValue(key, ptr); +} +static inline void usbi_tls_key_delete(usbi_tls_key_t key) +{ + (void)TlsFree(key); +} -int usbi_get_tid(void); +static inline int usbi_get_tid(void) +{ + return (int)GetCurrentThreadId(); +} #endif /* LIBUSB_THREADS_WINDOWS_H */ diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.c similarity index 94% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.c index 0d466b8c9c..a0f35e93e5 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.c @@ -31,7 +31,7 @@ #include "wince_usb.h" // Global variables -int windows_version = WINDOWS_CE; +int errno = 0; static uint64_t hires_frequency, hires_ticks_to_ps; static HANDLE driver_handle = INVALID_HANDLE_VALUE; static int concurrent_usage = -1; @@ -109,7 +109,7 @@ static int translate_driver_error(DWORD error) } } -static int init_dllimports(void) +static BOOL init_dllimports(void) { DLL_GET_HANDLE(ceusbkwrapper); DLL_LOAD_FUNC(ceusbkwrapper, UkwOpenDriver, TRUE); @@ -135,7 +135,7 @@ static int init_dllimports(void) DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueBulkTransfer, TRUE); DLL_LOAD_FUNC(ceusbkwrapper, UkwIsPipeHalted, TRUE); - return LIBUSB_SUCCESS; + return TRUE; } static void exit_dllimports(void) @@ -186,11 +186,8 @@ static int wince_init(struct libusb_context *ctx) // NB: concurrent usage supposes that init calls are equally balanced with // exit calls. If init is called more than exit, we will not exit properly if ( ++concurrent_usage == 0 ) { // First init? - // Initialize pollable file descriptors - init_polling(); - // Load DLL imports - if (init_dllimports() != LIBUSB_SUCCESS) { + if (!init_dllimports()) { usbi_err(ctx, "could not resolve DLL functions"); r = LIBUSB_ERROR_NOT_SUPPORTED; goto init_exit; @@ -223,7 +220,6 @@ static int wince_init(struct libusb_context *ctx) init_exit: // Holds semaphore here. if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? exit_dllimports(); - exit_polling(); if (driver_handle != INVALID_HANDLE_VALUE) { UkwCloseDriver(driver_handle); @@ -239,10 +235,11 @@ init_exit: // Holds semaphore here. return r; } -static void wince_exit(void) +static void wince_exit(struct libusb_context *ctx) { HANDLE semaphore; TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + UNUSED(ctx); _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); semaphore = CreateSemaphore(NULL, 1, 1, sem_name); @@ -259,7 +256,6 @@ static void wince_exit(void) // Only works if exits and inits are balanced exactly if (--concurrent_usage < 0) { // Last exit exit_dllimports(); - exit_polling(); if (driver_handle != INVALID_HANDLE_VALUE) { UkwCloseDriver(driver_handle); @@ -328,7 +324,7 @@ static int wince_get_device_list( } new_devices = discovered_devs_append(new_devices, dev); - if (!discdevs) { + if (!new_devices) { r = LIBUSB_ERROR_NO_MEM; goto err_out; } @@ -541,12 +537,9 @@ static void wince_destroy_device(struct libusb_device *dev) static void wince_clear_transfer_priv(struct usbi_transfer *itransfer) { struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd); - // No need to cancel transfer as it is either complete or abandoned - wfd.itransfer = NULL; - CloseHandle(wfd.handle); - usbi_free_fd(&transfer_priv->pollable_fd); + usbi_close(transfer_priv->pollable_fd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; } static int wince_cancel_transfer(struct usbi_transfer *itransfer) @@ -570,11 +563,10 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer BOOL direction_in, ret; struct winfd wfd; DWORD flags; - HANDLE eventHandle; PUKW_CONTROL_HEADER setup = NULL; const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL; + int r; - transfer_priv->pollable_fd = INVALID_WINFD; if (control_transfer) { setup = (PUKW_CONTROL_HEADER) transfer->buffer; direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN; @@ -584,19 +576,18 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER; flags |= UKW_TF_SHORT_TRANSFER_OK; - eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL); - if (eventHandle == NULL) { - usbi_err(ctx, "Failed to create event for async transfer"); + wfd = usbi_create_fd(); + if (wfd.fd < 0) return LIBUSB_ERROR_NO_MEM; - } - wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer); - if (wfd.fd < 0) { - CloseHandle(eventHandle); - return LIBUSB_ERROR_NO_MEM; + r = usbi_add_pollfd(ctx, wfd.fd, direction_in ? POLLIN : POLLOUT); + if (r) { + usbi_close(wfd.fd); + return r; } transfer_priv->pollable_fd = wfd; + if (control_transfer) { // Split out control setup header and data buffer DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER); @@ -612,19 +603,16 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer int libusbErr = translate_driver_error(GetLastError()); usbi_err(ctx, "UkwIssue%sTransfer failed: error %u", control_transfer ? "Control" : "Bulk", (unsigned int)GetLastError()); - wince_clear_transfer_priv(itransfer); + usbi_remove_pollfd(ctx, wfd.fd); + usbi_close(wfd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; return libusbErr; } - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT); + return LIBUSB_SUCCESS; } -static int wince_submit_iso_transfer(struct usbi_transfer *itransfer) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - static int wince_submit_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); @@ -635,7 +623,6 @@ static int wince_submit_transfer(struct usbi_transfer *itransfer) case LIBUSB_TRANSFER_TYPE_INTERRUPT: return wince_submit_control_or_bulk_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return wince_submit_iso_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_BULK_STREAM: return LIBUSB_ERROR_NOT_SUPPORTED; default: @@ -763,7 +750,7 @@ static int wince_handle_events( struct wince_transfer_priv* transfer_priv = NULL; POLL_NFDS_TYPE i = 0; BOOL found = FALSE; - struct usbi_transfer *transfer; + struct usbi_transfer *itransfer; DWORD io_size, io_result; int r = LIBUSB_SUCCESS; @@ -780,8 +767,8 @@ static int wince_handle_events( // Because a Windows OVERLAPPED is used for poll emulation, // a pollable fd is created and stored with each transfer usbi_mutex_lock(&ctx->flying_transfers_lock); - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - transfer_priv = usbi_transfer_get_os_priv(transfer); + list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) { + transfer_priv = usbi_transfer_get_os_priv(itransfer); if (transfer_priv->pollable_fd.fd == fds[i].fd) { found = TRUE; break; @@ -796,7 +783,7 @@ static int wince_handle_events( // let handle_callback free the event using the transfer wfd // If you don't use the transfer wfd, you run a risk of trying to free a // newly allocated wfd that took the place of the one from the transfer. - wince_handle_callback(transfer, io_result, io_size); + wince_handle_callback(itransfer, io_result, io_size); } else if (found) { usbi_err(ctx, "matching transfer for fd %d has not completed", fds[i]); r = LIBUSB_ERROR_OTHER; @@ -848,11 +835,12 @@ static int wince_clock_gettime(int clk_id, struct timespec *tp) } } -const struct usbi_os_backend wince_backend = { +const struct usbi_os_backend usbi_backend = { "Windows CE", 0, wince_init, wince_exit, + NULL, /* set_option() */ wince_get_device_list, NULL, /* hotplug_poll */ @@ -893,6 +881,7 @@ const struct usbi_os_backend wince_backend = { NULL, /* handle_transfer_completion() */ wince_clock_gettime, + 0, sizeof(struct wince_device_priv), 0, sizeof(struct wince_transfer_priv), diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.h similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.h diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_common.h similarity index 82% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/windows_common.h index 55344ca264..b1725c2e32 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_common.h @@ -68,31 +68,35 @@ /* * Macros for handling DLL themselves */ +#define DLL_HANDLE_NAME(name) __dll_##name##_handle + #define DLL_DECLARE_HANDLE(name) \ - static HMODULE __dll_##name##_handle = NULL + static HMODULE DLL_HANDLE_NAME(name) = NULL #define DLL_GET_HANDLE(name) \ do { \ - __dll_##name##_handle = DLL_LOAD_LIBRARY(name); \ - if (!__dll_##name##_handle) \ - return LIBUSB_ERROR_OTHER; \ + DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name); \ + if (!DLL_HANDLE_NAME(name)) \ + return FALSE; \ } while (0) #define DLL_FREE_HANDLE(name) \ do { \ - if (__dll_##name##_handle) { \ - FreeLibrary(__dll_##name##_handle); \ - __dll_##name##_handle = NULL; \ + if (DLL_HANDLE_NAME(name)) { \ + FreeLibrary(DLL_HANDLE_NAME(name)); \ + DLL_HANDLE_NAME(name) = NULL; \ } \ - } while(0) + } while (0) /* * Macros for handling functions within a DLL */ +#define DLL_FUNC_NAME(name) __dll_##name##_func_t + #define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \ - typedef ret (api * __dll_##name##_func_t)args; \ - static __dll_##name##_func_t prefixname = NULL + typedef ret (api * DLL_FUNC_NAME(name))args; \ + static DLL_FUNC_NAME(name) prefixname = NULL #define DLL_DECLARE_FUNC(api, ret, name, args) \ DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args) @@ -101,22 +105,22 @@ #define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \ do { \ - HMODULE h = __dll_##dll##_handle; \ - prefixname = (__dll_##name##_func_t)GetProcAddress(h, \ + HMODULE h = DLL_HANDLE_NAME(dll); \ + prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \ DLL_STRINGIFY(name)); \ if (prefixname) \ break; \ - prefixname = (__dll_##name##_func_t)GetProcAddress(h, \ + prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \ DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \ if (prefixname) \ break; \ - prefixname = (__dll_##name##_func_t)GetProcAddress(h, \ + prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \ DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \ if (prefixname) \ break; \ if (ret_on_failure) \ - return LIBUSB_ERROR_NOT_FOUND; \ - } while(0) + return FALSE; \ + } while (0) #define DLL_LOAD_FUNC(dll, name, ret_on_failure) \ DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure) diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.c similarity index 52% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.c index d935394a65..92dbde5a84 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.c @@ -32,6 +32,14 @@ #include "windows_common.h" #include "windows_nt_common.h" +// Public +BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED); +enum windows_version windows_version = WINDOWS_UNDEFINED; + + // Global variables for init/exit +static unsigned int init_count = 0; +static bool usbdk_available = false; + // Global variables for clock_gettime mechanism static uint64_t hires_ticks_to_ps; static uint64_t hires_frequency; @@ -50,6 +58,11 @@ struct timer_request { static HANDLE timer_thread = NULL; static DWORD timer_thread_id = 0; +/* Kernel32 dependencies */ +DLL_DECLARE_HANDLE(Kernel32); +/* This call is only available from XP SP2 */ +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL)); + /* User32 dependencies */ DLL_DECLARE_HANDLE(User32); DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, GetMessageA, (LPMSG, HWND, UINT, UINT)); @@ -111,6 +124,11 @@ const char *windows_error_str(DWORD error_code) } #endif +static inline struct windows_context_priv *_context_priv(struct libusb_context *ctx) +{ + return (struct windows_context_priv *)ctx->os_priv; +} + /* Hash table functions - modified From glibc 2.3.2: [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 [Knuth] The Art of Computer Programming, part 3 (6.4) */ @@ -123,7 +141,7 @@ typedef struct htab_entry { } htab_entry; static htab_entry *htab_table = NULL; -static usbi_mutex_t htab_mutex = NULL; +static usbi_mutex_t htab_mutex; static unsigned long htab_filled; /* Before using the hash table we must allocate memory for it. @@ -256,35 +274,46 @@ out_unlock: return idx; } -static int windows_init_dlls(void) +/* +* Make a transfer complete synchronously +*/ +void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size) { + overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + overlapped->InternalHigh = size; + SetEvent(overlapped->hEvent); +} + +static BOOL windows_init_dlls(void) +{ + DLL_GET_HANDLE(Kernel32); + DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE); + pCancelIoEx = (BOOL (WINAPI *)(HANDLE, LPOVERLAPPED)) + GetProcAddress(DLL_HANDLE_NAME(Kernel32), "CancelIoEx"); + usbi_dbg("Will use CancelIo%s for I/O cancellation", pCancelIoEx ? "Ex" : ""); + DLL_GET_HANDLE(User32); DLL_LOAD_FUNC_PREFIXED(User32, p, GetMessageA, TRUE); DLL_LOAD_FUNC_PREFIXED(User32, p, PeekMessageA, TRUE); DLL_LOAD_FUNC_PREFIXED(User32, p, PostThreadMessageA, TRUE); - return LIBUSB_SUCCESS; + return TRUE; } static void windows_exit_dlls(void) { + DLL_FREE_HANDLE(Kernel32); DLL_FREE_HANDLE(User32); } static bool windows_init_clock(struct libusb_context *ctx) { DWORD_PTR affinity, dummy; - HANDLE event = NULL; + HANDLE event; LARGE_INTEGER li_frequency; int i; if (QueryPerformanceFrequency(&li_frequency)) { - // Load DLL imports - if (windows_init_dlls() != LIBUSB_SUCCESS) { - usbi_err(ctx, "could not resolve DLL functions"); - return false; - } - // The hires frequency can go as high as 4 GHz, so we'll use a conversion // to picoseconds to compute the tv_nsecs part in clock_gettime hires_frequency = li_frequency.QuadPart; @@ -340,7 +369,7 @@ static bool windows_init_clock(struct libusb_context *ctx) return true; } -void windows_destroy_clock(void) +static void windows_destroy_clock(void) { if (timer_thread) { // actually the signal to quit the thread. @@ -357,6 +386,110 @@ void windows_destroy_clock(void) } } +/* Windows version detection */ +static BOOL is_x64(void) +{ + BOOL ret = FALSE; + + // Detect if we're running a 32 or 64 bit system + if (sizeof(uintptr_t) < 8) { + if (pIsWow64Process != NULL) + pIsWow64Process(GetCurrentProcess(), &ret); + } else { + ret = TRUE; + } + + return ret; +} + +static void get_windows_version(void) +{ + OSVERSIONINFOEXA vi, vi2; + const char *arch, *w = NULL; + unsigned major, minor, version; + ULONGLONG major_equal, minor_equal; + BOOL ws; + + windows_version = WINDOWS_UNDEFINED; + + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionExA((OSVERSIONINFOA *)&vi)) { + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if (!GetVersionExA((OSVERSIONINFOA *)&vi)) + return; + } + + if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) + return; + + if ((vi.dwMajorVersion > 6) || ((vi.dwMajorVersion == 6) && (vi.dwMinorVersion >= 2))) { + // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version + // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx + + major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + for (major = vi.dwMajorVersion; major <= 9; major++) { + memset(&vi2, 0, sizeof(vi2)); + vi2.dwOSVersionInfoSize = sizeof(vi2); + vi2.dwMajorVersion = major; + if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal)) + continue; + + if (vi.dwMajorVersion < major) { + vi.dwMajorVersion = major; + vi.dwMinorVersion = 0; + } + + minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL); + for (minor = vi.dwMinorVersion; minor <= 9; minor++) { + memset(&vi2, 0, sizeof(vi2)); + vi2.dwOSVersionInfoSize = sizeof(vi2); + vi2.dwMinorVersion = minor; + if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal)) + continue; + + vi.dwMinorVersion = minor; + break; + } + + break; + } + } + + if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf)) + return; + + ws = (vi.wProductType <= VER_NT_WORKSTATION); + version = vi.dwMajorVersion << 4 | vi.dwMinorVersion; + switch (version) { + case 0x50: windows_version = WINDOWS_2000; w = "2000"; break; + case 0x51: windows_version = WINDOWS_XP; w = "XP"; break; + case 0x52: windows_version = WINDOWS_2003; w = "2003"; break; + case 0x60: windows_version = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break; + case 0x61: windows_version = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break; + case 0x62: windows_version = WINDOWS_8; w = (ws ? "8" : "2012"); break; + case 0x63: windows_version = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break; + case 0x64: windows_version = WINDOWS_10; w = (ws ? "10" : "2016"); break; + default: + if (version < 0x50) { + return; + } else { + windows_version = WINDOWS_11_OR_LATER; + w = "11 or later"; + } + } + + arch = is_x64() ? "64-bit" : "32-bit"; + + if (vi.wServicePackMinor) + usbi_dbg("Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch); + else if (vi.wServicePackMajor) + usbi_dbg("Windows %s SP%u %s", w, vi.wServicePackMajor, arch); + else + usbi_dbg("Windows %s %s", w, arch); +} + /* * Monotonic and real time functions */ @@ -401,7 +534,379 @@ static unsigned __stdcall windows_clock_gettime_threaded(void *param) } } -int windows_clock_gettime(int clk_id, struct timespec *tp) +static void windows_transfer_callback(const struct windows_backend *backend, + struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size) +{ + int status, istatus; + + usbi_dbg("handling I/O completion with errcode %u, size %u", (unsigned int)io_result, (unsigned int)io_size); + + switch (io_result) { + case NO_ERROR: + status = backend->copy_transfer_data(itransfer, (uint32_t)io_size); + break; + case ERROR_GEN_FAILURE: + usbi_dbg("detected endpoint stall"); + status = LIBUSB_TRANSFER_STALL; + break; + case ERROR_SEM_TIMEOUT: + usbi_dbg("detected semaphore timeout"); + status = LIBUSB_TRANSFER_TIMED_OUT; + break; + case ERROR_OPERATION_ABORTED: + istatus = backend->copy_transfer_data(itransfer, (uint32_t)io_size); + if (istatus != LIBUSB_TRANSFER_COMPLETED) + usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus); + + usbi_dbg("detected operation aborted"); + status = LIBUSB_TRANSFER_CANCELLED; + break; + case ERROR_FILE_NOT_FOUND: + usbi_dbg("detected device removed"); + status = LIBUSB_TRANSFER_NO_DEVICE; + break; + default: + usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", (unsigned int)io_result, windows_error_str(io_result)); + status = LIBUSB_TRANSFER_ERROR; + break; + } + backend->clear_transfer_priv(itransfer); // Cancel polling + if (status == LIBUSB_TRANSFER_CANCELLED) + usbi_handle_transfer_cancellation(itransfer); + else + usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); +} + +static void windows_handle_callback(const struct windows_backend *backend, + struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + + switch (transfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + windows_transfer_callback(backend, itransfer, io_result, io_size); + break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform"); + break; + default: + usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); + } +} + +static int windows_init(struct libusb_context *ctx) +{ + struct windows_context_priv *priv = _context_priv(ctx); + HANDLE semaphore; + char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + int r = LIBUSB_ERROR_OTHER; + bool winusb_backend_init = false; + + sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); + semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); + if (semaphore == NULL) { + usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_MEM; + } + + // A successful wait brings our semaphore count to 0 (unsignaled) + // => any concurent wait stalls until the semaphore's release + if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { + usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); + CloseHandle(semaphore); + return LIBUSB_ERROR_NO_MEM; + } + + // NB: concurrent usage supposes that init calls are equally balanced with + // exit calls. If init is called more than exit, we will not exit properly + if (++init_count == 1) { // First init? + // Load DLL imports + if (!windows_init_dlls()) { + usbi_err(ctx, "could not resolve DLL functions"); + goto init_exit; + } + + get_windows_version(); + + if (windows_version == WINDOWS_UNDEFINED) { + usbi_err(ctx, "failed to detect Windows version"); + r = LIBUSB_ERROR_NOT_SUPPORTED; + goto init_exit; + } + + if (!windows_init_clock(ctx)) + goto init_exit; + + if (!htab_create(ctx)) + goto init_exit; + + r = winusb_backend.init(ctx); + if (r != LIBUSB_SUCCESS) + goto init_exit; + winusb_backend_init = true; + + r = usbdk_backend.init(ctx); + if (r == LIBUSB_SUCCESS) { + usbi_dbg("UsbDk backend is available"); + usbdk_available = true; + } else { + usbi_info(ctx, "UsbDk backend is not available"); + // Do not report this as an error + r = LIBUSB_SUCCESS; + } + } + + // By default, new contexts will use the WinUSB backend + priv->backend = &winusb_backend; + + r = LIBUSB_SUCCESS; + +init_exit: // Holds semaphore here + if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed? + if (winusb_backend_init) + winusb_backend.exit(ctx); + htab_destroy(); + windows_destroy_clock(); + windows_exit_dlls(); + --init_count; + } + + ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 + CloseHandle(semaphore); + return r; +} + +static void windows_exit(struct libusb_context *ctx) +{ + HANDLE semaphore; + char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0' + UNUSED(ctx); + + sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF)); + semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); + if (semaphore == NULL) + return; + + // A successful wait brings our semaphore count to 0 (unsignaled) + // => any concurent wait stalls until the semaphore release + if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { + CloseHandle(semaphore); + return; + } + + // Only works if exits and inits are balanced exactly + if (--init_count == 0) { // Last exit + if (usbdk_available) { + usbdk_backend.exit(ctx); + usbdk_available = false; + } + winusb_backend.exit(ctx); + htab_destroy(); + windows_destroy_clock(); + windows_exit_dlls(); + } + + ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 + CloseHandle(semaphore); +} + +static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap) +{ + struct windows_context_priv *priv = _context_priv(ctx); + + UNUSED(ap); + + switch (option) { + case LIBUSB_OPTION_USE_USBDK: + if (usbdk_available) { + usbi_dbg("switching context %p to use UsbDk backend", ctx); + priv->backend = &usbdk_backend; + } else { + usbi_err(ctx, "UsbDk backend not available"); + return LIBUSB_ERROR_NOT_FOUND; + } + return LIBUSB_SUCCESS; + default: + return LIBUSB_ERROR_NOT_SUPPORTED; + } + +} + +static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs) +{ + struct windows_context_priv *priv = _context_priv(ctx); + return priv->backend->get_device_list(ctx, discdevs); +} + +static int windows_open(struct libusb_device_handle *dev_handle) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->open(dev_handle); +} + +static void windows_close(struct libusb_device_handle *dev_handle) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + priv->backend->close(dev_handle); +} + +static int windows_get_device_descriptor(struct libusb_device *dev, + unsigned char *buffer, int *host_endian) +{ + struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev)); + *host_endian = 0; + return priv->backend->get_device_descriptor(dev, buffer); +} + +static int windows_get_active_config_descriptor(struct libusb_device *dev, + unsigned char *buffer, size_t len, int *host_endian) +{ + struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev)); + *host_endian = 0; + return priv->backend->get_active_config_descriptor(dev, buffer, len); +} + +static int windows_get_config_descriptor(struct libusb_device *dev, + uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) +{ + struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev)); + *host_endian = 0; + return priv->backend->get_config_descriptor(dev, config_index, buffer, len); +} + +static int windows_get_config_descriptor_by_value(struct libusb_device *dev, + uint8_t bConfigurationValue, unsigned char **buffer, int *host_endian) +{ + struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev)); + *host_endian = 0; + return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer); +} + +static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->get_configuration(dev_handle, config); +} + +static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->set_configuration(dev_handle, config); +} + +static int windows_claim_interface(struct libusb_device_handle *dev_handle, int interface_number) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->claim_interface(dev_handle, interface_number); +} + +static int windows_release_interface(struct libusb_device_handle *dev_handle, int interface_number) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->release_interface(dev_handle, interface_number); +} + +static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, + int interface_number, int altsetting) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting); +} + +static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->clear_halt(dev_handle, endpoint); +} + +static int windows_reset_device(struct libusb_device_handle *dev_handle) +{ + struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle)); + return priv->backend->reset_device(dev_handle); +} + +static void windows_destroy_device(struct libusb_device *dev) +{ + struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev)); + priv->backend->destroy_device(dev); +} + +static int windows_submit_transfer(struct usbi_transfer *itransfer) +{ + struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer)); + return priv->backend->submit_transfer(itransfer); +} + +static int windows_cancel_transfer(struct usbi_transfer *itransfer) +{ + struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer)); + return priv->backend->cancel_transfer(itransfer); +} + +static void windows_clear_transfer_priv(struct usbi_transfer *itransfer) +{ + struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer)); + priv->backend->clear_transfer_priv(itransfer); +} + +static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) +{ + struct windows_context_priv *priv = _context_priv(ctx); + struct usbi_transfer *itransfer; + DWORD io_size, io_result; + POLL_NFDS_TYPE i; + bool found; + int transfer_fd; + int r = LIBUSB_SUCCESS; + + usbi_mutex_lock(&ctx->open_devs_lock); + for (i = 0; i < nfds && num_ready > 0; i++) { + + usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents); + + if (!fds[i].revents) + continue; + + num_ready--; + + // Because a Windows OVERLAPPED is used for poll emulation, + // a pollable fd is created and stored with each transfer + found = false; + transfer_fd = -1; + usbi_mutex_lock(&ctx->flying_transfers_lock); + list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) { + transfer_fd = priv->backend->get_transfer_fd(itransfer); + if (transfer_fd == fds[i].fd) { + found = true; + break; + } + } + usbi_mutex_unlock(&ctx->flying_transfers_lock); + + if (found) { + priv->backend->get_overlapped_result(itransfer, &io_result, &io_size); + + usbi_remove_pollfd(ctx, transfer_fd); + + // let handle_callback free the event using the transfer wfd + // If you don't use the transfer wfd, you run a risk of trying to free a + // newly allocated wfd that took the place of the one from the transfer. + windows_handle_callback(priv->backend, itransfer, io_result, io_size); + } else { + usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd); + r = LIBUSB_ERROR_NOT_FOUND; + break; + } + } + usbi_mutex_unlock(&ctx->open_devs_lock); + + return r; +} + +static int windows_clock_gettime(int clk_id, struct timespec *tp) { struct timer_request request; #if !defined(_MSC_VER) || (_MSC_VER < 1900) @@ -460,132 +965,44 @@ int windows_clock_gettime(int clk_id, struct timespec *tp) } } -static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - int status, istatus; - - usbi_dbg("handling I/O completion with errcode %u, size %u", io_result, io_size); - - switch (io_result) { - case NO_ERROR: - status = windows_copy_transfer_data(itransfer, io_size); - break; - case ERROR_GEN_FAILURE: - usbi_dbg("detected endpoint stall"); - status = LIBUSB_TRANSFER_STALL; - break; - case ERROR_SEM_TIMEOUT: - usbi_dbg("detected semaphore timeout"); - status = LIBUSB_TRANSFER_TIMED_OUT; - break; - case ERROR_OPERATION_ABORTED: - istatus = windows_copy_transfer_data(itransfer, io_size); - if (istatus != LIBUSB_TRANSFER_COMPLETED) - usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus); - - usbi_dbg("detected operation aborted"); - status = LIBUSB_TRANSFER_CANCELLED; - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", io_result, windows_error_str(io_result)); - status = LIBUSB_TRANSFER_ERROR; - break; - } - windows_clear_transfer_priv(itransfer); // Cancel polling - if (status == LIBUSB_TRANSFER_CANCELLED) - usbi_handle_transfer_cancellation(itransfer); - else - usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); -} - -void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - windows_transfer_callback(itransfer, io_result, io_size); - break; - case LIBUSB_TRANSFER_TYPE_BULK_STREAM: - usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform"); - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - } -} - -int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) -{ - POLL_NFDS_TYPE i; - bool found = false; - struct usbi_transfer *transfer; - struct winfd *pollable_fd = NULL; - DWORD io_size, io_result; - int r = LIBUSB_SUCCESS; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - - usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents); - - if (!fds[i].revents) - continue; - - num_ready--; - - // Because a Windows OVERLAPPED is used for poll emulation, - // a pollable fd is created and stored with each transfer - usbi_mutex_lock(&ctx->flying_transfers_lock); - found = false; - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - pollable_fd = windows_get_fd(transfer); - if (pollable_fd->fd == fds[i].fd) { - found = true; - break; - } - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (found) { - windows_get_overlapped_result(transfer, pollable_fd, &io_result, &io_size); - - usbi_remove_pollfd(ctx, pollable_fd->fd); - // let handle_callback free the event using the transfer wfd - // If you don't use the transfer wfd, you run a risk of trying to free a - // newly allocated wfd that took the place of the one from the transfer. - windows_handle_callback(transfer, io_result, io_size); - } else { - usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]); - r = LIBUSB_ERROR_NOT_FOUND; - break; - } - } - usbi_mutex_unlock(&ctx->open_devs_lock); - - return r; -} - -int windows_common_init(struct libusb_context *ctx) -{ - if (!windows_init_clock(ctx)) - goto error_roll_back; - - if (!htab_create(ctx)) - goto error_roll_back; - - return LIBUSB_SUCCESS; - -error_roll_back: - windows_common_exit(); - return LIBUSB_ERROR_NO_MEM; -} - -void windows_common_exit(void) -{ - htab_destroy(); - windows_destroy_clock(); - windows_exit_dlls(); -} +// NB: MSVC6 does not support named initializers. +const struct usbi_os_backend usbi_backend = { + "Windows", + USBI_CAP_HAS_HID_ACCESS, + windows_init, + windows_exit, + windows_set_option, + windows_get_device_list, + NULL, /* hotplug_poll */ + windows_open, + windows_close, + windows_get_device_descriptor, + windows_get_active_config_descriptor, + windows_get_config_descriptor, + windows_get_config_descriptor_by_value, + windows_get_configuration, + windows_set_configuration, + windows_claim_interface, + windows_release_interface, + windows_set_interface_altsetting, + windows_clear_halt, + windows_reset_device, + NULL, /* alloc_streams */ + NULL, /* free_streams */ + NULL, /* dev_mem_alloc */ + NULL, /* dev_mem_free */ + NULL, /* kernel_driver_active */ + NULL, /* detach_kernel_driver */ + NULL, /* attach_kernel_driver */ + windows_destroy_device, + windows_submit_transfer, + windows_cancel_transfer, + windows_clear_transfer_priv, + windows_handle_events, + NULL, /* handle_transfer_completion */ + windows_clock_gettime, + sizeof(struct windows_context_priv), + sizeof(union windows_device_priv), + sizeof(union windows_device_handle_priv), + sizeof(union windows_transfer_priv), +}; diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h new file mode 100644 index 0000000000..e155b5d3e3 --- /dev/null +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h @@ -0,0 +1,110 @@ +/* + * Windows backend common header for libusb 1.0 + * + * This file brings together header code common between + * the desktop Windows backends. + * Copyright © 2012-2013 RealVNC Ltd. + * Copyright © 2009-2012 Pete Batard + * With contributions from Michael Plante, Orin Eman et al. + * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer + * Major code testing contribution by Xiaofan Chen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "windows_nt_shared_types.h" + + /* Windows versions */ +enum windows_version { + WINDOWS_UNDEFINED, + WINDOWS_2000, + WINDOWS_XP, + WINDOWS_2003, // Also XP x64 + WINDOWS_VISTA, + WINDOWS_7, + WINDOWS_8, + WINDOWS_8_1, + WINDOWS_10, + WINDOWS_11_OR_LATER +}; + +extern enum windows_version windows_version; + +/* This call is only available from Vista */ +extern BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED); + +struct windows_backend { + int (*init)(struct libusb_context *ctx); + void (*exit)(struct libusb_context *ctx); + int (*get_device_list)(struct libusb_context *ctx, + struct discovered_devs **discdevs); + int (*open)(struct libusb_device_handle *dev_handle); + void (*close)(struct libusb_device_handle *dev_handle); + int (*get_device_descriptor)(struct libusb_device *device, unsigned char *buffer); + int (*get_active_config_descriptor)(struct libusb_device *device, + unsigned char *buffer, size_t len); + int (*get_config_descriptor)(struct libusb_device *device, + uint8_t config_index, unsigned char *buffer, size_t len); + int (*get_config_descriptor_by_value)(struct libusb_device *device, + uint8_t bConfigurationValue, unsigned char **buffer); + int (*get_configuration)(struct libusb_device_handle *dev_handle, int *config); + int (*set_configuration)(struct libusb_device_handle *dev_handle, int config); + int (*claim_interface)(struct libusb_device_handle *dev_handle, int interface_number); + int (*release_interface)(struct libusb_device_handle *dev_handle, int interface_number); + int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle, + int interface_number, int altsetting); + int (*clear_halt)(struct libusb_device_handle *dev_handle, + unsigned char endpoint); + int (*reset_device)(struct libusb_device_handle *dev_handle); + void (*destroy_device)(struct libusb_device *dev); + int (*submit_transfer)(struct usbi_transfer *itransfer); + int (*cancel_transfer)(struct usbi_transfer *itransfer); + void (*clear_transfer_priv)(struct usbi_transfer *itransfer); + int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size); + int (*get_transfer_fd)(struct usbi_transfer *itransfer); + void (*get_overlapped_result)(struct usbi_transfer *itransfer, + DWORD *io_result, DWORD *io_size); +}; + +struct windows_context_priv { + const struct windows_backend *backend; +}; + +union windows_device_priv { + struct usbdk_device_priv usbdk_priv; + struct winusb_device_priv winusb_priv; +}; + +union windows_device_handle_priv { + struct usbdk_device_handle_priv usbdk_priv; + struct winusb_device_handle_priv winusb_priv; +}; + +union windows_transfer_priv { + struct usbdk_transfer_priv usbdk_priv; + struct winusb_transfer_priv winusb_priv; +}; + +extern const struct windows_backend usbdk_backend; +extern const struct windows_backend winusb_backend; + +unsigned long htab_hash(const char *str); +void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size); + +#if defined(ENABLE_LOGGING) +const char *windows_error_str(DWORD error_code); +#endif diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h new file mode 100644 index 0000000000..68bf261d5d --- /dev/null +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h @@ -0,0 +1,138 @@ +#pragma once + +#include "windows_common.h" + +#include + +typedef struct USB_DEVICE_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + USHORT bcdUSB; + UCHAR bDeviceClass; + UCHAR bDeviceSubClass; + UCHAR bDeviceProtocol; + UCHAR bMaxPacketSize0; + USHORT idVendor; + USHORT idProduct; + USHORT bcdDevice; + UCHAR iManufacturer; + UCHAR iProduct; + UCHAR iSerialNumber; + UCHAR bNumConfigurations; +} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; + +typedef struct USB_CONFIGURATION_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + USHORT wTotalLength; + UCHAR bNumInterfaces; + UCHAR bConfigurationValue; + UCHAR iConfiguration; + UCHAR bmAttributes; + UCHAR MaxPower; +} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; + +#include + +#define MAX_DEVICE_ID_LEN 200 + +typedef struct USB_DK_DEVICE_ID { + WCHAR DeviceID[MAX_DEVICE_ID_LEN]; + WCHAR InstanceID[MAX_DEVICE_ID_LEN]; +} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID; + +typedef struct USB_DK_DEVICE_INFO { + USB_DK_DEVICE_ID ID; + ULONG64 FilterID; + ULONG64 Port; + ULONG64 Speed; + USB_DEVICE_DESCRIPTOR DeviceDescriptor; +} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO; + +typedef struct USB_DK_ISO_TRANSFER_RESULT { + ULONG64 ActualLength; + ULONG64 TransferResult; +} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT; + +typedef struct USB_DK_GEN_TRANSFER_RESULT { + ULONG64 BytesTransferred; + ULONG64 UsbdStatus; // USBD_STATUS code +} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT; + +typedef struct USB_DK_TRANSFER_RESULT { + USB_DK_GEN_TRANSFER_RESULT GenResult; + PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT +} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT; + +typedef struct USB_DK_TRANSFER_REQUEST { + ULONG64 EndpointAddress; + PVOID64 Buffer; + ULONG64 BufferLength; + ULONG64 TransferType; + ULONG64 IsochronousPacketsArraySize; + PVOID64 IsochronousPacketsArray; + USB_DK_TRANSFER_RESULT Result; +} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST; + +struct usbdk_device_priv { + USB_DK_DEVICE_INFO info; + PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors; + HANDLE redirector_handle; + HANDLE system_handle; + uint8_t active_configuration; +}; + +struct winusb_device_priv { + bool initialized; + bool root_hub; + uint8_t active_config; + uint8_t depth; // distance to HCD + const struct windows_usb_api_backend *apib; + char *dev_id; + char *path; // device interface path + int sub_api; // for WinUSB-like APIs + struct { + char *path; // each interface needs a device interface path, + const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support), + int sub_api; + int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS) + uint8_t *endpoint; + bool restricted_functionality; // indicates if the interface functionality is restricted + // by Windows (eg. HID keyboards or mice cannot do R/W) + } usb_interface[USB_MAXINTERFACES]; + struct hid_device_priv *hid; + USB_DEVICE_DESCRIPTOR dev_descriptor; + PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors +}; + +struct usbdk_device_handle_priv { + // Not currently used + char dummy; +}; + +struct winusb_device_handle_priv { + int active_interface; + struct { + HANDLE dev_handle; // WinUSB needs an extra handle for the file + HANDLE api_handle; // used by the API to communicate with the device + } interface_handle[USB_MAXINTERFACES]; + int autoclaim_count[USB_MAXINTERFACES]; // For auto-release +}; + +struct usbdk_transfer_priv { + USB_DK_TRANSFER_REQUEST request; + struct winfd pollable_fd; + HANDLE system_handle; + PULONG64 IsochronousPacketsArray; + PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray; +}; + +struct winusb_transfer_priv { + struct winfd pollable_fd; + HANDLE handle; + uint8_t interface_number; + uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID + uint8_t *hid_dest; // transfer buffer destination, required for HID + size_t hid_expected_size; + void *iso_context; +}; diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.c similarity index 70% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c rename to vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.c index 7cc5793872..fbccbd5cff 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.c @@ -23,22 +23,12 @@ #include -#if defined(USE_USBDK) - #include -#include #include #include "libusbi.h" #include "windows_common.h" #include "windows_nt_common.h" - -#define ULONG64 uint64_t -#define PVOID64 uint64_t - -typedef CONST WCHAR *PCWCHAR; -#define wcsncpy_s wcsncpy - #include "windows_usbdk.h" #if !defined(STATUS_SUCCESS) @@ -55,7 +45,7 @@ typedef LONG NTSTATUS; #endif #if !defined(USBD_SUCCESS) -typedef int32_t USBD_STATUS; +typedef LONG USBD_STATUS; #define USBD_SUCCESS(Status) ((USBD_STATUS) (Status) >= 0) #define USBD_PENDING(Status) ((ULONG) (Status) >> 30 == 1) #define USBD_ERROR(Status) ((USBD_STATUS) (Status) < 0) @@ -66,22 +56,6 @@ typedef int32_t USBD_STATUS; #define USBD_STATUS_CANCELED ((USBD_STATUS) 0xc0010000) #endif -static int concurrent_usage = -1; - -struct usbdk_device_priv { - USB_DK_DEVICE_INFO info; - PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors; - HANDLE redirector_handle; - uint8_t active_configuration; -}; - -struct usbdk_transfer_priv { - USB_DK_TRANSFER_REQUEST request; - struct winfd pollable_fd; - PULONG64 IsochronousPacketsArray; - PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray; -}; - static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev) { return (struct usbdk_device_priv *)dev->os_priv; @@ -115,7 +89,7 @@ static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name) FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name); if (api_ptr == NULL) - usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError()); + usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0)); return api_ptr; } @@ -132,7 +106,7 @@ static int load_usbdk_helper_dll(struct libusb_context *ctx) { usbdk_helper.module = LoadLibraryA("UsbDkHelper"); if (usbdk_helper.module == NULL) { - usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", GetLastError()); + usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0)); return LIBUSB_ERROR_NOT_FOUND; } @@ -198,41 +172,41 @@ error_unload: static int usbdk_init(struct libusb_context *ctx) { - int r; + SC_HANDLE managerHandle; + SC_HANDLE serviceHandle; - if (++concurrent_usage == 0) { // First init? - r = load_usbdk_helper_dll(ctx); - if (r) - goto init_exit; - - init_polling(); - - r = windows_common_init(ctx); - if (r) - goto init_exit; - } - // At this stage, either we went through full init successfully, or didn't need to - r = LIBUSB_SUCCESS; - -init_exit: - if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? - exit_polling(); - windows_common_exit(); - unload_usbdk_helper_dll(); + managerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + if (managerHandle == NULL) { + usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0)); + return LIBUSB_ERROR_OTHER; } - if (r != LIBUSB_SUCCESS) - --concurrent_usage; // Not expected to call libusb_exit if we failed. + serviceHandle = OpenServiceA(managerHandle, "UsbDk", GENERIC_READ); + CloseServiceHandle(managerHandle); - return r; + if (serviceHandle == NULL) { + if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) + usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0)); + return LIBUSB_ERROR_NOT_FOUND; + } + + CloseServiceHandle(serviceHandle); + + return load_usbdk_helper_dll(ctx); +} + +static void usbdk_exit(struct libusb_context *ctx) +{ + UNUSED(ctx); + unload_usbdk_helper_dll(); } static int usbdk_get_session_id_for_device(struct libusb_context *ctx, PUSB_DK_DEVICE_ID id, unsigned long *session_id) { - char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)]; + char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1]; - if (sprintf(dev_identity, "%S%S", id->DeviceID, id->InstanceID) == -1) { + if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) { usbi_warn(ctx, "cannot form device identity", id->DeviceID); return LIBUSB_ERROR_NOT_SUPPORTED; } @@ -296,11 +270,11 @@ static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info) dev->port_number = (uint8_t)info->Port; dev->parent_dev = NULL; - //Addresses in libusb are 1-based + // Addresses in libusb are 1-based dev->device_address = (uint8_t)(info->Port + 1); dev->num_configurations = info->DeviceDescriptor.bNumConfigurations; - dev->device_descriptor = info->DeviceDescriptor; + memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE); switch (info->Speed) { case LowSpeed: @@ -330,7 +304,7 @@ static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_d ULONG dev_number; PUSB_DK_DEVICE_INFO devices; - if(!usbdk_helper.GetDevicesList(&devices, &dev_number)) + if (!usbdk_helper.GetDevicesList(&devices, &dev_number)) return LIBUSB_ERROR_OTHER; for (i = 0; i < dev_number; i++) { @@ -371,26 +345,16 @@ func_exit: return r; } -static void usbdk_exit(void) -{ - if (--concurrent_usage < 0) { - windows_common_exit(); - exit_polling(); - unload_usbdk_helper_dll(); - } -} - -static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) +static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer) { struct usbdk_device_priv *priv = _usbdk_device_priv(dev); memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH); - *host_endian = 0; return LIBUSB_SUCCESS; } -static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) +static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len) { struct usbdk_device_priv *priv = _usbdk_device_priv(dev); PUSB_CONFIGURATION_DESCRIPTOR config_header; @@ -403,15 +367,31 @@ static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config size = min(config_header->wTotalLength, len); memcpy(buffer, config_header, size); - *host_endian = 0; - return (int)size; } -static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) +static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue, + unsigned char **buffer) +{ + struct usbdk_device_priv *priv = _usbdk_device_priv(dev); + PUSB_CONFIGURATION_DESCRIPTOR config_header; + uint8_t index; + + for (index = 0; index < dev->num_configurations; index++) { + config_header = priv->config_descriptors[index]; + if (config_header->bConfigurationValue == bConfigurationValue) { + *buffer = (unsigned char *)priv->config_descriptors[index]; + return (int)config_header->wTotalLength; + } + } + + return LIBUSB_ERROR_NOT_FOUND; +} + +static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len) { return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration, - buffer, len, host_endian); + buffer, len); } static int usbdk_open(struct libusb_device_handle *dev_handle) @@ -424,6 +404,8 @@ static int usbdk_open(struct libusb_device_handle *dev_handle) return LIBUSB_ERROR_OTHER; } + priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle); + return LIBUSB_SUCCESS; } @@ -431,10 +413,8 @@ static void usbdk_close(struct libusb_device_handle *dev_handle) { struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); - if (!usbdk_helper.StopRedirect(priv->redirector_handle)) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - usbi_err(ctx, "Redirector shutdown failed"); - } + if (!usbdk_helper.StopRedirect(priv->redirector_handle)) + usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed"); } static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config) @@ -460,7 +440,7 @@ static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int if static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) { @@ -480,7 +460,7 @@ static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) { @@ -493,7 +473,7 @@ static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned ch static int usbdk_reset_device(struct libusb_device_handle *dev_handle) { - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev); if (!usbdk_helper.ResetDevice(priv->redirector_handle)) { @@ -504,27 +484,6 @@ static int usbdk_reset_device(struct libusb_device_handle *dev_handle) return LIBUSB_SUCCESS; } -static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface) -{ - UNUSED(dev_handle); - UNUSED(iface); - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - UNUSED(dev_handle); - UNUSED(iface); - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - UNUSED(dev_handle); - UNUSED(iface); - return LIBUSB_ERROR_NOT_SUPPORTED; -} - static void usbdk_destroy_device(struct libusb_device *dev) { struct usbdk_device_priv* p = _usbdk_device_priv(dev); @@ -533,12 +492,14 @@ static void usbdk_destroy_device(struct libusb_device *dev) usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations); } -void windows_clear_transfer_priv(struct usbi_transfer *itransfer) +static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer) { struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - usbi_free_fd(&transfer_priv->pollable_fd); + usbi_close(transfer_priv->pollable_fd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; + transfer_priv->system_handle = NULL; if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { safe_free(transfer_priv->IsochronousPacketsArray); @@ -551,47 +512,30 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer) struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct winfd wfd; - ULONG Length; + struct libusb_context *ctx = TRANSFER_CTX(transfer); + OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped; TransferResult transResult; - HANDLE sysHandle; - sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle); - - wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; - - transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer; + transfer_priv->request.Buffer = (PVOID64)transfer->buffer; transfer_priv->request.BufferLength = transfer->length; transfer_priv->request.TransferType = ControlTransferType; - transfer_priv->pollable_fd = INVALID_WINFD; - Length = (ULONG)transfer->length; - if (IS_XFERIN(transfer)) - transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped); + if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) + transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); else - transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped); + transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped); switch (transResult) { case TransferSuccess: - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)Length; + windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); break; case TransferSuccessAsync: break; case TransferFailure: usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); return LIBUSB_ERROR_IO; } - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); - return LIBUSB_SUCCESS; } @@ -600,12 +544,11 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct winfd wfd; + struct libusb_context *ctx = TRANSFER_CTX(transfer); + OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped; TransferResult transferRes; - HANDLE sysHandle; - transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer; + transfer_priv->request.Buffer = (PVOID64)transfer->buffer; transfer_priv->request.BufferLength = transfer->length; transfer_priv->request.EndpointAddress = transfer->endpoint; @@ -614,42 +557,29 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer) transfer_priv->request.TransferType = BulkTransferType; break; case LIBUSB_TRANSFER_TYPE_INTERRUPT: - transfer_priv->request.TransferType = IntertuptTransferType; + transfer_priv->request.TransferType = InterruptTransferType; break; default: - usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0)); + usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; } - transfer_priv->pollable_fd = INVALID_WINFD; - - sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle); - - wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) - return LIBUSB_ERROR_NO_MEM; - if (IS_XFERIN(transfer)) - transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped); + transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); else - transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped); + transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped); switch (transferRes) { case TransferSuccess: - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); break; case TransferSuccessAsync: break; case TransferFailure: usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); return LIBUSB_ERROR_IO; } - transfer_priv->pollable_fd = wfd; - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT); - return LIBUSB_SUCCESS; } @@ -658,68 +588,81 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct winfd wfd; + struct libusb_context *ctx = TRANSFER_CTX(transfer); + OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped; TransferResult transferRes; int i; - HANDLE sysHandle; - transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer; + transfer_priv->request.Buffer = (PVOID64)transfer->buffer; transfer_priv->request.BufferLength = transfer->length; transfer_priv->request.EndpointAddress = transfer->endpoint; transfer_priv->request.TransferType = IsochronousTransferType; transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets; transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64)); - transfer_priv->request.IsochronousPacketsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousPacketsArray; + transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray; if (!transfer_priv->IsochronousPacketsArray) { - usbi_err(ctx, "Allocation of IsochronousPacketsArray is failed, %s", windows_error_str(0)); - return LIBUSB_ERROR_IO; + usbi_err(ctx, "Allocation of IsochronousPacketsArray failed"); + return LIBUSB_ERROR_NO_MEM; } transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT)); - transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousResultsArray; + transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray; if (!transfer_priv->IsochronousResultsArray) { - usbi_err(ctx, "Allocation of isochronousResultsArray is failed, %s", windows_error_str(0)); - free(transfer_priv->IsochronousPacketsArray); - return LIBUSB_ERROR_IO; + usbi_err(ctx, "Allocation of isochronousResultsArray failed"); + return LIBUSB_ERROR_NO_MEM; } for (i = 0; i < transfer->num_iso_packets; i++) transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length; - transfer_priv->pollable_fd = INVALID_WINFD; - - sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle); - - wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - free(transfer_priv->IsochronousPacketsArray); - free(transfer_priv->IsochronousResultsArray); - return LIBUSB_ERROR_NO_MEM; - } - if (IS_XFERIN(transfer)) - transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped); + transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped); else - transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped); + transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped); switch (transferRes) { case TransferSuccess: - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; + windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred); break; case TransferSuccessAsync: break; case TransferFailure: - usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); - free(transfer_priv->IsochronousPacketsArray); - free(transfer_priv->IsochronousResultsArray); return LIBUSB_ERROR_IO; } + return LIBUSB_SUCCESS; +} + +static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer, + short events, int (*transfer_fn)(struct usbi_transfer *)) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = TRANSFER_CTX(transfer); + struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); + struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); + struct winfd wfd; + int r; + + wfd = usbi_create_fd(); + if (wfd.fd < 0) + return LIBUSB_ERROR_NO_MEM; + + r = usbi_add_pollfd(ctx, wfd.fd, events); + if (r) { + usbi_close(wfd.fd); + return r; + } + + // Use transfer_priv to store data needed for async polling transfer_priv->pollable_fd = wfd; - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT); + transfer_priv->system_handle = priv->system_handle; + + r = transfer_fn(itransfer); + if (r != LIBUSB_SUCCESS) { + usbi_remove_pollfd(ctx, wfd.fd); + usbdk_clear_transfer_priv(itransfer); + return r; + } return LIBUSB_SUCCESS; } @@ -727,33 +670,52 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer) static int usbdk_submit_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + int (*transfer_fn)(struct usbi_transfer *); + short events; switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: - return usbdk_do_control_transfer(itransfer); + events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT; + transfer_fn = usbdk_do_control_transfer; + break; case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk - else - return usbdk_do_bulk_transfer(itransfer); + events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; + transfer_fn = usbdk_do_bulk_transfer; + break; case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return usbdk_do_iso_transfer(itransfer); + events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; + transfer_fn = usbdk_do_iso_transfer; + break; default: usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; } + + return usbdk_do_submit_transfer(itransfer, events, transfer_fn); } static int usbdk_abort_transfers(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct libusb_context *ctx = TRANSFER_CTX(transfer); struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev); + struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); + struct winfd *pollable_fd = &transfer_priv->pollable_fd; - if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) { - usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; + if (pCancelIoEx != NULL) { + // Use CancelIoEx if available to cancel just a single transfer + if (!pCancelIoEx(priv->system_handle, pollable_fd->overlapped)) { + usbi_err(ctx, "CancelIoEx failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + } else { + if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) { + usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } } return LIBUSB_SUCCESS; @@ -778,16 +740,16 @@ static int usbdk_cancel_transfer(struct usbi_transfer *itransfer) } } -int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) +static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) { itransfer->transferred += io_size; return LIBUSB_TRANSFER_COMPLETED; } -struct winfd *windows_get_fd(struct usbi_transfer *transfer) +static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer) { - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer); - return &transfer_priv->pollable_fd; + struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); + return transfer_priv->pollable_fd.fd; } static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus) @@ -796,30 +758,28 @@ static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus) return NO_ERROR; switch (UsbdStatus) { - case USBD_STATUS_STALL_PID: - case USBD_STATUS_ENDPOINT_HALTED: - case USBD_STATUS_BAD_START_FRAME: - return ERROR_GEN_FAILURE; case USBD_STATUS_TIMEOUT: return ERROR_SEM_TIMEOUT; case USBD_STATUS_CANCELED: return ERROR_OPERATION_ABORTED; default: - return ERROR_FUNCTION_FAILED; + return ERROR_GEN_FAILURE; } } -void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size) +static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size) { - if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first - || GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped - struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer); - struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer); + struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer); + struct winfd *pollable_fd = &transfer_priv->pollable_fd; - if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { - int i; + if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first + || GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + + if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { + ULONG64 i; for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) { - struct libusb_iso_packet_descriptor *lib_desc = <ransfer->iso_packet_desc[i]; + struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; switch (transfer_priv->IsochronousResultsArray[i].TransferResult) { case STATUS_SUCCESS: @@ -836,70 +796,35 @@ void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd } } - *io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred; - *io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus); - } - else { + *io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred; + *io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus); + } else { *io_result = GetLastError(); } } -static int usbdk_clock_gettime(int clk_id, struct timespec *tp) -{ - return windows_clock_gettime(clk_id, tp); -} - -const struct usbi_os_backend usbdk_backend = { - "Windows", - USBI_CAP_HAS_HID_ACCESS, +const struct windows_backend usbdk_backend = { usbdk_init, usbdk_exit, - usbdk_get_device_list, - NULL, usbdk_open, usbdk_close, - usbdk_get_device_descriptor, usbdk_get_active_config_descriptor, usbdk_get_config_descriptor, - NULL, - + usbdk_get_config_descriptor_by_value, usbdk_get_configuration, usbdk_set_configuration, usbdk_claim_interface, usbdk_release_interface, - usbdk_set_interface_altsetting, usbdk_clear_halt, usbdk_reset_device, - - NULL, - NULL, - - NULL, // dev_mem_alloc() - NULL, // dev_mem_free() - - usbdk_kernel_driver_active, - usbdk_detach_kernel_driver, - usbdk_attach_kernel_driver, - usbdk_destroy_device, - usbdk_submit_transfer, usbdk_cancel_transfer, - windows_clear_transfer_priv, - - windows_handle_events, - NULL, - - usbdk_clock_gettime, -#if defined(USBI_TIMERFD_AVAILABLE) - NULL, -#endif - sizeof(struct usbdk_device_priv), - 0, - sizeof(struct usbdk_transfer_priv), + usbdk_clear_transfer_priv, + usbdk_copy_transfer_data, + usbdk_get_transfer_fd, + usbdk_get_overlapped_result, }; - -#endif /* USE_USBDK */ diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.h similarity index 64% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.h index 04a9787f2d..77660ae97f 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.h @@ -23,56 +23,13 @@ #pragma once -typedef struct tag_USB_DK_DEVICE_ID { - WCHAR DeviceID[MAX_DEVICE_ID_LEN]; - WCHAR InstanceID[MAX_DEVICE_ID_LEN]; -} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID; +#include "windows_nt_common.h" -static inline void UsbDkFillIDStruct(USB_DK_DEVICE_ID *ID, PCWCHAR DeviceID, PCWCHAR InstanceID) -{ - wcsncpy_s(ID->DeviceID, DeviceID, MAX_DEVICE_ID_LEN); - wcsncpy_s(ID->InstanceID, InstanceID, MAX_DEVICE_ID_LEN); -} - -typedef struct tag_USB_DK_DEVICE_INFO { - USB_DK_DEVICE_ID ID; - ULONG64 FilterID; - ULONG64 Port; - ULONG64 Speed; - USB_DEVICE_DESCRIPTOR DeviceDescriptor; -} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO; - -typedef struct tag_USB_DK_CONFIG_DESCRIPTOR_REQUEST { +typedef struct USB_DK_CONFIG_DESCRIPTOR_REQUEST { USB_DK_DEVICE_ID ID; ULONG64 Index; } USB_DK_CONFIG_DESCRIPTOR_REQUEST, *PUSB_DK_CONFIG_DESCRIPTOR_REQUEST; -typedef struct tag_USB_DK_ISO_TRANSFER_RESULT { - ULONG64 ActualLength; - ULONG64 TransferResult; -} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT; - -typedef struct tag_USB_DK_GEN_TRANSFER_RESULT { - ULONG64 BytesTransferred; - ULONG64 UsbdStatus; // USBD_STATUS code -} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT; - -typedef struct tag_USB_DK_TRANSFER_RESULT { - USB_DK_GEN_TRANSFER_RESULT GenResult; - PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT -} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT; - -typedef struct tag_USB_DK_TRANSFER_REQUEST { - ULONG64 EndpointAddress; - PVOID64 Buffer; - ULONG64 BufferLength; - ULONG64 TransferType; - ULONG64 IsochronousPacketsArraySize; - PVOID64 IsochronousPacketsArray; - - USB_DK_TRANSFER_RESULT Result; -} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST; - typedef enum { TransferFailure = 0, TransferSuccess, @@ -90,7 +47,7 @@ typedef enum { typedef enum { ControlTransferType, BulkTransferType, - IntertuptTransferType, + InterruptTransferType, IsochronousTransferType } USB_DK_TRANSFER_TYPE; diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c new file mode 100644 index 0000000000..ce1b55cd61 --- /dev/null +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c @@ -0,0 +1,3009 @@ +/* + * windows backend for libusb 1.0 + * Copyright © 2009-2012 Pete Batard + * Copyright © 2016-2018 Chris Dickens + * With contributions from Michael Plante, Orin Eman et al. + * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer + * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software + * Hash table functions adapted from glibc, by Ulrich Drepper et al. + * Major code testing contribution by Xiaofan Chen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libusbi.h" +#include "windows_common.h" +#include "windows_nt_common.h" +#include "windows_winusb.h" + +// Unfuckup the 'inferface' keyword +#undef interface + +#define HANDLE_VALID(h) (((h) != NULL) && ((h) != INVALID_HANDLE_VALUE)) + +// The 2 macros below are used in conjunction with safe loops. +#define LOOP_CHECK(fcall) \ + { \ + r = fcall; \ + if (r != LIBUSB_SUCCESS) \ + continue; \ + } +#define LOOP_BREAK(err) \ + { \ + r = err; \ + continue; \ + } + +// WinUSB-like API prototypes +static int winusbx_init(struct libusb_context *ctx); +static void winusbx_exit(void); +static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle); +static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle); +static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); +static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); +static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer); +static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle); +static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); +// Composite API prototypes +static int composite_open(int sub_api, struct libusb_device_handle *dev_handle); +static void composite_close(int sub_api, struct libusb_device_handle *dev_handle); +static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); +static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); +static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); +static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); +static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); +static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); +static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer); +static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer); +static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle); +static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); + +static usbi_mutex_t autoclaim_lock; + +// API globals +static HMODULE WinUSBX_handle = NULL; +static struct winusb_interface WinUSBX[SUB_API_MAX]; +#define CHECK_WINUSBX_AVAILABLE(sub_api) \ + do { \ + if (sub_api == SUB_API_NOTSET) \ + sub_api = priv->sub_api; \ + if (!WinUSBX[sub_api].initialized) \ + return LIBUSB_ERROR_ACCESS; \ + } while (0) + +static bool api_hid_available = false; +#define CHECK_HID_AVAILABLE \ + do { \ + if (!api_hid_available) \ + return LIBUSB_ERROR_ACCESS; \ + } while (0) + +#if defined(ENABLE_LOGGING) +static const char *guid_to_string(const GUID *guid) +{ + static char guid_string[MAX_GUID_STRING_LENGTH]; + + if (guid == NULL) + return ""; + + sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + (unsigned int)guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + + return guid_string; +} +#endif + +/* + * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes. + * Return an allocated sanitized string or NULL on error. + */ +static char *sanitize_path(const char *path) +{ + const char root_prefix[] = {'\\', '\\', '.', '\\'}; + size_t j, size; + char *ret_path; + size_t add_root = 0; + + if (path == NULL) + return NULL; + + size = strlen(path) + 1; + + // Microsoft indiscriminately uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes. + if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\')) + || ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) { + add_root = sizeof(root_prefix); + size += add_root; + } + + ret_path = malloc(size); + if (ret_path == NULL) + return NULL; + + strcpy(&ret_path[add_root], path); + + // Ensure consistency with root prefix + memcpy(ret_path, root_prefix, sizeof(root_prefix)); + + // Same goes for '\' and '#' after the root prefix. Ensure '#' is used + for (j = sizeof(root_prefix); j < size; j++) { + ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too + if (ret_path[j] == '\\') + ret_path[j] = '#'; + } + + return ret_path; +} + +/* + * Cfgmgr32, AdvAPI32, OLE32 and SetupAPI DLL functions + */ +static BOOL init_dlls(void) +{ + DLL_GET_HANDLE(Cfgmgr32); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE); + DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE); + + // Prefixed to avoid conflict with header files + DLL_GET_HANDLE(AdvAPI32); + DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE); + DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE); + + DLL_GET_HANDLE(OLE32); + DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, TRUE); + + DLL_GET_HANDLE(SetupAPI); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE); + DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE); + + return TRUE; +} + +static void exit_dlls(void) +{ + DLL_FREE_HANDLE(Cfgmgr32); + DLL_FREE_HANDLE(AdvAPI32); + DLL_FREE_HANDLE(OLE32); + DLL_FREE_HANDLE(SetupAPI); +} + +/* + * enumerate interfaces for the whole USB class + * + * Parameters: + * dev_info: a pointer to a dev_info list + * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) + * enumerator: the generic USB class for which to retrieve interface details + * index: zero based index of the interface in the device info list + * + * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA + * structure returned and call this function repeatedly using the same guid (with an + * incremented index starting at zero) until all interfaces have been returned. + */ +static bool get_devinfo_data(struct libusb_context *ctx, + HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char *enumerator, unsigned _index) +{ + if (_index == 0) { + *dev_info = pSetupDiGetClassDevsA(NULL, enumerator, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); + if (*dev_info == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "could not obtain device info set for PnP enumerator '%s': %s", + enumerator, windows_error_str(0)); + return false; + } + } + + dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); + if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "could not obtain device info data for PnP enumerator '%s' index %u: %s", + enumerator, _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return false; + } + return true; +} + +/* + * enumerate interfaces for a specific GUID + * + * Parameters: + * dev_info: a pointer to a dev_info list + * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) + * guid: the GUID for which to retrieve interface details + * index: zero based index of the interface in the device info list + * + * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA + * structure returned and call this function repeatedly using the same guid (with an + * incremented index starting at zero) until all interfaces have been returned. + */ +static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, + PSP_DEVINFO_DATA dev_info_data, LPCGUID guid, DWORD *_index, char **dev_interface_path) +{ + SP_DEVICE_INTERFACE_DATA dev_interface_data; + PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details; + DWORD size; + + dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); + dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + for (;;) { + if (!pSetupDiEnumDeviceInfo(dev_info, *_index, dev_info_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) { + usbi_err(ctx, "Could not obtain device info data for %s index %u: %s", + guid_to_string(guid), *_index, windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + + // No more devices + return LIBUSB_SUCCESS; + } + + // Always advance the index for the next iteration + (*_index)++; + + if (pSetupDiEnumDeviceInterfaces(dev_info, dev_info_data, guid, 0, &dev_interface_data)) + break; + + if (GetLastError() != ERROR_NO_MORE_ITEMS) { + usbi_err(ctx, "Could not obtain interface data for %s devInst %X: %s", + guid_to_string(guid), dev_info_data->DevInst, windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + + // Device does not have an interface matching this GUID, skip + } + + // Read interface data (dummy + actual) to access the device path + if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { + // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + usbi_err(ctx, "could not access interface data (dummy) for %s devInst %X: %s", + guid_to_string(guid), dev_info_data->DevInst, windows_error_str(0)); + return LIBUSB_ERROR_OTHER; + } + } else { + usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong"); + return LIBUSB_ERROR_OTHER; + } + + dev_interface_details = malloc(size); + if (dev_interface_details == NULL) { + usbi_err(ctx, "could not allocate interface data for %s devInst %X", + guid_to_string(guid), dev_info_data->DevInst); + return LIBUSB_ERROR_NO_MEM; + } + + dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data, + dev_interface_details, size, NULL, NULL)) { + usbi_err(ctx, "could not access interface data (actual) for %s devInst %X: %s", + guid_to_string(guid), dev_info_data->DevInst, windows_error_str(0)); + free(dev_interface_details); + return LIBUSB_ERROR_OTHER; + } + + *dev_interface_path = sanitize_path(dev_interface_details->DevicePath); + free(dev_interface_details); + + if (*dev_interface_path == NULL) { + usbi_err(ctx, "could not allocate interface path for %s devInst %X", + guid_to_string(guid), dev_info_data->DevInst); + return LIBUSB_ERROR_NO_MEM; + } + + return LIBUSB_SUCCESS; +} + +/* For libusb0 filter */ +static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct libusb_context *ctx, + HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index, char *filter_path) +{ + SP_DEVICE_INTERFACE_DATA dev_interface_data; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details; + DWORD size; + + if (_index == 0) + *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); + + if (dev_info_data != NULL) { + dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); + if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "Could not obtain device info data for index %u: %s", + _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; + } + } + + dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { + if (GetLastError() != ERROR_NO_MORE_ITEMS) + usbi_err(ctx, "Could not obtain interface data for index %u: %s", + _index, windows_error_str(0)); + + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; + } + + // Read interface data (dummy + actual) to access the device path + if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { + // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", + _index, windows_error_str(0)); + goto err_exit; + } + } else { + usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); + goto err_exit; + } + + dev_interface_details = calloc(1, size); + if (dev_interface_details == NULL) { + usbi_err(ctx, "could not allocate interface data for index %u.", _index); + goto err_exit; + } + + dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, dev_interface_details, size, &size, NULL)) + usbi_err(ctx, "could not access interface data (actual) for index %u: %s", + _index, windows_error_str(0)); + + // [trobinso] lookup the libusb0 symbolic index. + if (dev_interface_details) { + HKEY hkey_device_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ); + if (hkey_device_interface != INVALID_HANDLE_VALUE) { + DWORD libusb0_symboliclink_index = 0; + DWORD value_length = sizeof(DWORD); + DWORD value_type = 0; + LONG status; + + status = pRegQueryValueExW(hkey_device_interface, L"LUsb0", NULL, &value_type, + (LPBYTE)&libusb0_symboliclink_index, &value_length); + if (status == ERROR_SUCCESS) { + if (libusb0_symboliclink_index < 256) { + // libusb0.sys is connected to this device instance. + // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter. + sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index); + usbi_dbg("assigned libusb0 symbolic link %s", filter_path); + } else { + // libusb0.sys was connected to this device instance at one time; but not anymore. + } + } + pRegCloseKey(hkey_device_interface); + } + } + + return dev_interface_details; + +err_exit: + pSetupDiDestroyDeviceInfoList(*dev_info); + *dev_info = INVALID_HANDLE_VALUE; + return NULL; +} + +/* + * Returns the first known ancestor of a device + */ +static struct libusb_device *get_ancestor(struct libusb_context *ctx, + DEVINST devinst, PDEVINST _parent_devinst) +{ + struct libusb_device *dev = NULL; + DEVINST parent_devinst; + + while (dev == NULL) { + if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS) + break; + devinst = parent_devinst; + dev = usbi_get_device_by_session_id(ctx, (unsigned long)devinst); + } + + if ((dev != NULL) && (_parent_devinst != NULL)) + *_parent_devinst = devinst; + + return dev; +} + +/* + * Determine which interface the given endpoint address belongs to + */ +static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep) +{ + const struct libusb_interface *intf; + const struct libusb_interface_descriptor *intf_desc; + int i, j, k; + + for (i = 0; i < conf_desc->bNumInterfaces; i++) { + intf = &conf_desc->interface[i]; + for (j = 0; j < intf->num_altsetting; j++) { + intf_desc = &intf->altsetting[j]; + for (k = 0; k < intf_desc->bNumEndpoints; k++) { + if (intf_desc->endpoint[k].bEndpointAddress == ep) { + usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i); + return intf_desc->bInterfaceNumber; + } + } + } + } + + usbi_dbg("endpoint %02X not found on any interface", ep); + return LIBUSB_ERROR_NOT_FOUND; +} + +/* + * Populate the endpoints addresses of the device_priv interface helper structs + */ +static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + int i, r; + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + struct libusb_config_descriptor *conf_desc; + const struct libusb_interface_descriptor *if_desc; + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + + r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc); + if (r != LIBUSB_SUCCESS) { + usbi_warn(ctx, "could not read config descriptor: error %d", r); + return r; + } + + if_desc = &conf_desc->interface[iface].altsetting[altsetting]; + safe_free(priv->usb_interface[iface].endpoint); + + if (if_desc->bNumEndpoints == 0) { + usbi_dbg("no endpoints found for interface %d", iface); + libusb_free_config_descriptor(conf_desc); + return LIBUSB_SUCCESS; + } + + priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints); + if (priv->usb_interface[iface].endpoint == NULL) { + libusb_free_config_descriptor(conf_desc); + return LIBUSB_ERROR_NO_MEM; + } + + priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints; + for (i = 0; i < if_desc->bNumEndpoints; i++) { + priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress; + usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface); + } + libusb_free_config_descriptor(conf_desc); + + // Extra init may be required to configure endpoints + if (priv->apib->configure_endpoints) + r = priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface); + + return r; +} + +// Lookup for a match in the list of API driver names +// return -1 if not found, driver match number otherwise +static int get_sub_api(char *driver, int api) +{ + int i; + const char sep_str[2] = {LIST_SEPARATOR, 0}; + char *tok, *tmp_str; + size_t len = strlen(driver); + + if (len == 0) + return SUB_API_NOTSET; + + tmp_str = _strdup(driver); + if (tmp_str == NULL) + return SUB_API_NOTSET; + + tok = strtok(tmp_str, sep_str); + while (tok != NULL) { + for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) { + if (_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) { + free(tmp_str); + return i; + } + } + tok = strtok(NULL, sep_str); + } + + free(tmp_str); + return SUB_API_NOTSET; +} + +/* + * auto-claiming and auto-release helper functions + */ +static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) +{ + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv( + transfer->dev_handle); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = *interface_number; + int r = LIBUSB_SUCCESS; + + switch (api_type) { + case USB_API_WINUSBX: + case USB_API_HID: + break; + default: + return LIBUSB_ERROR_INVALID_PARAM; + } + + usbi_mutex_lock(&autoclaim_lock); + if (current_interface < 0) { // No serviceable interface was found + for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) { + // Must claim an interface of the same API type + if ((priv->usb_interface[current_interface].apib->id == api_type) + && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) { + usbi_dbg("auto-claimed interface %d for control request", current_interface); + if (handle_priv->autoclaim_count[current_interface] != 0) + usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero"); + handle_priv->autoclaim_count[current_interface]++; + break; + } + } + if (current_interface == USB_MAXINTERFACES) { + usbi_err(ctx, "could not auto-claim any interface"); + r = LIBUSB_ERROR_NOT_FOUND; + } + } else { + // If we have a valid interface that was autoclaimed, we must increment + // its autoclaim count so that we can prevent an early release. + if (handle_priv->autoclaim_count[current_interface] != 0) + handle_priv->autoclaim_count[current_interface]++; + } + usbi_mutex_unlock(&autoclaim_lock); + + *interface_number = current_interface; + return r; +} + +static void auto_release(struct usbi_transfer *itransfer) +{ + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + libusb_device_handle *dev_handle = transfer->dev_handle; + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + int r; + + usbi_mutex_lock(&autoclaim_lock); + if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) { + handle_priv->autoclaim_count[transfer_priv->interface_number]--; + if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) { + r = libusb_release_interface(dev_handle, transfer_priv->interface_number); + if (r == LIBUSB_SUCCESS) + usbi_dbg("auto-released interface %d", transfer_priv->interface_number); + else + usbi_dbg("failed to auto-release interface %d (%s)", + transfer_priv->interface_number, libusb_error_name((enum libusb_error)r)); + } + } + usbi_mutex_unlock(&autoclaim_lock); +} + +/* + * init: libusb backend init function + */ +static int winusb_init(struct libusb_context *ctx) +{ + int i; + + // We need a lock for proper auto-release + usbi_mutex_init(&autoclaim_lock); + + // Load DLL imports + if (!init_dlls()) { + usbi_err(ctx, "could not resolve DLL functions"); + return LIBUSB_ERROR_OTHER; + } + + // Initialize the low level APIs (we don't care about errors at this stage) + for (i = 0; i < USB_API_MAX; i++) { + if (usb_api_backend[i].init && usb_api_backend[i].init(ctx)) + usbi_warn(ctx, "error initializing %s backend", + usb_api_backend[i].designation); + } + + return LIBUSB_SUCCESS; +} + +/* +* exit: libusb backend deinitialization function +*/ +static void winusb_exit(struct libusb_context *ctx) +{ + int i; + + for (i = 0; i < USB_API_MAX; i++) { + if (usb_api_backend[i].exit) + usb_api_backend[i].exit(); + } + + exit_dlls(); + usbi_mutex_destroy(&autoclaim_lock); +} + +/* + * fetch and cache all the config descriptors through I/O + */ +static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev); + struct winusb_device_priv *priv = _device_priv(dev); + DWORD size, ret_size; + uint8_t i; + + USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request + PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request + PUSB_CONFIGURATION_DESCRIPTOR cd_data; + + if (dev->num_configurations == 0) + return; + + priv->config_descriptor = calloc(dev->num_configurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR)); + if (priv->config_descriptor == NULL) { + usbi_err(ctx, "could not allocate configuration descriptor array for '%s'", priv->dev_id); + return; + } + + for (i = 0; i <= dev->num_configurations; i++) { + safe_free(cd_buf_actual); + + if (i == dev->num_configurations) + break; + + size = sizeof(cd_buf_short); + memset(&cd_buf_short, 0, size); + + cd_buf_short.req.ConnectionIndex = (ULONG)dev->port_number; + cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; + cd_buf_short.req.SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR; + cd_buf_short.req.SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i; + cd_buf_short.req.SetupPacket.wIndex = 0; + cd_buf_short.req.SetupPacket.wLength = (USHORT)sizeof(USB_CONFIGURATION_DESCRIPTOR); + + // Dummy call to get the required data size. Initial failures are reported as info rather + // than error as they can occur for non-penalizing situations, such as with some hubs. + // coverity[tainted_data_argument] + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size, + &cd_buf_short, size, &ret_size, NULL)) { + usbi_info(ctx, "could not access configuration descriptor %u (dummy) for '%s': %s", i, priv->dev_id, windows_error_str(0)); + continue; + } + + if ((ret_size != size) || (cd_buf_short.desc.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) { + usbi_info(ctx, "unexpected configuration descriptor %u size (dummy) for '%s'", i, priv->dev_id); + continue; + } + + size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.desc.wTotalLength; + cd_buf_actual = malloc(size); + if (cd_buf_actual == NULL) { + usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id); + continue; + } + + // Actual call + cd_buf_actual->ConnectionIndex = (ULONG)dev->port_number; + cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; + cd_buf_actual->SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR; + cd_buf_actual->SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i; + cd_buf_actual->SetupPacket.wIndex = 0; + cd_buf_actual->SetupPacket.wLength = cd_buf_short.desc.wTotalLength; + + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size, + cd_buf_actual, size, &ret_size, NULL)) { + usbi_err(ctx, "could not access configuration descriptor %u (actual) for '%s': %s", i, priv->dev_id, windows_error_str(0)); + continue; + } + + cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST)); + + if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.desc.wTotalLength)) { + usbi_err(ctx, "unexpected configuration descriptor %u size (actual) for '%s'", i, priv->dev_id); + continue; + } + + if (cd_data->bDescriptorType != LIBUSB_DT_CONFIG) { + usbi_err(ctx, "descriptor %u not a configuration descriptor for '%s'", i, priv->dev_id); + continue; + } + + usbi_dbg("cached config descriptor %u (bConfigurationValue=%u, %u bytes)", + i, cd_data->bConfigurationValue, cd_data->wTotalLength); + + // Cache the descriptor + priv->config_descriptor[i] = malloc(cd_data->wTotalLength); + if (priv->config_descriptor[i] != NULL) { + memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength); + } else { + usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id); + } + } +} + +/* + * Populate a libusb device structure + */ +static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev, + uint8_t port_number, DEVINST devinst) +{ + struct libusb_context *ctx; + struct libusb_device *tmp_dev; + struct winusb_device_priv *priv, *parent_priv; + USB_NODE_CONNECTION_INFORMATION_EX conn_info; + USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2; + HANDLE hub_handle; + DWORD size; + uint8_t bus_number, depth; + int r; + + priv = _device_priv(dev); + + // If the device is already initialized, we can stop here + if (priv->initialized) + return LIBUSB_SUCCESS; + + if (parent_dev != NULL) { // Not a HCD root hub + ctx = DEVICE_CTX(dev); + parent_priv = _device_priv(parent_dev); + if (parent_priv->apib->id != USB_API_HUB) { + usbi_warn(ctx, "parent for device '%s' is not a hub", priv->dev_id); + return LIBUSB_ERROR_NOT_FOUND; + } + + // Calculate depth and fetch bus number + bus_number = parent_dev->bus_number; + if (bus_number == 0) { + tmp_dev = get_ancestor(ctx, devinst, &devinst); + if (tmp_dev != parent_dev) { + usbi_err(ctx, "program assertion failed - first ancestor is not parent"); + return LIBUSB_ERROR_NOT_FOUND; + } + libusb_unref_device(tmp_dev); + + for (depth = 1; bus_number == 0; depth++) { + tmp_dev = get_ancestor(ctx, devinst, &devinst); + if (tmp_dev->bus_number != 0) { + bus_number = tmp_dev->bus_number; + depth += _device_priv(tmp_dev)->depth; + } + libusb_unref_device(tmp_dev); + } + } else { + depth = parent_priv->depth + 1; + } + + if (bus_number == 0) { + usbi_err(ctx, "program assertion failed - bus number not found for '%s'", priv->dev_id); + return LIBUSB_ERROR_NOT_FOUND; + } + + dev->bus_number = bus_number; + dev->port_number = port_number; + dev->parent_dev = parent_dev; + priv->depth = depth; + + hub_handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + 0, NULL); + if (hub_handle == INVALID_HANDLE_VALUE) { + usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0)); + return LIBUSB_ERROR_ACCESS; + } + + memset(&conn_info, 0, sizeof(conn_info)); + conn_info.ConnectionIndex = (ULONG)port_number; + // coverity[tainted_data_argument] + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info), + &conn_info, sizeof(conn_info), &size, NULL)) { + usbi_warn(ctx, "could not get node connection information for device '%s': %s", + priv->dev_id, windows_error_str(0)); + CloseHandle(hub_handle); + return LIBUSB_ERROR_NO_DEVICE; + } + + if (conn_info.ConnectionStatus == NoDeviceConnected) { + usbi_err(ctx, "device '%s' is no longer connected!", priv->dev_id); + CloseHandle(hub_handle); + return LIBUSB_ERROR_NO_DEVICE; + } + + memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); + dev->num_configurations = priv->dev_descriptor.bNumConfigurations; + priv->active_config = conn_info.CurrentConfigurationValue; + usbi_dbg("found %u configurations (active conf: %u)", dev->num_configurations, priv->active_config); + + // Cache as many config descriptors as we can + cache_config_descriptors(dev, hub_handle); + + // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8 + if (windows_version >= WINDOWS_8) { + conn_info_v2.ConnectionIndex = (ULONG)port_number; + conn_info_v2.Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2); + conn_info_v2.SupportedUsbProtocols.Usb300 = 1; + if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, + &conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) { + usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s", + priv->dev_id, windows_error_str(0)); + } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) { + conn_info.Speed = 3; + } + } + + CloseHandle(hub_handle); + + if (conn_info.DeviceAddress > UINT8_MAX) + usbi_err(ctx, "program assertion failed - device address overflow"); + + dev->device_address = (uint8_t)conn_info.DeviceAddress; + + switch (conn_info.Speed) { + case 0: dev->speed = LIBUSB_SPEED_LOW; break; + case 1: dev->speed = LIBUSB_SPEED_FULL; break; + case 2: dev->speed = LIBUSB_SPEED_HIGH; break; + case 3: dev->speed = LIBUSB_SPEED_SUPER; break; + default: + usbi_warn(ctx, "unknown device speed %u", conn_info.Speed); + break; + } + } + + r = usbi_sanitize_device(dev); + if (r) + return r; + + priv->initialized = true; + + usbi_dbg("(bus: %u, addr: %u, depth: %u, port: %u): '%s'", + dev->bus_number, dev->device_address, priv->depth, dev->port_number, priv->dev_id); + + return LIBUSB_SUCCESS; +} + +static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id, + uint8_t bus_number, DEVINST devinst) +{ + struct libusb_device *dev; + struct winusb_device_priv *priv; + unsigned long session_id; + DEVINST child_devinst; + + if (CM_Get_Child(&child_devinst, devinst, 0) != CR_SUCCESS) { + usbi_err(ctx, "could not get child devinst for '%s'", dev_id); + return LIBUSB_ERROR_OTHER; + } + + session_id = (unsigned long)child_devinst; + dev = usbi_get_device_by_session_id(ctx, session_id); + if (dev == NULL) { + usbi_err(ctx, "program assertion failed - HCD '%s' child not found", dev_id); + return LIBUSB_ERROR_NO_DEVICE; + } + + if (dev->bus_number == 0) { + // Only do this once + usbi_dbg("assigning HCD '%s' bus number %u", dev_id, bus_number); + priv = _device_priv(dev); + dev->bus_number = bus_number; + dev->num_configurations = 1; + priv->dev_descriptor.bLength = LIBUSB_DT_DEVICE_SIZE; + priv->dev_descriptor.bDescriptorType = LIBUSB_DT_DEVICE; + priv->dev_descriptor.bDeviceClass = LIBUSB_CLASS_HUB; + priv->dev_descriptor.bNumConfigurations = 1; + priv->active_config = 1; + priv->root_hub = true; + if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &priv->dev_descriptor.idVendor, &priv->dev_descriptor.idProduct) != 2) { + usbi_warn(ctx, "could not infer VID/PID of HCD root hub from '%s'", dev_id); + priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub + priv->dev_descriptor.idProduct = 1; + } + } + + libusb_unref_device(dev); + return LIBUSB_SUCCESS; +} + +// Returns the api type, or 0 if not found/unsupported +static void get_api_type(struct libusb_context *ctx, HDEVINFO *dev_info, + SP_DEVINFO_DATA *dev_info_data, int *api, int *sub_api) +{ + // Precedence for filter drivers vs driver is in the order of this array + struct driver_lookup lookup[3] = { + {"\0\0", SPDRP_SERVICE, "driver"}, + {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"}, + {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"} + }; + DWORD size, reg_type; + unsigned k, l; + int i, j; + + // Check the service & filter names to know the API we should use + for (k = 0; k < 3; k++) { + if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop, + ®_type, (PBYTE)lookup[k].list, MAX_KEY_LENGTH, &size)) { + // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ + if (lookup[k].reg_prop == SPDRP_SERVICE) + // our buffers are MAX_KEY_LENGTH + 1 so we can overflow if needed + lookup[k].list[strlen(lookup[k].list) + 1] = 0; + + // MULTI_SZ is a pain to work with. Turn it into something much more manageable + // NB: none of the driver names we check against contain LIST_SEPARATOR, + // (currently ';'), so even if an unsuported one does, it's not an issue + for (l = 0; (lookup[k].list[l] != 0) || (lookup[k].list[l + 1] != 0); l++) { + if (lookup[k].list[l] == 0) + lookup[k].list[l] = LIST_SEPARATOR; + } + usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); + } else { + if (GetLastError() != ERROR_INVALID_DATA) + usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); + lookup[k].list[0] = 0; + } + } + + for (i = 2; i < USB_API_MAX; i++) { + for (k = 0; k < 3; k++) { + j = get_sub_api(lookup[k].list, i); + if (j >= 0) { + usbi_dbg("matched %s name against %s", lookup[k].designation, + (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : usb_api_backend[i].driver_name_list[j]); + *api = i; + *sub_api = j; + return; + } + } + } +} + +static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev, + char *dev_interface_path, char *device_id, int api, int sub_api) +{ + struct winusb_device_priv *priv = _device_priv(dev); + int interface_number; + const char *mi_str; + + // Because MI_## are not necessarily in sequential order (some composite + // devices will have only MI_00 & MI_03 for instance), we retrieve the actual + // interface number from the path's MI value + mi_str = strstr(device_id, "MI_"); + if ((mi_str != NULL) && isdigit(mi_str[3]) && isdigit(mi_str[4])) { + interface_number = ((mi_str[3] - '0') * 10) + (mi_str[4] - '0'); + } else { + usbi_warn(ctx, "failure to read interface number for %s, using default value", device_id); + interface_number = 0; + } + + if (interface_number >= USB_MAXINTERFACES) { + usbi_warn(ctx, "interface %d too large - ignoring interface path %s", interface_number, dev_interface_path); + return LIBUSB_ERROR_ACCESS; + } + + if (priv->usb_interface[interface_number].path != NULL) { + if (api == USB_API_HID) { + // HID devices can have multiple collections (COL##) for each MI_## interface + usbi_dbg("interface[%d] already set - ignoring HID collection: %s", + interface_number, device_id); + return LIBUSB_ERROR_ACCESS; + } + // In other cases, just use the latest data + safe_free(priv->usb_interface[interface_number].path); + } + + usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path); + priv->usb_interface[interface_number].path = dev_interface_path; + priv->usb_interface[interface_number].apib = &usb_api_backend[api]; + priv->usb_interface[interface_number].sub_api = sub_api; + if ((api == USB_API_HID) && (priv->hid == NULL)) { + priv->hid = calloc(1, sizeof(struct hid_device_priv)); + if (priv->hid == NULL) + return LIBUSB_ERROR_NO_MEM; + } + + return LIBUSB_SUCCESS; +} + +static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev, + char *dev_interface_path) +{ + int i; + struct winusb_device_priv *priv = _device_priv(dev); + + if (priv->hid == NULL) { + usbi_err(ctx, "program assertion failed: parent is not HID"); + return LIBUSB_ERROR_NO_DEVICE; + } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) { + usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device"); + return LIBUSB_ERROR_NO_DEVICE; + } + + for (i = 0; i < priv->hid->nb_interfaces; i++) { + if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) { + usbi_dbg("interface[%d] already set to %s", i, dev_interface_path); + return LIBUSB_ERROR_ACCESS; + } + } + + priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path; + priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID]; + usbi_dbg("interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path); + priv->hid->nb_interfaces++; + return LIBUSB_SUCCESS; +} + +/* + * get_device_list: libusb backend device enumeration function + */ +static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) +{ + struct discovered_devs *discdevs; + HDEVINFO *dev_info, dev_info_intf, dev_info_enum; + SP_DEVINFO_DATA dev_info_data; + DWORD _index = 0; + GUID hid_guid; + int r = LIBUSB_SUCCESS; + int api, sub_api; + unsigned int pass, i, j; + char enumerator[16]; + char dev_id[MAX_PATH_LENGTH]; + struct libusb_device *dev, *parent_dev; + struct winusb_device_priv *priv, *parent_priv; + char *dev_interface_path = NULL; + unsigned long session_id; + DWORD size, port_nr, reg_type, install_state; + HKEY key; + WCHAR guid_string_w[MAX_GUID_STRING_LENGTH]; + GUID *if_guid; + LONG s; +#define HUB_PASS 0 +#define DEV_PASS 1 +#define HCD_PASS 2 +#define GEN_PASS 3 +#define HID_PASS 4 +#define EXT_PASS 5 + // Keep a list of guids that will be enumerated +#define GUID_SIZE_STEP 8 + const GUID **guid_list, **new_guid_list; + unsigned int guid_size = GUID_SIZE_STEP; + unsigned int nb_guids; + // Keep a list of PnP enumerator strings that are found + char *usb_enumerator[8] = { "USB" }; + unsigned int nb_usb_enumerators = 1; + unsigned int usb_enum_index = 0; + // Keep a list of newly allocated devs to unref +#define UNREF_SIZE_STEP 16 + libusb_device **unref_list, **new_unref_list; + unsigned int unref_size = UNREF_SIZE_STEP; + unsigned int unref_cur = 0; + + // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug) + // PASS 2 : (re)enumerate HUBS + // PASS 3 : (re)enumerate generic USB devices (including driverless) + // and list additional USB device interface GUIDs to explore + // PASS 4 : (re)enumerate master USB devices that have a device interface + // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and + // set the device interfaces. + + // Init the GUID table + guid_list = malloc(guid_size * sizeof(void *)); + if (guid_list == NULL) { + usbi_err(ctx, "failed to alloc guid list"); + return LIBUSB_ERROR_NO_MEM; + } + + guid_list[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB; + guid_list[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE; + guid_list[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER; + guid_list[GEN_PASS] = NULL; + if (api_hid_available) { + HidD_GetHidGuid(&hid_guid); + guid_list[HID_PASS] = &hid_guid; + } else { + guid_list[HID_PASS] = NULL; + } + nb_guids = EXT_PASS; + + unref_list = malloc(unref_size * sizeof(void *)); + if (unref_list == NULL) { + usbi_err(ctx, "failed to alloc unref list"); + free((void *)guid_list); + return LIBUSB_ERROR_NO_MEM; + } + + dev_info_intf = pSetupDiGetClassDevsA(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (dev_info_intf == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "failed to obtain device info list: %s", windows_error_str(0)); + free(unref_list); + free((void *)guid_list); + return LIBUSB_ERROR_OTHER; + } + + for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) { +//#define ENUM_DEBUG +#if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG) + const char * const passname[] = {"HUB", "DEV", "HCD", "GEN", "HID", "EXT"}; + usbi_dbg("#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass])); +#endif + if ((pass == HID_PASS) && (guid_list[HID_PASS] == NULL)) + continue; + + dev_info = (pass != GEN_PASS) ? &dev_info_intf : &dev_info_enum; + + for (i = 0; ; i++) { + // safe loop: free up any (unprotected) dynamic resource + // NB: this is always executed before breaking the loop + safe_free(dev_interface_path); + priv = parent_priv = NULL; + dev = parent_dev = NULL; + + // Safe loop: end of loop conditions + if (r != LIBUSB_SUCCESS) + break; + + if ((pass == HCD_PASS) && (i == UINT8_MAX)) { + usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest.", UINT8_MAX); + break; + } + + if (pass != GEN_PASS) { + // Except for GEN, all passes deal with device interfaces + r = get_interface_details(ctx, *dev_info, &dev_info_data, guid_list[pass], &_index, &dev_interface_path); + if ((r != LIBUSB_SUCCESS) || (dev_interface_path == NULL)) { + _index = 0; + break; + } + } else { + // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are + // being listed under the "NUSB3" PnP Symbolic Name rather than "USB". + // The Intel USB 3.0 driver behaves similar, but uses "IUSB3" + // The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3" + for (; usb_enum_index < nb_usb_enumerators; usb_enum_index++) { + if (get_devinfo_data(ctx, dev_info, &dev_info_data, usb_enumerator[usb_enum_index], i)) + break; + i = 0; + } + if (usb_enum_index == nb_usb_enumerators) + break; + } + + // Read the Device ID path + if (!pSetupDiGetDeviceInstanceIdA(*dev_info, &dev_info_data, dev_id, sizeof(dev_id), NULL)) { + usbi_warn(ctx, "could not read the device instance ID for devInst %X, skipping", + dev_info_data.DevInst); + continue; + } + +#ifdef ENUM_DEBUG + usbi_dbg("PRO: %s", dev_id); +#endif + + // Set API to use or get additional data from generic pass + api = USB_API_UNSUPPORTED; + sub_api = SUB_API_NOTSET; + switch (pass) { + case HCD_PASS: + break; + case HUB_PASS: + api = USB_API_HUB; + // Fetch the PnP enumerator class for this hub + // This will allow us to enumerate all classes during the GEN pass + if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME, + NULL, (PBYTE)enumerator, sizeof(enumerator), NULL)) { + usbi_err(ctx, "could not read enumerator string for device '%s': %s", dev_id, windows_error_str(0)); + LOOP_BREAK(LIBUSB_ERROR_OTHER); + } + for (j = 0; j < nb_usb_enumerators; j++) { + if (strcmp(usb_enumerator[j], enumerator) == 0) + break; + } + if (j == nb_usb_enumerators) { + usbi_dbg("found new PnP enumerator string '%s'", enumerator); + if (nb_usb_enumerators < ARRAYSIZE(usb_enumerator)) { + usb_enumerator[nb_usb_enumerators] = _strdup(enumerator); + if (usb_enumerator[nb_usb_enumerators] != NULL) { + nb_usb_enumerators++; + } else { + usbi_err(ctx, "could not allocate enumerator string '%s'", enumerator); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + } else { + usbi_warn(ctx, "too many enumerator strings, some devices may not be accessible"); + } + } + break; + case GEN_PASS: + // We use the GEN pass to detect driverless devices... + if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_DRIVER, + NULL, NULL, 0, NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { + usbi_info(ctx, "The following device has no driver: '%s'", dev_id); + usbi_info(ctx, "libusb will not be able to access it"); + } + // ...and to add the additional device interface GUIDs + key = pSetupDiOpenDevRegKey(*dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + if (key == INVALID_HANDLE_VALUE) + break; + // Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order + size = sizeof(guid_string_w); + s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, ®_type, + (LPBYTE)guid_string_w, &size); + if (s == ERROR_FILE_NOT_FOUND) + s = pRegQueryValueExW(key, L"DeviceInterfaceGUID", NULL, ®_type, + (LPBYTE)guid_string_w, &size); + pRegCloseKey(key); + if ((s == ERROR_SUCCESS) && + (((reg_type == REG_SZ) && (size == (sizeof(guid_string_w) - sizeof(WCHAR)))) || + ((reg_type == REG_MULTI_SZ) && (size == sizeof(guid_string_w))))) { + if (nb_guids == guid_size) { + new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *)); + if (new_guid_list == NULL) { + usbi_err(ctx, "failed to realloc guid list"); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + guid_list = new_guid_list; + guid_size += GUID_SIZE_STEP; + } + if_guid = malloc(sizeof(*if_guid)); + if (if_guid == NULL) { + usbi_err(ctx, "failed to alloc if_guid"); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + if (pIIDFromString(guid_string_w, if_guid) != 0) { + usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string, skipping", dev_id); + free(if_guid); + } else { + // Check if we've already seen this GUID + for (j = EXT_PASS; j < nb_guids; j++) { + if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0) + break; + } + if (j == nb_guids) { + usbi_dbg("extra GUID: %s", guid_to_string(if_guid)); + guid_list[nb_guids++] = if_guid; + } else { + // Duplicate, ignore + free(if_guid); + } + } + } else if (s == ERROR_SUCCESS) { + usbi_warn(ctx, "unexpected type/size of DeviceInterfaceGUID for '%s'", dev_id); + } + break; + case HID_PASS: + api = USB_API_HID; + break; + default: + // Get the API type (after checking that the driver installation is OK) + if ((!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_INSTALL_STATE, + NULL, (PBYTE)&install_state, sizeof(install_state), &size)) || (size != sizeof(install_state))) { + usbi_warn(ctx, "could not detect installation state of driver for '%s': %s", + dev_id, windows_error_str(0)); + } else if (install_state != 0) { + usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %u) - skipping", + dev_id, (unsigned int)install_state); + continue; + } + get_api_type(ctx, dev_info, &dev_info_data, &api, &sub_api); + break; + } + + // Find parent device (for the passes that need it) + if (pass >= GEN_PASS) { + parent_dev = get_ancestor(ctx, dev_info_data.DevInst, NULL); + if (parent_dev == NULL) { + // Root hubs will not have a parent + dev = usbi_get_device_by_session_id(ctx, (unsigned long)dev_info_data.DevInst); + if (dev != NULL) { + priv = _device_priv(dev); + if (priv->root_hub) + goto track_unref; + libusb_unref_device(dev); + } + + usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id); + continue; + } + + parent_priv = _device_priv(parent_dev); + // virtual USB devices are also listed during GEN - don't process these yet + if ((pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB)) { + libusb_unref_device(parent_dev); + continue; + } + } + + // Create new or match existing device, using the devInst as session id + if ((pass <= GEN_PASS) && (pass != HCD_PASS)) { // For subsequent passes, we'll lookup the parent + // These are the passes that create "new" devices + session_id = (unsigned long)dev_info_data.DevInst; + dev = usbi_get_device_by_session_id(ctx, session_id); + if (dev == NULL) { + alloc_device: + usbi_dbg("allocating new device for session [%lX]", session_id); + dev = usbi_alloc_device(ctx, session_id); + if (dev == NULL) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + + priv = winusb_device_priv_init(dev); + priv->dev_id = _strdup(dev_id); + if (priv->dev_id == NULL) { + libusb_unref_device(dev); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + } else { + usbi_dbg("found existing device for session [%lX]", session_id); + + priv = _device_priv(dev); + if (strcmp(priv->dev_id, dev_id) != 0) { + usbi_dbg("device instance ID for session [%lX] changed", session_id); + usbi_disconnect_device(dev); + libusb_unref_device(dev); + goto alloc_device; + } + } + + track_unref: + // Keep track of devices that need unref + if (unref_cur == unref_size) { + new_unref_list = realloc(unref_list, (unref_size + UNREF_SIZE_STEP) * sizeof(void *)); + if (new_unref_list == NULL) { + usbi_err(ctx, "could not realloc list for unref - aborting"); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + unref_list = new_unref_list; + unref_size += UNREF_SIZE_STEP; + } + unref_list[unref_cur++] = dev; + } + + // Setup device + switch (pass) { + case HUB_PASS: + case DEV_PASS: + // If the device has already been setup, don't do it again + if (priv->path != NULL) + break; + // Take care of API initialization + priv->path = dev_interface_path; + dev_interface_path = NULL; + priv->apib = &usb_api_backend[api]; + priv->sub_api = sub_api; + switch (api) { + case USB_API_COMPOSITE: + case USB_API_HUB: + break; + case USB_API_HID: + priv->hid = calloc(1, sizeof(struct hid_device_priv)); + if (priv->hid == NULL) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + break; + default: + // For other devices, the first interface is the same as the device + priv->usb_interface[0].path = _strdup(priv->path); + if (priv->usb_interface[0].path == NULL) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + // The following is needed if we want API calls to work for both simple + // and composite devices. + for (j = 0; j < USB_MAXINTERFACES; j++) + priv->usb_interface[j].apib = &usb_api_backend[api]; + break; + } + break; + case HCD_PASS: + r = enumerate_hcd_root_hub(ctx, dev_id, (uint8_t)(i + 1), dev_info_data.DevInst); + break; + case GEN_PASS: + // The SPDRP_ADDRESS for USB devices is the device port number on the hub + port_nr = 0; + if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_ADDRESS, + NULL, (PBYTE)&port_nr, sizeof(port_nr), &size) || (size != sizeof(port_nr))) + usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0)); + r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_info_data.DevInst); + if (r == LIBUSB_SUCCESS) { + // Append device to the list of discovered devices + discdevs = discovered_devs_append(*_discdevs, dev); + if (!discdevs) + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + + *_discdevs = discdevs; + } else if (r == LIBUSB_ERROR_NO_DEVICE) { + // This can occur if the device was disconnected but Windows hasn't + // refreshed its enumeration yet - in that case, we ignore the device + r = LIBUSB_SUCCESS; + } + break; + default: // HID_PASS and later + if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) { + if (parent_priv->apib->id == USB_API_HID) { + usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data); + r = set_hid_interface(ctx, parent_dev, dev_interface_path); + } else { + usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data); + r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id, api, sub_api); + } + switch (r) { + case LIBUSB_SUCCESS: + dev_interface_path = NULL; + break; + case LIBUSB_ERROR_ACCESS: + // interface has already been set => make sure dev_interface_path is freed then + r = LIBUSB_SUCCESS; + break; + default: + LOOP_BREAK(r); + break; + } + } + libusb_unref_device(parent_dev); + break; + } + } + } + + pSetupDiDestroyDeviceInfoList(dev_info_intf); + + // Free any additional GUIDs + for (pass = EXT_PASS; pass < nb_guids; pass++) + free((void *)guid_list[pass]); + free((void *)guid_list); + + // Free any PnP enumerator strings + for (i = 1; i < nb_usb_enumerators; i++) + free(usb_enumerator[i]); + + // Unref newly allocated devs + for (i = 0; i < unref_cur; i++) + libusb_unref_device(unref_list[i]); + free(unref_list); + + return r; +} + +static int winusb_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer) +{ + struct winusb_device_priv *priv = _device_priv(dev); + + memcpy(buffer, &priv->dev_descriptor, DEVICE_DESC_LENGTH); + return LIBUSB_SUCCESS; +} + +static int winusb_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len) +{ + struct winusb_device_priv *priv = _device_priv(dev); + PUSB_CONFIGURATION_DESCRIPTOR config_header; + size_t size; + + // config index is zero based + if (config_index >= dev->num_configurations) + return LIBUSB_ERROR_INVALID_PARAM; + + if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL)) + return LIBUSB_ERROR_NOT_FOUND; + + config_header = priv->config_descriptor[config_index]; + + size = MIN(config_header->wTotalLength, len); + memcpy(buffer, priv->config_descriptor[config_index], size); + return (int)size; +} + +static int winusb_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue, + unsigned char **buffer) +{ + struct winusb_device_priv *priv = _device_priv(dev); + PUSB_CONFIGURATION_DESCRIPTOR config_header; + uint8_t index; + + if (priv->config_descriptor == NULL) + return LIBUSB_ERROR_NOT_FOUND; + + for (index = 0; index < dev->num_configurations; index++) { + config_header = priv->config_descriptor[index]; + if (config_header == NULL) + continue; + if (config_header->bConfigurationValue == bConfigurationValue) { + *buffer = (unsigned char *)priv->config_descriptor[index]; + return (int)config_header->wTotalLength; + } + } + + return LIBUSB_ERROR_NOT_FOUND; +} + +/* + * return the cached copy of the active config descriptor + */ +static int winusb_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len) +{ + struct winusb_device_priv *priv = _device_priv(dev); + unsigned char *config_desc; + int r; + + if (priv->active_config == 0) + return LIBUSB_ERROR_NOT_FOUND; + + r = winusb_get_config_descriptor_by_value(dev, priv->active_config, &config_desc); + if (r < 0) + return r; + + len = MIN((size_t)r, len); + memcpy(buffer, config_desc, len); + return (int)len; +} + +static int winusb_open(struct libusb_device_handle *dev_handle) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_SUPPORTED_API(priv->apib, open); + + return priv->apib->open(SUB_API_NOTSET, dev_handle); +} + +static void winusb_close(struct libusb_device_handle *dev_handle) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + if (priv->apib->close) + priv->apib->close(SUB_API_NOTSET, dev_handle); +} + +static int winusb_get_configuration(struct libusb_device_handle *dev_handle, int *config) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + if (priv->active_config == 0) { + *config = 0; + return LIBUSB_ERROR_NOT_FOUND; + } + + *config = priv->active_config; + return LIBUSB_SUCCESS; +} + +/* + * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver + * does not currently expose a service that allows higher-level drivers to set + * the configuration." + */ +static int winusb_set_configuration(struct libusb_device_handle *dev_handle, int config) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + int r = LIBUSB_SUCCESS; + + if (config >= USB_MAXCONFIG) + return LIBUSB_ERROR_INVALID_PARAM; + + r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | + LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config, + 0, NULL, 0, 1000); + + if (r == LIBUSB_SUCCESS) + priv->active_config = (uint8_t)config; + + return r; +} + +static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + int r; + + CHECK_SUPPORTED_API(priv->apib, claim_interface); + + safe_free(priv->usb_interface[iface].endpoint); + priv->usb_interface[iface].nb_endpoints = 0; + + r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface); + + if (r == LIBUSB_SUCCESS) + r = windows_assign_endpoints(dev_handle, iface, 0); + + return r; +} + +static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + int r; + + CHECK_SUPPORTED_API(priv->apib, set_interface_altsetting); + + safe_free(priv->usb_interface[iface].endpoint); + priv->usb_interface[iface].nb_endpoints = 0; + + r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting); + + if (r == LIBUSB_SUCCESS) + r = windows_assign_endpoints(dev_handle, iface, altsetting); + + return r; +} + +static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_SUPPORTED_API(priv->apib, release_interface); + + return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface); +} + +static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_SUPPORTED_API(priv->apib, clear_halt); + + return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint); +} + +static int winusb_reset_device(struct libusb_device_handle *dev_handle) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_SUPPORTED_API(priv->apib, reset_device); + + return priv->apib->reset_device(SUB_API_NOTSET, dev_handle); +} + +static void winusb_destroy_device(struct libusb_device *dev) +{ + winusb_device_priv_release(dev); +} + +static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer) +{ + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + + usbi_close(transfer_priv->pollable_fd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; + transfer_priv->handle = NULL; + safe_free(transfer_priv->hid_buffer); + safe_free(transfer_priv->iso_context); + + // When auto claim is in use, attempt to release the auto-claimed interface + auto_release(itransfer); +} + +static int do_submit_transfer(struct usbi_transfer *itransfer, short events, + int (*transfer_fn)(int, struct usbi_transfer *)) +{ + struct libusb_context *ctx = ITRANSFER_CTX(itransfer); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winfd wfd; + int r; + + wfd = usbi_create_fd(); + if (wfd.fd < 0) + return LIBUSB_ERROR_NO_MEM; + + r = usbi_add_pollfd(ctx, wfd.fd, events); + if (r) { + usbi_close(wfd.fd); + return r; + } + + // Use transfer_priv to store data needed for async polling + transfer_priv->pollable_fd = wfd; + + r = transfer_fn(SUB_API_NOTSET, itransfer); + + if ((r != LIBUSB_SUCCESS) && (r != LIBUSB_ERROR_OVERFLOW)) { + usbi_remove_pollfd(ctx, wfd.fd); + usbi_close(wfd.fd); + transfer_priv->pollable_fd = INVALID_WINFD; + } + + return r; +} + +static int winusb_submit_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int (*transfer_fn)(int, struct usbi_transfer *); + short events; + + switch (transfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT; + transfer_fn = priv->apib->submit_control_transfer; + break; + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) + return LIBUSB_ERROR_NOT_SUPPORTED; + events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; + transfer_fn = priv->apib->submit_bulk_transfer; + break; + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + events = IS_XFERIN(transfer) ? POLLIN : POLLOUT; + transfer_fn = priv->apib->submit_iso_transfer; + break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; + default: + usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); + return LIBUSB_ERROR_INVALID_PARAM; + } + + if (transfer_fn == NULL) { + usbi_warn(TRANSFER_CTX(transfer), + "unsupported transfer type %d (unrecognized device driver)", + transfer->type); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + + return do_submit_transfer(itransfer, events, transfer_fn); +} + +static int windows_abort_control(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + + CHECK_SUPPORTED_API(priv->apib, abort_control); + + return priv->apib->abort_control(SUB_API_NOTSET, itransfer); +} + +static int windows_abort_transfers(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + + CHECK_SUPPORTED_API(priv->apib, abort_transfers); + + return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer); +} + +static int winusb_cancel_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + + switch (transfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + return windows_abort_control(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + return windows_abort_transfers(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; + default: + usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); + return LIBUSB_ERROR_INVALID_PARAM; + } +} + +static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size); +} + +static int winusb_get_transfer_fd(struct usbi_transfer *itransfer) +{ + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + return transfer_priv->pollable_fd.fd; +} + +static void winusb_get_overlapped_result(struct usbi_transfer *itransfer, + DWORD *io_result, DWORD *io_size) +{ + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winfd *pollable_fd = &transfer_priv->pollable_fd; + + if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) { + *io_result = NO_ERROR; + *io_size = (DWORD)pollable_fd->overlapped->InternalHigh; + } else if (GetOverlappedResult(transfer_priv->handle, pollable_fd->overlapped, io_size, FALSE)) { + // Regular async overlapped + *io_result = NO_ERROR; + } else { + *io_result = GetLastError(); + } +} + +// NB: MSVC6 does not support named initializers. +const struct windows_backend winusb_backend = { + winusb_init, + winusb_exit, + winusb_get_device_list, + winusb_open, + winusb_close, + winusb_get_device_descriptor, + winusb_get_active_config_descriptor, + winusb_get_config_descriptor, + winusb_get_config_descriptor_by_value, + winusb_get_configuration, + winusb_set_configuration, + winusb_claim_interface, + winusb_release_interface, + winusb_set_interface_altsetting, + winusb_clear_halt, + winusb_reset_device, + winusb_destroy_device, + winusb_submit_transfer, + winusb_cancel_transfer, + winusb_clear_transfer_priv, + winusb_copy_transfer_data, + winusb_get_transfer_fd, + winusb_get_overlapped_result, +}; + +/* + * USB API backends + */ + +static const char * const composite_driver_names[] = {"USBCCGP"}; +static const char * const winusbx_driver_names[] = {"libusbK", "libusb0", "WinUSB"}; +static const char * const hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"}; +const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { + { + USB_API_UNSUPPORTED, + "Unsupported API", + // No supported operations + }, + { + USB_API_HUB, + "HUB API", + // No supported operations + }, + { + USB_API_COMPOSITE, + "Composite API", + composite_driver_names, + ARRAYSIZE(composite_driver_names), + NULL, /* init */ + NULL, /* exit */ + composite_open, + composite_close, + NULL, /* configure_endpoints */ + composite_claim_interface, + composite_set_interface_altsetting, + composite_release_interface, + composite_clear_halt, + composite_reset_device, + composite_submit_bulk_transfer, + composite_submit_iso_transfer, + composite_submit_control_transfer, + composite_abort_control, + composite_abort_transfers, + composite_copy_transfer_data, + }, + { + USB_API_WINUSBX, + "WinUSB-like APIs", + winusbx_driver_names, + ARRAYSIZE(winusbx_driver_names), + winusbx_init, + winusbx_exit, + winusbx_open, + winusbx_close, + winusbx_configure_endpoints, + winusbx_claim_interface, + winusbx_set_interface_altsetting, + winusbx_release_interface, + winusbx_clear_halt, + winusbx_reset_device, + winusbx_submit_bulk_transfer, + winusbx_submit_iso_transfer, + winusbx_submit_control_transfer, + winusbx_abort_control, + winusbx_abort_transfers, + winusbx_copy_transfer_data, + }, + { + USB_API_HID, + "HID API", + // No supported operations + }, +}; + + +/* + * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions + */ +#define WinUSBX_Set(fn) \ + do { \ + if (native_winusb) \ + WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \ + else \ + pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn); \ + } while (0) + +static int winusbx_init(struct libusb_context *ctx) +{ + HMODULE h; + bool native_winusb; + int i; + KLIB_VERSION LibK_Version; + LibK_GetProcAddress_t pLibK_GetProcAddress = NULL; + LibK_GetVersion_t pLibK_GetVersion; + + h = LoadLibraryA("libusbK"); + + if (h == NULL) { + usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB"); + h = LoadLibraryA("WinUSB"); + + if (h == NULL) { + usbi_warn(ctx, "WinUSB DLL is not available either, " + "you will not be able to access devices outside of enumeration"); + return LIBUSB_ERROR_NOT_FOUND; + } + } else { + usbi_dbg("using libusbK DLL for universal access"); + pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion"); + if (pLibK_GetVersion != NULL) { + pLibK_GetVersion(&LibK_Version); + usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, + LibK_Version.Micro, LibK_Version.Nano); + } + pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress"); + if (pLibK_GetProcAddress == NULL) { + usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL"); + FreeLibrary(h); + return LIBUSB_ERROR_NOT_FOUND; + } + } + + native_winusb = (pLibK_GetProcAddress == NULL); + for (i = 0; i < SUB_API_MAX; i++) { + WinUSBX_Set(AbortPipe); + WinUSBX_Set(ControlTransfer); + WinUSBX_Set(FlushPipe); + WinUSBX_Set(Free); + WinUSBX_Set(GetAssociatedInterface); + WinUSBX_Set(Initialize); + WinUSBX_Set(ReadPipe); + if (!native_winusb) + WinUSBX_Set(ResetDevice); + WinUSBX_Set(ResetPipe); + WinUSBX_Set(SetCurrentAlternateSetting); + WinUSBX_Set(SetPipePolicy); + WinUSBX_Set(WritePipe); + WinUSBX_Set(IsoReadPipe); + WinUSBX_Set(IsoWritePipe); + + if (WinUSBX[i].Initialize != NULL) { + WinUSBX[i].initialized = true; + // Assume driver supports CancelIoEx() if it is available + WinUSBX[i].CancelIoEx_supported = (pCancelIoEx != NULL); + usbi_dbg("initalized sub API %s", winusbx_driver_names[i]); + } else { + usbi_warn(ctx, "Failed to initalize sub API %s", winusbx_driver_names[i]); + WinUSBX[i].initialized = false; + } + } + + WinUSBX_handle = h; + return LIBUSB_SUCCESS; +} + +static void winusbx_exit(void) +{ + if (WinUSBX_handle != NULL) { + FreeLibrary(WinUSBX_handle); + WinUSBX_handle = NULL; + + /* Reset the WinUSBX API structures */ + memset(&WinUSBX, 0, sizeof(WinUSBX)); + } +} + +// NB: open and close must ensure that they only handle interface of +// the right API type, as these functions can be called wholesale from +// composite_open(), with interfaces belonging to different APIs +static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + HANDLE file_handle; + int i; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // WinUSB requires a separate handle for each interface + for (i = 0; i < USB_MAXINTERFACES; i++) { + if ((priv->usb_interface[i].path != NULL) + && (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) { + file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (file_handle == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); + switch (GetLastError()) { + case ERROR_FILE_NOT_FOUND: // The device was disconnected + return LIBUSB_ERROR_NO_DEVICE; + case ERROR_ACCESS_DENIED: + return LIBUSB_ERROR_ACCESS; + default: + return LIBUSB_ERROR_IO; + } + } + handle_priv->interface_handle[i].dev_handle = file_handle; + } + } + return LIBUSB_SUCCESS; +} + +static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE handle; + int i; + + if (sub_api == SUB_API_NOTSET) + sub_api = priv->sub_api; + + if (!WinUSBX[sub_api].initialized) + return; + + if (priv->apib->id == USB_API_COMPOSITE) { + // If this is a composite device, just free and close all WinUSB-like + // interfaces directly (each is independent and not associated with another) + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) { + handle = handle_priv->interface_handle[i].api_handle; + if (HANDLE_VALID(handle)) + WinUSBX[sub_api].Free(handle); + + handle = handle_priv->interface_handle[i].dev_handle; + if (HANDLE_VALID(handle)) + CloseHandle(handle); + } + } + } else { + // If this is a WinUSB device, free all interfaces above interface 0, + // then free and close interface 0 last + for (i = 1; i < USB_MAXINTERFACES; i++) { + handle = handle_priv->interface_handle[i].api_handle; + if (HANDLE_VALID(handle)) + WinUSBX[sub_api].Free(handle); + } + handle = handle_priv->interface_handle[0].api_handle; + if (HANDLE_VALID(handle)) + WinUSBX[sub_api].Free(handle); + + handle = handle_priv->interface_handle[0].dev_handle; + if (HANDLE_VALID(handle)) + CloseHandle(handle); + } +} + +static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle; + UCHAR policy; + ULONG timeout = 0; + uint8_t endpoint_address; + int i; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // With handle and enpoints set (in parent), we can setup the default pipe properties + // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx + for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) { + endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i]; + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) + usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address); + + if ((i == -1) || (sub_api == SUB_API_LIBUSB0)) + continue; // Other policies don't apply to control endpoint or libusb0 + + policy = false; + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) + usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); + + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) + usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); + + policy = true; + /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See: + https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */ + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) + usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); + + if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, + AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) + usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); + } + + return LIBUSB_SUCCESS; +} + +static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE); + SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; + HDEVINFO dev_info = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA dev_info_data; + char *dev_path_no_guid = NULL; + char filter_path[] = "\\\\.\\libusb0-0000"; + bool found_filter = false; + HANDLE file_handle, winusb_handle; + DWORD err; + int i; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // If the device is composite, but using the default Windows composite parent driver (usbccgp) + // or if it's the first WinUSB-like interface, we get a handle through Initialize(). + if ((is_using_usbccgp) || (iface == 0)) { + // composite device (independent interfaces) or interface 0 + file_handle = handle_priv->interface_handle[iface].dev_handle; + if (!HANDLE_VALID(file_handle)) + return LIBUSB_ERROR_NOT_FOUND; + + if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { + handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; + err = GetLastError(); + switch (err) { + case ERROR_BAD_COMMAND: + // The device was disconnected + usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + default: + // it may be that we're using the libusb0 filter driver. + // TODO: can we move this whole business into the K/0 DLL? + for (i = 0; ; i++) { + safe_free(dev_interface_details); + safe_free(dev_path_no_guid); + + dev_interface_details = get_interface_details_filter(ctx, &dev_info, &dev_info_data, &GUID_DEVINTERFACE_LIBUSB0_FILTER, i, filter_path); + if ((found_filter) || (dev_interface_details == NULL)) + break; + + // ignore GUID part + dev_path_no_guid = sanitize_path(strtok(dev_interface_details->DevicePath, "{")); + if (dev_path_no_guid == NULL) + continue; + + if (strncmp(dev_path_no_guid, priv->usb_interface[iface].path, strlen(dev_path_no_guid)) == 0) { + file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (file_handle != INVALID_HANDLE_VALUE) { + if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { + // Replace the existing file handle with the working one + CloseHandle(handle_priv->interface_handle[iface].dev_handle); + handle_priv->interface_handle[iface].dev_handle = file_handle; + found_filter = true; + } else { + usbi_err(ctx, "could not initialize filter driver for %s", filter_path); + CloseHandle(file_handle); + } + } else { + usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0)); + } + } + } + free(dev_interface_details); + if (!found_filter) { + usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(err)); + return LIBUSB_ERROR_ACCESS; + } + } + } + handle_priv->interface_handle[iface].api_handle = winusb_handle; + } else { + // For all other interfaces, use GetAssociatedInterface() + winusb_handle = handle_priv->interface_handle[0].api_handle; + // It is a requirement for multiple interface devices on Windows that, to you + // must first claim the first interface before you claim the others + if (!HANDLE_VALID(winusb_handle)) { + file_handle = handle_priv->interface_handle[0].dev_handle; + if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { + handle_priv->interface_handle[0].api_handle = winusb_handle; + usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface); + } else { + usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB): %s", iface, windows_error_str(0)); + return LIBUSB_ERROR_ACCESS; + } + } + if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1), + &handle_priv->interface_handle[iface].api_handle)) { + handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; + switch (GetLastError()) { + case ERROR_NO_MORE_ITEMS: // invalid iface + return LIBUSB_ERROR_NOT_FOUND; + case ERROR_BAD_COMMAND: // The device was disconnected + return LIBUSB_ERROR_NO_DEVICE; + case ERROR_ALREADY_EXISTS: // already claimed + return LIBUSB_ERROR_BUSY; + default: + usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); + return LIBUSB_ERROR_ACCESS; + } + } + } + usbi_dbg("claimed interface %d", iface); + handle_priv->active_interface = iface; + + return LIBUSB_SUCCESS; +} + +static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + winusb_handle = handle_priv->interface_handle[iface].api_handle; + if (!HANDLE_VALID(winusb_handle)) + return LIBUSB_ERROR_NOT_FOUND; + + WinUSBX[sub_api].Free(winusb_handle); + handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; + + return LIBUSB_SUCCESS; +} + +/* + * Return the first valid interface (of the same API type), for control transfers + */ +static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id) +{ + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + int i; + + if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) { + usbi_dbg("unsupported API ID"); + return -1; + } + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle) + && HANDLE_VALID(handle_priv->interface_handle[i].api_handle) + && (priv->usb_interface[i].apib->id == api_id)) + return i; + } + + return -1; +} + +/* + * Lookup interface by endpoint address. -1 if not found + */ +static int interface_by_endpoint(struct winusb_device_priv *priv, + struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address) +{ + int i, j; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle)) + continue; + if (priv->usb_interface[i].endpoint == NULL) + continue; + for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { + if (priv->usb_interface[i].endpoint[j] == endpoint_address) + return i; + } + } + + return -1; +} + +static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer; + ULONG size; + HANDLE winusb_handle; + OVERLAPPED *overlapped; + int current_interface; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; + + // Windows places upper limits on the control transfer size + // See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538112.aspx + if (size > MAX_CTRL_BUFFER_LENGTH) + return LIBUSB_ERROR_INVALID_PARAM; + + current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX); + if (current_interface < 0) { + if (auto_claim(transfer, ¤t_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS) + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("will use interface %d", current_interface); + + transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + overlapped = transfer_priv->pollable_fd.overlapped; + + // Sending of set configuration control requests from WinUSB creates issues + if ((LIBUSB_REQ_TYPE(setup->RequestType) == LIBUSB_REQUEST_TYPE_STANDARD) + && (setup->Request == LIBUSB_REQUEST_SET_CONFIGURATION)) { + if (setup->Value != priv->active_config) { + usbi_warn(ctx, "cannot set configuration other than the default one"); + return LIBUSB_ERROR_INVALID_PARAM; + } + windows_force_sync_completion(overlapped, 0); + } else { + if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; + } + } else { + windows_force_sync_completion(overlapped, size); + } + } + + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + +static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + if (altsetting > 255) + return LIBUSB_ERROR_INVALID_PARAM; + + winusb_handle = handle_priv->interface_handle[iface].api_handle; + if (!HANDLE_VALID(winusb_handle)) { + usbi_err(ctx, "interface must be claimed first"); + return LIBUSB_ERROR_NOT_FOUND; + } + + if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) { + usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; + } + + return LIBUSB_SUCCESS; +} + +static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + HANDLE winusb_handle; + OVERLAPPED *overlapped; + bool ret; + int current_interface; + int i; + UINT offset; + PKISO_CONTEXT iso_context; + size_t iso_ctx_size; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + if ((sub_api != SUB_API_LIBUSBK) && (sub_api != SUB_API_LIBUSB0)) { + // iso only supported on libusbk-based backends + PRINT_UNSUPPORTED_API(submit_iso_transfer); + return LIBUSB_ERROR_NOT_SUPPORTED; + }; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + + transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + overlapped = transfer_priv->pollable_fd.overlapped; + + iso_ctx_size = sizeof(KISO_CONTEXT) + (transfer->num_iso_packets * sizeof(KISO_PACKET)); + transfer_priv->iso_context = iso_context = calloc(1, iso_ctx_size); + if (transfer_priv->iso_context == NULL) + return LIBUSB_ERROR_NO_MEM; + + // start ASAP + iso_context->StartFrame = 0; + iso_context->NumberOfPackets = (SHORT)transfer->num_iso_packets; + + // convert the transfer packet lengths to iso_packet offsets + offset = 0; + for (i = 0; i < transfer->num_iso_packets; i++) { + iso_context->IsoPackets[i].offset = offset; + offset += transfer->iso_packet_desc[i].length; + } + + if (IS_XFERIN(transfer)) { + usbi_dbg("reading %d iso packets", transfer->num_iso_packets); + ret = WinUSBX[sub_api].IsoReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context); + } else { + usbi_dbg("writing %d iso packets", transfer->num_iso_packets); + ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context); + } + + if (!ret) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; + } + } else { + windows_force_sync_completion(overlapped, (ULONG)transfer->length); + } + + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + +static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + HANDLE winusb_handle; + OVERLAPPED *overlapped; + bool ret; + int current_interface; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + + transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + overlapped = transfer_priv->pollable_fd.overlapped; + + if (IS_XFERIN(transfer)) { + usbi_dbg("reading %d bytes", transfer->length); + ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped); + } else { + usbi_dbg("writing %d bytes", transfer->length); + ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped); + } + + if (!ret) { + if (GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_IO; + } + } else { + windows_force_sync_completion(overlapped, (ULONG)transfer->length); + } + + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + +static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle; + int current_interface; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + current_interface = interface_by_endpoint(priv, handle_priv, endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); + winusb_handle = handle_priv->interface_handle[current_interface].api_handle; + + if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) { + usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + + return LIBUSB_SUCCESS; +} + +/* + * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed + * through testing as well): + * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel + * the control transfer using CancelIo" + */ +static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer) +{ + // Cancelling of the I/O is done in the parent + return LIBUSB_SUCCESS; +} + +static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + HANDLE handle; + int current_interface; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + current_interface = transfer_priv->interface_number; + if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { + usbi_err(ctx, "program assertion failed: invalid interface_number"); + return LIBUSB_ERROR_NOT_FOUND; + } + usbi_dbg("will use interface %d", current_interface); + + if (WinUSBX[sub_api].CancelIoEx_supported) { + // Try to use CancelIoEx if available to cancel just a single transfer + handle = handle_priv->interface_handle[current_interface].dev_handle; + if (pCancelIoEx(handle, transfer_priv->pollable_fd.overlapped)) + return LIBUSB_SUCCESS; + else if (GetLastError() == ERROR_NOT_FOUND) + return LIBUSB_ERROR_NOT_FOUND; + + // Not every driver implements the necessary functionality for CancelIoEx + usbi_warn(ctx, "CancelIoEx not supported for sub API %s", winusbx_driver_names[sub_api]); + WinUSBX[sub_api].CancelIoEx_supported = false; + } + + handle = handle_priv->interface_handle[current_interface].api_handle; + if (!WinUSBX[sub_api].AbortPipe(handle, transfer->endpoint)) { + usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); + return LIBUSB_ERROR_NO_DEVICE; + } + + return LIBUSB_SUCCESS; +} + +/* + * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper + * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx): + * "WinUSB does not support host-initiated reset port and cycle port operations" and + * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the + * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is + * cycle the pipes (and even then, the control pipe can not be reset using WinUSB) + */ +// TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?) +static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + HANDLE winusb_handle; + int i, j; + + CHECK_WINUSBX_AVAILABLE(sub_api); + + // Reset any available pipe (except control) + for (i = 0; i < USB_MAXINTERFACES; i++) { + winusb_handle = handle_priv->interface_handle[i].api_handle; + if (HANDLE_VALID(winusb_handle)) { + for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { + usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); + if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) + usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s", + priv->usb_interface[i].endpoint[j], windows_error_str(0)); + + // FlushPipe seems to fail on OUT pipes + if (IS_EPIN(priv->usb_interface[i].endpoint[j]) + && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))) + usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s", + priv->usb_interface[i].endpoint[j], windows_error_str(0)); + + if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) + usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s", + priv->usb_interface[i].endpoint[j], windows_error_str(0)); + } + } + } + + // libusbK & libusb0 have the ability to issue an actual device reset + if (WinUSBX[sub_api].ResetDevice != NULL) { + winusb_handle = handle_priv->interface_handle[0].api_handle; + if (HANDLE_VALID(winusb_handle)) + WinUSBX[sub_api].ResetDevice(winusb_handle); + } + + return LIBUSB_SUCCESS; +} + +static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + PKISO_CONTEXT iso_context; + int i; + + if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { + CHECK_WINUSBX_AVAILABLE(sub_api); + + // for isochronous, need to copy the individual iso packet actual_lengths and statuses + if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) { + // iso only supported on libusbk-based backends for now + iso_context = transfer_priv->iso_context; + for (i = 0; i < transfer->num_iso_packets; i++) { + transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length; + // TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status + //transfer->iso_packet_desc[i].status = transfer_priv->iso_context->IsoPackets[i].status; + } + } else { + // This should only occur if backend is not set correctly or other backend isoc is partially implemented + PRINT_UNSUPPORTED_API(copy_transfer_data); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + } + + itransfer->transferred += io_size; + return LIBUSB_TRANSFER_COMPLETED; +} + +/* + * Composite API functions + */ +static int composite_open(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + int r = LIBUSB_ERROR_NOT_FOUND; + uint8_t i; + // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID + bool available[SUB_API_MAX + 1] = { 0 }; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + switch (priv->usb_interface[i].apib->id) { + case USB_API_WINUSBX: + if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) { + available[priv->usb_interface[i].sub_api] = true; + } + break; + case USB_API_HID: + available[SUB_API_MAX] = true; + break; + default: + break; + } + } + + for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers + if (available[i]) { + r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle); + if (r != LIBUSB_SUCCESS) { + return r; + } + } + } +/* + if (available[SUB_API_MAX]) // HID driver + r = hid_open(SUB_API_NOTSET, dev_handle); +*/ + return r; +} + +static void composite_close(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + uint8_t i; + // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID + bool available[SUB_API_MAX + 1] = { 0 }; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + switch (priv->usb_interface[i].apib->id) { + case USB_API_WINUSBX: + if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) + available[priv->usb_interface[i].sub_api] = true; + break; + case USB_API_HID: + available[SUB_API_MAX] = true; + break; + default: + break; + } + } + + for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers + if (available[i]) + usb_api_backend[USB_API_WINUSBX].close(i, dev_handle); + } +/* + if (available[SUB_API_MAX]) // HID driver + hid_close(SUB_API_NOTSET, dev_handle); +*/ +} + +static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, claim_interface); + + return priv->usb_interface[iface].apib-> + claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); +} + +static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, set_interface_altsetting); + + return priv->usb_interface[iface].apib-> + set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting); +} + +static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + + CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, release_interface); + + return priv->usb_interface[iface].apib-> + release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); +} + +static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + struct libusb_config_descriptor *conf_desc; + WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; + int iface, pass, r; + + // Interface shouldn't matter for control, but it does in practice, with Windows' + // restrictions with regards to accessing HID keyboards and mice. Try to target + // a specific interface first, if possible. + switch (LIBUSB_REQ_RECIPIENT(setup->RequestType)) { + case LIBUSB_RECIPIENT_INTERFACE: + iface = setup->Index & 0xFF; + break; + case LIBUSB_RECIPIENT_ENDPOINT: + r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc); + if (r == LIBUSB_SUCCESS) { + iface = get_interface_by_endpoint(conf_desc, (setup->Index & 0xFF)); + libusb_free_config_descriptor(conf_desc); + break; + } + // Fall through if not able to determine interface + default: + iface = -1; + break; + } + + // Try and target a specific interface if the control setup indicates such + if ((iface >= 0) && (iface < USB_MAXINTERFACES)) { + usbi_dbg("attempting control transfer targeted to interface %d", iface); + if ((priv->usb_interface[iface].path != NULL) + && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) { + r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); + if (r == LIBUSB_SUCCESS) + return r; + } + } + + // Either not targeted to a specific interface or no luck in doing so. + // Try a 2 pass approach with all interfaces. + for (pass = 0; pass < 2; pass++) { + for (iface = 0; iface < USB_MAXINTERFACES; iface++) { + if ((priv->usb_interface[iface].path != NULL) + && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) { + if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) { + usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface); + continue; + } + usbi_dbg("using interface %d", iface); + r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); + // If not supported on this API, it may be supported on another, so don't give up yet!! + if (r == LIBUSB_ERROR_NOT_SUPPORTED) + continue; + return r; + } + } + } + usbi_err(ctx, "no libusb supported interfaces to complete request"); + return LIBUSB_ERROR_NOT_FOUND; +} + +static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_bulk_transfer); + + return priv->usb_interface[current_interface].apib-> + submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer); +} + +static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) { + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_iso_transfer); + + return priv->usb_interface[current_interface].apib-> + submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer); +} + +static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + int current_interface; + + current_interface = interface_by_endpoint(priv, handle_priv, endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); + return LIBUSB_ERROR_NOT_FOUND; + } + + CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, clear_halt); + + return priv->usb_interface[current_interface].apib-> + clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint); +} + +static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = transfer_priv->interface_number; + + if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { + usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number"); + return LIBUSB_ERROR_NOT_FOUND; + } + + CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_control); + + return priv->usb_interface[current_interface].apib-> + abort_control(priv->usb_interface[current_interface].sub_api, itransfer); +} + +static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = transfer_priv->interface_number; + + if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { + usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number"); + return LIBUSB_ERROR_NOT_FOUND; + } + + CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_transfers); + + return priv->usb_interface[current_interface].apib-> + abort_transfers(priv->usb_interface[current_interface].sub_api, itransfer); +} + +static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle) +{ + struct winusb_device_priv *priv = _device_priv(dev_handle->dev); + int r; + uint8_t i; + bool available[SUB_API_MAX]; + + for (i = 0; i < SUB_API_MAX; i++) + available[i] = false; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX) + && (priv->usb_interface[i].sub_api != SUB_API_NOTSET)) + available[priv->usb_interface[i].sub_api] = true; + } + + for (i = 0; i < SUB_API_MAX; i++) { + if (available[i]) { + r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle); + if (r != LIBUSB_SUCCESS) + return r; + } + } + + return LIBUSB_SUCCESS; +} + +static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) +{ + struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev); + int current_interface = transfer_priv->interface_number; + + CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, copy_transfer_data); + + return priv->usb_interface[current_interface].apib-> + copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, io_size); +} diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.h similarity index 54% rename from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h rename to vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.h index b7b9cd919a..c1ad4eb9b2 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.h @@ -36,15 +36,14 @@ #endif // Missing from MSVC6 setupapi.h -#if !defined(SPDRP_ADDRESS) +#ifndef SPDRP_ADDRESS #define SPDRP_ADDRESS 28 #endif -#if !defined(SPDRP_INSTALL_STATE) +#ifndef SPDRP_INSTALL_STATE #define SPDRP_INSTALL_STATE 34 #endif #define MAX_CTRL_BUFFER_LENGTH 4096 -#define MAX_USB_DEVICES 256 #define MAX_USB_STRING_LENGTH 128 #define MAX_HID_REPORT_SIZE 1024 #define MAX_HID_DESCRIPTOR_SIZE 256 @@ -61,17 +60,17 @@ // http://msdn.microsoft.com/en-us/library/ff545978.aspx // http://msdn.microsoft.com/en-us/library/ff545972.aspx // http://msdn.microsoft.com/en-us/library/ff545982.aspx -#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER) -const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} }; +#ifndef GUID_DEVINTERFACE_USB_HOST_CONTROLLER +const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = {0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27}}; #endif -#if !defined(GUID_DEVINTERFACE_USB_DEVICE) -const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} }; +#ifndef GUID_DEVINTERFACE_USB_DEVICE +const GUID GUID_DEVINTERFACE_USB_DEVICE = {0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}; #endif -#if !defined(GUID_DEVINTERFACE_USB_HUB) -const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} }; +#ifndef GUID_DEVINTERFACE_USB_HUB +const GUID GUID_DEVINTERFACE_USB_HUB = {0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8}}; #endif -#if !defined(GUID_DEVINTERFACE_LIBUSB0_FILTER) -const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9} }; +#ifndef GUID_DEVINTERFACE_LIBUSB0_FILTER +const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}}; #endif @@ -84,8 +83,6 @@ const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8 #define USB_API_WINUSBX 3 #define USB_API_HID 4 #define USB_API_MAX 5 -// The following is used to indicate if the HID or composite extra props have already been set. -#define USB_API_SET (1 << USB_API_MAX) // Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL) // Must have the same values as the KUSB_DRVID enum from libusbk.h @@ -95,15 +92,13 @@ const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8 #define SUB_API_WINUSB 2 #define SUB_API_MAX 3 -#define WINUSBX_DRV_NAMES {"libusbK", "libusb0", "WinUSB"} - struct windows_usb_api_backend { const uint8_t id; - const char *designation; - const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp" + const char * const designation; + const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp" const uint8_t nb_driver_names; - int (*init)(int sub_api, struct libusb_context *ctx); - int (*exit)(int sub_api); + int (*init)(struct libusb_context *ctx); + void (*exit)(void); int (*open)(int sub_api, struct libusb_device_handle *dev_handle); void (*close)(int sub_api, struct libusb_device_handle *dev_handle); int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, int iface); @@ -123,9 +118,16 @@ struct windows_usb_api_backend { extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX]; #define PRINT_UNSUPPORTED_API(fname) \ - usbi_dbg("unsupported API call for '" \ - #fname "' (unrecognized device driver)"); \ - return LIBUSB_ERROR_NOT_SUPPORTED; + usbi_dbg("unsupported API call for '%s' " \ + "(unrecognized device driver)", #fname) + +#define CHECK_SUPPORTED_API(apip, fname) \ + do { \ + if ((apip)->fname == NULL) { \ + PRINT_UNSUPPORTED_API(fname); \ + return LIBUSB_ERROR_NOT_SUPPORTED; \ + } \ + } while (0) /* * private structures definition @@ -154,15 +156,16 @@ struct libusb_hid_descriptor { #define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN) #define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type)) +#ifndef CTL_CODE +#define CTL_CODE(DeviceType, Function, Method, Access) \ + (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) +#endif + // The following are used for HID reports IOCTLs -#define HID_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS) -#define HID_BUFFER_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS) #define HID_IN_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS) + CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS) #define HID_OUT_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) #define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104) @@ -193,39 +196,20 @@ struct hid_device_priv { uint16_t input_report_size; uint16_t output_report_size; uint16_t feature_report_size; + uint16_t usage; + uint16_t usagePage; WCHAR string[3][MAX_USB_STRING_LENGTH]; uint8_t string_index[3]; // man, prod, ser }; -struct windows_device_priv { - uint8_t depth; // distance to HCD - uint8_t port; // port number on the hub - uint8_t active_config; - struct windows_usb_api_backend const *apib; - char *path; // device interface path - int sub_api; // for WinUSB-like APIs - struct { - char *path; // each interface needs a device interface path, - struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support), - int sub_api; - int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS) - uint8_t *endpoint; - bool restricted_functionality; // indicates if the interface functionality is restricted - // by Windows (eg. HID keyboards or mice cannot do R/W) - } usb_interface[USB_MAXINTERFACES]; - struct hid_device_priv *hid; - USB_DEVICE_DESCRIPTOR dev_descriptor; - unsigned char **config_descriptor; // list of pointers to the cached config descriptors -}; - -static inline struct windows_device_priv *_device_priv(struct libusb_device *dev) +static inline struct winusb_device_priv *_device_priv(struct libusb_device *dev) { - return (struct windows_device_priv *)dev->os_priv; + return (struct winusb_device_priv *)dev->os_priv; } -static inline struct windows_device_priv *windows_device_priv_init(struct libusb_device *dev) +static inline struct winusb_device_priv *winusb_device_priv_init(struct libusb_device *dev) { - struct windows_device_priv *p = _device_priv(dev); + struct winusb_device_priv *p = _device_priv(dev); int i; p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; @@ -238,11 +222,12 @@ static inline struct windows_device_priv *windows_device_priv_init(struct libusb return p; } -static inline void windows_device_priv_release(struct libusb_device *dev) +static inline void winusb_device_priv_release(struct libusb_device *dev) { - struct windows_device_priv *p = _device_priv(dev); + struct winusb_device_priv *p = _device_priv(dev); int i; + free(p->dev_id); free(p->path); if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { for (i = 0; i < dev->num_configurations; i++) @@ -256,32 +241,12 @@ static inline void windows_device_priv_release(struct libusb_device *dev) } } -struct interface_handle_t { - HANDLE dev_handle; // WinUSB needs an extra handle for the file - HANDLE api_handle; // used by the API to communicate with the device -}; - -struct windows_device_handle_priv { - int active_interface; - struct interface_handle_t interface_handle[USB_MAXINTERFACES]; - int autoclaim_count[USB_MAXINTERFACES]; // For auto-release -}; - -static inline struct windows_device_handle_priv *_device_handle_priv( +static inline struct winusb_device_handle_priv *_device_handle_priv( struct libusb_device_handle *handle) { - return (struct windows_device_handle_priv *)handle->os_priv; + return (struct winusb_device_handle_priv *)handle->os_priv; } -// used for async polling functions -struct windows_transfer_priv { - struct winfd pollable_fd; - uint8_t interface_number; - uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID - uint8_t *hid_dest; // transfer buffer destination, required for HID - size_t hid_expected_size; -}; - // used to match a device driver (including filter drivers) against a supported API struct driver_lookup { char list[MAX_KEY_LENGTH + 1]; // REG_MULTI_SZ list of services (driver) names @@ -289,34 +254,6 @@ struct driver_lookup { const char* designation; // internal designation (for debug output) }; -/* OLE32 dependency */ -DLL_DECLARE_HANDLE(OLE32); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID)); - -/* Kernel32 dependencies */ -DLL_DECLARE_HANDLE(Kernel32); -/* This call is only available from XP SP2 */ -DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL)); - -/* SetupAPI dependencies */ -DLL_DECLARE_HANDLE(SetupAPI); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, - const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, - PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, - PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD)); - -/* AdvAPI32 dependencies */ -DLL_DECLARE_HANDLE(AdvAPI32); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD)); -DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY)); - /* * Windows DDK API definitions. Most of it copied from MinGW's includes */ @@ -325,58 +262,64 @@ typedef DEVNODE *PDEVNODE, *PDEVINST; typedef DWORD RETURN_TYPE; typedef RETURN_TYPE CONFIGRET; -#define CR_SUCCESS 0x00000000 -#define CR_NO_SUCH_DEVNODE 0x0000000D +#define CR_SUCCESS 0x00000000 -#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE -#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG -#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING -#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE -#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT +/* Cfgmgr32 dependencies */ +DLL_DECLARE_HANDLE(Cfgmgr32); +DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); -#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS -#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE -#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE -#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS -#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR -#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR -#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION -#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION -#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE -#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE -#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME +/* AdvAPI32 dependencies */ +DLL_DECLARE_HANDLE(AdvAPI32); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY)); -#define USB_GET_NODE_INFORMATION 258 -#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 -#define USB_GET_NODE_CONNECTION_NAME 261 -#define USB_GET_HUB_CAPABILITIES 271 -#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX) -#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 +/* OLE32 dependency */ +DLL_DECLARE_HANDLE(OLE32); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, IIDFromString, (LPCOLESTR, LPIID)); + +/* SetupAPI dependencies */ +DLL_DECLARE_HANDLE(SetupAPI); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, + LPCGUID, DWORD, PSP_DEVICE_INTERFACE_DATA)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInstanceIdA, (HDEVINFO, PSP_DEVINFO_DATA, + PCSTR, DWORD, PDWORD)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, + PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, + PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM)); +DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD)); + + +#ifndef USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION +#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 #endif -#if !defined(USB_GET_HUB_CAPABILITIES_EX) -#define USB_GET_HUB_CAPABILITIES_EX 276 +#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX +#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 #endif -#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2) +#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 #define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279 #endif -#ifndef METHOD_BUFFERED -#define METHOD_BUFFERED 0 -#endif -#ifndef FILE_ANY_ACCESS -#define FILE_ANY_ACCESS 0x00000000 -#endif -#ifndef FILE_DEVICE_UNKNOWN -#define FILE_DEVICE_UNKNOWN 0x00000022 -#endif #ifndef FILE_DEVICE_USB -#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN +#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN #endif -#ifndef CTL_CODE -#define CTL_CODE(DeviceType, Function, Method, Access) \ - (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) -#endif +#define USB_CTL_CODE(id) \ + CTL_CODE(FILE_DEVICE_USB, (id), METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ + USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION) + +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ + USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX) + +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \ + USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2) typedef enum USB_CONNECTION_STATUS { NoDeviceConnected, @@ -395,42 +338,25 @@ typedef enum USB_HUB_NODE { UsbMIParent } USB_HUB_NODE; -/* Cfgmgr32.dll interface */ -DLL_DECLARE_HANDLE(Cfgmgr32); -DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); - -#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ - CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_HUB_CAPABILITIES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_ROOT_HUB_NAME \ - CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_INFORMATION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - // Most of the structures below need to be packed -#pragma pack(push, 1) +#include + +typedef struct _USB_DESCRIPTOR_REQUEST { + ULONG ConnectionIndex; + struct { + UCHAR bmRequest; + UCHAR bRequest; + USHORT wValue; + USHORT wIndex; + USHORT wLength; + } SetupPacket; +// UCHAR Data[0]; +} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; + +typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT { + USB_DESCRIPTOR_REQUEST req; + USB_CONFIGURATION_DESCRIPTOR desc; +} USB_CONFIGURATION_DESCRIPTOR_SHORT; typedef struct USB_INTERFACE_DESCRIPTOR { UCHAR bLength; @@ -444,103 +370,7 @@ typedef struct USB_INTERFACE_DESCRIPTOR { UCHAR iInterface; } USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; -typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT { - struct { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; - } req; - USB_CONFIGURATION_DESCRIPTOR data; -} USB_CONFIGURATION_DESCRIPTOR_SHORT; - -typedef struct USB_ENDPOINT_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bEndpointAddress; - UCHAR bmAttributes; - USHORT wMaxPacketSize; - UCHAR bInterval; -} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; - -typedef struct USB_DESCRIPTOR_REQUEST { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; -// UCHAR Data[0]; -} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - -typedef struct USB_HUB_DESCRIPTOR { - UCHAR bDescriptorLength; - UCHAR bDescriptorType; - UCHAR bNumberOfPorts; - USHORT wHubCharacteristics; - UCHAR bPowerOnToPowerGood; - UCHAR bHubControlCurrent; - UCHAR bRemoveAndPowerMask[64]; -} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; - -typedef struct USB_ROOT_HUB_NAME { - ULONG ActualLength; - WCHAR RootHubName[1]; -} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME; - -typedef struct USB_ROOT_HUB_NAME_FIXED { - ULONG ActualLength; - WCHAR RootHubName[MAX_PATH_LENGTH]; -} USB_ROOT_HUB_NAME_FIXED; - -typedef struct USB_NODE_CONNECTION_NAME { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[1]; -} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; - -typedef struct USB_NODE_CONNECTION_NAME_FIXED { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[MAX_PATH_LENGTH]; -} USB_NODE_CONNECTION_NAME_FIXED; - -typedef struct USB_HUB_NAME_FIXED { - union { - USB_ROOT_HUB_NAME_FIXED root; - USB_NODE_CONNECTION_NAME_FIXED node; - } u; -} USB_HUB_NAME_FIXED; - -typedef struct USB_HUB_INFORMATION { - USB_HUB_DESCRIPTOR HubDescriptor; - BOOLEAN HubIsBusPowered; -} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; - -typedef struct USB_MI_PARENT_INFORMATION { - ULONG NumberOfInterfaces; -} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; - -typedef struct USB_NODE_INFORMATION { - USB_HUB_NODE NodeType; - union { - USB_HUB_INFORMATION HubInformation; - USB_MI_PARENT_INFORMATION MiParentInformation; - } u; -} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; - -typedef struct USB_PIPE_INFO { - USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; - ULONG ScheduleOffset; -} USB_PIPE_INFO, *PUSB_PIPE_INFO; - -typedef struct USB_NODE_CONNECTION_INFORMATION_EX { +typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { ULONG ConnectionIndex; USB_DEVICE_DESCRIPTOR DeviceDescriptor; UCHAR CurrentConfigurationValue; @@ -578,25 +408,7 @@ typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 { USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags; } USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2; -typedef struct USB_HUB_CAP_FLAGS { - ULONG HubIsHighSpeedCapable:1; - ULONG HubIsHighSpeed:1; - ULONG HubIsMultiTtCapable:1; - ULONG HubIsMultiTt:1; - ULONG HubIsRoot:1; - ULONG HubIsArmedWakeOnConnect:1; - ULONG ReservedMBZ:26; -} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; - -typedef struct USB_HUB_CAPABILITIES { - ULONG HubIs2xCapable:1; -} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES; - -typedef struct USB_HUB_CAPABILITIES_EX { - USB_HUB_CAP_FLAGS CapabilityFlags; -} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; - -#pragma pack(pop) +#include /* winusb.dll interface */ @@ -608,36 +420,25 @@ typedef struct USB_HUB_CAPABILITIES_EX { #define AUTO_FLUSH 0x06 #define RAW_IO 0x07 #define MAXIMUM_TRANSFER_SIZE 0x08 -#define AUTO_SUSPEND 0x81 -#define SUSPEND_DELAY 0x83 -#define DEVICE_SPEED 0x01 -#define LowSpeed 0x01 -#define FullSpeed 0x02 -#define HighSpeed 0x03 -typedef enum USBD_PIPE_TYPE { +typedef enum _USBD_PIPE_TYPE { UsbdPipeTypeControl, UsbdPipeTypeIsochronous, UsbdPipeTypeBulk, UsbdPipeTypeInterrupt } USBD_PIPE_TYPE; -typedef struct { - USBD_PIPE_TYPE PipeType; - UCHAR PipeId; - USHORT MaximumPacketSize; - UCHAR Interval; -} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; +#include -#pragma pack(1) -typedef struct { - UCHAR request_type; - UCHAR request; - USHORT value; - USHORT index; - USHORT length; +typedef struct _WINUSB_SETUP_PACKET { + UCHAR RequestType; + UCHAR Request; + USHORT Value; + USHORT Index; + USHORT Length; } WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; -#pragma pack() + +#include typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; @@ -665,59 +466,10 @@ typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)( UCHAR AssociatedInterfaceIndex, PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle ); -typedef BOOL (WINAPI *WinUsb_GetCurrentAlternateSetting_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - PUCHAR AlternateSetting -); -typedef BOOL (WINAPI *WinUsb_GetDescriptor_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - UCHAR DescriptorType, - UCHAR Index, - USHORT LanguageID, - PUCHAR Buffer, - ULONG BufferLength, - PULONG LengthTransferred -); -typedef BOOL (WINAPI *WinUsb_GetOverlappedResult_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - LPOVERLAPPED lpOverlapped, - LPDWORD lpNumberOfBytesTransferred, - BOOL bWait -); -typedef BOOL (WINAPI *WinUsb_GetPipePolicy_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - UCHAR PipeID, - ULONG PolicyType, - PULONG ValueLength, - PVOID Value -); -typedef BOOL (WINAPI *WinUsb_GetPowerPolicy_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - ULONG PolicyType, - PULONG ValueLength, - PVOID Value -); typedef BOOL (WINAPI *WinUsb_Initialize_t)( HANDLE DeviceHandle, PWINUSB_INTERFACE_HANDLE InterfaceHandle ); -typedef BOOL (WINAPI *WinUsb_QueryDeviceInformation_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - ULONG InformationType, - PULONG BufferLength, - PVOID Buffer -); -typedef BOOL (WINAPI *WinUsb_QueryInterfaceSettings_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - UCHAR AlternateSettingNumber, - PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor -); -typedef BOOL (WINAPI *WinUsb_QueryPipe_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - UCHAR AlternateInterfaceNumber, - UCHAR PipeIndex, - PWINUSB_PIPE_INFORMATION PipeInformation -); typedef BOOL (WINAPI *WinUsb_ReadPipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, @@ -726,6 +478,9 @@ typedef BOOL (WINAPI *WinUsb_ReadPipe_t)( PULONG LengthTransferred, LPOVERLAPPED Overlapped ); +typedef BOOL (WINAPI *WinUsb_ResetDevice_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle +); typedef BOOL (WINAPI *WinUsb_ResetPipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID @@ -741,12 +496,6 @@ typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)( ULONG ValueLength, PVOID Value ); -typedef BOOL (WINAPI *WinUsb_SetPowerPolicy_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle, - ULONG PolicyType, - ULONG ValueLength, - PVOID Value -); typedef BOOL (WINAPI *WinUsb_WritePipe_t)( WINUSB_INTERFACE_HANDLE InterfaceHandle, UCHAR PipeID, @@ -755,9 +504,6 @@ typedef BOOL (WINAPI *WinUsb_WritePipe_t)( PULONG LengthTransferred, LPOVERLAPPED Overlapped ); -typedef BOOL (WINAPI *WinUsb_ResetDevice_t)( - WINUSB_INTERFACE_HANDLE InterfaceHandle -); /* /!\ These must match the ones from the official libusbk.h */ typedef enum _KUSB_FNID { @@ -803,8 +549,7 @@ typedef struct _KLIB_VERSION { INT Minor; INT Micro; INT Nano; -} KLIB_VERSION; -typedef KLIB_VERSION* PKLIB_VERSION; +} KLIB_VERSION, *PKLIB_VERSION; typedef BOOL (WINAPI *LibK_GetProcAddress_t)( PVOID *ProcAddress, @@ -816,29 +561,63 @@ typedef VOID (WINAPI *LibK_GetVersion_t)( PKLIB_VERSION Version ); +//KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths +typedef struct _KISO_PACKET { + UINT offset; + USHORT actual_length; //changed from libusbk_shared.h "Length" for clarity + USHORT status; +} KISO_PACKET, *PKISO_PACKET; + +typedef enum _KISO_FLAG { + KISO_FLAG_NONE = 0, + KISO_FLAG_SET_START_FRAME = 0x00000001, +} KISO_FLAG; + +//KISO_CONTEXT is the conceptual equivalent of libusb_transfer except is isochronous-specific and must match libusbk's version +typedef struct _KISO_CONTEXT { + KISO_FLAG Flags; + UINT StartFrame; + SHORT ErrorCount; + SHORT NumberOfPackets; + UINT UrbHdrStatus; + KISO_PACKET IsoPackets[0]; +} KISO_CONTEXT, *PKISO_CONTEXT; + +typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + LPOVERLAPPED Overlapped, + PKISO_CONTEXT IsoContext +); + +typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)( + WINUSB_INTERFACE_HANDLE InterfaceHandle, + UCHAR PipeID, + PUCHAR Buffer, + ULONG BufferLength, + LPOVERLAPPED Overlapped, + PKISO_CONTEXT IsoContext +); + struct winusb_interface { bool initialized; + bool CancelIoEx_supported; WinUsb_AbortPipe_t AbortPipe; WinUsb_ControlTransfer_t ControlTransfer; WinUsb_FlushPipe_t FlushPipe; WinUsb_Free_t Free; WinUsb_GetAssociatedInterface_t GetAssociatedInterface; - WinUsb_GetCurrentAlternateSetting_t GetCurrentAlternateSetting; - WinUsb_GetDescriptor_t GetDescriptor; - WinUsb_GetOverlappedResult_t GetOverlappedResult; - WinUsb_GetPipePolicy_t GetPipePolicy; - WinUsb_GetPowerPolicy_t GetPowerPolicy; WinUsb_Initialize_t Initialize; - WinUsb_QueryDeviceInformation_t QueryDeviceInformation; - WinUsb_QueryInterfaceSettings_t QueryInterfaceSettings; - WinUsb_QueryPipe_t QueryPipe; WinUsb_ReadPipe_t ReadPipe; + WinUsb_ResetDevice_t ResetDevice; WinUsb_ResetPipe_t ResetPipe; WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting; WinUsb_SetPipePolicy_t SetPipePolicy; - WinUsb_SetPowerPolicy_t SetPowerPolicy; WinUsb_WritePipe_t WritePipe; - WinUsb_ResetDevice_t ResetDevice; + WinUsb_IsoReadPipe_t IsoReadPipe; + WinUsb_IsoWritePipe_t IsoWritePipe; }; /* hid.dll interface */ @@ -846,34 +625,10 @@ struct winusb_interface { #define HIDP_STATUS_SUCCESS 0x110000 typedef void * PHIDP_PREPARSED_DATA; -#pragma pack(1) -typedef struct { - ULONG Size; - USHORT VendorID; - USHORT ProductID; - USHORT VersionNumber; -} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; -#pragma pack() +#include +#include typedef USHORT USAGE; -typedef struct { - USAGE Usage; - USAGE UsagePage; - USHORT InputReportByteLength; - USHORT OutputReportByteLength; - USHORT FeatureReportByteLength; - USHORT Reserved[17]; - USHORT NumberLinkCollectionNodes; - USHORT NumberInputButtonCaps; - USHORT NumberInputValueCaps; - USHORT NumberInputDataIndices; - USHORT NumberOutputButtonCaps; - USHORT NumberOutputValueCaps; - USHORT NumberOutputDataIndices; - USHORT NumberFeatureButtonCaps; - USHORT NumberFeatureValueCaps; - USHORT NumberFeatureDataIndices; -} HIDP_CAPS, *PHIDP_CAPS; typedef enum _HIDP_REPORT_TYPE { HidP_Input, @@ -919,19 +674,7 @@ typedef struct _HIDP_VALUE_CAPS { } HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; DLL_DECLARE_HANDLE(hid); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES)); DLL_DECLARE_FUNC(WINAPI, VOID, HidD_GetHidGuid, (LPGUID)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG)); -DLL_DECLARE_FUNC(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG)); DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG)); DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE)); -DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); \ No newline at end of file +DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/strerror.c b/vendor/github.com/karalabe/usb/libusb/libusb/strerror.c similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/strerror.c rename to vendor/github.com/karalabe/usb/libusb/libusb/strerror.c diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/sync.c b/vendor/github.com/karalabe/usb/libusb/libusb/sync.c similarity index 100% rename from vendor/github.com/karalabe/hid/libusb/libusb/sync.c rename to vendor/github.com/karalabe/usb/libusb/libusb/sync.c diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/version.h b/vendor/github.com/karalabe/usb/libusb/libusb/version.h similarity index 94% rename from vendor/github.com/karalabe/hid/libusb/libusb/version.h rename to vendor/github.com/karalabe/usb/libusb/libusb/version.h index 6ce48a7d01..c6dfe37093 100644 --- a/vendor/github.com/karalabe/hid/libusb/libusb/version.h +++ b/vendor/github.com/karalabe/usb/libusb/libusb/version.h @@ -7,7 +7,7 @@ #define LIBUSB_MINOR 0 #endif #ifndef LIBUSB_MICRO -#define LIBUSB_MICRO 21 +#define LIBUSB_MICRO 22 #endif #ifndef LIBUSB_NANO #define LIBUSB_NANO 0 diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h b/vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h new file mode 100644 index 0000000000..90a782a6bf --- /dev/null +++ b/vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h @@ -0,0 +1 @@ +#define LIBUSB_NANO 11312 diff --git a/vendor/github.com/karalabe/usb/raw_disabled.go b/vendor/github.com/karalabe/usb/raw_disabled.go new file mode 100644 index 0000000000..a05ef8ebb2 --- /dev/null +++ b/vendor/github.com/karalabe/usb/raw_disabled.go @@ -0,0 +1,42 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2017 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build !freebsd,!linux,!darwin,!windows ios !cgo + +package usb + +// RawDevice is a live raw USB connected device handle. On platforms that this file +// implements, the type lacks the actual USB device and all methods are noop. +type RawDevice struct { + DeviceInfo // Embed the infos for easier access +} + +// Close releases the USB device handle. On platforms that this file implements, +// the method is just a noop. +func (dev *RawDevice) Close() error { + return ErrUnsupportedPlatform +} + +// Write sends a binary blob to a USB device. On platforms that this file +// implements, the method just returns an error. +func (dev *RawDevice) Write(b []byte) (int, error) { + return 0, ErrUnsupportedPlatform +} + +// Read retrieves a binary blob from a USB device. On platforms that this file +// implements, the method just returns an error. +func (dev *RawDevice) Read(b []byte) (int, error) { + return 0, ErrUnsupportedPlatform +} diff --git a/vendor/github.com/karalabe/usb/raw_enabled.go b/vendor/github.com/karalabe/usb/raw_enabled.go new file mode 100644 index 0000000000..326ac97add --- /dev/null +++ b/vendor/github.com/karalabe/usb/raw_enabled.go @@ -0,0 +1,253 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2019 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo + +package usb + +/* + #include "./libusb/libusb/libusb.h" + + // ctx is a global libusb context to interact with devices through. + libusb_context* ctx; +*/ +import "C" + +import ( + "fmt" + "reflect" + "sync" + "unsafe" +) + +// enumerateRaw returns a list of all the USB devices attached to the system which +// match the vendor and product id: +// - If the vendor id is set to 0 then any vendor matches. +// - If the product id is set to 0 then any product matches. +// - If the vendor and product id are both 0, all USB devices are returned. +func enumerateRaw(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + // Enumerate the devices, and free all the matching refcounts (we'll reopen any + // explicitly requested). + infos, err := enumerateRawWithRef(vendorID, productID) + for _, info := range infos { + C.libusb_unref_device(info.rawDevice.(*C.libusb_device)) + } + // If enumeration failed, don't return anything, otherwise everything + if err != nil { + return nil, err + } + return infos, nil +} + +// enumerateRawWithRef is the internal device enumerator that retains 1 reference +// to every matched device so they may selectively be opened on request. +func enumerateRawWithRef(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + // Ensure we have a libusb context to interact through. The enumerate call is + // protexted by a mutex outside, so it's fine to do the below check and init. + if C.ctx == nil { + if err := fromRawErrno(C.libusb_init((**C.libusb_context)(&C.ctx))); err != nil { + return nil, fmt.Errorf("failed to initialize libusb: %v", err) + } + } + // Retrieve all the available USB devices and wrap them in Go + var deviceList **C.libusb_device + count := C.libusb_get_device_list(C.ctx, &deviceList) + if count < 0 { + return nil, rawError(count) + } + defer C.libusb_free_device_list(deviceList, 1) + + var devices []*C.libusb_device + *(*reflect.SliceHeader)(unsafe.Pointer(&devices)) = reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(deviceList)), + Len: int(count), + Cap: int(count), + } + // + var infos []DeviceInfo + for devnum, dev := range devices { + // Retrieve the libusb device descriptor and skip non-queried ones + var desc C.struct_libusb_device_descriptor + if err := fromRawErrno(C.libusb_get_device_descriptor(dev, &desc)); err != nil { + return infos, fmt.Errorf("failed to get device %d descriptor: %v", devnum, err) + } + if (vendorID > 0 && uint16(desc.idVendor) != vendorID) || (productID > 0 && uint16(desc.idProduct) != productID) { + continue + } + // Skip HID devices, they are handled directly by OS libraries + if desc.bDeviceClass == C.LIBUSB_CLASS_HID { + continue + } + // Iterate over all the configurations and find raw interfaces + for cfgnum := 0; cfgnum < int(desc.bNumConfigurations); cfgnum++ { + // Retrieve the all the possible USB configurations of the device + var cfg *C.struct_libusb_config_descriptor + if err := fromRawErrno(C.libusb_get_config_descriptor(dev, C.uint8_t(cfgnum), &cfg)); err != nil { + return infos, fmt.Errorf("failed to get device %d config %d: %v", devnum, cfgnum, err) + } + var ifaces []C.struct_libusb_interface + *(*reflect.SliceHeader)(unsafe.Pointer(&ifaces)) = reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(cfg._interface)), + Len: int(cfg.bNumInterfaces), + Cap: int(cfg.bNumInterfaces), + } + // Drill down into each advertised interface + for ifacenum, iface := range ifaces { + if iface.num_altsetting == 0 { + continue + } + var alts []C.struct_libusb_interface_descriptor + *(*reflect.SliceHeader)(unsafe.Pointer(&alts)) = reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(iface.altsetting)), + Len: int(iface.num_altsetting), + Cap: int(iface.num_altsetting), + } + for _, alt := range alts { + // Skip HID interfaces, they are handled directly by OS libraries + if alt.bInterfaceClass == C.LIBUSB_CLASS_HID { + continue + } + // Find the endpoints that can speak libusb interrupts + var ends []C.struct_libusb_endpoint_descriptor + *(*reflect.SliceHeader)(unsafe.Pointer(&ends)) = reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(alt.endpoint)), + Len: int(alt.bNumEndpoints), + Cap: int(alt.bNumEndpoints), + } + var reader, writer *uint8 + for _, end := range ends { + // Skip any non-interrupt endpoints + if end.bmAttributes != C.LIBUSB_TRANSFER_TYPE_INTERRUPT { + continue + } + if end.bEndpointAddress&C.LIBUSB_ENDPOINT_IN == C.LIBUSB_ENDPOINT_IN { + reader = new(uint8) + *reader = uint8(end.bEndpointAddress) + } else { + writer = new(uint8) + *writer = uint8(end.bEndpointAddress) + } + } + // If both in and out interrupts are available, match the device + if reader != nil && writer != nil { + // Enumeration matched, bump the device refcount to avoid cleaning it up + C.libusb_ref_device(dev) + + port := uint8(C.libusb_get_port_number(dev)) + infos = append(infos, DeviceInfo{ + Path: fmt.Sprintf("%04x:%04x:%02d", vendorID, uint16(desc.idProduct), port), + VendorID: uint16(desc.idVendor), + ProductID: uint16(desc.idProduct), + Interface: ifacenum, + rawDevice: dev, + rawPort: &port, + rawReader: reader, + rawWriter: writer, + }) + } + } + } + } + } + return infos, nil +} + +// openRaw connects to a low level libusb device by its path name. +func openRaw(info DeviceInfo) (*rawDevice, error) { + // Enumerate all the devices matching this particular info + matches, err := enumerateRawWithRef(info.VendorID, info.ProductID) + if err != nil { + // Enumeration failed, make sure any subresults are released + for _, match := range matches { + C.libusb_unref_device(match.rawDevice.(*C.libusb_device)) + } + return nil, err + } + // Find the specific endpoint we're interested in + var device *C.libusb_device + for _, match := range matches { + // Keep the matching device reference, release anything else + if device == nil && *match.rawPort == *info.rawPort && match.Interface == info.Interface { + device = match.rawDevice.(*C.libusb_device) + } else { + C.libusb_unref_device(match.rawDevice.(*C.libusb_device)) + } + } + if device == nil { + return nil, fmt.Errorf("failed to open device: not found") + } + // Open the mathcing device + info.rawDevice = device + + var handle *C.struct_libusb_device_handle + if err := fromRawErrno(C.libusb_open(info.rawDevice.(*C.libusb_device), (**C.struct_libusb_device_handle)(&handle))); err != nil { + return nil, fmt.Errorf("failed to open device: %v", err) + } + if err := fromRawErrno(C.libusb_claim_interface(handle, (C.int)(info.Interface))); err != nil { + C.libusb_close(handle) + return nil, fmt.Errorf("failed to claim interface: %v", err) + } + return &rawDevice{ + DeviceInfo: info, + handle: handle, + }, nil +} + +// rawDevice is a live low level USB connected device handle. +type rawDevice struct { + DeviceInfo // Embed the infos for easier access + + handle *C.struct_libusb_device_handle // Low level USB device to communicate through + lock sync.Mutex +} + +// Close releases the raw USB device handle. +func (dev *rawDevice) Close() error { + dev.lock.Lock() + defer dev.lock.Unlock() + + if dev.handle != nil { + C.libusb_release_interface(dev.handle, (C.int)(dev.Interface)) + C.libusb_close(dev.handle) + dev.handle = nil + } + C.libusb_unref_device(dev.rawDevice.(*C.libusb_device)) + + return nil +} + +// Write sends a binary blob to a low level USB device. +func (dev *rawDevice) Write(b []byte) (int, error) { + dev.lock.Lock() + defer dev.lock.Unlock() + + var transferred C.int + if err := fromRawErrno(C.libusb_interrupt_transfer(dev.handle, (C.uchar)(*dev.rawWriter), (*C.uchar)(&b[0]), (C.int)(len(b)), &transferred, (C.uint)(0))); err != nil { + return 0, fmt.Errorf("failed to write to device: %v", err) + } + return int(transferred), nil +} + +// Read retrieves a binary blob from a low level USB device. +func (dev *rawDevice) Read(b []byte) (int, error) { + dev.lock.Lock() + defer dev.lock.Unlock() + + var transferred C.int + if err := fromRawErrno(C.libusb_interrupt_transfer(dev.handle, (C.uchar)(*dev.rawReader), (*C.uchar)(&b[0]), (C.int)(len(b)), &transferred, (C.uint)(0))); err != nil { + return 0, fmt.Errorf("failed to read from device: %v", err) + } + return int(transferred), nil +} diff --git a/vendor/github.com/karalabe/usb/raw_errors.go b/vendor/github.com/karalabe/usb/raw_errors.go new file mode 100644 index 0000000000..9e071f861f --- /dev/null +++ b/vendor/github.com/karalabe/usb/raw_errors.go @@ -0,0 +1,74 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Copyright 2016 the gousb Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package usb + +import ( + "fmt" +) + +// #include "./libusb/libusb/libusb.h" +import "C" + +// rawError is an error code from libusb. +type rawError C.int + +// Error implements the error interface. +func (e rawError) Error() string { + return fmt.Sprintf("libusb: %s [code %d]", rawErrorString[e], e) +} + +// fromRawErrno converts a raw libusb error into a Go type. +func fromRawErrno(errno C.int) error { + err := rawError(errno) + if err == errSuccess { + return nil + } + return err +} + +const ( + errSuccess rawError = C.LIBUSB_SUCCESS + errIO rawError = C.LIBUSB_ERROR_IO + errInvalidParam rawError = C.LIBUSB_ERROR_INVALID_PARAM + errAccess rawError = C.LIBUSB_ERROR_ACCESS + errNoDevice rawError = C.LIBUSB_ERROR_NO_DEVICE + errNotFound rawError = C.LIBUSB_ERROR_NOT_FOUND + errBusy rawError = C.LIBUSB_ERROR_BUSY + errTimeout rawError = C.LIBUSB_ERROR_TIMEOUT + errOverflow rawError = C.LIBUSB_ERROR_OVERFLOW + errPipe rawError = C.LIBUSB_ERROR_PIPE + errInterrupted rawError = C.LIBUSB_ERROR_INTERRUPTED + errNoMem rawError = C.LIBUSB_ERROR_NO_MEM + errNotSupported rawError = C.LIBUSB_ERROR_NOT_SUPPORTED + errOther rawError = C.LIBUSB_ERROR_OTHER +) + +var rawErrorString = map[rawError]string{ + errSuccess: "success", + errIO: "i/o error", + errInvalidParam: "invalid param", + errAccess: "bad access", + errNoDevice: "no device", + errNotFound: "not found", + errBusy: "device or resource busy", + errTimeout: "timeout", + errOverflow: "overflow", + errPipe: "pipe error", + errInterrupted: "interrupted", + errNoMem: "out of memory", + errNotSupported: "not supported", + errOther: "unknown error", +} diff --git a/vendor/github.com/karalabe/usb/usb.go b/vendor/github.com/karalabe/usb/usb.go new file mode 100644 index 0000000000..96a1e2502c --- /dev/null +++ b/vendor/github.com/karalabe/usb/usb.go @@ -0,0 +1,68 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2019 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// Package usb provide interfaces for generic USB devices. +package usb + +import "errors" + +// ErrDeviceClosed is returned for operations where the device closed before or +// during the execution. +var ErrDeviceClosed = errors.New("usb: device closed") + +// ErrUnsupportedPlatform is returned for all operations where the underlying +// operating system is not supported by the library. +var ErrUnsupportedPlatform = errors.New("usb: unsupported platform") + +// DeviceInfo contains all the information we know about a USB device. In case of +// HID devices, that might be a lot more extensive (empty fields for raw USB). +type DeviceInfo struct { + Path string // Platform-specific device path + VendorID uint16 // Device Vendor ID + ProductID uint16 // Device Product ID + Release uint16 // Device Release Number in binary-coded decimal, also known as Device Version Number + Serial string // Serial Number + Manufacturer string // Manufacturer String + Product string // Product string + UsagePage uint16 // Usage Page for this Device/Interface (Windows/Mac only) + Usage uint16 // Usage for this Device/Interface (Windows/Mac only) + + // The USB interface which this logical device + // represents. Valid on both Linux implementations + // in all cases, and valid on the Windows implementation + // only if the device contains more than one interface. + Interface int + + // Raw low level libusb endpoint data for simplified communication + rawDevice interface{} + rawPort *uint8 // Pointer to differentiate between unset and port 0 + rawReader *uint8 // Pointer to differentiate between unset and endpoint 0 + rawWriter *uint8 // Pointer to differentiate between unset and endpoint 0 +} + +// Device is a generic USB device interface. It may either be backed by a USB HID +// device or a low level raw (libusb) device. +type Device interface { + // Close releases the USB device handle. + Close() error + + // Write sends a binary blob to a USB device. For HID devices write uses reports, + // for low level USB write uses interrupt transfers. + Write(b []byte) (int, error) + + // Read retrieves a binary blob from a USB device. For HID devices read uses + // reports, for low level USB read uses interrupt transfers. + Read(b []byte) (int, error) +} diff --git a/vendor/github.com/karalabe/usb/usb_disabled.go b/vendor/github.com/karalabe/usb/usb_disabled.go new file mode 100644 index 0000000000..39259856ee --- /dev/null +++ b/vendor/github.com/karalabe/usb/usb_disabled.go @@ -0,0 +1,46 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2019 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build !freebsd,!linux,!darwin,!windows ios !cgo + +package usb + +// Supported returns whether this platform is supported by the USB library or not. +// The goal of this method is to allow programatically handling platforms that do +// not support USB and not having to fall back to build constraints. +func Supported() bool { + return false +} + +// Enumerate returns a list of all the USB devices attached to the system which +// match the vendor and product id. On platforms that this file implements the +// function is a noop and returns an empty list always. +func Enumerate(vendorID uint16, productID uint16) []DeviceInfo { + return nil +} + +// EnumerateRaw returns a list of all the USB devices attached to the system which +// match the vendor and product id. On platforms that this file implements the +// function is a noop and returns an empty list always. +func EnumerateRaw(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + return nil +} + +// EnumerateHid returns a list of all the HID devices attached to the system which +// match the vendor and product id. On platforms that this file implements the +// function is a noop and returns an empty list always. +func EnumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + return nil +} diff --git a/vendor/github.com/karalabe/usb/usb_enabled.go b/vendor/github.com/karalabe/usb/usb_enabled.go new file mode 100644 index 0000000000..6ba37af7be --- /dev/null +++ b/vendor/github.com/karalabe/usb/usb_enabled.go @@ -0,0 +1,98 @@ +// usb - Self contained USB and HID library for Go +// Copyright 2019 The library Authors +// +// This library is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// The library is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with the library. If not, see . + +// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo + +package usb + +import ( + "sync" +) + +// enumerateLock is a mutex serializing access to USB device enumeration needed +// by the macOS USB HID system calls, which require 2 consecutive method calls +// for enumeration, causing crashes if called concurrently. +// +// For more details, see: +// https://developer.apple.com/documentation/iokit/1438371-iohidmanagersetdevicematching +// > "subsequent calls will cause the hid manager to release previously enumerated devices" +var enumerateLock sync.Mutex + +// Supported returns whether this platform is supported by the USB library or not. +// The goal of this method is to allow programatically handling platforms that do +// not support USB and not having to fall back to build constraints. +func Supported() bool { + return true +} + +// Enumerate returns a list of all the USB devices attached to the system which +// match the vendor and product id: +// - If the vendor id is set to 0 then any vendor matches. +// - If the product id is set to 0 then any product matches. +// - If the vendor and product id are both 0, all devices are returned. +// +// For any device that is HID capable, the enumeration will return an interface +// to the HID endpoints. For pure raw USB access, please use EnumerateRaw. +func Enumerate(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + enumerateLock.Lock() + defer enumerateLock.Unlock() + + // Enumerate all the raw USB devices and skip the HID ones + raws, err := enumerateRaw(vendorID, productID) + if err != nil { + return nil, err + } + // Enumerate all the HID USB devices + hids, err := enumerateHid(vendorID, productID) + if err != nil { + return nil, err + } + return append(raws, hids...), nil +} + +// EnumerateRaw returns a list of all the USB devices attached to the system which +// match the vendor and product id: +// - If the vendor id is set to 0 then any vendor matches. +// - If the product id is set to 0 then any product matches. +// - If the vendor and product id are both 0, all devices are returned. +func EnumerateRaw(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + enumerateLock.Lock() + defer enumerateLock.Unlock() + + return enumerateRaw(vendorID, productID) +} + +// EnumerateHid returns a list of all the HID devices attached to the system which +// match the vendor and product id: +// - If the vendor id is set to 0 then any vendor matches. +// - If the product id is set to 0 then any product matches. +// - If the vendor and product id are both 0, all devices are returned. +func EnumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + enumerateLock.Lock() + defer enumerateLock.Unlock() + + return enumerateHid(vendorID, productID) +} + +// Open connects to a previsouly discovered USB device. +func (info DeviceInfo) Open() (Device, error) { + enumerateLock.Lock() + defer enumerateLock.Unlock() + + if info.rawDevice == nil { + return openHid(info) + } + return openRaw(info) +} diff --git a/vendor/github.com/karalabe/hid/wchar.go b/vendor/github.com/karalabe/usb/wchar.go similarity index 99% rename from vendor/github.com/karalabe/hid/wchar.go rename to vendor/github.com/karalabe/usb/wchar.go index 640550dedb..cbc7e4d569 100644 --- a/vendor/github.com/karalabe/hid/wchar.go +++ b/vendor/github.com/karalabe/usb/wchar.go @@ -9,7 +9,7 @@ // +build !ios // +build freebsd linux darwin windows -package hid +package usb /* #include diff --git a/vendor/vendor.json b/vendor/vendor.json index 6fd5e58b27..6e16243068 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -267,10 +267,10 @@ "revisionTime": "2017-04-30T22:20:11Z" }, { - "checksumSHA1": "p6UjFsx/1ACWAhsdEOWrXAHptGY=", - "path": "github.com/karalabe/hid", - "revision": "e40407cce1c217644c09da5415bbfb07d330ea5e", - "revisionTime": "2019-05-28T15:16:06Z", + "checksumSHA1": "3v8Z4/daUVp9PCcFzEGYVkPadG8=", + "path": "github.com/karalabe/usb", + "revision": "c012609e094b8a96375fee53cc11f1bcd5cf3aa2", + "revisionTime": "2019-06-04T10:57:36Z", "tree": true }, { From d97f0372b19c0d58261c8f357ddc27cb3265b5a4 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Tue, 4 Jun 2019 17:40:34 +0200 Subject: [PATCH 33/47] accounts/scwallet: don't error when pcsc socket is missing (#19662) * scwallet: don't error when pcsc socket is missing * review feedback * more review feedback --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 7e19ebc0cb..7e84639257 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1161,7 +1161,7 @@ func setSmartCard(ctx *cli.Context, cfg *node.Config) { // Sanity check that the smartcard path is valid fi, err := os.Stat(path) if err != nil { - log.Error("Failed to verify smartcard daemon path", "path", path, "err", err) + log.Info("Smartcard socket not found, disabling", err", err) return } if fi.Mode()&os.ModeType != os.ModeSocket { From 645756cda5becf364ec9442891e9b7a7945e2cb3 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 4 Jun 2019 21:17:12 +0200 Subject: [PATCH 34/47] cmd/utils: close quote (#19665) --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 7e84639257..002d37f164 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1161,7 +1161,7 @@ func setSmartCard(ctx *cli.Context, cfg *node.Config) { // Sanity check that the smartcard path is valid fi, err := os.Stat(path) if err != nil { - log.Info("Smartcard socket not found, disabling", err", err) + log.Info("Smartcard socket not found, disabling", "err", err) return } if fi.Mode()&os.ModeType != os.ModeSocket { From 7641bbe5354bcbcd17c3aa154cf3a2d9a8ef0e89 Mon Sep 17 00:00:00 2001 From: gary rong Date: Wed, 5 Jun 2019 20:00:46 +0800 Subject: [PATCH 35/47] eth/downloader: make syncing error more obvious (#19413) --- eth/downloader/downloader.go | 69 +++++++++++++++---------------- eth/downloader/downloader_test.go | 6 --- eth/downloader/statesync.go | 12 +++++- 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 321c4473b6..874e6e07f6 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -83,16 +83,11 @@ var ( errPeersUnavailable = errors.New("no peers available or all tried for download") errInvalidAncestor = errors.New("retrieved ancestor is invalid") errInvalidChain = errors.New("retrieved hash chain is invalid") - errInvalidBlock = errors.New("retrieved block is invalid") errInvalidBody = errors.New("retrieved block body is invalid") errInvalidReceipt = errors.New("retrieved receipt is invalid") - errCancelBlockFetch = errors.New("block download canceled (requested)") - errCancelHeaderFetch = errors.New("block header download canceled (requested)") - errCancelBodyFetch = errors.New("block body download canceled (requested)") - errCancelReceiptFetch = errors.New("receipt download canceled (requested)") errCancelStateFetch = errors.New("state data download canceled (requested)") - errCancelHeaderProcessing = errors.New("header processing canceled (requested)") errCancelContentProcessing = errors.New("content processing canceled (requested)") + errCanceled = errors.New("syncing canceled (requested)") errNoSyncActive = errors.New("no sync active") errTooOld = errors.New("peer doesn't speak recent enough protocol version (need version >= 62)") ) @@ -319,14 +314,6 @@ func (d *Downloader) UnregisterPeer(id string) error { } d.queue.Revoke(id) - // If this peer was the master peer, abort sync immediately - d.cancelLock.RLock() - master := id == d.cancelPeer - d.cancelLock.RUnlock() - - if master { - d.cancel() - } return nil } @@ -336,7 +323,7 @@ func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode err := d.synchronise(id, head, td, mode) switch err { case nil: - case errBusy: + case errBusy, errCanceled: case errTimeout, errBadPeer, errStallingPeer, errUnsyncedPeer, errEmptyHeaderSet, errPeersUnavailable, errTooOld, @@ -555,7 +542,7 @@ func (d *Downloader) spawnSync(fetchers []func() error) error { // it has processed the queue. d.queue.Close() } - if err = <-errc; err != nil { + if err = <-errc; err != nil && err != errCanceled { break } } @@ -621,7 +608,7 @@ func (d *Downloader) fetchHeight(p *peerConnection) (*types.Header, error) { for { select { case <-d.cancelCh: - return nil, errCancelBlockFetch + return nil, errCanceled case packet := <-d.headerCh: // Discard anything not from the origin peer @@ -767,7 +754,7 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) for finished := false; !finished; { select { case <-d.cancelCh: - return 0, errCancelHeaderFetch + return 0, errCanceled case packet := <-d.headerCh: // Discard anything not from the origin peer @@ -853,7 +840,7 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) for arrived := false; !arrived; { select { case <-d.cancelCh: - return 0, errCancelHeaderFetch + return 0, errCanceled case packer := <-d.headerCh: // Discard anything not from the origin peer @@ -954,7 +941,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64) for { select { case <-d.cancelCh: - return errCancelHeaderFetch + return errCanceled case packet := <-d.headerCh: // Make sure the active peer is giving us the skeleton headers @@ -981,7 +968,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64) getHeaders(from) continue case <-d.cancelCh: - return errCancelHeaderFetch + return errCanceled } } // Pivot done (or not in fast sync) and no more headers, terminate the process @@ -990,7 +977,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64) case d.headerProcCh <- nil: return nil case <-d.cancelCh: - return errCancelHeaderFetch + return errCanceled } } headers := packet.(*headerPack).headers @@ -1041,7 +1028,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64) select { case d.headerProcCh <- headers: case <-d.cancelCh: - return errCancelHeaderFetch + return errCanceled } from += uint64(len(headers)) getHeaders(from) @@ -1053,7 +1040,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64) getHeaders(from) continue case <-d.cancelCh: - return errCancelHeaderFetch + return errCanceled } } @@ -1112,7 +1099,7 @@ func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) ( capacity = func(p *peerConnection) int { return p.HeaderCapacity(d.requestRTT()) } setIdle = func(p *peerConnection, accepted int) { p.SetHeadersIdle(accepted) } ) - err := d.fetchParts(errCancelHeaderFetch, d.headerCh, deliver, d.queue.headerContCh, expire, + err := d.fetchParts(d.headerCh, deliver, d.queue.headerContCh, expire, d.queue.PendingHeaders, d.queue.InFlightHeaders, throttle, reserve, nil, fetch, d.queue.CancelHeaders, capacity, d.peers.HeaderIdlePeers, setIdle, "headers") @@ -1138,7 +1125,7 @@ func (d *Downloader) fetchBodies(from uint64) error { capacity = func(p *peerConnection) int { return p.BlockCapacity(d.requestRTT()) } setIdle = func(p *peerConnection, accepted int) { p.SetBodiesIdle(accepted) } ) - err := d.fetchParts(errCancelBodyFetch, d.bodyCh, deliver, d.bodyWakeCh, expire, + err := d.fetchParts(d.bodyCh, deliver, d.bodyWakeCh, expire, d.queue.PendingBlocks, d.queue.InFlightBlocks, d.queue.ShouldThrottleBlocks, d.queue.ReserveBodies, d.bodyFetchHook, fetch, d.queue.CancelBodies, capacity, d.peers.BodyIdlePeers, setIdle, "bodies") @@ -1162,7 +1149,7 @@ func (d *Downloader) fetchReceipts(from uint64) error { capacity = func(p *peerConnection) int { return p.ReceiptCapacity(d.requestRTT()) } setIdle = func(p *peerConnection, accepted int) { p.SetReceiptsIdle(accepted) } ) - err := d.fetchParts(errCancelReceiptFetch, d.receiptCh, deliver, d.receiptWakeCh, expire, + err := d.fetchParts(d.receiptCh, deliver, d.receiptWakeCh, expire, d.queue.PendingReceipts, d.queue.InFlightReceipts, d.queue.ShouldThrottleReceipts, d.queue.ReserveReceipts, d.receiptFetchHook, fetch, d.queue.CancelReceipts, capacity, d.peers.ReceiptIdlePeers, setIdle, "receipts") @@ -1195,7 +1182,7 @@ func (d *Downloader) fetchReceipts(from uint64) error { // - idle: network callback to retrieve the currently (type specific) idle peers that can be assigned tasks // - setIdle: network callback to set a peer back to idle and update its estimated capacity (traffic shaping) // - kind: textual label of the type being downloaded to display in log mesages -func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliver func(dataPack) (int, error), wakeCh chan bool, +func (d *Downloader) fetchParts(deliveryCh chan dataPack, deliver func(dataPack) (int, error), wakeCh chan bool, expire func() map[string]int, pending func() int, inFlight func() bool, throttle func() bool, reserve func(*peerConnection, int) (*fetchRequest, bool, error), fetchHook func([]*types.Header), fetch func(*peerConnection, *fetchRequest) error, cancel func(*fetchRequest), capacity func(*peerConnection) int, idle func() ([]*peerConnection, int), setIdle func(*peerConnection, int), kind string) error { @@ -1211,7 +1198,7 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv for { select { case <-d.cancelCh: - return errCancel + return errCanceled case packet := <-deliveryCh: // If the peer was previously banned and failed to deliver its pack @@ -1282,12 +1269,23 @@ func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliv setIdle(peer, 0) } else { peer.log.Debug("Stalling delivery, dropping", "type", kind) + if d.dropPeer == nil { // The dropPeer method is nil when `--copydb` is used for a local copy. // Timeouts can occur if e.g. compaction hits at the wrong time, and can be ignored peer.log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", pid) } else { d.dropPeer(pid) + + // If this peer was the master peer, abort sync immediately + d.cancelLock.RLock() + master := pid == d.cancelPeer + d.cancelLock.RUnlock() + + if master { + d.cancel() + return errTimeout + } } } } @@ -1392,7 +1390,7 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er for { select { case <-d.cancelCh: - return errCancelHeaderProcessing + return errCanceled case headers := <-d.headerProcCh: // Terminate header processing if we synced up @@ -1445,7 +1443,7 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er // Terminate if something failed in between processing chunks select { case <-d.cancelCh: - return errCancelHeaderProcessing + return errCanceled default: } // Select the next chunk of headers to import @@ -1488,7 +1486,7 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er for d.queue.PendingBlocks() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { select { case <-d.cancelCh: - return errCancelHeaderProcessing + return errCanceled case <-time.After(time.Second): } } @@ -1579,7 +1577,7 @@ func (d *Downloader) processFastSyncContent(latest *types.Header) error { stateSync := d.syncState(latest.Root) defer stateSync.Cancel() go func() { - if err := stateSync.Wait(); err != nil && err != errCancelStateFetch { + if err := stateSync.Wait(); err != nil && err != errCancelStateFetch && err != errCanceled { d.queue.Close() // wake up Results } }() @@ -1607,7 +1605,8 @@ func (d *Downloader) processFastSyncContent(latest *types.Header) error { // If sync failed, stop select { case <-d.cancelCh: - return stateSync.Cancel() + stateSync.Cancel() + return errCanceled default: } } @@ -1637,7 +1636,7 @@ func (d *Downloader) processFastSyncContent(latest *types.Header) error { stateSync = d.syncState(P.Header.Root) defer stateSync.Cancel() go func() { - if err := stateSync.Wait(); err != nil && err != errCancelStateFetch { + if err := stateSync.Wait(); err != nil && err != errCancelStateFetch && err != errCanceled { d.queue.Close() // wake up Results } }() diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 5b56ff161a..e1f0e03fcd 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -1114,14 +1114,8 @@ func testBlockHeaderAttackerDropping(t *testing.T, protocol int) { {errPeersUnavailable, true}, // Nobody had the advertised blocks, drop the advertiser {errInvalidAncestor, true}, // Agreed upon ancestor is not acceptable, drop the chain rewriter {errInvalidChain, true}, // Hash chain was detected as invalid, definitely drop - {errInvalidBlock, false}, // A bad peer was detected, but not the sync origin {errInvalidBody, false}, // A bad peer was detected, but not the sync origin {errInvalidReceipt, false}, // A bad peer was detected, but not the sync origin - {errCancelBlockFetch, false}, // Synchronisation was canceled, origin may be innocent, don't drop - {errCancelHeaderFetch, false}, // Synchronisation was canceled, origin may be innocent, don't drop - {errCancelBodyFetch, false}, // Synchronisation was canceled, origin may be innocent, don't drop - {errCancelReceiptFetch, false}, // Synchronisation was canceled, origin may be innocent, don't drop - {errCancelHeaderProcessing, false}, // Synchronisation was canceled, origin may be innocent, don't drop {errCancelContentProcessing, false}, // Synchronisation was canceled, origin may be innocent, don't drop } // Run the tests and check disconnection status diff --git a/eth/downloader/statesync.go b/eth/downloader/statesync.go index 7e156f46e7..1ccdf4def9 100644 --- a/eth/downloader/statesync.go +++ b/eth/downloader/statesync.go @@ -302,7 +302,7 @@ func (s *stateSync) loop() (err error) { return errCancelStateFetch case <-s.d.cancelCh: - return errCancelStateFetch + return errCanceled case req := <-s.deliver: // Response, disconnect or timeout triggered, drop the peer if stalling @@ -317,6 +317,16 @@ func (s *stateSync) loop() (err error) { req.peer.log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", req.peer.id) } else { s.d.dropPeer(req.peer.id) + + // If this peer was the master peer, abort sync immediately + s.d.cancelLock.RLock() + master := req.peer.id == s.d.cancelPeer + s.d.cancelLock.RUnlock() + + if master { + s.d.cancel() + return errTimeout + } } } // Process all the received blobs and check for stale delivery From 7c9307c683702b5be4ab2c409cef45e017d6c62d Mon Sep 17 00:00:00 2001 From: ledgerwatch Date: Wed, 5 Jun 2019 13:03:23 +0100 Subject: [PATCH 36/47] cmd: Add retesteth command (to support execution and generation of tests via retesteth) (#19631) * Add retesteth command * Remove label and insert full version * mineBlock - break the inner loop when the block is full * Fixes for touched non-reward accounts, gas limit issues * Not fail when SendTx has transaction with incorrect RLP * Fix linter (unnecessary conversion) * retesteth: add usage string to flag --- cmd/geth/main.go | 2 + cmd/geth/retesteth.go | 888 ++++++++++++++++++++++++++++++++ cmd/geth/retesteth_copypaste.go | 148 ++++++ 3 files changed, 1038 insertions(+) create mode 100644 cmd/geth/retesteth.go create mode 100644 cmd/geth/retesteth_copypaste.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d0a9bb08ae..00809e2e10 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -220,6 +220,8 @@ func init() { licenseCommand, // See config.go dumpConfigCommand, + // See retesteth.go + retestethCommand, } sort.Sort(cli.CommandsByName(app.Commands)) diff --git a/cmd/geth/retesteth.go b/cmd/geth/retesteth.go new file mode 100644 index 0000000000..6d5763f887 --- /dev/null +++ b/cmd/geth/retesteth.go @@ -0,0 +1,888 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "context" + "fmt" + "math/big" + "os" + "os/signal" + "strings" + "time" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/trie" + + cli "gopkg.in/urfave/cli.v1" +) + +var ( + rpcPortFlag = cli.IntFlag{ + Name: "rpcport", + Usage: "HTTP-RPC server listening port", + Value: node.DefaultHTTPPort, + } + retestethCommand = cli.Command{ + Action: utils.MigrateFlags(retesteth), + Name: "retesteth", + Usage: "Launches geth in retesteth mode", + ArgsUsage: "", + Flags: []cli.Flag{rpcPortFlag}, + Category: "MISCELLANEOUS COMMANDS", + Description: `Launches geth in retesteth mode (no database, no network, only retesteth RPC interface)`, + } +) + +type RetestethTestAPI interface { + SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error) + MineBlocks(ctx context.Context, number uint64) (bool, error) + ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) + ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error) + RewindToBlock(ctx context.Context, number uint64) (bool, error) + GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, error) +} + +type RetestethEthAPI interface { + SendRawTransaction(ctx context.Context, rawTx hexutil.Bytes) (common.Hash, error) + BlockNumber(ctx context.Context) (uint64, error) + GetBlockByNumber(ctx context.Context, blockNr math.HexOrDecimal64, fullTx bool) (map[string]interface{}, error) + GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error) + GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error) + GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error) +} + +type RetestethDebugAPI interface { + AccountRangeAt(ctx context.Context, + blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, + addressHash *math.HexOrDecimal256, maxResults uint64, + ) (AccountRangeResult, error) + StorageRangeAt(ctx context.Context, + blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, + address common.Address, + begin *math.HexOrDecimal256, maxResults uint64, + ) (StorageRangeResult, error) +} + +type RetestWeb3API interface { + ClientVersion(ctx context.Context) (string, error) +} + +type RetestethAPI struct { + ethDb ethdb.Database + db state.Database + chainConfig *params.ChainConfig + author common.Address + extraData []byte + genesisHash common.Hash + engine *NoRewardEngine + blockchain *core.BlockChain + blockNumber uint64 + txMap map[common.Address]map[uint64]*types.Transaction // Sender -> Nonce -> Transaction + txSenders map[common.Address]struct{} // Set of transaction senders + blockInterval uint64 +} + +type ChainParams struct { + SealEngine string `json:"sealEngine"` + Params CParamsParams `json:"params"` + Genesis CParamsGenesis `json:"genesis"` + Accounts map[common.Address]CParamsAccount `json:"accounts"` +} + +type CParamsParams struct { + AccountStartNonce math.HexOrDecimal64 `json:"accountStartNonce"` + HomesteadForkBlock *math.HexOrDecimal64 `json:"homesteadForkBlock"` + EIP150ForkBlock *math.HexOrDecimal64 `json:"EIP150ForkBlock"` + EIP158ForkBlock *math.HexOrDecimal64 `json:"EIP158ForkBlock"` + DaoHardforkBlock *math.HexOrDecimal64 `json:"daoHardforkBlock"` + ByzantiumForkBlock *math.HexOrDecimal64 `json:"byzantiumForkBlock"` + ConstantinopleForkBlock *math.HexOrDecimal64 `json:"constantinopleForkBlock"` + ConstantinopleFixForkBlock *math.HexOrDecimal64 `json:"constantinopleFixForkBlock"` + ChainID *math.HexOrDecimal256 `json:"chainID"` + MaximumExtraDataSize math.HexOrDecimal64 `json:"maximumExtraDataSize"` + TieBreakingGas bool `json:"tieBreakingGas"` + MinGasLimit math.HexOrDecimal64 `json:"minGasLimit"` + MaxGasLimit math.HexOrDecimal64 `json:"maxGasLimit"` + GasLimitBoundDivisor math.HexOrDecimal64 `json:"gasLimitBoundDivisor"` + MinimumDifficulty math.HexOrDecimal256 `json:"minimumDifficulty"` + DifficultyBoundDivisor math.HexOrDecimal256 `json:"difficultyBoundDivisor"` + DurationLimit math.HexOrDecimal256 `json:"durationLimit"` + BlockReward math.HexOrDecimal256 `json:"blockReward"` + NetworkID math.HexOrDecimal256 `json:"networkID"` +} + +type CParamsGenesis struct { + Nonce math.HexOrDecimal64 `json:"nonce"` + Difficulty *math.HexOrDecimal256 `json:"difficulty"` + MixHash *math.HexOrDecimal256 `json:"mixHash"` + Author common.Address `json:"author"` + Timestamp math.HexOrDecimal64 `json:"timestamp"` + ParentHash common.Hash `json:"parentHash"` + ExtraData hexutil.Bytes `json:"extraData"` + GasLimit math.HexOrDecimal64 `json:"gasLimit"` +} + +type CParamsAccount struct { + Balance *math.HexOrDecimal256 `json:"balance"` + Precompiled *CPAccountPrecompiled `json:"precompiled"` + Code hexutil.Bytes `json:"code"` + Storage map[string]string `json:"storage"` + Nonce *math.HexOrDecimal64 `json:"nonce"` +} + +type CPAccountPrecompiled struct { + Name string `json:"name"` + StartingBlock math.HexOrDecimal64 `json:"startingBlock"` + Linear *CPAPrecompiledLinear `json:"linear"` +} + +type CPAPrecompiledLinear struct { + Base uint64 `json:"base"` + Word uint64 `json:"word"` +} + +type AccountRangeResult struct { + AddressMap map[common.Hash]common.Address `json:"addressMap"` + NextKey common.Hash `json:"nextKey"` +} + +type StorageRangeResult struct { + Complete bool `json:"complete"` + Storage map[common.Hash]SRItem `json:"storage"` +} + +type SRItem struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type NoRewardEngine struct { + inner consensus.Engine + rewardsOn bool +} + +func (e *NoRewardEngine) Author(header *types.Header) (common.Address, error) { + return e.inner.Author(header) +} + +func (e *NoRewardEngine) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { + return e.inner.VerifyHeader(chain, header, seal) +} + +func (e *NoRewardEngine) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { + return e.inner.VerifyHeaders(chain, headers, seals) +} + +func (e *NoRewardEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { + return e.inner.VerifyUncles(chain, block) +} + +func (e *NoRewardEngine) VerifySeal(chain consensus.ChainReader, header *types.Header) error { + return e.inner.VerifySeal(chain, header) +} + +func (e *NoRewardEngine) Prepare(chain consensus.ChainReader, header *types.Header) error { + return e.inner.Prepare(chain, header) +} + +func (e *NoRewardEngine) accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) { + // Simply touch miner and uncle coinbase accounts + reward := big.NewInt(0) + for _, uncle := range uncles { + state.AddBalance(uncle.Coinbase, reward) + } + state.AddBalance(header.Coinbase, reward) +} + +func (e *NoRewardEngine) Finalize(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB, txs []*types.Transaction, + uncles []*types.Header) { + if e.rewardsOn { + e.inner.Finalize(chain, header, statedb, txs, uncles) + } else { + e.accumulateRewards(chain.Config(), statedb, header, uncles) + header.Root = statedb.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + } +} + +func (e *NoRewardEngine) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB, txs []*types.Transaction, + uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { + if e.rewardsOn { + return e.inner.FinalizeAndAssemble(chain, header, statedb, txs, uncles, receipts) + } else { + e.accumulateRewards(chain.Config(), statedb, header, uncles) + header.Root = statedb.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + + // Header seems complete, assemble into a block and return + return types.NewBlock(header, txs, uncles, receipts), nil + } +} + +func (e *NoRewardEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { + return e.inner.Seal(chain, block, results, stop) +} + +func (e *NoRewardEngine) SealHash(header *types.Header) common.Hash { + return e.inner.SealHash(header) +} + +func (e *NoRewardEngine) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { + return e.inner.CalcDifficulty(chain, time, parent) +} + +func (e *NoRewardEngine) APIs(chain consensus.ChainReader) []rpc.API { + return e.inner.APIs(chain) +} + +func (e *NoRewardEngine) Close() error { + return e.inner.Close() +} + +func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error) { + // Clean up + if api.blockchain != nil { + api.blockchain.Stop() + } + if api.engine != nil { + api.engine.Close() + } + if api.ethDb != nil { + api.ethDb.Close() + } + ethDb := rawdb.NewMemoryDatabase() + accounts := make(core.GenesisAlloc) + for address, account := range chainParams.Accounts { + balance := big.NewInt(0) + if account.Balance != nil { + balance.Set((*big.Int)(account.Balance)) + } + var nonce uint64 + if account.Nonce != nil { + nonce = uint64(*account.Nonce) + } + if account.Precompiled == nil || account.Balance != nil { + storage := make(map[common.Hash]common.Hash) + for k, v := range account.Storage { + storage[common.HexToHash(k)] = common.HexToHash(v) + } + accounts[address] = core.GenesisAccount{ + Balance: balance, + Code: account.Code, + Nonce: nonce, + Storage: storage, + } + } + } + chainId := big.NewInt(1) + if chainParams.Params.ChainID != nil { + chainId.Set((*big.Int)(chainParams.Params.ChainID)) + } + var ( + homesteadBlock *big.Int + daoForkBlock *big.Int + eip150Block *big.Int + eip155Block *big.Int + eip158Block *big.Int + byzantiumBlock *big.Int + constantinopleBlock *big.Int + petersburgBlock *big.Int + ) + if chainParams.Params.HomesteadForkBlock != nil { + homesteadBlock = big.NewInt(int64(*chainParams.Params.HomesteadForkBlock)) + } + if chainParams.Params.DaoHardforkBlock != nil { + daoForkBlock = big.NewInt(int64(*chainParams.Params.DaoHardforkBlock)) + } + if chainParams.Params.EIP150ForkBlock != nil { + eip150Block = big.NewInt(int64(*chainParams.Params.EIP150ForkBlock)) + } + if chainParams.Params.EIP158ForkBlock != nil { + eip158Block = big.NewInt(int64(*chainParams.Params.EIP158ForkBlock)) + eip155Block = eip158Block + } + if chainParams.Params.ByzantiumForkBlock != nil { + byzantiumBlock = big.NewInt(int64(*chainParams.Params.ByzantiumForkBlock)) + } + if chainParams.Params.ConstantinopleForkBlock != nil { + constantinopleBlock = big.NewInt(int64(*chainParams.Params.ConstantinopleForkBlock)) + } + if chainParams.Params.ConstantinopleFixForkBlock != nil { + petersburgBlock = big.NewInt(int64(*chainParams.Params.ConstantinopleFixForkBlock)) + } + if constantinopleBlock != nil && petersburgBlock == nil { + petersburgBlock = big.NewInt(100000000000) + } + genesis := &core.Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: chainId, + HomesteadBlock: homesteadBlock, + DAOForkBlock: daoForkBlock, + DAOForkSupport: false, + EIP150Block: eip150Block, + EIP155Block: eip155Block, + EIP158Block: eip158Block, + ByzantiumBlock: byzantiumBlock, + ConstantinopleBlock: constantinopleBlock, + PetersburgBlock: petersburgBlock, + }, + Nonce: uint64(chainParams.Genesis.Nonce), + Timestamp: uint64(chainParams.Genesis.Timestamp), + ExtraData: chainParams.Genesis.ExtraData, + GasLimit: uint64(chainParams.Genesis.GasLimit), + Difficulty: big.NewInt(0).Set((*big.Int)(chainParams.Genesis.Difficulty)), + Mixhash: common.BigToHash((*big.Int)(chainParams.Genesis.MixHash)), + Coinbase: chainParams.Genesis.Author, + ParentHash: chainParams.Genesis.ParentHash, + Alloc: accounts, + } + chainConfig, genesisHash, err := core.SetupGenesisBlock(ethDb, genesis) + if err != nil { + return false, err + } + fmt.Printf("Chain config: %v\n", chainConfig) + + var inner consensus.Engine + switch chainParams.SealEngine { + case "NoProof", "NoReward": + inner = ethash.NewFaker() + case "Ethash": + inner = ethash.New(ethash.Config{ + CacheDir: "ethash", + CachesInMem: 2, + CachesOnDisk: 3, + DatasetsInMem: 1, + DatasetsOnDisk: 2, + }, nil, false) + default: + return false, fmt.Errorf("unrecognised seal engine: %s", chainParams.SealEngine) + } + engine := &NoRewardEngine{inner: inner, rewardsOn: chainParams.SealEngine != "NoReward"} + + blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil) + if err != nil { + return false, err + } + + api.chainConfig = chainConfig + api.genesisHash = genesisHash + api.author = chainParams.Genesis.Author + api.extraData = chainParams.Genesis.ExtraData + api.ethDb = ethDb + api.engine = engine + api.blockchain = blockchain + api.db = state.NewDatabase(api.ethDb) + api.blockNumber = 0 + api.txMap = make(map[common.Address]map[uint64]*types.Transaction) + api.txSenders = make(map[common.Address]struct{}) + api.blockInterval = 0 + return true, nil +} + +func (api *RetestethAPI) SendRawTransaction(ctx context.Context, rawTx hexutil.Bytes) (common.Hash, error) { + tx := new(types.Transaction) + if err := rlp.DecodeBytes(rawTx, tx); err != nil { + // Return nil is not by mistake - some tests include sending transaction where gasLimit overflows uint64 + return common.Hash{}, nil + } + signer := types.MakeSigner(api.chainConfig, big.NewInt(int64(api.blockNumber))) + sender, err := types.Sender(signer, tx) + if err != nil { + return common.Hash{}, err + } + if nonceMap, ok := api.txMap[sender]; ok { + nonceMap[tx.Nonce()] = tx + } else { + nonceMap = make(map[uint64]*types.Transaction) + nonceMap[tx.Nonce()] = tx + api.txMap[sender] = nonceMap + } + api.txSenders[sender] = struct{}{} + return tx.Hash(), nil +} + +func (api *RetestethAPI) MineBlocks(ctx context.Context, number uint64) (bool, error) { + for i := 0; i < int(number); i++ { + if err := api.mineBlock(); err != nil { + return false, err + } + } + fmt.Printf("Mined %d blocks\n", number) + return true, nil +} + +func (api *RetestethAPI) mineBlock() error { + parentHash := rawdb.ReadCanonicalHash(api.ethDb, api.blockNumber) + parent := rawdb.ReadBlock(api.ethDb, parentHash, api.blockNumber) + var timestamp uint64 + if api.blockInterval == 0 { + timestamp = uint64(time.Now().Unix()) + } else { + timestamp = parent.Time() + api.blockInterval + } + gasLimit := core.CalcGasLimit(parent, 9223372036854775807, 9223372036854775807) + header := &types.Header{ + ParentHash: parent.Hash(), + Number: big.NewInt(int64(api.blockNumber + 1)), + GasLimit: gasLimit, + Extra: api.extraData, + Time: timestamp, + } + header.Coinbase = api.author + if api.engine != nil { + api.engine.Prepare(api.blockchain, header) + } + // If we are care about TheDAO hard-fork check whether to override the extra-data or not + if daoBlock := api.chainConfig.DAOForkBlock; daoBlock != nil { + // Check whether the block is among the fork extra-override range + limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) + if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { + // Depending whether we support or oppose the fork, override differently + if api.chainConfig.DAOForkSupport { + header.Extra = common.CopyBytes(params.DAOForkBlockExtra) + } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { + header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data + } + } + } + statedb, err := api.blockchain.StateAt(parent.Root()) + if err != nil { + return err + } + if api.chainConfig.DAOForkSupport && api.chainConfig.DAOForkBlock != nil && api.chainConfig.DAOForkBlock.Cmp(header.Number) == 0 { + misc.ApplyDAOHardFork(statedb) + } + gasPool := new(core.GasPool).AddGas(header.GasLimit) + txCount := 0 + var txs []*types.Transaction + var receipts []*types.Receipt + var coalescedLogs []*types.Log + var blockFull = gasPool.Gas() < params.TxGas + for address := range api.txSenders { + if blockFull { + break + } + m := api.txMap[address] + for nonce := statedb.GetNonce(address); ; nonce++ { + if tx, ok := m[nonce]; ok { + // Try to apply transactions to the state + statedb.Prepare(tx.Hash(), common.Hash{}, txCount) + snap := statedb.Snapshot() + + receipt, _, err := core.ApplyTransaction( + api.chainConfig, + api.blockchain, + &api.author, + gasPool, + statedb, + header, tx, &header.GasUsed, *api.blockchain.GetVMConfig(), + ) + if err != nil { + statedb.RevertToSnapshot(snap) + break + } + txs = append(txs, tx) + receipts = append(receipts, receipt) + coalescedLogs = append(coalescedLogs, receipt.Logs...) + delete(m, nonce) + if len(m) == 0 { + // Last tx for the sender + delete(api.txMap, address) + delete(api.txSenders, address) + } + txCount++ + if gasPool.Gas() < params.TxGas { + blockFull = true + break + } + } else { + break // Gap in the nonces + } + } + } + block, err := api.engine.FinalizeAndAssemble(api.blockchain, header, statedb, txs, []*types.Header{}, receipts) + return api.importBlock(block) +} + +func (api *RetestethAPI) importBlock(block *types.Block) error { + if _, err := api.blockchain.InsertChain([]*types.Block{block}); err != nil { + return err + } + api.blockNumber = block.NumberU64() + fmt.Printf("Imported block %d\n", block.NumberU64()) + return nil +} + +func (api *RetestethAPI) ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) { + api.blockInterval = interval + return true, nil +} + +func (api *RetestethAPI) ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error) { + block := new(types.Block) + if err := rlp.DecodeBytes(rawBlock, block); err != nil { + return common.Hash{}, err + } + fmt.Printf("Importing block %d with parent hash: %x, genesisHash: %x\n", block.NumberU64(), block.ParentHash(), api.genesisHash) + if err := api.importBlock(block); err != nil { + return common.Hash{}, err + } + return block.Hash(), nil +} + +func (api *RetestethAPI) RewindToBlock(ctx context.Context, newHead uint64) (bool, error) { + if err := api.blockchain.SetHead(newHead); err != nil { + return false, err + } + api.blockNumber = newHead + return true, nil +} + +var emptyListHash common.Hash = common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") + +func (api *RetestethAPI) GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, error) { + receipt, _, _, _ := rawdb.ReadReceipt(api.ethDb, txHash, api.chainConfig) + if receipt == nil { + return emptyListHash, nil + } else { + if logListRlp, err := rlp.EncodeToBytes(receipt.Logs); err != nil { + return common.Hash{}, err + } else { + return common.BytesToHash(crypto.Keccak256(logListRlp)), nil + } + } +} + +func (api *RetestethAPI) BlockNumber(ctx context.Context) (uint64, error) { + //fmt.Printf("BlockNumber, response: %d\n", api.blockNumber) + return api.blockNumber, nil +} + +func (api *RetestethAPI) GetBlockByNumber(ctx context.Context, blockNr math.HexOrDecimal64, fullTx bool) (map[string]interface{}, error) { + block := api.blockchain.GetBlockByNumber(uint64(blockNr)) + if block != nil { + response, err := RPCMarshalBlock(block, true, fullTx) + if err != nil { + return nil, err + } + response["author"] = response["miner"] + response["totalDifficulty"] = (*hexutil.Big)(api.blockchain.GetTd(block.Hash(), uint64(blockNr))) + return response, err + } + return nil, fmt.Errorf("block %d not found", blockNr) +} + +func (api *RetestethAPI) AccountRangeAt(ctx context.Context, + blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, + addressHash *math.HexOrDecimal256, maxResults uint64, +) (AccountRangeResult, error) { + var ( + header *types.Header + block *types.Block + ) + if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 { + blockHash := common.BigToHash((*big.Int)(blockHashOrNumber)) + header = api.blockchain.GetHeaderByHash(blockHash) + block = api.blockchain.GetBlockByHash(blockHash) + //fmt.Printf("Account range: %x, txIndex %d, start: %x, maxResults: %d\n", blockHash, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults) + } else { + blockNumber := (*big.Int)(blockHashOrNumber).Uint64() + header = api.blockchain.GetHeaderByNumber(blockNumber) + block = api.blockchain.GetBlockByNumber(blockNumber) + //fmt.Printf("Account range: %d, txIndex %d, start: %x, maxResults: %d\n", blockNumber, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults) + } + parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash) + var root common.Hash + var statedb *state.StateDB + var err error + if parentHeader == nil || int(txIndex) >= len(block.Transactions()) { + root = header.Root + statedb, err = api.blockchain.StateAt(root) + if err != nil { + return AccountRangeResult{}, err + } + } else { + root = parentHeader.Root + statedb, err = api.blockchain.StateAt(root) + if err != nil { + return AccountRangeResult{}, err + } + // Recompute transactions up to the target index. + signer := types.MakeSigner(api.blockchain.Config(), block.Number()) + for idx, tx := range block.Transactions() { + // Assemble the transaction call message and return if the requested offset + msg, _ := tx.AsMessage(signer) + context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) + // Not yet the searched for transaction, execute on top of the current state + vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) + if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + } + // Ensure any modifications are committed to the state + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + root = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number())) + if idx == int(txIndex) { + // This is to make sure root can be opened by OpenTrie + root, err = statedb.Commit(api.chainConfig.IsEIP158(block.Number())) + if err != nil { + return AccountRangeResult{}, err + } + break + } + } + } + accountTrie, err := statedb.Database().OpenTrie(root) + if err != nil { + return AccountRangeResult{}, err + } + it := trie.NewIterator(accountTrie.NodeIterator(common.BigToHash((*big.Int)(addressHash)).Bytes())) + result := AccountRangeResult{AddressMap: make(map[common.Hash]common.Address)} + for i := 0; /*i < int(maxResults) && */ it.Next(); i++ { + if preimage := accountTrie.GetKey(it.Key); preimage != nil { + result.AddressMap[common.BytesToHash(it.Key)] = common.BytesToAddress(preimage) + //fmt.Printf("%x: %x\n", it.Key, preimage) + } else { + //fmt.Printf("could not find preimage for %x\n", it.Key) + } + } + //fmt.Printf("Number of entries returned: %d\n", len(result.AddressMap)) + // Add the 'next key' so clients can continue downloading. + if it.Next() { + next := common.BytesToHash(it.Key) + result.NextKey = next + } + return result, nil +} + +func (api *RetestethAPI) GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error) { + //fmt.Printf("GetBalance %x, block %d\n", address, blockNr) + header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) + statedb, err := api.blockchain.StateAt(header.Root) + if err != nil { + return nil, err + } + return (*math.HexOrDecimal256)(statedb.GetBalance(address)), nil +} + +func (api *RetestethAPI) GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error) { + header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) + statedb, err := api.blockchain.StateAt(header.Root) + if err != nil { + return nil, err + } + return statedb.GetCode(address), nil +} + +func (api *RetestethAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error) { + header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) + statedb, err := api.blockchain.StateAt(header.Root) + if err != nil { + return 0, err + } + return statedb.GetNonce(address), nil +} + +func (api *RetestethAPI) StorageRangeAt(ctx context.Context, + blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, + address common.Address, + begin *math.HexOrDecimal256, maxResults uint64, +) (StorageRangeResult, error) { + var ( + header *types.Header + block *types.Block + ) + if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 { + blockHash := common.BigToHash((*big.Int)(blockHashOrNumber)) + header = api.blockchain.GetHeaderByHash(blockHash) + block = api.blockchain.GetBlockByHash(blockHash) + //fmt.Printf("Storage range: %x, txIndex %d, addr: %x, start: %x, maxResults: %d\n", + // blockHash, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults) + } else { + blockNumber := (*big.Int)(blockHashOrNumber).Uint64() + header = api.blockchain.GetHeaderByNumber(blockNumber) + block = api.blockchain.GetBlockByNumber(blockNumber) + //fmt.Printf("Storage range: %d, txIndex %d, addr: %x, start: %x, maxResults: %d\n", + // blockNumber, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults) + } + parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash) + var root common.Hash + var statedb *state.StateDB + var err error + if parentHeader == nil || int(txIndex) >= len(block.Transactions()) { + root = header.Root + statedb, err = api.blockchain.StateAt(root) + if err != nil { + return StorageRangeResult{}, err + } + } else { + root = parentHeader.Root + statedb, err = api.blockchain.StateAt(root) + if err != nil { + return StorageRangeResult{}, err + } + // Recompute transactions up to the target index. + signer := types.MakeSigner(api.blockchain.Config(), block.Number()) + for idx, tx := range block.Transactions() { + // Assemble the transaction call message and return if the requested offset + msg, _ := tx.AsMessage(signer) + context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) + // Not yet the searched for transaction, execute on top of the current state + vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) + if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + } + // Ensure any modifications are committed to the state + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + root = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number())) + if idx == int(txIndex) { + // This is to make sure root can be opened by OpenTrie + root, err = statedb.Commit(vmenv.ChainConfig().IsEIP158(block.Number())) + if err != nil { + return StorageRangeResult{}, err + } + } + } + } + storageTrie := statedb.StorageTrie(address) + it := trie.NewIterator(storageTrie.NodeIterator(common.BigToHash((*big.Int)(begin)).Bytes())) + result := StorageRangeResult{Storage: make(map[common.Hash]SRItem)} + for i := 0; /*i < int(maxResults) && */ it.Next(); i++ { + if preimage := storageTrie.GetKey(it.Key); preimage != nil { + key := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(preimage)) + v, _, err := rlp.SplitString(it.Value) + if err != nil { + return StorageRangeResult{}, err + } + value := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(v)) + ks, _ := key.MarshalText() + vs, _ := value.MarshalText() + if len(ks)%2 != 0 { + ks = append(append(append([]byte{}, ks[:2]...), byte('0')), ks[2:]...) + } + if len(vs)%2 != 0 { + vs = append(append(append([]byte{}, vs[:2]...), byte('0')), vs[2:]...) + } + result.Storage[common.BytesToHash(it.Key)] = SRItem{ + Key: string(ks), + Value: string(vs), + } + //fmt.Printf("Key: %s, Value: %s\n", ks, vs) + } else { + //fmt.Printf("Did not find preimage for %x\n", it.Key) + } + } + if it.Next() { + result.Complete = false + } else { + result.Complete = true + } + return result, nil +} + +func (api *RetestethAPI) ClientVersion(ctx context.Context) (string, error) { + return "Geth-" + params.VersionWithCommit(gitCommit, gitDate), nil +} + +// splitAndTrim splits input separated by a comma +// and trims excessive white space from the substrings. +func splitAndTrim(input string) []string { + result := strings.Split(input, ",") + for i, r := range result { + result[i] = strings.TrimSpace(r) + } + return result +} + +func retesteth(ctx *cli.Context) error { + log.Info("Welcome to retesteth!") + // register signer API with server + var ( + extapiURL = "n/a" + ) + apiImpl := &RetestethAPI{} + var testApi RetestethTestAPI = apiImpl + var ethApi RetestethEthAPI = apiImpl + var debugApi RetestethDebugAPI = apiImpl + var web3Api RetestWeb3API = apiImpl + rpcAPI := []rpc.API{ + { + Namespace: "test", + Public: true, + Service: testApi, + Version: "1.0", + }, + { + Namespace: "eth", + Public: true, + Service: ethApi, + Version: "1.0", + }, + { + Namespace: "debug", + Public: true, + Service: debugApi, + Version: "1.0", + }, + { + Namespace: "web3", + Public: true, + Service: web3Api, + Version: "1.0", + }, + } + vhosts := splitAndTrim(ctx.GlobalString(utils.RPCVirtualHostsFlag.Name)) + cors := splitAndTrim(ctx.GlobalString(utils.RPCCORSDomainFlag.Name)) + + // start http server + httpEndpoint := fmt.Sprintf("%s:%d", ctx.GlobalString(utils.RPCListenAddrFlag.Name), ctx.Int(rpcPortFlag.Name)) + listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"test", "eth", "debug", "web3"}, cors, vhosts, rpc.DefaultHTTPTimeouts) + if err != nil { + utils.Fatalf("Could not start RPC api: %v", err) + } + extapiURL = fmt.Sprintf("http://%s", httpEndpoint) + log.Info("HTTP endpoint opened", "url", extapiURL) + + defer func() { + listener.Close() + log.Info("HTTP endpoint closed", "url", httpEndpoint) + }() + + abortChan := make(chan os.Signal) + signal.Notify(abortChan, os.Interrupt) + + sig := <-abortChan + log.Info("Exiting...", "signal", sig) + return nil +} diff --git a/cmd/geth/retesteth_copypaste.go b/cmd/geth/retesteth_copypaste.go new file mode 100644 index 0000000000..e2795af7f9 --- /dev/null +++ b/cmd/geth/retesteth_copypaste.go @@ -0,0 +1,148 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" +) + +// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +type RPCTransaction struct { + BlockHash common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex hexutil.Uint `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` +} + +// newRPCTransaction returns a transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction { + var signer types.Signer = types.FrontierSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) + } + from, _ := types.Sender(signer, tx) + v, r, s := tx.RawSignatureValues() + + result := &RPCTransaction{ + From: from, + Gas: hexutil.Uint64(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), + To: tx.To(), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), + } + if blockHash != (common.Hash{}) { + result.BlockHash = blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = hexutil.Uint(index) + } + return result +} + +// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index) +} + +// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { + for idx, tx := range b.Transactions() { + if tx.Hash() == hash { + return newRPCTransactionFromBlockIndex(b, uint64(idx)) + } + } + return nil +} + +// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are +// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain +// transaction hashes. +func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + head := b.Header() // copies the header once + fields := map[string]interface{}{ + "number": (*hexutil.Big)(head.Number), + "hash": b.Hash(), + "parentHash": head.ParentHash, + "nonce": head.Nonce, + "mixHash": head.MixDigest, + "sha3Uncles": head.UncleHash, + "logsBloom": head.Bloom, + "stateRoot": head.Root, + "miner": head.Coinbase, + "difficulty": (*hexutil.Big)(head.Difficulty), + "extraData": hexutil.Bytes(head.Extra), + "size": hexutil.Uint64(b.Size()), + "gasLimit": hexutil.Uint64(head.GasLimit), + "gasUsed": hexutil.Uint64(head.GasUsed), + "timestamp": hexutil.Uint64(head.Time), + "transactionsRoot": head.TxHash, + "receiptsRoot": head.ReceiptHash, + } + + if inclTx { + formatTx := func(tx *types.Transaction) (interface{}, error) { + return tx.Hash(), nil + } + if fullTx { + formatTx = func(tx *types.Transaction) (interface{}, error) { + return newRPCTransactionFromBlockHash(b, tx.Hash()), nil + } + } + txs := b.Transactions() + transactions := make([]interface{}, len(txs)) + var err error + for i, tx := range txs { + if transactions[i], err = formatTx(tx); err != nil { + return nil, err + } + } + fields["transactions"] = transactions + } + + uncles := b.Uncles() + uncleHashes := make([]common.Hash, len(uncles)) + for i, uncle := range uncles { + uncleHashes[i] = uncle.Hash() + } + fields["uncles"] = uncleHashes + + return fields, nil +} From b8ca3cb7d2063911bb4e0a28fcb746e7e27d145d Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Wed, 5 Jun 2019 15:27:37 +0200 Subject: [PATCH 37/47] cmd/clef: enable smartcard hub (#19649) * cmd/clef: Enable smartcard hub * clef: don't error is pcsc is not installed --- cmd/clef/main.go | 4 +++- signer/core/api.go | 24 +++++++++++++++++++++++- signer/core/api_test.go | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/cmd/clef/main.go b/cmd/clef/main.go index ad7ba186d0..0ea6f36f10 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -194,6 +194,7 @@ func init() { chainIdFlag, utils.LightKDFFlag, utils.NoUSBFlag, + utils.SmartCardDaemonPathFlag, utils.RPCListenAddrFlag, utils.RPCVirtualHostsFlag, utils.IPCDisabledFlag, @@ -419,10 +420,11 @@ func signer(c *cli.Context) error { lightKdf = c.GlobalBool(utils.LightKDFFlag.Name) advanced = c.GlobalBool(advancedMode.Name) nousb = c.GlobalBool(utils.NoUSBFlag.Name) + scpath = c.GlobalString(utils.SmartCardDaemonPathFlag.Name) ) log.Info("Starting signer", "chainid", chainId, "keystore", ksLoc, "light-kdf", lightKdf, "advanced", advanced) - am := core.StartClefAccountManager(ksLoc, nousb, lightKdf) + am := core.StartClefAccountManager(ksLoc, nousb, lightKdf, scpath) apiImpl := core.NewSignerAPI(am, chainId, nousb, ui, db, advanced, pwStorage) // Establish the bidirectional communication, by creating a new UI backend and registering diff --git a/signer/core/api.go b/signer/core/api.go index 9798ff2b57..251ee55dcd 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -22,11 +22,13 @@ import ( "errors" "fmt" "math/big" + "os" "reflect" "strings" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -124,7 +126,7 @@ type Metadata struct { Origin string `json:"Origin"` } -func StartClefAccountManager(ksLocation string, nousb, lightKDF bool) *accounts.Manager { +func StartClefAccountManager(ksLocation string, nousb, lightKDF bool, scpath string) *accounts.Manager { var ( backends []accounts.Backend n, p = keystore.StandardScryptN, keystore.StandardScryptP @@ -159,6 +161,26 @@ func StartClefAccountManager(ksLocation string, nousb, lightKDF bool) *accounts. log.Debug("Trezor support enabled via WebUSB") } } + + // Start a smart card hub + if len(scpath) > 0 { + // Sanity check that the smartcard path is valid + fi, err := os.Stat(scpath) + if err != nil { + log.Info("Smartcard socket file missing, disabling", "err", err) + } else { + if fi.Mode()&os.ModeType != os.ModeSocket { + log.Error("Invalid smartcard socket file type", "path", scpath, "type", fi.Mode().String()) + } else { + if schub, err := scwallet.NewHub(scpath, scwallet.Scheme, ksLocation); err != nil { + log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) + } else { + backends = append(backends, schub) + } + } + } + } + // Clef doesn't allow insecure http account unlock. return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: false}, backends...) } diff --git a/signer/core/api_test.go b/signer/core/api_test.go index b458aa03ed..1eba20ef40 100644 --- a/signer/core/api_test.go +++ b/signer/core/api_test.go @@ -125,7 +125,7 @@ func setup(t *testing.T) (*core.SignerAPI, *headlessUi) { t.Fatal(err.Error()) } ui := &headlessUi{make(chan string, 20), make(chan string, 20)} - am := core.StartClefAccountManager(tmpDirName(t), true, true) + am := core.StartClefAccountManager(tmpDirName(t), true, true, "") api := core.NewSignerAPI(am, 1337, true, ui, db, true, &storage.NoStorage{}) return api, ui From 2fae1bde426abd063847c10021eae7bafdc63c3d Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 5 Jun 2019 10:57:10 +0200 Subject: [PATCH 38/47] account/usbwallet: abort usb enumeration after failures --- accounts/usbwallet/hub.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index 8f34d63e8a..23be98a084 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -20,6 +20,7 @@ import ( "errors" "runtime" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/accounts" @@ -64,6 +65,7 @@ type Hub struct { // TODO(karalabe): remove if hotplug lands on Windows commsPend int // Number of operations blocking enumeration commsLock sync.Mutex // Lock protecting the pending counter and enumeration + enumFails uint32 // Number of times enumeration has failed } // NewLedgerHub creates a new hardware wallet manager for Ledger devices. @@ -138,6 +140,10 @@ func (hub *Hub) refreshWallets() { if elapsed < refreshThrottling { return } + // If USB enumeration is continually failing, don't keep trying indefinitely + if atomic.LoadUint32(&hub.enumFails) > 2 { + return + } // Retrieve the current list of USB wallet devices var devices []usb.DeviceInfo @@ -156,13 +162,17 @@ func (hub *Hub) refreshWallets() { } infos, err := usb.Enumerate(hub.vendorID, 0) if err != nil { + failcount := atomic.AddUint32(&hub.enumFails, 1) if runtime.GOOS == "linux" { // See rationale before the enumeration why this is needed and only on Linux. hub.commsLock.Unlock() } - log.Error("error enumerating USB enumeration: ", "code", err) + log.Error("Failed to enumerate USB devices", "hub", hub.scheme, + "vendor", hub.vendorID, "failcount", failcount, "err", err) return } + atomic.StoreUint32(&hub.enumFails, 0) + for _, info := range infos { for _, id := range hub.productIDs { // Windows and Macos use UsageID matching, Linux uses Interface matching From 2823ce0086736e01cdb7b715d567d5ada445e3e4 Mon Sep 17 00:00:00 2001 From: Nguyen Kien Trung Date: Thu, 6 Jun 2019 04:49:35 -0400 Subject: [PATCH 39/47] eth: check for DefaultConfig.NetworkId in test (#17599) This makes the test work if NetworkId is changed in forks of go-ethereum. --- eth/protocol_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/protocol_test.go b/eth/protocol_test.go index aa43dfa920..e817d673a6 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -64,7 +64,7 @@ func testStatusMsgErrors(t *testing.T, protocol int) { }, { code: StatusMsg, data: statusData{uint32(protocol), 999, td, head.Hash(), genesis.Hash()}, - wantError: errResp(ErrNetworkIdMismatch, "999 (!= 1)"), + wantError: errResp(ErrNetworkIdMismatch, "999 (!= %d)", DefaultConfig.NetworkId), }, { code: StatusMsg, data: statusData{uint32(protocol), DefaultConfig.NetworkId, td, head.Hash(), common.Hash{3}}, From c52390d0780163c5633fc768130b66965412a558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 6 Jun 2019 10:32:51 +0300 Subject: [PATCH 40/47] vendor: pull fixed usb library for nocgo builds --- vendor/github.com/karalabe/usb/AUTHORS | 1 + vendor/github.com/karalabe/usb/appveyor.yml | 3 ++ .../karalabe/usb/hidapi/hidapi/hidapi.h | 3 +- .../karalabe/usb/hidapi/windows/hid.c | 38 +++++++++---------- .../github.com/karalabe/usb/usb_disabled.go | 8 ++-- vendor/vendor.json | 6 +-- 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/vendor/github.com/karalabe/usb/AUTHORS b/vendor/github.com/karalabe/usb/AUTHORS index 4112a92f33..bae45b3ec2 100644 --- a/vendor/github.com/karalabe/usb/AUTHORS +++ b/vendor/github.com/karalabe/usb/AUTHORS @@ -1,6 +1,7 @@ Felix Lange Guillaume Ballet Jakob Weisblat +Martin Holst Swende Mateusz Mikołajczyk Péter Szilágyi Rosen Penev diff --git a/vendor/github.com/karalabe/usb/appveyor.yml b/vendor/github.com/karalabe/usb/appveyor.yml index 8d2d3da55c..1f94b37332 100644 --- a/vendor/github.com/karalabe/usb/appveyor.yml +++ b/vendor/github.com/karalabe/usb/appveyor.yml @@ -30,3 +30,6 @@ install: build_script: - go install ./... - go test -v ./... + - set CGO_ENABLED=0 + - go install ./... + - go test -v ./... diff --git a/vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h b/vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h index e5bc2dc40a..166f3509ab 100644 --- a/vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h +++ b/vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h @@ -87,7 +87,7 @@ extern "C" { needed. This function should be called at the beginning of execution however, if there is a chance of HIDAPI handles being opened by different threads simultaneously. - + @ingroup API @returns @@ -388,4 +388,3 @@ extern "C" { #endif #endif - diff --git a/vendor/github.com/karalabe/usb/hidapi/windows/hid.c b/vendor/github.com/karalabe/usb/hidapi/windows/hid.c index 86810d7e56..4e92cc8bc9 100644 --- a/vendor/github.com/karalabe/usb/hidapi/windows/hid.c +++ b/vendor/github.com/karalabe/usb/hidapi/windows/hid.c @@ -8,7 +8,7 @@ 8/22/2009 Copyright 2009, All Rights Reserved. - + At the discretion of the user of this library, this software may be licensed under the terms of the GNU General Public License v3, a BSD-Style license, or the @@ -181,7 +181,7 @@ static void register_error(hid_device *device, const char *op) MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPVOID)&msg, 0/*sz*/, NULL); - + /* Get rid of the CR and LF that FormatMessage() sticks at the end of the message. Thanks Microsoft! */ ptr = msg; @@ -292,9 +292,9 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor /* Get information for all the devices belonging to the HID class. */ device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - + /* Iterate over each device in the HID class, looking for the right one. */ - + for (;;) { HANDLE write_handle = INVALID_HANDLE_VALUE; DWORD required_size = 0; @@ -305,7 +305,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor &InterfaceClassGuid, device_index, &device_interface_data); - + if (!res) { /* A return of FALSE from this function means that there are no more devices. */ @@ -377,7 +377,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor /* Unable to open the device. */ //register_error(dev, "CreateFile"); goto cont_close; - } + } /* Get the Vendor ID and Product ID for this device. */ @@ -421,14 +421,14 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor HidD_FreePreparsedData(pp_data); } - + /* Fill out the record */ cur_dev->next = NULL; str = device_interface_detail_data->DevicePath; if (str) { len = strlen(str); cur_dev->path = (char*) calloc(len+1, sizeof(char)); - strncpy(cur_dev->path, str, len+1); + strncpy(cur_dev->path, str, sizeof(cur_dev->path)); cur_dev->path[len] = '\0'; } else @@ -521,7 +521,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi struct hid_device_info *devs, *cur_dev; const char *path_to_open = NULL; hid_device *handle = NULL; - + devs = hid_enumerate(vendor_id, product_id); cur_dev = devs; while (cur_dev) { @@ -547,7 +547,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi } hid_free_enumeration(devs); - + return handle; } @@ -590,7 +590,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) } nt_res = HidP_GetCaps(pp_data, &caps); if (nt_res != HIDP_STATUS_SUCCESS) { - register_error(dev, "HidP_GetCaps"); + register_error(dev, "HidP_GetCaps"); goto err_pp_data; } dev->output_report_length = caps.OutputReportByteLength; @@ -603,7 +603,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) err_pp_data: HidD_FreePreparsedData(pp_data); -err: +err: free_hid_device(dev); return NULL; } @@ -636,7 +636,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char * } res = WriteFile(dev->device_handle, buf, length, NULL, &ol); - + if (!res) { if (GetLastError() != ERROR_IO_PENDING) { /* WriteFile() failed. Return error. */ @@ -679,7 +679,7 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char memset(dev->read_buf, 0, dev->input_report_length); ResetEvent(ev); res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); - + if (!res) { if (GetLastError() != ERROR_IO_PENDING) { /* ReadFile() has failed. @@ -705,7 +705,7 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char we are in non-blocking mode. Get the number of bytes read. The actual data has been copied to the data[] array which was passed to ReadFile(). */ res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); - + /* Set pending back to false, even if GetOverlappedResult() returned error. */ dev->read_pending = FALSE; @@ -725,13 +725,13 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char memcpy(data, dev->read_buf, copy_len); } } - + end_of_function: if (!res) { register_error(dev, "GetOverlappedResult"); return -1; } - + return copy_len; } @@ -876,7 +876,7 @@ HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) /*#define PICPGM*/ /*#define S11*/ #define P32 -#ifdef S11 +#ifdef S11 unsigned short VendorID = 0xa0a0; unsigned short ProductID = 0x0001; #endif @@ -906,7 +906,7 @@ int __cdecl main(int argc, char* argv[]) memset(buf,0x00,sizeof(buf)); buf[0] = 0; buf[1] = 0x81; - + /* Open the device. */ int handle = open(VendorID, ProductID, L"12345"); diff --git a/vendor/github.com/karalabe/usb/usb_disabled.go b/vendor/github.com/karalabe/usb/usb_disabled.go index 39259856ee..f7f42a4cfe 100644 --- a/vendor/github.com/karalabe/usb/usb_disabled.go +++ b/vendor/github.com/karalabe/usb/usb_disabled.go @@ -27,20 +27,20 @@ func Supported() bool { // Enumerate returns a list of all the USB devices attached to the system which // match the vendor and product id. On platforms that this file implements the // function is a noop and returns an empty list always. -func Enumerate(vendorID uint16, productID uint16) []DeviceInfo { - return nil +func Enumerate(vendorID uint16, productID uint16) ([]DeviceInfo, error) { + return nil, nil } // EnumerateRaw returns a list of all the USB devices attached to the system which // match the vendor and product id. On platforms that this file implements the // function is a noop and returns an empty list always. func EnumerateRaw(vendorID uint16, productID uint16) ([]DeviceInfo, error) { - return nil + return nil, nil } // EnumerateHid returns a list of all the HID devices attached to the system which // match the vendor and product id. On platforms that this file implements the // function is a noop and returns an empty list always. func EnumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) { - return nil + return nil, nil } diff --git a/vendor/vendor.json b/vendor/vendor.json index 6e16243068..946508a333 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -267,10 +267,10 @@ "revisionTime": "2017-04-30T22:20:11Z" }, { - "checksumSHA1": "3v8Z4/daUVp9PCcFzEGYVkPadG8=", + "checksumSHA1": "0ixnoiChdbeva2xNe3z/vYzqcL4=", "path": "github.com/karalabe/usb", - "revision": "c012609e094b8a96375fee53cc11f1bcd5cf3aa2", - "revisionTime": "2019-06-04T10:57:36Z", + "revision": "0efdeddd92369dc00d4fb1b9cd56a442bdb61f82", + "revisionTime": "2019-06-06T09:23:27Z", "tree": true }, { From 19fa9064d713369796da01ed3299a9b8f5a58401 Mon Sep 17 00:00:00 2001 From: Ethan Heilman Date: Thu, 6 Jun 2019 08:40:52 -0400 Subject: [PATCH 41/47] SECURITY.md: create security policy (#19666) Github has started supporting SECURITY.md to contain a project's security policy. Adding this information to the repository makes it easier to determine how to disclosure a vulnerability as SECURITY.md becomes a standard. The pgp fingerprint and key is taken from bounty.ethereum.org. --- SECURITY.md | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..bc54ede42f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,120 @@ +# Security Policy + +## Supported Versions + +Please see Releases. We recommend to use the most recent released version. + +## Audit reports + +Audit reports are published in the `docs` folder: https://github.com/ethereum/go-ethereum/tree/master/docs/audits + + +| Scope | Date | Report Link | +| ------- | ------- | ----------- | +| `geth` | 20170425 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2017-04-25_Geth-audit_Truesec.pdf) | +| `clef` | 20180914 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2018-09-14_Clef-audit_NCC.pdf) | + + + +## Reporting a Vulnerability + +**Please do not file a public ticket** mentioning the vulnerability. + +To find out how to disclose a vulnerability in Ethereum visit [https://bounty.ethereum.org](https://bounty.ethereum.org) or email bounty@ethereum.org. + +The following key may be used to communicate sensitive information to developers. + +Fingerprint: `AE96 ED96 9E47 9B00 84F3 E17F E88D 3334 FA5F 6A0A` + + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFgl3tgBEAC8A1tUBkD9YV+eLrOmtgy+/JS/H9RoZvkg3K1WZ8IYfj6iIRaY +neAk3Bp182GUPVz/zhKr2g0tMXIScDR3EnaDsY+Qg+JqQl8NOG+Cikr1nnkG2on9 +L8c8yiqry1ZTCmYMqCa2acTFqnyuXJ482aZNtB4QG2BpzfhW4k8YThpegk/EoRUi +m+y7buJDtoNf7YILlhDQXN8qlHB02DWOVUihph9tUIFsPK6BvTr9SIr/eG6j6k0b +fUo9pexOn7LS4SojoJmsm/5dp6AoKlac48cZU5zwR9AYcq/nvkrfmf2WkObg/xRd +EvKZzn05jRopmAIwmoC3CiLmqCHPmT5a29vEob/yPFE335k+ujjZCPOu7OwjzDk7 +M0zMSfnNfDq8bXh16nn+ueBxJ0NzgD1oC6c2PhM+XRQCXChoyI8vbfp4dGvCvYqv +QAE1bWjqnumZ/7vUPgZN6gDfiAzG2mUxC2SeFBhacgzDvtQls+uuvm+FnQOUgg2H +h8x2zgoZ7kqV29wjaUPFREuew7e+Th5BxielnzOfVycVXeSuvvIn6cd3g/s8mX1c +2kLSXJR7+KdWDrIrR5Az0kwAqFZt6B6QTlDrPswu3mxsm5TzMbny0PsbL/HBM+GZ +EZCjMXxB8bqV2eSaktjnSlUNX1VXxyOxXA+ZG2jwpr51egi57riVRXokrQARAQAB +tDlFdGhlcmV1bSBGb3VuZGF0aW9uIFNlY3VyaXR5IFRlYW0gPHNlY3VyaXR5QGV0 +aGVyZXVtLm9yZz6JAj4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheA +BQJaCWH6BQkFo2BYAAoJEOiNMzT6X2oK+DEP/3H6dxkm0hvHZKoHLVuuxcu3EHYo +k5sd3MMWPrZSN8qzZnY7ayEDMxnarWOizc+2jfOxfJlzX/g8lR1/fsHdWPFPhPoV +Qk8ygrHn1H8U8+rpw/U03BqmqHpYCDzJ+CIis9UWROniqXw1nuqu/FtWOsdWxNKh +jUo6k/0EsaXsxRPzgJv7fEUcVcQ7as/C3x9sy3muc2gvgA4/BKoGPb1/U0GuA8lV +fDIDshAggmnSUAg+TuYSAAdoFQ1sKwFMPigcLJF2eyKuK3iUyixJrec/c4LSf3wA +cGghbeuqI8INP0Y2zvXDQN2cByxsFAuoZG+m0cyKGaDH2MVUvOKKYqn/03qvrf15 +AWAsW0l0yQwOTCo3FbsNzemClm5Bj/xH0E4XuwXwChcMCMOWJrFoxyvCEI+keoQc +c08/a8/MtS7vBAABXwOziSmm6CNqmzpWrh/fDrjlJlba9U3MxzvqU3IFlTdMratv +6V+SgX+L25lCzW4NxxUavoB8fAlvo8lxpHKo24FP+RcLQ8XqkU3RiUsgRjQRFOqQ +TaJcsp8mimmiYyf24mNu6b48pi+a5c/eQR9w59emeEUZqsJU+nqv8BWIIp7o4Agh +NYnKjkhPlY5e1fLVfAHIADZFynWwRPkPMJSrBiP5EtcOFxQGHGjRxU/KjXkvE0hV +xYb1PB8pWMTu/beeiQI+BBMBAgAoBQJYJd7YAhsDBQkB4TOABgsJCAcDAgYVCAIJ +CgsEFgIDAQIeAQIXgAAKCRDojTM0+l9qCplDD/9IZ2i+m1cnqQKtiyHbyFGx32oL +fzqPylX2bOG5DPsSTorSUdJMGVfT04oVxXc4S/2DVnNvi7RAbSiLapCWSplgtBOj +j1xlblOoXxT3m7s1XHGCX5tENxI9fVSSPVKJn+fQaWpPB2MhBA+1lUI6GJ+11T7K +J8LrP/fiw1/nOb7rW61HW44Gtyox23sA/d1+DsFVaF8hxJlNj5coPKr8xWzQ8pQl +juzdjHDukjevuw4rRmRq9vozvj9keEU9XJ5dldyEVXFmdDk7KT0p0Rla9nxYhzf/ +r/Bv8Bzy0HCWRb2D31BjXXGG05oVnYmNGxGFxYja4MwgrMmne3ilEVjfUJsapsqi +w41BAyQgIdfREulYN7ahsF5PrjVAqBd9IGtE8ULelF2SQxEBQBngEkP0ahP6tRAL +i7/CBjPKOyKijtqVny7qrGOnU2ygcA88/WDibexDhrjz0Gx8WmErU7rIWZiZ5u4Y +vJYVRo0+6rBCXRPeSJfiP5h1p17Anr2l42boAYslfcrzquB8MHtrNcyn650OLtHG +nbxgIdniKrpuzGN6Opw+O2id2JhD1/1p4SOemwAmthplr1MIyOHNP3q93rEj2J7h +5zPS/AJuKkMDFUpslPNLQjCOwPXtdzL7/kUZGBSyez1T3TaW1uY6l9XaJJRaSn+v +1zPgfp4GJ3lPs4AlAbQ0RXRoZXJldW0gRm91bmRhdGlvbiBCdWcgQm91bnR5IDxi +b3VudHlAZXRoZXJldW0ub3JnPokCPgQTAQIAKAIbAwYLCQgHAwIGFQgCCQoLBBYC +AwECHgECF4AFAloJYfoFCQWjYFgACgkQ6I0zNPpfagoENg/+LnSaVeMxiGVtcjWl +b7Xd73yrEy4uxiESS1AalW9mMf7oZzfI05f7QIQlaLAkNac74vZDJbPKjtb7tpMO +RFhRZMCveq6CPKU6pd1SI8IUVUKwpEe6AJP3lHdVP57dquieFE2HlYKm6uHbCGWU +0cjyTA+uu2KbgCHGmofsPY/xOcZLGEHTHqa5w60JJAQm+BSDKnw8wTyrxGvA3EK/ +ePSvOZMYa+iw6vYuZeBIMbdiXR/A2keBi3GuvqB8tDMj7P22TrH5mVDm3zNqGYD6 +amDPeiWp4cztY3aZyLcgYotqXPpDceZzDn+HopBPzAb/llCdE7bVswKRhphVMw4b +bhL0R/TQY7Sf6TK2LKSBrjv0DWOSijikE71SJcBnJvHU7EpKrQQ0lMGclm3ynyji +Nf0YTPXQt4I+fwTmOew2GFeK3UytNWbWI7oXX7Nm4bj9bhf3IJ0kmZb/Gs73+xII +e7Rz52Mby436tWyQIQiF9ITYNGvNf53TwBBZMn0pKPiTyr3Ur7FHEotkEOFNh1// +4zQY10XxuBdLrYGyZ4V8xHJM+oKre8Eg2R9qHXVbjvErHE+7CvgnV7YUip0criPr +BlKRvuoJaSliH2JFhSjWVrkPmFGrWN0BAx10yIqMnEplfKeHf4P9Elek3oInS8WP +G1zJG6s/t5+hQK0X37+TB+6rd3GJAj4EEwECACgFAlgl4TsCGwMFCQHhM4AGCwkI +BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOiNMzT6X2oKzf8P/iIKd77WHTbp4pMN +8h52HyZJtDJmjA1DPZrbGl1TesW/Z9uTd12txlgqZnbG2GfN9+LSP6EOPzR6v2xC +OVhR+RdWhZDJJuQCVS7lJIqQrZgmeTZG0TyQPZdLjVFBOrrhVwYX+HXbu429IzHr +URf5InyR1QgqOXyElDYS6e28HFqvaoA0DWTWDDqOLPVl+U5fuceIE2XXdv3AGLeP +Yf8J5MPobjPiZtBqI6S6iENY2Yn35qLX+axeC/iYSCHVtFuCCIdb/QYR1ZZV8Ps/ +aI9DwC7LU+YfPw7iqCIoqxSeA3o1PORkdSigEg3jtfRv5UqVo9a0oBb9jdoADsat +F/gW0E7mto3XGOiaR0eB9SSdsM3x7Bz4A0HIGNaxpZo1RWqlO91leP4c13Px7ISv +5OGXfLg+M8qb+qxbGd1HpitGi9s1y1aVfEj1kOtZ0tN8eu+Upg5WKwPNBDX3ar7J +9NCULgVSL+E79FG+zXw62gxiQrLfKzm4wU/9L5wVkwQnm29hLJ0tokrSBZFnc/1l +7OC+GM63tYicKkY4rqmoWUeYx7IwFH9mtDtvR1RxO85RbQhZizwpZpdpRkH0DqZu +ZJRmRa5r7rPqmfa7d+VIFhz2Xs8pJMLVqxTsLKcLglmjw7aOrYG0SWeH7YraXWGD +N3SlvSBiVwcK7QUKzLLvpadLwxfsuQINBFgl3tgBEACbgq6HTN5gEBi0lkD/MafI +nmNi+59U5gRGYqk46WlfRjhHudXjDpgD0lolGb4hYontkMaKRlCg2Rvgjvk3Zve0 +PKWjKw7gr8YBa9fMFY8BhAXI32OdyI9rFhxEZFfWAfwKVmT19BdeAQRFvcfd+8w8 +f1XVc+zddULMJFBTr+xKDlIRWwTkdLPQeWbjo0eHl/g4tuLiLrTxVbnj26bf+2+1 +DbM/w5VavzPrkviHqvKe/QP/gay4QDViWvFgLb90idfAHIdsPgflp0VDS5rVHFL6 +D73rSRdIRo3I8c8mYoNjSR4XDuvgOkAKW9LR3pvouFHHjp6Fr0GesRbrbb2EG66i +PsR99MQ7FqIL9VMHPm2mtR+XvbnKkH2rYyEqaMbSdk29jGapkAWle4sIhSKk749A +4tGkHl08KZ2N9o6GrfUehP/V2eJLaph2DioFL1HxRryrKy80QQKLMJRekxigq8gr +eW8xB4zuf9Mkuou+RHNmo8PebHjFstLigiD6/zP2e+4tUmrT0/JTGOShoGMl8Rt0 +VRxdPImKun+4LOXbfOxArOSkY6i35+gsgkkSy1gTJE0BY3S9auT6+YrglY/TWPQ9 +IJxWVOKlT+3WIp5wJu2bBKQ420VLqDYzkoWytel/bM1ACUtipMiIVeUs2uFiRjpz +A1Wy0QHKPTdSuGlJPRrfcQARAQABiQIlBBgBAgAPAhsMBQJaCWIIBQkFo2BYAAoJ +EOiNMzT6X2oKgSwQAKKs7BGF8TyZeIEO2EUK7R2bdQDCdSGZY06tqLFg3IHMGxDM +b/7FVoa2AEsFgv6xpoebxBB5zkhUk7lslgxvKiSLYjxfNjTBltfiFJ+eQnf+OTs8 +KeR51lLa66rvIH2qUzkNDCCTF45H4wIDpV05AXhBjKYkrDCrtey1rQyFp5fxI+0I +Q1UKKXvzZK4GdxhxDbOUSd38MYy93nqcmclGSGK/gF8XiyuVjeifDCM6+T1NQTX0 +K9lneidcqtBDvlggJTLJtQPO33o5EHzXSiud+dKth1uUhZOFEaYRZoye1YE3yB0T +NOOE8fXlvu8iuIAMBSDL9ep6sEIaXYwoD60I2gHdWD0lkP0DOjGQpi4ouXM3Edsd +5MTi0MDRNTij431kn8T/D0LCgmoUmYYMBgbwFhXr67axPZlKjrqR0z3F/Elv0ZPP +cVg1tNznsALYQ9Ovl6b5M3cJ5GapbbvNWC7yEE1qScl9HiMxjt/H6aPastH63/7w +cN0TslW+zRBy05VNJvpWGStQXcngsSUeJtI1Gd992YNjUJq4/Lih6Z1TlwcFVap+ +cTcDptoUvXYGg/9mRNNPZwErSfIJ0Ibnx9wPVuRN6NiCLOt2mtKp2F1pM6AOQPpZ +85vEh6I8i6OaO0w/Z0UHBwvpY6jDUliaROsWUQsqz78Z34CVj4cy6vPW2EF4 +=r6KK +-----END PGP PUBLIC KEY BLOCK----- +``` From 9805288cdd852f6de70b27451a2df320d071af28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 7 Jun 2019 12:30:50 +0300 Subject: [PATCH 42/47] vendor: pull in USB fix for docker (alpine/musl) --- vendor/github.com/karalabe/usb/Dockerfile.alpine | 6 ++++++ vendor/github.com/karalabe/usb/Dockerfile.ubuntu | 4 ++++ vendor/github.com/karalabe/usb/libs.go | 2 +- vendor/vendor.json | 6 +++--- 4 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 vendor/github.com/karalabe/usb/Dockerfile.alpine create mode 100644 vendor/github.com/karalabe/usb/Dockerfile.ubuntu diff --git a/vendor/github.com/karalabe/usb/Dockerfile.alpine b/vendor/github.com/karalabe/usb/Dockerfile.alpine new file mode 100644 index 0000000000..342bdf79a7 --- /dev/null +++ b/vendor/github.com/karalabe/usb/Dockerfile.alpine @@ -0,0 +1,6 @@ +FROM golang:alpine + +RUN apk add --no-cache git gcc musl-dev linux-headers + +ADD . $GOPATH/src/github.com/karalabe/usb +RUN cd $GOPATH/src/github.com/karalabe/usb && go install diff --git a/vendor/github.com/karalabe/usb/Dockerfile.ubuntu b/vendor/github.com/karalabe/usb/Dockerfile.ubuntu new file mode 100644 index 0000000000..b861e497be --- /dev/null +++ b/vendor/github.com/karalabe/usb/Dockerfile.ubuntu @@ -0,0 +1,4 @@ +FROM golang:latest + +ADD . $GOPATH/src/github.com/karalabe/usb +RUN cd $GOPATH/src/github.com/karalabe/usb && go install diff --git a/vendor/github.com/karalabe/usb/libs.go b/vendor/github.com/karalabe/usb/libs.go index 94720fbd46..6446acee9e 100644 --- a/vendor/github.com/karalabe/usb/libs.go +++ b/vendor/github.com/karalabe/usb/libs.go @@ -23,7 +23,7 @@ package usb #cgo CFLAGS: -DDEFAULT_VISIBILITY="" #cgo CFLAGS: -DPOLL_NFDS_TYPE=int -#cgo linux CFLAGS: -DOS_LINUX -D_GNU_SOURCE +#cgo linux CFLAGS: -DOS_LINUX -D_GNU_SOURCE -DHAVE_SYS_TIME_H #cgo linux,!android LDFLAGS: -lrt #cgo darwin CFLAGS: -DOS_DARWIN -DHAVE_SYS_TIME_H #cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit -lobjc diff --git a/vendor/vendor.json b/vendor/vendor.json index 946508a333..94f4742e65 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -267,10 +267,10 @@ "revisionTime": "2017-04-30T22:20:11Z" }, { - "checksumSHA1": "0ixnoiChdbeva2xNe3z/vYzqcL4=", + "checksumSHA1": "wqKuSmlxa4hVZwfs4ZjtKtM5Yp0=", "path": "github.com/karalabe/usb", - "revision": "0efdeddd92369dc00d4fb1b9cd56a442bdb61f82", - "revisionTime": "2019-06-06T09:23:27Z", + "revision": "3eff4807c21acef1c5f1b712a225ab09a8961504", + "revisionTime": "2019-06-07T09:24:32Z", "tree": true }, { From 1b15c6da33bac1f8c79415a66f22463511ac15a8 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Fri, 7 Jun 2019 11:41:54 +0200 Subject: [PATCH 43/47] accounts/scwallet: Disable macos support (#19679) --- .../gballet/go-libpcsclite/doc_bsd.go | 4 +-- .../gballet/go-libpcsclite/doc_darwin.go | 35 +++++++++++++++++++ vendor/vendor.json | 6 ++-- 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc_darwin.go diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go b/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go index ddec46c670..672c672e4f 100644 --- a/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go +++ b/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go @@ -28,8 +28,8 @@ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +build dragonfly darwin freebsd netbsd openbsd solaris +// +build dragonfly freebsd netbsd openbsd solaris package pcsc -const PCSCDSockName string = "/var/run/pcscd/pcscd.comm" \ No newline at end of file +const PCSCDSockName string = "/var/run/pcscd/pcscd.comm" diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_darwin.go b/vendor/github.com/gballet/go-libpcsclite/doc_darwin.go new file mode 100644 index 0000000000..3dec7c79b4 --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/doc_darwin.go @@ -0,0 +1,35 @@ +// BSD 3-Clause License +// +// Copyright (c) 2019, Guillaume Ballet +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build darwin + +package pcsc + +const PCSCDSockName string = "" diff --git a/vendor/vendor.json b/vendor/vendor.json index 94f4742e65..a1f21f0e17 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -135,10 +135,10 @@ "revisionTime": "2018-04-18T12:24:29Z" }, { - "checksumSHA1": "+fiJGimxPPRSfi9sED4Lp6ytBeo=", + "checksumSHA1": "gsiYVjwKzFKe+JuIimgKlrPyipA=", "path": "github.com/gballet/go-libpcsclite", - "revision": "2fd9b619dd3c5d74acbd975f997a6441984d74a7", - "revisionTime": "2019-05-28T10:50:17Z" + "revision": "2772fd86a8ff4306d2749f610a386bfee9e0d727", + "revisionTime": "2019-06-07T06:51:34Z" }, { "checksumSHA1": "gxV/cPPLkByTdY8y172t7v4qcZA=", From 896322bf88f40329b400d691cbdce9275739310e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 7 Jun 2019 15:29:16 +0200 Subject: [PATCH 44/47] cmd/devp2p: add devp2p debug tool (#19657) * p2p/discover: export Ping and RequestENR These two are useful for checking the status of a node. * cmd/devp2p: add devp2p debug tool This is a new tool for debugging p2p issues. It supports a few basic tasks for now, but many more things can and will be added in the near future. devp2p enrdump -- prints ENRs readably devp2p discv4 ping -- checks if a node is up devp2p discv4 requestenr -- gets a node's record devp2p discv4 resolve -- finds a node through the DHT --- cmd/devp2p/discv4cmd.go | 166 ++++++++++++++++++++++++++ cmd/devp2p/enrcmd.go | 198 ++++++++++++++++++++++++++++++++ cmd/devp2p/main.go | 68 +++++++++++ p2p/discover/table.go | 4 +- p2p/discover/table_util_test.go | 2 +- p2p/discover/v4_udp.go | 16 ++- 6 files changed, 446 insertions(+), 8 deletions(-) create mode 100644 cmd/devp2p/discv4cmd.go create mode 100644 cmd/devp2p/enrcmd.go create mode 100644 cmd/devp2p/main.go diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go new file mode 100644 index 0000000000..1e56687a6c --- /dev/null +++ b/cmd/devp2p/discv4cmd.go @@ -0,0 +1,166 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "net" + "sort" + "strings" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params" + "gopkg.in/urfave/cli.v1" +) + +var ( + discv4Command = cli.Command{ + Name: "discv4", + Usage: "Node Discovery v4 tools", + Subcommands: []cli.Command{ + discv4PingCommand, + discv4RequestRecordCommand, + discv4ResolveCommand, + }, + } + discv4PingCommand = cli.Command{ + Name: "ping", + Usage: "Sends ping to a node", + Action: discv4Ping, + } + discv4RequestRecordCommand = cli.Command{ + Name: "requestenr", + Usage: "Requests a node record using EIP-868 enrRequest", + Action: discv4RequestRecord, + } + discv4ResolveCommand = cli.Command{ + Name: "resolve", + Usage: "Finds a node in the DHT", + Action: discv4Resolve, + Flags: []cli.Flag{bootnodesFlag}, + } +) + +var bootnodesFlag = cli.StringFlag{ + Name: "bootnodes", + Usage: "Comma separated nodes used for bootstrapping", +} + +func discv4Ping(ctx *cli.Context) error { + n, disc, err := getNodeArgAndStartV4(ctx) + if err != nil { + return err + } + defer disc.Close() + + start := time.Now() + if err := disc.Ping(n); err != nil { + return fmt.Errorf("node didn't respond: %v", err) + } + fmt.Printf("node responded to ping (RTT %v).\n", time.Since(start)) + return nil +} + +func discv4RequestRecord(ctx *cli.Context) error { + n, disc, err := getNodeArgAndStartV4(ctx) + if err != nil { + return err + } + defer disc.Close() + + respN, err := disc.RequestENR(n) + if err != nil { + return fmt.Errorf("can't retrieve record: %v", err) + } + fmt.Println(respN.String()) + return nil +} + +func discv4Resolve(ctx *cli.Context) error { + n, disc, err := getNodeArgAndStartV4(ctx) + if err != nil { + return err + } + defer disc.Close() + + fmt.Println(disc.Resolve(n).String()) + return nil +} + +func getNodeArgAndStartV4(ctx *cli.Context) (*enode.Node, *discover.UDPv4, error) { + if ctx.NArg() != 1 { + return nil, nil, fmt.Errorf("missing node as command-line argument") + } + n, err := parseNode(ctx.Args()[0]) + if err != nil { + return nil, nil, err + } + var bootnodes []*enode.Node + if commandHasFlag(ctx, bootnodesFlag) { + bootnodes, err = parseBootnodes(ctx) + if err != nil { + return nil, nil, err + } + } + disc, err := startV4(bootnodes) + return n, disc, err +} + +func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) { + s := params.RinkebyBootnodes + if ctx.IsSet(bootnodesFlag.Name) { + s = strings.Split(ctx.String(bootnodesFlag.Name), ",") + } + nodes := make([]*enode.Node, len(s)) + var err error + for i, record := range s { + nodes[i], err = parseNode(record) + if err != nil { + return nil, fmt.Errorf("invalid bootstrap node: %v", err) + } + } + return nodes, nil +} + +// commandHasFlag returns true if the current command supports the given flag. +func commandHasFlag(ctx *cli.Context, flag cli.Flag) bool { + flags := ctx.FlagNames() + sort.Strings(flags) + i := sort.SearchStrings(flags, flag.GetName()) + return i != len(flags) && flags[i] == flag.GetName() +} + +// startV4 starts an ephemeral discovery V4 node. +func startV4(bootnodes []*enode.Node) (*discover.UDPv4, error) { + var cfg discover.Config + cfg.Bootnodes = bootnodes + cfg.PrivateKey, _ = crypto.GenerateKey() + db, _ := enode.OpenDB("") + ln := enode.NewLocalNode(db, cfg.PrivateKey) + + socket, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IP{0, 0, 0, 0}}) + if err != nil { + return nil, err + } + addr := socket.LocalAddr().(*net.UDPAddr) + ln.SetFallbackIP(net.IP{127, 0, 0, 1}) + ln.SetFallbackUDP(addr.Port) + return discover.ListenUDP(socket, ln, cfg) +} diff --git a/cmd/devp2p/enrcmd.go b/cmd/devp2p/enrcmd.go new file mode 100644 index 0000000000..15d77dd011 --- /dev/null +++ b/cmd/devp2p/enrcmd.go @@ -0,0 +1,198 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "encoding/base64" + "encoding/hex" + "fmt" + "io/ioutil" + "net" + "os" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" + "gopkg.in/urfave/cli.v1" +) + +var enrdumpCommand = cli.Command{ + Name: "enrdump", + Usage: "Pretty-prints node records", + Action: enrdump, + Flags: []cli.Flag{ + cli.StringFlag{Name: "file"}, + }, +} + +func enrdump(ctx *cli.Context) error { + var source string + if file := ctx.String("file"); file != "" { + if ctx.NArg() != 0 { + return fmt.Errorf("can't dump record from command-line argument in -file mode") + } + var b []byte + var err error + if file == "-" { + b, err = ioutil.ReadAll(os.Stdin) + } else { + b, err = ioutil.ReadFile(file) + } + if err != nil { + return err + } + source = string(b) + } else if ctx.NArg() == 1 { + source = ctx.Args()[0] + } else { + return fmt.Errorf("need record as argument") + } + + r, err := parseRecord(source) + if err != nil { + return fmt.Errorf("INVALID: %v", err) + } + fmt.Print(dumpRecord(r)) + return nil +} + +// dumpRecord creates a human-readable description of the given node record. +func dumpRecord(r *enr.Record) string { + out := new(bytes.Buffer) + if n, err := enode.New(enode.ValidSchemes, r); err != nil { + fmt.Fprintf(out, "INVALID: %v\n", err) + } else { + fmt.Fprintf(out, "Node ID: %v\n", n.ID()) + } + kv := r.AppendElements(nil)[1:] + fmt.Fprintf(out, "Record has sequence number %d and %d key/value pairs.\n", r.Seq(), len(kv)/2) + fmt.Fprint(out, dumpRecordKV(kv, 2)) + return out.String() +} + +func dumpRecordKV(kv []interface{}, indent int) string { + // Determine the longest key name for alignment. + var out string + var longestKey = 0 + for i := 0; i < len(kv); i += 2 { + key := kv[i].(string) + if len(key) > longestKey { + longestKey = len(key) + } + } + // Print the keys, invoking formatters for known keys. + for i := 0; i < len(kv); i += 2 { + key := kv[i].(string) + val := kv[i+1].(rlp.RawValue) + pad := longestKey - len(key) + out += strings.Repeat(" ", indent) + strconv.Quote(key) + strings.Repeat(" ", pad+1) + formatter := attrFormatters[key] + if formatter == nil { + formatter = formatAttrRaw + } + fmtval, ok := formatter(val) + if ok { + out += fmtval + "\n" + } else { + out += hex.EncodeToString(val) + " (!)\n" + } + } + return out +} + +// parseNode parses a node record and verifies its signature. +func parseNode(source string) (*enode.Node, error) { + if strings.HasPrefix(source, "enode://") { + return enode.ParseV4(source) + } + r, err := parseRecord(source) + if err != nil { + return nil, err + } + return enode.New(enode.ValidSchemes, r) +} + +// parseRecord parses a node record from hex, base64, or raw binary input. +func parseRecord(source string) (*enr.Record, error) { + bin := []byte(source) + if d, ok := decodeRecordHex(bytes.TrimSpace(bin)); ok { + bin = d + } else if d, ok := decodeRecordBase64(bytes.TrimSpace(bin)); ok { + bin = d + } + var r enr.Record + err := rlp.DecodeBytes(bin, &r) + return &r, err +} + +func decodeRecordHex(b []byte) ([]byte, bool) { + if bytes.HasPrefix(b, []byte("0x")) { + b = b[2:] + } + dec := make([]byte, hex.DecodedLen(len(b))) + _, err := hex.Decode(dec, b) + return dec, err == nil +} + +func decodeRecordBase64(b []byte) ([]byte, bool) { + if bytes.HasPrefix(b, []byte("enr:")) { + b = b[4:] + } + dec := make([]byte, base64.RawURLEncoding.DecodedLen(len(b))) + n, err := base64.RawURLEncoding.Decode(dec, b) + return dec[:n], err == nil +} + +// attrFormatters contains formatting functions for well-known ENR keys. +var attrFormatters = map[string]func(rlp.RawValue) (string, bool){ + "id": formatAttrString, + "ip": formatAttrIP, + "ip6": formatAttrIP, + "tcp": formatAttrUint, + "tcp6": formatAttrUint, + "udp": formatAttrUint, + "udp6": formatAttrUint, +} + +func formatAttrRaw(v rlp.RawValue) (string, bool) { + s := hex.EncodeToString(v) + return s, true +} + +func formatAttrString(v rlp.RawValue) (string, bool) { + content, _, err := rlp.SplitString(v) + return strconv.Quote(string(content)), err == nil +} + +func formatAttrIP(v rlp.RawValue) (string, bool) { + content, _, err := rlp.SplitString(v) + if err != nil || len(content) != 4 && len(content) != 6 { + return "", false + } + return net.IP(content).String(), true +} + +func formatAttrUint(v rlp.RawValue) (string, bool) { + var x uint64 + if err := rlp.DecodeBytes(v, &x); err != nil { + return "", false + } + return strconv.FormatUint(x, 10), true +} diff --git a/cmd/devp2p/main.go b/cmd/devp2p/main.go new file mode 100644 index 0000000000..4532ab9683 --- /dev/null +++ b/cmd/devp2p/main.go @@ -0,0 +1,68 @@ +// Copyright 2019 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/ethereum/go-ethereum/internal/debug" + "github.com/ethereum/go-ethereum/params" + "gopkg.in/urfave/cli.v1" +) + +var ( + // Git information set by linker when building with ci.go. + gitCommit string + gitDate string + app = &cli.App{ + Name: filepath.Base(os.Args[0]), + Usage: "go-ethereum devp2p tool", + Version: params.VersionWithCommit(gitCommit, gitDate), + Writer: os.Stdout, + HideVersion: true, + } +) + +func init() { + // Set up the CLI app. + app.Flags = append(app.Flags, debug.Flags...) + app.Before = func(ctx *cli.Context) error { + return debug.Setup(ctx, "") + } + app.After = func(ctx *cli.Context) error { + debug.Exit() + return nil + } + app.CommandNotFound = func(ctx *cli.Context, cmd string) { + fmt.Fprintf(os.Stderr, "No such command: %s\n", cmd) + os.Exit(1) + } + // Add subcommands. + app.Commands = []cli.Command{ + enrdumpCommand, + discv4Command, + } +} + +func main() { + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 3460e8377c..e0a46792b4 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -85,10 +85,10 @@ type Table struct { // transport is implemented by the UDP transports. type transport interface { Self() *enode.Node + RequestENR(*enode.Node) (*enode.Node, error) lookupRandom() []*enode.Node lookupSelf() []*enode.Node ping(*enode.Node) (seq uint64, err error) - requestENR(*enode.Node) (*enode.Node, error) } // bucket contains nodes, ordered by their last activity. the entry @@ -344,7 +344,7 @@ func (tab *Table) doRevalidate(done chan<- struct{}) { // Also fetch record if the node replied and returned a higher sequence number. if last.Seq() < remoteSeq { - n, err := tab.net.requestENR(unwrapNode(last)) + n, err := tab.net.RequestENR(unwrapNode(last)) if err != nil { tab.log.Debug("ENR request failed", "id", last.ID(), "addr", last.addr(), "err", err) } else { diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 3075c43408..8e5fc7374b 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -145,7 +145,7 @@ func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) { } // requestENR simulates an ENR request. -func (t *pingRecorder) requestENR(n *enode.Node) (*enode.Node, error) { +func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { t.mu.Lock() defer t.mu.Unlock() diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index b3569b6719..b2a5d85cf4 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -415,13 +415,13 @@ func (t *UDPv4) lookupWorker(n *node, targetKey encPubkey, reply chan<- []*node) // version of the node record for it. It returns n if the node could not be resolved. func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { // Try asking directly. This works if the node is still responding on the endpoint we have. - if rn, err := t.requestENR(n); err == nil { + if rn, err := t.RequestENR(n); err == nil { return rn } // Check table for the ID, we might have a newer version there. if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() { n = intable - if rn, err := t.requestENR(n); err == nil { + if rn, err := t.RequestENR(n); err == nil { return rn } } @@ -433,7 +433,7 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { result := t.LookupPubkey((*ecdsa.PublicKey)(&key)) for _, rn := range result { if rn.ID() == n.ID() { - if rn, err := t.requestENR(rn); err == nil { + if rn, err := t.RequestENR(rn); err == nil { return rn } } @@ -447,6 +447,12 @@ func (t *UDPv4) ourEndpoint() rpcEndpoint { return makeEndpoint(a, uint16(n.TCP())) } +// Ping sends a ping message to the given node. +func (t *UDPv4) Ping(n *enode.Node) error { + _, err := t.ping(n) + return err +} + // ping sends a ping message to the given node and waits for a reply. func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { rm := t.sendPing(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, nil) @@ -521,8 +527,8 @@ func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ( return nodes, <-rm.errc } -// requestENR sends enrRequest to the given node and waits for a response. -func (t *UDPv4) requestENR(n *enode.Node) (*enode.Node, error) { +// RequestENR sends enrRequest to the given node and waits for a response. +func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} t.ensureBond(n.ID(), addr) From e83c3ccc47b2001b7871b60084d10c5f861c9c93 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 7 Jun 2019 15:31:00 +0200 Subject: [PATCH 45/47] p2p/enode: improve IPv6 support, add ENR text representation (#19663) * p2p/enr: add entries for for IPv4/IPv6 separation This adds entry types for "ip6", "udp6", "tcp6" keys. The IP type stays around because removing it would break a lot of code and force everyone to care about the distinction. * p2p/enode: track IPv4 and IPv6 address separately LocalNode predicts the local node's UDP endpoint and updates the record. This change makes it predict IPv4 and IPv6 endpoints separately since they can now be in the record at the same time. * p2p/enode: implement base64 text format * all: switch to enode.Parse(...) This allows passing base64-encoded node records to all the places that previously accepted enode:// URLs. The URL format is still supported. * cmd/bootnode, p2p: log node URL instead of ENR ...and return the base64 record in NodeInfo. --- cmd/bootnode/main.go | 2 +- cmd/faucet/faucet.go | 2 +- cmd/utils/flags.go | 2 +- cmd/wnode/main.go | 6 +- les/serverpool.go | 2 +- les/ulc.go | 2 +- node/api.go | 8 +- node/config.go | 2 +- p2p/discover/v4_udp_test.go | 8 +- p2p/enode/localnode.go | 120 +++++++++++++++-------- p2p/enode/localnode_test.go | 46 +++++++++ p2p/enode/node.go | 67 ++++++++++--- p2p/enode/node_test.go | 87 ++++++++++++++++- p2p/enode/urlv4.go | 18 ++-- p2p/enode/urlv4_test.go | 187 +++++++++++++----------------------- p2p/enr/enr.go | 12 ++- p2p/enr/enr_test.go | 24 ++--- p2p/enr/entries.go | 76 ++++++++++++++- p2p/server.go | 9 +- whisper/whisperv6/api.go | 4 +- 20 files changed, 464 insertions(+), 220 deletions(-) diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go index a40b32b600..2f9bba1117 100644 --- a/cmd/bootnode/main.go +++ b/cmd/bootnode/main.go @@ -143,7 +143,7 @@ func printNotice(nodeKey *ecdsa.PublicKey, addr net.UDPAddr) { addr.IP = net.IP{127, 0, 0, 1} } n := enode.NewV4(nodeKey, addr.IP, 0, addr.Port) - fmt.Println(n.String()) + fmt.Println(n.URLv4()) fmt.Println("Note: you're using cmd/bootnode, a developer tool.") fmt.Println("We recommend using a regular node as bootstrap node for production deployments.") } diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 08b23d46cd..f8092084ad 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -260,7 +260,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u return nil, err } for _, boot := range enodes { - old, err := enode.ParseV4(boot.String()) + old, err := enode.Parse(enode.ValidSchemes, boot.String()) if err == nil { stack.Server().AddPeer(old) } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 002d37f164..973e47ea0c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -794,7 +794,7 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) for _, url := range urls { if url != "" { - node, err := enode.ParseV4(url) + node, err := enode.Parse(enode.ValidSchemes, url) if err != nil { log.Crit("Bootstrap URL invalid", "enode", url, "err", err) continue diff --git a/cmd/wnode/main.go b/cmd/wnode/main.go index 97e5852013..99cf84ec1b 100644 --- a/cmd/wnode/main.go +++ b/cmd/wnode/main.go @@ -203,7 +203,7 @@ func initialize() { if len(*argEnode) == 0 { argEnode = scanLineA("Please enter the peer's enode: ") } - peer := enode.MustParseV4(*argEnode) + peer := enode.MustParse(*argEnode) peers = append(peers, peer) } @@ -747,9 +747,9 @@ func requestExpiredMessagesLoop() { } func extractIDFromEnode(s string) []byte { - n, err := enode.ParseV4(s) + n, err := enode.Parse(enode.ValidSchemes, s) if err != nil { - utils.Fatalf("Failed to parse enode: %s", err) + utils.Fatalf("Failed to parse node: %s", err) } return n.ID().Bytes() } diff --git a/les/serverpool.go b/les/serverpool.go index 668f39c562..3e8cdee410 100644 --- a/les/serverpool.go +++ b/les/serverpool.go @@ -505,7 +505,7 @@ func parseTrustedNodes(trustedNodes []string) map[enode.ID]*enode.Node { nodes := make(map[enode.ID]*enode.Node) for _, node := range trustedNodes { - node, err := enode.ParseV4(node) + node, err := enode.Parse(enode.ValidSchemes, node) if err != nil { log.Warn("Trusted node URL invalid", "enode", node, "err", err) continue diff --git a/les/ulc.go b/les/ulc.go index c6d4155529..8792f60d3c 100644 --- a/les/ulc.go +++ b/les/ulc.go @@ -34,7 +34,7 @@ func newULC(ulcConfig *eth.ULCConfig) *ulc { } m := make(map[string]struct{}, len(ulcConfig.TrustedServers)) for _, id := range ulcConfig.TrustedServers { - node, err := enode.ParseV4(id) + node, err := enode.Parse(enode.ValidSchemes, id) if err != nil { log.Debug("Failed to parse trusted server", "id", id, "err", err) continue diff --git a/node/api.go b/node/api.go index cc80efabec..66cd1dde33 100644 --- a/node/api.go +++ b/node/api.go @@ -49,7 +49,7 @@ func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { return false, ErrNodeStopped } // Try to add the url as a static peer and return - node, err := enode.ParseV4(url) + node, err := enode.Parse(enode.ValidSchemes, url) if err != nil { return false, fmt.Errorf("invalid enode: %v", err) } @@ -65,7 +65,7 @@ func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { return false, ErrNodeStopped } // Try to remove the url as a static peer and return - node, err := enode.ParseV4(url) + node, err := enode.Parse(enode.ValidSchemes, url) if err != nil { return false, fmt.Errorf("invalid enode: %v", err) } @@ -80,7 +80,7 @@ func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) { if server == nil { return false, ErrNodeStopped } - node, err := enode.ParseV4(url) + node, err := enode.Parse(enode.ValidSchemes, url) if err != nil { return false, fmt.Errorf("invalid enode: %v", err) } @@ -96,7 +96,7 @@ func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) { if server == nil { return false, ErrNodeStopped } - node, err := enode.ParseV4(url) + node, err := enode.Parse(enode.ValidSchemes, url) if err != nil { return false, fmt.Errorf("invalid enode: %v", err) } diff --git a/node/config.go b/node/config.go index 31d36f203f..1905ac7fa5 100644 --- a/node/config.go +++ b/node/config.go @@ -425,7 +425,7 @@ func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node { if url == "" { continue } - node, err := enode.ParseV4(url) + node, err := enode.Parse(enode.ValidSchemes, url) if err != nil { log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) continue diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 9d7badea19..c4f5b5de0f 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -342,10 +342,10 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { // send the reply as two packets. list := []*node{ - wrapNode(enode.MustParseV4("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304")), - wrapNode(enode.MustParseV4("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303")), - wrapNode(enode.MustParseV4("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17")), - wrapNode(enode.MustParseV4("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303")), + wrapNode(enode.MustParse("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304")), + wrapNode(enode.MustParse("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303")), + wrapNode(enode.MustParse("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17")), + wrapNode(enode.MustParse("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303")), } rpclist := make([]rpcNode, len(list)) for i := range list { diff --git a/p2p/enode/localnode.go b/p2p/enode/localnode.go index 623f8eae18..d8aa02a77e 100644 --- a/p2p/enode/localnode.go +++ b/p2p/enode/localnode.go @@ -48,23 +48,32 @@ type LocalNode struct { db *DB // everything below is protected by a lock - mu sync.Mutex - seq uint64 - entries map[string]enr.Entry - udpTrack *netutil.IPTracker // predicts external UDP endpoint - staticIP net.IP - fallbackIP net.IP - fallbackUDP int + mu sync.Mutex + seq uint64 + entries map[string]enr.Entry + endpoint4 lnEndpoint + endpoint6 lnEndpoint +} + +type lnEndpoint struct { + track *netutil.IPTracker + staticIP, fallbackIP net.IP + fallbackUDP int } // NewLocalNode creates a local node. func NewLocalNode(db *DB, key *ecdsa.PrivateKey) *LocalNode { ln := &LocalNode{ - id: PubkeyToIDV4(&key.PublicKey), - db: db, - key: key, - udpTrack: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), - entries: make(map[string]enr.Entry), + id: PubkeyToIDV4(&key.PublicKey), + db: db, + key: key, + entries: make(map[string]enr.Entry), + endpoint4: lnEndpoint{ + track: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), + }, + endpoint6: lnEndpoint{ + track: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), + }, } ln.seq = db.localSeq(ln.id) ln.invalidate() @@ -89,13 +98,22 @@ func (ln *LocalNode) Node() *Node { return ln.cur.Load().(*Node) } +// Seq returns the current sequence number of the local node record. +func (ln *LocalNode) Seq() uint64 { + ln.mu.Lock() + defer ln.mu.Unlock() + + return ln.seq +} + // ID returns the local node ID. func (ln *LocalNode) ID() ID { return ln.id } -// Set puts the given entry into the local record, overwriting -// any existing value. +// Set puts the given entry into the local record, overwriting any existing value. +// Use Set*IP and SetFallbackUDP to set IP addresses and UDP port, otherwise they'll +// be overwritten by the endpoint predictor. func (ln *LocalNode) Set(e enr.Entry) { ln.mu.Lock() defer ln.mu.Unlock() @@ -127,13 +145,20 @@ func (ln *LocalNode) delete(e enr.Entry) { } } +func (ln *LocalNode) endpointForIP(ip net.IP) *lnEndpoint { + if ip.To4() != nil { + return &ln.endpoint4 + } + return &ln.endpoint6 +} + // SetStaticIP sets the local IP to the given one unconditionally. // This disables endpoint prediction. func (ln *LocalNode) SetStaticIP(ip net.IP) { ln.mu.Lock() defer ln.mu.Unlock() - ln.staticIP = ip + ln.endpointForIP(ip).staticIP = ip ln.updateEndpoints() } @@ -143,17 +168,18 @@ func (ln *LocalNode) SetFallbackIP(ip net.IP) { ln.mu.Lock() defer ln.mu.Unlock() - ln.fallbackIP = ip + ln.endpointForIP(ip).fallbackIP = ip ln.updateEndpoints() } -// SetFallbackUDP sets the last-resort UDP port. This port is used +// SetFallbackUDP sets the last-resort UDP-on-IPv4 port. This port is used // if no endpoint prediction can be made. func (ln *LocalNode) SetFallbackUDP(port int) { ln.mu.Lock() defer ln.mu.Unlock() - ln.fallbackUDP = port + ln.endpoint4.fallbackUDP = port + ln.endpoint6.fallbackUDP = port ln.updateEndpoints() } @@ -163,7 +189,7 @@ func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint *net.UDPAddr) { ln.mu.Lock() defer ln.mu.Unlock() - ln.udpTrack.AddStatement(fromaddr.String(), endpoint.String()) + ln.endpointForIP(endpoint.IP).track.AddStatement(fromaddr.String(), endpoint.String()) ln.updateEndpoints() } @@ -173,32 +199,50 @@ func (ln *LocalNode) UDPContact(toaddr *net.UDPAddr) { ln.mu.Lock() defer ln.mu.Unlock() - ln.udpTrack.AddContact(toaddr.String()) + ln.endpointForIP(toaddr.IP).track.AddContact(toaddr.String()) ln.updateEndpoints() } +// updateEndpoints updates the record with predicted endpoints. func (ln *LocalNode) updateEndpoints() { - // Determine the endpoints. - newIP := ln.fallbackIP - newUDP := ln.fallbackUDP - if ln.staticIP != nil { - newIP = ln.staticIP - } else if ip, port := predictAddr(ln.udpTrack); ip != nil { - newIP = ip - newUDP = port - } + ip4, udp4 := ln.endpoint4.get() + ip6, udp6 := ln.endpoint6.get() - // Update the record. - if newIP != nil && !newIP.IsUnspecified() { - ln.set(enr.IP(newIP)) - if newUDP != 0 { - ln.set(enr.UDP(newUDP)) - } else { - ln.delete(enr.UDP(0)) - } + if ip4 != nil && !ip4.IsUnspecified() { + ln.set(enr.IPv4(ip4)) } else { - ln.delete(enr.IP{}) + ln.delete(enr.IPv4{}) } + if ip6 != nil && !ip6.IsUnspecified() { + ln.set(enr.IPv6(ip6)) + } else { + ln.delete(enr.IPv6{}) + } + if udp4 != 0 { + ln.set(enr.UDP(udp4)) + } else { + ln.delete(enr.UDP(0)) + } + if udp6 != 0 && udp6 != udp4 { + ln.set(enr.UDP6(udp6)) + } else { + ln.delete(enr.UDP6(0)) + } +} + +// get returns the endpoint with highest precedence. +func (e *lnEndpoint) get() (newIP net.IP, newPort int) { + newPort = e.fallbackUDP + if e.fallbackIP != nil { + newIP = e.fallbackIP + } + if e.staticIP != nil { + newIP = e.staticIP + } else if ip, port := predictAddr(e.track); ip != nil { + newIP = ip + newPort = port + } + return newIP, newPort } // predictAddr wraps IPTracker.PredictEndpoint, converting from its string-based diff --git a/p2p/enode/localnode_test.go b/p2p/enode/localnode_test.go index f5e3496d63..00746a8d27 100644 --- a/p2p/enode/localnode_test.go +++ b/p2p/enode/localnode_test.go @@ -17,10 +17,13 @@ package enode import ( + "math/rand" + "net" "testing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/stretchr/testify/assert" ) func newLocalNodeForTesting() (*LocalNode, *DB) { @@ -74,3 +77,46 @@ func TestLocalNodeSeqPersist(t *testing.T) { t.Fatalf("wrong seq %d on instance with changed key, want 1", s) } } + +// This test checks behavior of the endpoint predictor. +func TestLocalNodeEndpoint(t *testing.T) { + var ( + fallback = &net.UDPAddr{IP: net.IP{127, 0, 0, 1}, Port: 80} + predicted = &net.UDPAddr{IP: net.IP{127, 0, 1, 2}, Port: 81} + staticIP = net.IP{127, 0, 1, 2} + ) + ln, db := newLocalNodeForTesting() + defer db.Close() + + // Nothing is set initially. + assert.Equal(t, net.IP(nil), ln.Node().IP()) + assert.Equal(t, 0, ln.Node().UDP()) + assert.Equal(t, uint64(1), ln.Node().Seq()) + + // Set up fallback address. + ln.SetFallbackIP(fallback.IP) + ln.SetFallbackUDP(fallback.Port) + assert.Equal(t, fallback.IP, ln.Node().IP()) + assert.Equal(t, fallback.Port, ln.Node().UDP()) + assert.Equal(t, uint64(2), ln.Node().Seq()) + + // Add endpoint statements from random hosts. + for i := 0; i < iptrackMinStatements; i++ { + assert.Equal(t, fallback.IP, ln.Node().IP()) + assert.Equal(t, fallback.Port, ln.Node().UDP()) + assert.Equal(t, uint64(2), ln.Node().Seq()) + + from := &net.UDPAddr{IP: make(net.IP, 4), Port: 90} + rand.Read(from.IP) + ln.UDPEndpointStatement(from, predicted) + } + assert.Equal(t, predicted.IP, ln.Node().IP()) + assert.Equal(t, predicted.Port, ln.Node().UDP()) + assert.Equal(t, uint64(3), ln.Node().Seq()) + + // Static IP overrides prediction. + ln.SetStaticIP(staticIP) + assert.Equal(t, staticIP, ln.Node().IP()) + assert.Equal(t, fallback.Port, ln.Node().UDP()) + assert.Equal(t, uint64(4), ln.Node().Seq()) +} diff --git a/p2p/enode/node.go b/p2p/enode/node.go index b454ab2554..9eb2544ffe 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -18,6 +18,7 @@ package enode import ( "crypto/ecdsa" + "encoding/base64" "encoding/hex" "errors" "fmt" @@ -27,8 +28,11 @@ import ( "strings" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" ) +var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record") + // Node represents a host on the network. type Node struct { r enr.Record @@ -48,6 +52,34 @@ func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { return node, nil } +// MustParse parses a node record or enode:// URL. It panics if the input is invalid. +func MustParse(rawurl string) *Node { + n, err := Parse(ValidSchemes, rawurl) + if err != nil { + panic("invalid node: " + err.Error()) + } + return n +} + +// Parse decodes and verifies a base64-encoded node record. +func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) { + if strings.HasPrefix(input, "enode://") { + return ParseV4(input) + } + if !strings.HasPrefix(input, "enr:") { + return nil, errMissingPrefix + } + bin, err := base64.RawURLEncoding.DecodeString(input[4:]) + if err != nil { + return nil, err + } + var r enr.Record + if err := rlp.DecodeBytes(bin, &r); err != nil { + return nil, err + } + return New(validSchemes, &r) +} + // ID returns the node identifier. func (n *Node) ID() ID { return n.id @@ -68,11 +100,19 @@ func (n *Node) Load(k enr.Entry) error { return n.r.Load(k) } -// IP returns the IP address of the node. +// IP returns the IP address of the node. This prefers IPv4 addresses. func (n *Node) IP() net.IP { - var ip net.IP - n.Load((*enr.IP)(&ip)) - return ip + var ( + ip4 enr.IPv4 + ip6 enr.IPv6 + ) + if n.Load(&ip4) == nil { + return net.IP(ip4) + } + if n.Load(&ip6) == nil { + return net.IP(ip6) + } + return nil } // UDP returns the UDP port of the node. @@ -105,10 +145,11 @@ func (n *Node) Record() *enr.Record { return &cpy } -// checks whether n is a valid complete node. +// ValidateComplete checks whether n has a valid IP and UDP port. +// Deprecated: don't use this method. func (n *Node) ValidateComplete() error { if n.Incomplete() { - return errors.New("incomplete node") + return errors.New("missing IP address") } if n.UDP() == 0 { return errors.New("missing UDP port") @@ -122,20 +163,24 @@ func (n *Node) ValidateComplete() error { return n.Load(&key) } -// The string representation of a Node is a URL. -// Please see ParseNode for a description of the format. +// String returns the text representation of the record. func (n *Node) String() string { - return n.v4URL() + if isNewV4(n) { + return n.URLv4() // backwards-compatibility glue for NewV4 nodes + } + enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid + b64 := base64.RawURLEncoding.EncodeToString(enc) + return "enr:" + b64 } // MarshalText implements encoding.TextMarshaler. func (n *Node) MarshalText() ([]byte, error) { - return []byte(n.v4URL()), nil + return []byte(n.String()), nil } // UnmarshalText implements encoding.TextUnmarshaler. func (n *Node) UnmarshalText(text []byte) error { - dec, err := ParseV4(string(text)) + dec, err := Parse(ValidSchemes, string(text)) if err == nil { *n = *dec } diff --git a/p2p/enode/node_test.go b/p2p/enode/node_test.go index 861a70bd64..d15859c477 100644 --- a/p2p/enode/node_test.go +++ b/p2p/enode/node_test.go @@ -17,9 +17,12 @@ package enode import ( + "bytes" "encoding/hex" "fmt" + "math/big" "testing" + "testing/quick" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" @@ -43,7 +46,7 @@ func TestPythonInterop(t *testing.T) { var ( wantID = HexID("a448f24c6d18e575453db13171562b71999873db5b286df957af199ec94617f7") wantSeq = uint64(1) - wantIP = enr.IP{127, 0, 0, 1} + wantIP = enr.IPv4{127, 0, 0, 1} wantUDP = enr.UDP(30303) ) if n.Seq() != wantSeq { @@ -52,7 +55,7 @@ func TestPythonInterop(t *testing.T) { if n.ID() != wantID { t.Errorf("wrong id: got %x, want %x", n.ID(), wantID) } - want := map[enr.Entry]interface{}{new(enr.IP): &wantIP, new(enr.UDP): &wantUDP} + want := map[enr.Entry]interface{}{new(enr.IPv4): &wantIP, new(enr.UDP): &wantUDP} for k, v := range want { desc := fmt.Sprintf("loading key %q", k.ENRKey()) if assert.NoError(t, n.Load(k), desc) { @@ -60,3 +63,83 @@ func TestPythonInterop(t *testing.T) { } } } + +func TestHexID(t *testing.T) { + ref := ID{0, 0, 0, 0, 0, 0, 0, 128, 106, 217, 182, 31, 165, 174, 1, 67, 7, 235, 220, 150, 66, 83, 173, 205, 159, 44, 10, 57, 42, 161, 26, 188} + id1 := HexID("0x00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") + id2 := HexID("00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") + + if id1 != ref { + t.Errorf("wrong id1\ngot %v\nwant %v", id1[:], ref[:]) + } + if id2 != ref { + t.Errorf("wrong id2\ngot %v\nwant %v", id2[:], ref[:]) + } +} + +func TestID_textEncoding(t *testing.T) { + ref := ID{ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, + 0x31, 0x32, + } + hex := "0102030405060708091011121314151617181920212223242526272829303132" + + text, err := ref.MarshalText() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(text, []byte(hex)) { + t.Fatalf("text encoding did not match\nexpected: %s\ngot: %s", hex, text) + } + + id := new(ID) + if err := id.UnmarshalText(text); err != nil { + t.Fatal(err) + } + if *id != ref { + t.Fatalf("text decoding did not match\nexpected: %s\ngot: %s", ref, id) + } +} + +func TestID_distcmp(t *testing.T) { + distcmpBig := func(target, a, b ID) int { + tbig := new(big.Int).SetBytes(target[:]) + abig := new(big.Int).SetBytes(a[:]) + bbig := new(big.Int).SetBytes(b[:]) + return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig)) + } + if err := quick.CheckEqual(DistCmp, distcmpBig, nil); err != nil { + t.Error(err) + } +} + +// The random tests is likely to miss the case where a and b are equal, +// this test checks it explicitly. +func TestID_distcmpEqual(t *testing.T) { + base := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + x := ID{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + if DistCmp(base, x, x) != 0 { + t.Errorf("DistCmp(base, x, x) != 0") + } +} + +func TestID_logdist(t *testing.T) { + logdistBig := func(a, b ID) int { + abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:]) + return new(big.Int).Xor(abig, bbig).BitLen() + } + if err := quick.CheckEqual(LogDist, logdistBig, nil); err != nil { + t.Error(err) + } +} + +// The random tests is likely to miss the case where a and b are equal, +// this test checks it explicitly. +func TestID_logdistEqual(t *testing.T) { + x := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + if LogDist(x, x) != 0 { + t.Errorf("LogDist(x, x) != 0") + } +} diff --git a/p2p/enode/urlv4.go b/p2p/enode/urlv4.go index 50e9485d04..2372d4820b 100644 --- a/p2p/enode/urlv4.go +++ b/p2p/enode/urlv4.go @@ -70,7 +70,7 @@ func ParseV4(rawurl string) (*Node, error) { if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { id, err := parsePubkey(m[1]) if err != nil { - return nil, fmt.Errorf("invalid node ID (%v)", err) + return nil, fmt.Errorf("invalid public key (%v)", err) } return NewV4(id, nil, 0, 0), nil } @@ -81,7 +81,7 @@ func ParseV4(rawurl string) (*Node, error) { // contained in the node has a zero-length signature. func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp int) *Node { var r enr.Record - if ip != nil { + if len(ip) > 0 { r.Set(enr.IP(ip)) } if udp != 0 { @@ -98,6 +98,12 @@ func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp int) *Node { return n } +// isNewV4 returns true for nodes created by NewV4. +func isNewV4(n *Node) bool { + var k s256raw + return n.r.IdentityScheme() == "" && n.r.Load(&k) == nil && len(n.r.Signature()) == 0 +} + func parseComplete(rawurl string) (*Node, error) { var ( id *ecdsa.PublicKey @@ -116,7 +122,7 @@ func parseComplete(rawurl string) (*Node, error) { return nil, errors.New("does not contain node ID") } if id, err = parsePubkey(u.User.String()); err != nil { - return nil, fmt.Errorf("invalid node ID (%v)", err) + return nil, fmt.Errorf("invalid public key (%v)", err) } // Parse the IP address. host, port, err := net.SplitHostPort(u.Host) @@ -126,10 +132,6 @@ func parseComplete(rawurl string) (*Node, error) { if ip = net.ParseIP(host); ip == nil { return nil, errors.New("invalid IP address") } - // Ensure the IP is 4 bytes long for IPv4 addresses. - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } // Parse the port numbers. if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { return nil, errors.New("invalid port") @@ -157,7 +159,7 @@ func parsePubkey(in string) (*ecdsa.PublicKey, error) { return crypto.UnmarshalPubkey(b) } -func (n *Node) v4URL() string { +func (n *Node) URLv4() string { var ( scheme enr.ID nodeid string diff --git a/p2p/enode/urlv4_test.go b/p2p/enode/urlv4_test.go index 3680ab6b78..69ed111021 100644 --- a/p2p/enode/urlv4_test.go +++ b/p2p/enode/urlv4_test.go @@ -17,44 +17,63 @@ package enode import ( - "bytes" "crypto/ecdsa" - "math/big" "net" "reflect" "strings" "testing" - "testing/quick" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enr" ) var parseNodeTests = []struct { - rawurl string + input string wantError string wantResult *Node }{ + // Records { - rawurl: "http://foobar", - wantError: `invalid URL scheme, want "enode"`, + input: "enr:-IS4QGrdq0ugARp5T2BZ41TrZOqLc_oKvZoPuZP5--anqWE_J-Tucc1xgkOL7qXl0puJgT7qc2KSvcupc4NCb0nr4tdjgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQM6UUF2Rm-oFe1IH_rQkRCi00T2ybeMHRSvw1HDpRvjPYN1ZHCCdl8", + wantResult: func() *Node { + testKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") + var r enr.Record + r.Set(enr.IP{127, 0, 0, 1}) + r.Set(enr.UDP(30303)) + r.SetSeq(99) + SignV4(&r, testKey) + n, _ := New(ValidSchemes, &r) + return n + }(), + }, + // Invalid Records + { + input: "enr:", + wantError: "EOF", // could be nicer }, { - rawurl: "enode://01010101@123.124.125.126:3", - wantError: `invalid node ID (wrong length, want 128 hex chars)`, + input: "enr:x", + wantError: "illegal base64 data at input byte 0", }, - // Complete nodes with IP address. { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3", + input: "enr:-EmGZm9vYmFyY4JpZIJ2NIJpcIR_AAABiXNlY3AyNTZrMaEDOlFBdkZvqBXtSB_60JEQotNE9sm3jB0Ur8NRw6Ub4z2DdWRwgnZf", + wantError: enr.ErrInvalidSig.Error(), + }, + // Complete node URLs with IP address and ports + { + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3", wantError: `invalid IP address`, }, { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo", + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo", wantError: `invalid port`, }, { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo", + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo", wantError: `invalid discport in query`, }, { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150", + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150", wantResult: NewV4( hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.IP{0x7f, 0x0, 0x0, 0x1}, @@ -63,7 +82,7 @@ var parseNodeTests = []struct { ), }, { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150", + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150", wantResult: NewV4( hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.ParseIP("::"), @@ -72,7 +91,7 @@ var parseNodeTests = []struct { ), }, { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150", + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150", wantResult: NewV4( hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), @@ -81,7 +100,7 @@ var parseNodeTests = []struct { ), }, { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334", + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334", wantResult: NewV4( hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), net.IP{0x7f, 0x0, 0x0, 0x1}, @@ -89,16 +108,9 @@ var parseNodeTests = []struct { 22334, ), }, - // Incomplete nodes with no address. + // Incomplete node URLs with no address { - rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", - wantResult: NewV4( - hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), - nil, 0, 0, - ), - }, - { - rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", wantResult: NewV4( hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), nil, 0, 0, @@ -106,17 +118,32 @@ var parseNodeTests = []struct { }, // Invalid URLs { - rawurl: "01010101", - wantError: `invalid node ID (wrong length, want 128 hex chars)`, + input: "", + wantError: errMissingPrefix.Error(), }, { - rawurl: "enode://01010101", - wantError: `invalid node ID (wrong length, want 128 hex chars)`, + input: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", + wantError: errMissingPrefix.Error(), }, { - // This test checks that errors from url.Parse are handled. - rawurl: "://foo", - wantError: `parse ://foo: missing protocol scheme`, + input: "01010101", + wantError: errMissingPrefix.Error(), + }, + { + input: "enode://01010101@123.124.125.126:3", + wantError: `invalid public key (wrong length, want 128 hex chars)`, + }, + { + input: "enode://01010101", + wantError: `invalid public key (wrong length, want 128 hex chars)`, + }, + { + input: "http://foobar", + wantError: errMissingPrefix.Error(), + }, + { + input: "://foo", + wantError: errMissingPrefix.Error(), }, } @@ -130,22 +157,22 @@ func hexPubkey(h string) *ecdsa.PublicKey { func TestParseNode(t *testing.T) { for _, test := range parseNodeTests { - n, err := ParseV4(test.rawurl) + n, err := Parse(ValidSchemes, test.input) if test.wantError != "" { if err == nil { - t.Errorf("test %q:\n got nil error, expected %#q", test.rawurl, test.wantError) + t.Errorf("test %q:\n got nil error, expected %#q", test.input, test.wantError) continue } else if err.Error() != test.wantError { - t.Errorf("test %q:\n got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError) + t.Errorf("test %q:\n got error %#q, expected %#q", test.input, err.Error(), test.wantError) continue } } else { if err != nil { - t.Errorf("test %q:\n unexpected error: %v", test.rawurl, err) + t.Errorf("test %q:\n unexpected error: %v", test.input, err) continue } if !reflect.DeepEqual(n, test.wantResult) { - t.Errorf("test %q:\n result mismatch:\ngot: %#v\nwant: %#v", test.rawurl, n, test.wantResult) + t.Errorf("test %q:\n result mismatch:\ngot: %#v\nwant: %#v", test.input, n, test.wantResult) } } } @@ -153,91 +180,11 @@ func TestParseNode(t *testing.T) { func TestNodeString(t *testing.T) { for i, test := range parseNodeTests { - if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") { + if test.wantError == "" && strings.HasPrefix(test.input, "enode://") { str := test.wantResult.String() - if str != test.rawurl { - t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.rawurl) + if str != test.input { + t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.input) } } } } - -func TestHexID(t *testing.T) { - ref := ID{0, 0, 0, 0, 0, 0, 0, 128, 106, 217, 182, 31, 165, 174, 1, 67, 7, 235, 220, 150, 66, 83, 173, 205, 159, 44, 10, 57, 42, 161, 26, 188} - id1 := HexID("0x00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") - id2 := HexID("00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") - - if id1 != ref { - t.Errorf("wrong id1\ngot %v\nwant %v", id1[:], ref[:]) - } - if id2 != ref { - t.Errorf("wrong id2\ngot %v\nwant %v", id2[:], ref[:]) - } -} - -func TestID_textEncoding(t *testing.T) { - ref := ID{ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, - 0x31, 0x32, - } - hex := "0102030405060708091011121314151617181920212223242526272829303132" - - text, err := ref.MarshalText() - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(text, []byte(hex)) { - t.Fatalf("text encoding did not match\nexpected: %s\ngot: %s", hex, text) - } - - id := new(ID) - if err := id.UnmarshalText(text); err != nil { - t.Fatal(err) - } - if *id != ref { - t.Fatalf("text decoding did not match\nexpected: %s\ngot: %s", ref, id) - } -} - -func TestNodeID_distcmp(t *testing.T) { - distcmpBig := func(target, a, b ID) int { - tbig := new(big.Int).SetBytes(target[:]) - abig := new(big.Int).SetBytes(a[:]) - bbig := new(big.Int).SetBytes(b[:]) - return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig)) - } - if err := quick.CheckEqual(DistCmp, distcmpBig, nil); err != nil { - t.Error(err) - } -} - -// The random tests is likely to miss the case where a and b are equal, -// this test checks it explicitly. -func TestNodeID_distcmpEqual(t *testing.T) { - base := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - x := ID{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0} - if DistCmp(base, x, x) != 0 { - t.Errorf("DistCmp(base, x, x) != 0") - } -} - -func TestNodeID_logdist(t *testing.T) { - logdistBig := func(a, b ID) int { - abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:]) - return new(big.Int).Xor(abig, bbig).BitLen() - } - if err := quick.CheckEqual(LogDist, logdistBig, nil); err != nil { - t.Error(err) - } -} - -// The random tests is likely to miss the case where a and b are equal, -// this test checks it explicitly. -func TestNodeID_logdistEqual(t *testing.T) { - x := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - if LogDist(x, x) != 0 { - t.Errorf("LogDist(x, x) != 0") - } -} diff --git a/p2p/enr/enr.go b/p2p/enr/enr.go index 444820c158..c36ae9e3ed 100644 --- a/p2p/enr/enr.go +++ b/p2p/enr/enr.go @@ -163,6 +163,16 @@ func (r *Record) invalidate() { r.raw = nil } +// Signature returns the signature of the record. +func (r *Record) Signature() []byte { + if r.signature == nil { + return nil + } + cpy := make([]byte, len(r.signature)) + copy(cpy, r.signature) + return cpy +} + // EncodeRLP implements rlp.Encoder. Encoding fails if // the record is unsigned. func (r Record) EncodeRLP(w io.Writer) error { @@ -173,7 +183,7 @@ func (r Record) EncodeRLP(w io.Writer) error { return err } -// DecodeRLP implements rlp.Decoder. Decoding verifies the signature. +// DecodeRLP implements rlp.Decoder. Decoding doesn't verify the signature. func (r *Record) DecodeRLP(s *rlp.Stream) error { dec, raw, err := decodeRecord(s) if err != nil { diff --git a/p2p/enr/enr_test.go b/p2p/enr/enr_test.go index 449c898a84..434685e0b6 100644 --- a/p2p/enr/enr_test.go +++ b/p2p/enr/enr_test.go @@ -49,23 +49,23 @@ func TestGetSetID(t *testing.T) { } // TestGetSetIP4 tests encoding/decoding and setting/getting of the IP key. -func TestGetSetIP4(t *testing.T) { - ip := IP{192, 168, 0, 3} +func TestGetSetIPv4(t *testing.T) { + ip := IPv4{192, 168, 0, 3} var r Record r.Set(ip) - var ip2 IP + var ip2 IPv4 require.NoError(t, r.Load(&ip2)) assert.Equal(t, ip, ip2) } -// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP key. -func TestGetSetIP6(t *testing.T) { - ip := IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68} +// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP6 key. +func TestGetSetIPv6(t *testing.T) { + ip := IPv6{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68} var r Record r.Set(ip) - var ip2 IP + var ip2 IPv6 require.NoError(t, r.Load(&ip2)) assert.Equal(t, ip, ip2) } @@ -83,7 +83,7 @@ func TestGetSetUDP(t *testing.T) { func TestLoadErrors(t *testing.T) { var r Record - ip4 := IP{127, 0, 0, 1} + ip4 := IPv4{127, 0, 0, 1} r.Set(ip4) // Check error for missing keys. @@ -185,13 +185,13 @@ func TestSeq(t *testing.T) { func TestGetSetOverwrite(t *testing.T) { var r Record - ip := IP{192, 168, 0, 3} + ip := IPv4{192, 168, 0, 3} r.Set(ip) - ip2 := IP{192, 168, 0, 4} + ip2 := IPv4{192, 168, 0, 4} r.Set(ip2) - var ip3 IP + var ip3 IPv4 require.NoError(t, r.Load(&ip3)) assert.Equal(t, ip2, ip3) } @@ -200,7 +200,7 @@ func TestGetSetOverwrite(t *testing.T) { func TestSignEncodeAndDecode(t *testing.T) { var r Record r.Set(UDP(30303)) - r.Set(IP{127, 0, 0, 1}) + r.Set(IPv4{127, 0, 0, 1}) require.NoError(t, signTest([]byte{5}, &r)) blob, err := rlp.EncodeToBytes(r) diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index 347990ab64..f2118401af 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -60,11 +60,21 @@ type TCP uint16 func (v TCP) ENRKey() string { return "tcp" } +// UDP is the "udp" key, which holds the IPv6-specific UDP port of the node. +type TCP6 uint16 + +func (v TCP6) ENRKey() string { return "tcp6" } + // UDP is the "udp" key, which holds the UDP port of the node. type UDP uint16 func (v UDP) ENRKey() string { return "udp" } +// UDP is the "udp" key, which holds the IPv6-specific UDP port of the node. +type UDP6 uint16 + +func (v UDP6) ENRKey() string { return "udp6" } + // ID is the "id" key, which holds the name of the identity scheme. type ID string @@ -72,17 +82,27 @@ const IDv4 = ID("v4") // the default identity scheme func (v ID) ENRKey() string { return "id" } -// IP is the "ip" key, which holds the IP address of the node. +// IP is either the "ip" or "ip6" key, depending on the value. +// Use this value to encode IP addresses that can be either v4 or v6. +// To load an address from a record use the IPv4 or IPv6 types. type IP net.IP -func (v IP) ENRKey() string { return "ip" } +func (v IP) ENRKey() string { + if net.IP(v).To4() == nil { + return "ip6" + } + return "ip" +} // EncodeRLP implements rlp.Encoder. func (v IP) EncodeRLP(w io.Writer) error { if ip4 := net.IP(v).To4(); ip4 != nil { return rlp.Encode(w, ip4) } - return rlp.Encode(w, net.IP(v)) + if ip6 := net.IP(v).To16(); ip6 != nil { + return rlp.Encode(w, ip6) + } + return fmt.Errorf("invalid IP address: %v", net.IP(v)) } // DecodeRLP implements rlp.Decoder. @@ -96,6 +116,56 @@ func (v *IP) DecodeRLP(s *rlp.Stream) error { return nil } +// IPv4 is the "ip" key, which holds the IP address of the node. +type IPv4 net.IP + +func (v IPv4) ENRKey() string { return "ip" } + +// EncodeRLP implements rlp.Encoder. +func (v IPv4) EncodeRLP(w io.Writer) error { + ip4 := net.IP(v).To4() + if ip4 == nil { + return fmt.Errorf("invalid IPv4 address: %v", net.IP(v)) + } + return rlp.Encode(w, ip4) +} + +// DecodeRLP implements rlp.Decoder. +func (v *IPv4) DecodeRLP(s *rlp.Stream) error { + if err := s.Decode((*net.IP)(v)); err != nil { + return err + } + if len(*v) != 4 { + return fmt.Errorf("invalid IPv4 address, want 4 bytes: %v", *v) + } + return nil +} + +// IPv6 is the "ip6" key, which holds the IP address of the node. +type IPv6 net.IP + +func (v IPv6) ENRKey() string { return "ip6" } + +// EncodeRLP implements rlp.Encoder. +func (v IPv6) EncodeRLP(w io.Writer) error { + ip6 := net.IP(v).To16() + if ip6 == nil { + return fmt.Errorf("invalid IPv6 address: %v", net.IP(v)) + } + return rlp.Encode(w, ip6) +} + +// DecodeRLP implements rlp.Decoder. +func (v *IPv6) DecodeRLP(s *rlp.Stream) error { + if err := s.Decode((*net.IP)(v)); err != nil { + return err + } + if len(*v) != 16 { + return fmt.Errorf("invalid IPv6 address, want 16 bytes: %v", *v) + } + return nil +} + // KeyError is an error related to a key. type KeyError struct { Key string diff --git a/p2p/server.go b/p2p/server.go index 566f01ffc5..f17ef2c2bf 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" - "github.com/ethereum/go-ethereum/rlp" ) const ( @@ -602,7 +601,7 @@ type dialer interface { } func (srv *Server) run(dialstate dialer) { - srv.log.Info("Started P2P networking", "self", srv.localnode.Node()) + srv.log.Info("Started P2P networking", "self", srv.localnode.Node().URLv4()) defer srv.loopWG.Done() defer srv.nodedb.Close() @@ -1034,7 +1033,7 @@ func (srv *Server) NodeInfo() *NodeInfo { node := srv.Self() info := &NodeInfo{ Name: srv.Name, - Enode: node.String(), + Enode: node.URLv4(), ID: node.ID().String(), IP: node.IP().String(), ListenAddr: srv.ListenAddr, @@ -1042,9 +1041,7 @@ func (srv *Server) NodeInfo() *NodeInfo { } info.Ports.Discovery = node.UDP() info.Ports.Listener = node.TCP() - if enc, err := rlp.EncodeToBytes(node.Record()); err == nil { - info.ENR = "0x" + hex.EncodeToString(enc) - } + info.ENR = node.String() // Gather all the running protocol infos (only once per protocol type) for _, proto := range srv.Protocols { diff --git a/whisper/whisperv6/api.go b/whisper/whisperv6/api.go index 7609a03c28..d6d4c8d3de 100644 --- a/whisper/whisperv6/api.go +++ b/whisper/whisperv6/api.go @@ -103,7 +103,7 @@ func (api *PublicWhisperAPI) SetBloomFilter(ctx context.Context, bloom hexutil.B // MarkTrustedPeer marks a peer trusted, which will allow it to send historic (expired) messages. // Note: This function is not adding new nodes, the node needs to exists as a peer. func (api *PublicWhisperAPI) MarkTrustedPeer(ctx context.Context, url string) (bool, error) { - n, err := enode.ParseV4(url) + n, err := enode.Parse(enode.ValidSchemes, url) if err != nil { return false, err } @@ -291,7 +291,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil. // send to specific node (skip PoW check) if len(req.TargetPeer) > 0 { - n, err := enode.ParseV4(req.TargetPeer) + n, err := enode.Parse(enode.ValidSchemes, req.TargetPeer) if err != nil { return nil, fmt.Errorf("failed to parse target peer: %s", err) } From afb9e6513f953a813d508633d6ff786fbd18b0b3 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 7 Jun 2019 16:51:18 +0200 Subject: [PATCH 46/47] vendor: remove unused dependencies (#19683) * vendor: remove unused dependencies These were used by swarm code, which has now migrated to its own repository. * travis.yml: remove sudo requirement for test builders These needed sudo to run FUSE tests for swarm. --- .travis.yml | 12 - vendor/bazil.org/fuse/LICENSE | 93 - vendor/bazil.org/fuse/README.md | 23 - vendor/bazil.org/fuse/buffer.go | 35 - vendor/bazil.org/fuse/debug.go | 21 - vendor/bazil.org/fuse/error_darwin.go | 17 - vendor/bazil.org/fuse/error_freebsd.go | 15 - vendor/bazil.org/fuse/error_linux.go | 17 - vendor/bazil.org/fuse/error_std.go | 31 - vendor/bazil.org/fuse/fs/serve.go | 1568 ----------- vendor/bazil.org/fuse/fs/tree.go | 99 - vendor/bazil.org/fuse/fuse.go | 2303 ----------------- vendor/bazil.org/fuse/fuse.iml | 9 - vendor/bazil.org/fuse/fuse_darwin.go | 9 - vendor/bazil.org/fuse/fuse_freebsd.go | 6 - vendor/bazil.org/fuse/fuse_kernel.go | 774 ------ vendor/bazil.org/fuse/fuse_kernel_darwin.go | 88 - vendor/bazil.org/fuse/fuse_kernel_freebsd.go | 62 - vendor/bazil.org/fuse/fuse_kernel_linux.go | 70 - vendor/bazil.org/fuse/fuse_kernel_std.go | 1 - vendor/bazil.org/fuse/fuse_linux.go | 7 - vendor/bazil.org/fuse/fuseutil/fuseutil.go | 20 - vendor/bazil.org/fuse/mount.go | 38 - vendor/bazil.org/fuse/mount_darwin.go | 208 -- vendor/bazil.org/fuse/mount_freebsd.go | 111 - vendor/bazil.org/fuse/mount_linux.go | 150 -- vendor/bazil.org/fuse/options.go | 310 --- vendor/bazil.org/fuse/options_darwin.go | 35 - vendor/bazil.org/fuse/options_freebsd.go | 28 - vendor/bazil.org/fuse/options_linux.go | 25 - vendor/bazil.org/fuse/protocol.go | 75 - vendor/bazil.org/fuse/unmount.go | 6 - vendor/bazil.org/fuse/unmount_linux.go | 21 - vendor/bazil.org/fuse/unmount_std.go | 17 - .../github.com/codahale/hdrhistogram/LICENSE | 21 - .../codahale/hdrhistogram/README.md | 15 - .../github.com/codahale/hdrhistogram/hdr.go | 564 ---- .../codahale/hdrhistogram/window.go | 45 - .../uber/jaeger-client-go/CHANGELOG.md | 186 -- .../uber/jaeger-client-go/CONTRIBUTING.md | 170 -- vendor/github.com/uber/jaeger-client-go/DCO | 37 - .../uber/jaeger-client-go/Gopkg.lock | 164 -- .../uber/jaeger-client-go/Gopkg.toml | 27 - .../github.com/uber/jaeger-client-go/LICENSE | 201 -- .../github.com/uber/jaeger-client-go/Makefile | 117 - .../uber/jaeger-client-go/README.md | 260 -- .../uber/jaeger-client-go/RELEASE.md | 11 - .../uber/jaeger-client-go/baggage_setter.go | 77 - .../uber/jaeger-client-go/config/config.go | 373 --- .../jaeger-client-go/config/config_env.go | 205 -- .../uber/jaeger-client-go/config/options.go | 148 -- .../uber/jaeger-client-go/constants.go | 88 - .../uber/jaeger-client-go/context.go | 258 -- .../uber/jaeger-client-go/contrib_observer.go | 56 - .../github.com/uber/jaeger-client-go/doc.go | 24 - .../uber/jaeger-client-go/glide.lock | 89 - .../uber/jaeger-client-go/glide.yaml | 22 - .../uber/jaeger-client-go/header.go | 64 - .../internal/baggage/remote/options.go | 101 - .../baggage/remote/restriction_manager.go | 157 -- .../internal/baggage/restriction_manager.go | 71 - .../jaeger-client-go/internal/spanlog/json.go | 81 - .../internal/throttler/remote/options.go | 99 - .../internal/throttler/remote/throttler.go | 216 -- .../internal/throttler/throttler.go | 32 - .../uber/jaeger-client-go/interop.go | 55 - .../uber/jaeger-client-go/jaeger_tag.go | 84 - .../jaeger-client-go/jaeger_thrift_span.go | 179 -- .../uber/jaeger-client-go/log/logger.go | 90 - .../uber/jaeger-client-go/logger.go | 53 - .../uber/jaeger-client-go/metrics.go | 107 - .../uber/jaeger-client-go/observer.go | 88 - .../uber/jaeger-client-go/process.go | 29 - .../uber/jaeger-client-go/propagation.go | 300 --- .../uber/jaeger-client-go/reference.go | 23 - .../uber/jaeger-client-go/reporter.go | 289 --- .../uber/jaeger-client-go/reporter_options.go | 69 - .../jaeger-client-go/rpcmetrics/README.md | 5 - .../uber/jaeger-client-go/rpcmetrics/doc.go | 16 - .../jaeger-client-go/rpcmetrics/endpoints.go | 63 - .../jaeger-client-go/rpcmetrics/metrics.go | 124 - .../jaeger-client-go/rpcmetrics/normalizer.go | 101 - .../jaeger-client-go/rpcmetrics/observer.go | 171 -- .../uber/jaeger-client-go/sampler.go | 556 ---- .../uber/jaeger-client-go/sampler_options.go | 81 - .../github.com/uber/jaeger-client-go/span.go | 249 -- .../thrift-gen/agent/agent.go | 411 --- .../thrift-gen/agent/constants.go | 23 - .../thrift-gen/agent/ttypes.go | 21 - .../baggage/baggagerestrictionmanager.go | 435 ---- .../thrift-gen/baggage/constants.go | 18 - .../thrift-gen/baggage/ttypes.go | 154 -- .../thrift-gen/jaeger/agent.go | 242 -- .../thrift-gen/jaeger/constants.go | 18 - .../thrift-gen/jaeger/ttypes.go | 1838 ------------- .../thrift-gen/sampling/constants.go | 18 - .../thrift-gen/sampling/samplingmanager.go | 410 --- .../thrift-gen/sampling/ttypes.go | 873 ------- .../thrift-gen/zipkincore/constants.go | 32 - .../thrift-gen/zipkincore/ttypes.go | 1247 --------- .../thrift-gen/zipkincore/zipkincollector.go | 446 ---- .../uber/jaeger-client-go/thrift/README.md | 7 - .../thrift/application_exception.go | 142 - .../thrift/binary_protocol.go | 514 ---- .../thrift/compact_protocol.go | 815 ------ .../uber/jaeger-client-go/thrift/exception.go | 44 - .../jaeger-client-go/thrift/memory_buffer.go | 79 - .../jaeger-client-go/thrift/messagetype.go | 31 - .../uber/jaeger-client-go/thrift/numeric.go | 164 -- .../uber/jaeger-client-go/thrift/processor.go | 30 - .../uber/jaeger-client-go/thrift/protocol.go | 175 -- .../thrift/protocol_exception.go | 78 - .../thrift/protocol_factory.go | 25 - .../jaeger-client-go/thrift/rich_transport.go | 69 - .../jaeger-client-go/thrift/serializer.go | 75 - .../thrift/simple_json_protocol.go | 1337 ---------- .../uber/jaeger-client-go/thrift/transport.go | 68 - .../thrift/transport_exception.go | 90 - .../thrift/transport_factory.go | 39 - .../uber/jaeger-client-go/thrift/type.go | 69 - .../uber/jaeger-client-go/tracer.go | 431 --- .../uber/jaeger-client-go/tracer_options.go | 159 -- .../uber/jaeger-client-go/transport.go | 38 - .../uber/jaeger-client-go/transport_udp.go | 131 - .../uber/jaeger-client-go/utils/http_json.go | 54 - .../uber/jaeger-client-go/utils/localip.go | 84 - .../uber/jaeger-client-go/utils/rand.go | 46 - .../jaeger-client-go/utils/rate_limiter.go | 77 - .../uber/jaeger-client-go/utils/udp_client.go | 98 - .../uber/jaeger-client-go/utils/utils.go | 87 - .../uber/jaeger-client-go/zipkin.go | 76 - .../jaeger-client-go/zipkin_thrift_span.go | 322 --- vendor/github.com/uber/jaeger-lib/LICENSE | 201 -- .../uber/jaeger-lib/metrics/counter.go | 28 - .../uber/jaeger-lib/metrics/factory.go | 35 - .../uber/jaeger-lib/metrics/gauge.go | 28 - .../uber/jaeger-lib/metrics/local.go | 337 --- .../uber/jaeger-lib/metrics/metrics.go | 85 - .../uber/jaeger-lib/metrics/stopwatch.go | 43 - .../uber/jaeger-lib/metrics/timer.go | 33 - vendor/vendor.json | 126 - 141 files changed, 25571 deletions(-) delete mode 100644 vendor/bazil.org/fuse/LICENSE delete mode 100644 vendor/bazil.org/fuse/README.md delete mode 100644 vendor/bazil.org/fuse/buffer.go delete mode 100644 vendor/bazil.org/fuse/debug.go delete mode 100644 vendor/bazil.org/fuse/error_darwin.go delete mode 100644 vendor/bazil.org/fuse/error_freebsd.go delete mode 100644 vendor/bazil.org/fuse/error_linux.go delete mode 100644 vendor/bazil.org/fuse/error_std.go delete mode 100644 vendor/bazil.org/fuse/fs/serve.go delete mode 100644 vendor/bazil.org/fuse/fs/tree.go delete mode 100644 vendor/bazil.org/fuse/fuse.go delete mode 100644 vendor/bazil.org/fuse/fuse.iml delete mode 100644 vendor/bazil.org/fuse/fuse_darwin.go delete mode 100644 vendor/bazil.org/fuse/fuse_freebsd.go delete mode 100644 vendor/bazil.org/fuse/fuse_kernel.go delete mode 100644 vendor/bazil.org/fuse/fuse_kernel_darwin.go delete mode 100644 vendor/bazil.org/fuse/fuse_kernel_freebsd.go delete mode 100644 vendor/bazil.org/fuse/fuse_kernel_linux.go delete mode 100644 vendor/bazil.org/fuse/fuse_kernel_std.go delete mode 100644 vendor/bazil.org/fuse/fuse_linux.go delete mode 100644 vendor/bazil.org/fuse/fuseutil/fuseutil.go delete mode 100644 vendor/bazil.org/fuse/mount.go delete mode 100644 vendor/bazil.org/fuse/mount_darwin.go delete mode 100644 vendor/bazil.org/fuse/mount_freebsd.go delete mode 100644 vendor/bazil.org/fuse/mount_linux.go delete mode 100644 vendor/bazil.org/fuse/options.go delete mode 100644 vendor/bazil.org/fuse/options_darwin.go delete mode 100644 vendor/bazil.org/fuse/options_freebsd.go delete mode 100644 vendor/bazil.org/fuse/options_linux.go delete mode 100644 vendor/bazil.org/fuse/protocol.go delete mode 100644 vendor/bazil.org/fuse/unmount.go delete mode 100644 vendor/bazil.org/fuse/unmount_linux.go delete mode 100644 vendor/bazil.org/fuse/unmount_std.go delete mode 100644 vendor/github.com/codahale/hdrhistogram/LICENSE delete mode 100644 vendor/github.com/codahale/hdrhistogram/README.md delete mode 100644 vendor/github.com/codahale/hdrhistogram/hdr.go delete mode 100644 vendor/github.com/codahale/hdrhistogram/window.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/CHANGELOG.md delete mode 100644 vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md delete mode 100644 vendor/github.com/uber/jaeger-client-go/DCO delete mode 100644 vendor/github.com/uber/jaeger-client-go/Gopkg.lock delete mode 100644 vendor/github.com/uber/jaeger-client-go/Gopkg.toml delete mode 100644 vendor/github.com/uber/jaeger-client-go/LICENSE delete mode 100644 vendor/github.com/uber/jaeger-client-go/Makefile delete mode 100644 vendor/github.com/uber/jaeger-client-go/README.md delete mode 100644 vendor/github.com/uber/jaeger-client-go/RELEASE.md delete mode 100644 vendor/github.com/uber/jaeger-client-go/baggage_setter.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/config/config.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/config/config_env.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/config/options.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/constants.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/context.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/contrib_observer.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/doc.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/glide.lock delete mode 100644 vendor/github.com/uber/jaeger-client-go/glide.yaml delete mode 100644 vendor/github.com/uber/jaeger-client-go/header.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/options.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/throttler.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/internal/throttler/throttler.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/interop.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/jaeger_tag.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/log/logger.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/logger.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/metrics.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/observer.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/process.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/propagation.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/reference.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/reporter.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/reporter_options.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md delete mode 100644 vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/sampler.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/sampler_options.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/span.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/agent.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/constants.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/ttypes.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/baggagerestrictionmanager.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/constants.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/ttypes.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/agent.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/constants.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/constants.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/samplingmanager.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/ttypes.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/constants.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/zipkincollector.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/README.md delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/application_exception.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/binary_protocol.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/compact_protocol.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/exception.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/memory_buffer.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/messagetype.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/numeric.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/processor.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/protocol.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/protocol_exception.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/protocol_factory.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/rich_transport.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/serializer.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/transport.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/transport_exception.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/transport_factory.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/thrift/type.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/tracer.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/tracer_options.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/transport.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/transport_udp.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/utils/http_json.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/utils/localip.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/utils/rand.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/utils/udp_client.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/utils/utils.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/zipkin.go delete mode 100644 vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go delete mode 100644 vendor/github.com/uber/jaeger-lib/LICENSE delete mode 100644 vendor/github.com/uber/jaeger-lib/metrics/counter.go delete mode 100644 vendor/github.com/uber/jaeger-lib/metrics/factory.go delete mode 100644 vendor/github.com/uber/jaeger-lib/metrics/gauge.go delete mode 100644 vendor/github.com/uber/jaeger-lib/metrics/local.go delete mode 100644 vendor/github.com/uber/jaeger-lib/metrics/metrics.go delete mode 100644 vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go delete mode 100644 vendor/github.com/uber/jaeger-lib/metrics/timer.go diff --git a/.travis.yml b/.travis.yml index 552a0f1d77..36defe308b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,35 +5,23 @@ matrix: include: - os: linux dist: xenial - sudo: required go: 1.10.x script: - - sudo modprobe fuse - - sudo chmod 666 /dev/fuse - - sudo chown root:$USER /etc/fuse.conf - go run build/ci.go install - go run build/ci.go test -coverage $TEST_PACKAGES - os: linux dist: xenial - sudo: required go: 1.11.x script: - - sudo modprobe fuse - - sudo chmod 666 /dev/fuse - - sudo chown root:$USER /etc/fuse.conf - go run build/ci.go install - go run build/ci.go test -coverage $TEST_PACKAGES # These are the latest Go versions. - os: linux dist: xenial - sudo: required go: 1.12.x script: - - sudo modprobe fuse - - sudo chmod 666 /dev/fuse - - sudo chown root:$USER /etc/fuse.conf - go run build/ci.go install - go run build/ci.go test -coverage $TEST_PACKAGES diff --git a/vendor/bazil.org/fuse/LICENSE b/vendor/bazil.org/fuse/LICENSE deleted file mode 100644 index 4ac7cd8389..0000000000 --- a/vendor/bazil.org/fuse/LICENSE +++ /dev/null @@ -1,93 +0,0 @@ -Copyright (c) 2013-2015 Tommi Virtanen. -Copyright (c) 2009, 2011, 2012 The Go Authors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -The following included software components have additional copyright -notices and license terms that may differ from the above. - - -File fuse.go: - -// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c, -// which carries this notice: -// -// The files in this directory are subject to the following license. -// -// The author of this software is Russ Cox. -// -// Copyright (c) 2006 Russ Cox -// -// Permission to use, copy, modify, and distribute this software for any -// purpose without fee is hereby granted, provided that this entire notice -// is included in all copies of any software which is or includes a copy -// or modification of this software and in all copies of the supporting -// documentation for such software. -// -// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY -// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS -// FITNESS FOR ANY PARTICULAR PURPOSE. - - -File fuse_kernel.go: - -// Derived from FUSE's fuse_kernel.h -/* - This file defines the kernel interface of FUSE - Copyright (C) 2001-2007 Miklos Szeredi - - - This -- and only this -- header file may also be distributed under - the terms of the BSD Licence as follows: - - Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. -*/ diff --git a/vendor/bazil.org/fuse/README.md b/vendor/bazil.org/fuse/README.md deleted file mode 100644 index 8c6d556ee3..0000000000 --- a/vendor/bazil.org/fuse/README.md +++ /dev/null @@ -1,23 +0,0 @@ -bazil.org/fuse -- Filesystems in Go -=================================== - -`bazil.org/fuse` is a Go library for writing FUSE userspace -filesystems. - -It is a from-scratch implementation of the kernel-userspace -communication protocol, and does not use the C library from the -project called FUSE. `bazil.org/fuse` embraces Go fully for safety and -ease of programming. - -Here’s how to get going: - - go get bazil.org/fuse - -Website: http://bazil.org/fuse/ - -Github repository: https://github.com/bazil/fuse - -API docs: http://godoc.org/bazil.org/fuse - -Our thanks to Russ Cox for his fuse library, which this project is -based on. diff --git a/vendor/bazil.org/fuse/buffer.go b/vendor/bazil.org/fuse/buffer.go deleted file mode 100644 index bb1d2b7769..0000000000 --- a/vendor/bazil.org/fuse/buffer.go +++ /dev/null @@ -1,35 +0,0 @@ -package fuse - -import "unsafe" - -// buffer provides a mechanism for constructing a message from -// multiple segments. -type buffer []byte - -// alloc allocates size bytes and returns a pointer to the new -// segment. -func (w *buffer) alloc(size uintptr) unsafe.Pointer { - s := int(size) - if len(*w)+s > cap(*w) { - old := *w - *w = make([]byte, len(*w), 2*cap(*w)+s) - copy(*w, old) - } - l := len(*w) - *w = (*w)[:l+s] - return unsafe.Pointer(&(*w)[l]) -} - -// reset clears out the contents of the buffer. -func (w *buffer) reset() { - for i := range (*w)[:cap(*w)] { - (*w)[i] = 0 - } - *w = (*w)[:0] -} - -func newBuffer(extra uintptr) buffer { - const hdrSize = unsafe.Sizeof(outHeader{}) - buf := make(buffer, hdrSize, hdrSize+extra) - return buf -} diff --git a/vendor/bazil.org/fuse/debug.go b/vendor/bazil.org/fuse/debug.go deleted file mode 100644 index be9f900d5e..0000000000 --- a/vendor/bazil.org/fuse/debug.go +++ /dev/null @@ -1,21 +0,0 @@ -package fuse - -import ( - "runtime" -) - -func stack() string { - buf := make([]byte, 1024) - return string(buf[:runtime.Stack(buf, false)]) -} - -func nop(msg interface{}) {} - -// Debug is called to output debug messages, including protocol -// traces. The default behavior is to do nothing. -// -// The messages have human-friendly string representations and are -// safe to marshal to JSON. -// -// Implementations must not retain msg. -var Debug func(msg interface{}) = nop diff --git a/vendor/bazil.org/fuse/error_darwin.go b/vendor/bazil.org/fuse/error_darwin.go deleted file mode 100644 index a3fb89ca29..0000000000 --- a/vendor/bazil.org/fuse/error_darwin.go +++ /dev/null @@ -1,17 +0,0 @@ -package fuse - -import ( - "syscall" -) - -const ( - ENOATTR = Errno(syscall.ENOATTR) -) - -const ( - errNoXattr = ENOATTR -) - -func init() { - errnoNames[errNoXattr] = "ENOATTR" -} diff --git a/vendor/bazil.org/fuse/error_freebsd.go b/vendor/bazil.org/fuse/error_freebsd.go deleted file mode 100644 index c6ea6d6e71..0000000000 --- a/vendor/bazil.org/fuse/error_freebsd.go +++ /dev/null @@ -1,15 +0,0 @@ -package fuse - -import "syscall" - -const ( - ENOATTR = Errno(syscall.ENOATTR) -) - -const ( - errNoXattr = ENOATTR -) - -func init() { - errnoNames[errNoXattr] = "ENOATTR" -} diff --git a/vendor/bazil.org/fuse/error_linux.go b/vendor/bazil.org/fuse/error_linux.go deleted file mode 100644 index 6f113e71ed..0000000000 --- a/vendor/bazil.org/fuse/error_linux.go +++ /dev/null @@ -1,17 +0,0 @@ -package fuse - -import ( - "syscall" -) - -const ( - ENODATA = Errno(syscall.ENODATA) -) - -const ( - errNoXattr = ENODATA -) - -func init() { - errnoNames[errNoXattr] = "ENODATA" -} diff --git a/vendor/bazil.org/fuse/error_std.go b/vendor/bazil.org/fuse/error_std.go deleted file mode 100644 index 398f43fbf6..0000000000 --- a/vendor/bazil.org/fuse/error_std.go +++ /dev/null @@ -1,31 +0,0 @@ -package fuse - -// There is very little commonality in extended attribute errors -// across platforms. -// -// getxattr return value for "extended attribute does not exist" is -// ENOATTR on OS X, and ENODATA on Linux and apparently at least -// NetBSD. There may be a #define ENOATTR on Linux too, but the value -// is ENODATA in the actual syscalls. FreeBSD and OpenBSD have no -// ENODATA, only ENOATTR. ENOATTR is not in any of the standards, -// ENODATA exists but is only used for STREAMs. -// -// Each platform will define it a errNoXattr constant, and this file -// will enforce that it implements the right interfaces and hide the -// implementation. -// -// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/getxattr.2.html -// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013090.html -// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013097.html -// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html -// http://www.freebsd.org/cgi/man.cgi?query=extattr_get_file&sektion=2 -// http://nixdoc.net/man-pages/openbsd/man2/extattr_get_file.2.html - -// ErrNoXattr is a platform-independent error value meaning the -// extended attribute was not found. It can be used to respond to -// GetxattrRequest and such. -const ErrNoXattr = errNoXattr - -var _ error = ErrNoXattr -var _ Errno = ErrNoXattr -var _ ErrorNumber = ErrNoXattr diff --git a/vendor/bazil.org/fuse/fs/serve.go b/vendor/bazil.org/fuse/fs/serve.go deleted file mode 100644 index e9fc56590f..0000000000 --- a/vendor/bazil.org/fuse/fs/serve.go +++ /dev/null @@ -1,1568 +0,0 @@ -// FUSE service loop, for servers that wish to use it. - -package fs // import "bazil.org/fuse/fs" - -import ( - "encoding/binary" - "fmt" - "hash/fnv" - "io" - "log" - "reflect" - "runtime" - "strings" - "sync" - "time" - - "golang.org/x/net/context" -) - -import ( - "bytes" - - "bazil.org/fuse" - "bazil.org/fuse/fuseutil" -) - -const ( - attrValidTime = 1 * time.Minute - entryValidTime = 1 * time.Minute -) - -// TODO: FINISH DOCS - -// An FS is the interface required of a file system. -// -// Other FUSE requests can be handled by implementing methods from the -// FS* interfaces, for example FSStatfser. -type FS interface { - // Root is called to obtain the Node for the file system root. - Root() (Node, error) -} - -type FSStatfser interface { - // Statfs is called to obtain file system metadata. - // It should write that data to resp. - Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error -} - -type FSDestroyer interface { - // Destroy is called when the file system is shutting down. - // - // Linux only sends this request for block device backed (fuseblk) - // filesystems, to allow them to flush writes to disk before the - // unmount completes. - Destroy() -} - -type FSInodeGenerator interface { - // GenerateInode is called to pick a dynamic inode number when it - // would otherwise be 0. - // - // Not all filesystems bother tracking inodes, but FUSE requires - // the inode to be set, and fewer duplicates in general makes UNIX - // tools work better. - // - // Operations where the nodes may return 0 inodes include Getattr, - // Setattr and ReadDir. - // - // If FS does not implement FSInodeGenerator, GenerateDynamicInode - // is used. - // - // Implementing this is useful to e.g. constrain the range of - // inode values used for dynamic inodes. - GenerateInode(parentInode uint64, name string) uint64 -} - -// A Node is the interface required of a file or directory. -// See the documentation for type FS for general information -// pertaining to all methods. -// -// A Node must be usable as a map key, that is, it cannot be a -// function, map or slice. -// -// Other FUSE requests can be handled by implementing methods from the -// Node* interfaces, for example NodeOpener. -// -// Methods returning Node should take care to return the same Node -// when the result is logically the same instance. Without this, each -// Node will get a new NodeID, causing spurious cache invalidations, -// extra lookups and aliasing anomalies. This may not matter for a -// simple, read-only filesystem. -type Node interface { - // Attr fills attr with the standard metadata for the node. - // - // Fields with reasonable defaults are prepopulated. For example, - // all times are set to a fixed moment when the program started. - // - // If Inode is left as 0, a dynamic inode number is chosen. - // - // The result may be cached for the duration set in Valid. - Attr(ctx context.Context, attr *fuse.Attr) error -} - -type NodeGetattrer interface { - // Getattr obtains the standard metadata for the receiver. - // It should store that metadata in resp. - // - // If this method is not implemented, the attributes will be - // generated based on Attr(), with zero values filled in. - Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error -} - -type NodeSetattrer interface { - // Setattr sets the standard metadata for the receiver. - // - // Note, this is also used to communicate changes in the size of - // the file, outside of Writes. - // - // req.Valid is a bitmask of what fields are actually being set. - // For example, the method should not change the mode of the file - // unless req.Valid.Mode() is true. - Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error -} - -type NodeSymlinker interface { - // Symlink creates a new symbolic link in the receiver, which must be a directory. - // - // TODO is the above true about directories? - Symlink(ctx context.Context, req *fuse.SymlinkRequest) (Node, error) -} - -// This optional request will be called only for symbolic link nodes. -type NodeReadlinker interface { - // Readlink reads a symbolic link. - Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) -} - -type NodeLinker interface { - // Link creates a new directory entry in the receiver based on an - // existing Node. Receiver must be a directory. - Link(ctx context.Context, req *fuse.LinkRequest, old Node) (Node, error) -} - -type NodeRemover interface { - // Remove removes the entry with the given name from - // the receiver, which must be a directory. The entry to be removed - // may correspond to a file (unlink) or to a directory (rmdir). - Remove(ctx context.Context, req *fuse.RemoveRequest) error -} - -type NodeAccesser interface { - // Access checks whether the calling context has permission for - // the given operations on the receiver. If so, Access should - // return nil. If not, Access should return EPERM. - // - // Note that this call affects the result of the access(2) system - // call but not the open(2) system call. If Access is not - // implemented, the Node behaves as if it always returns nil - // (permission granted), relying on checks in Open instead. - Access(ctx context.Context, req *fuse.AccessRequest) error -} - -type NodeStringLookuper interface { - // Lookup looks up a specific entry in the receiver, - // which must be a directory. Lookup should return a Node - // corresponding to the entry. If the name does not exist in - // the directory, Lookup should return ENOENT. - // - // Lookup need not to handle the names "." and "..". - Lookup(ctx context.Context, name string) (Node, error) -} - -type NodeRequestLookuper interface { - // Lookup looks up a specific entry in the receiver. - // See NodeStringLookuper for more. - Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (Node, error) -} - -type NodeMkdirer interface { - Mkdir(ctx context.Context, req *fuse.MkdirRequest) (Node, error) -} - -type NodeOpener interface { - // Open opens the receiver. After a successful open, a client - // process has a file descriptor referring to this Handle. - // - // Open can also be also called on non-files. For example, - // directories are Opened for ReadDir or fchdir(2). - // - // If this method is not implemented, the open will always - // succeed, and the Node itself will be used as the Handle. - // - // XXX note about access. XXX OpenFlags. - Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (Handle, error) -} - -type NodeCreater interface { - // Create creates a new directory entry in the receiver, which - // must be a directory. - Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (Node, Handle, error) -} - -type NodeForgetter interface { - // Forget about this node. This node will not receive further - // method calls. - // - // Forget is not necessarily seen on unmount, as all nodes are - // implicitly forgotten as part part of the unmount. - Forget() -} - -type NodeRenamer interface { - Rename(ctx context.Context, req *fuse.RenameRequest, newDir Node) error -} - -type NodeMknoder interface { - Mknod(ctx context.Context, req *fuse.MknodRequest) (Node, error) -} - -// TODO this should be on Handle not Node -type NodeFsyncer interface { - Fsync(ctx context.Context, req *fuse.FsyncRequest) error -} - -type NodeGetxattrer interface { - // Getxattr gets an extended attribute by the given name from the - // node. - // - // If there is no xattr by that name, returns fuse.ErrNoXattr. - Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error -} - -type NodeListxattrer interface { - // Listxattr lists the extended attributes recorded for the node. - Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error -} - -type NodeSetxattrer interface { - // Setxattr sets an extended attribute with the given name and - // value for the node. - Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error -} - -type NodeRemovexattrer interface { - // Removexattr removes an extended attribute for the name. - // - // If there is no xattr by that name, returns fuse.ErrNoXattr. - Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error -} - -var startTime = time.Now() - -func nodeAttr(ctx context.Context, n Node, attr *fuse.Attr) error { - attr.Valid = attrValidTime - attr.Nlink = 1 - attr.Atime = startTime - attr.Mtime = startTime - attr.Ctime = startTime - attr.Crtime = startTime - if err := n.Attr(ctx, attr); err != nil { - return err - } - return nil -} - -// A Handle is the interface required of an opened file or directory. -// See the documentation for type FS for general information -// pertaining to all methods. -// -// Other FUSE requests can be handled by implementing methods from the -// Handle* interfaces. The most common to implement are HandleReader, -// HandleReadDirer, and HandleWriter. -// -// TODO implement methods: Getlk, Setlk, Setlkw -type Handle interface { -} - -type HandleFlusher interface { - // Flush is called each time the file or directory is closed. - // Because there can be multiple file descriptors referring to a - // single opened file, Flush can be called multiple times. - Flush(ctx context.Context, req *fuse.FlushRequest) error -} - -type HandleReadAller interface { - ReadAll(ctx context.Context) ([]byte, error) -} - -type HandleReadDirAller interface { - ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) -} - -type HandleReader interface { - // Read requests to read data from the handle. - // - // There is a page cache in the kernel that normally submits only - // page-aligned reads spanning one or more pages. However, you - // should not rely on this. To see individual requests as - // submitted by the file system clients, set OpenDirectIO. - // - // Note that reads beyond the size of the file as reported by Attr - // are not even attempted (except in OpenDirectIO mode). - Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error -} - -type HandleWriter interface { - // Write requests to write data into the handle at the given offset. - // Store the amount of data written in resp.Size. - // - // There is a writeback page cache in the kernel that normally submits - // only page-aligned writes spanning one or more pages. However, - // you should not rely on this. To see individual requests as - // submitted by the file system clients, set OpenDirectIO. - // - // Writes that grow the file are expected to update the file size - // (as seen through Attr). Note that file size changes are - // communicated also through Setattr. - Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error -} - -type HandleReleaser interface { - Release(ctx context.Context, req *fuse.ReleaseRequest) error -} - -type Config struct { - // Function to send debug log messages to. If nil, use fuse.Debug. - // Note that changing this or fuse.Debug may not affect existing - // calls to Serve. - // - // See fuse.Debug for the rules that log functions must follow. - Debug func(msg interface{}) - - // Function to put things into context for processing the request. - // The returned context must have ctx as its parent. - // - // Note that changing this may not affect existing calls to Serve. - // - // Must not retain req. - WithContext func(ctx context.Context, req fuse.Request) context.Context -} - -// New returns a new FUSE server ready to serve this kernel FUSE -// connection. -// -// Config may be nil. -func New(conn *fuse.Conn, config *Config) *Server { - s := &Server{ - conn: conn, - req: map[fuse.RequestID]*serveRequest{}, - nodeRef: map[Node]fuse.NodeID{}, - dynamicInode: GenerateDynamicInode, - } - if config != nil { - s.debug = config.Debug - s.context = config.WithContext - } - if s.debug == nil { - s.debug = fuse.Debug - } - return s -} - -type Server struct { - // set in New - conn *fuse.Conn - debug func(msg interface{}) - context func(ctx context.Context, req fuse.Request) context.Context - - // set once at Serve time - fs FS - dynamicInode func(parent uint64, name string) uint64 - - // state, protected by meta - meta sync.Mutex - req map[fuse.RequestID]*serveRequest - node []*serveNode - nodeRef map[Node]fuse.NodeID - handle []*serveHandle - freeNode []fuse.NodeID - freeHandle []fuse.HandleID - nodeGen uint64 - - // Used to ensure worker goroutines finish before Serve returns - wg sync.WaitGroup -} - -// Serve serves the FUSE connection by making calls to the methods -// of fs and the Nodes and Handles it makes available. It returns only -// when the connection has been closed or an unexpected error occurs. -func (s *Server) Serve(fs FS) error { - defer s.wg.Wait() // Wait for worker goroutines to complete before return - - s.fs = fs - if dyn, ok := fs.(FSInodeGenerator); ok { - s.dynamicInode = dyn.GenerateInode - } - - root, err := fs.Root() - if err != nil { - return fmt.Errorf("cannot obtain root node: %v", err) - } - // Recognize the root node if it's ever returned from Lookup, - // passed to Invalidate, etc. - s.nodeRef[root] = 1 - s.node = append(s.node, nil, &serveNode{ - inode: 1, - generation: s.nodeGen, - node: root, - refs: 1, - }) - s.handle = append(s.handle, nil) - - for { - req, err := s.conn.ReadRequest() - if err != nil { - if err == io.EOF { - break - } - return err - } - - s.wg.Add(1) - go func() { - defer s.wg.Done() - s.serve(req) - }() - } - return nil -} - -// Serve serves a FUSE connection with the default settings. See -// Server.Serve. -func Serve(c *fuse.Conn, fs FS) error { - server := New(c, nil) - return server.Serve(fs) -} - -type nothing struct{} - -type serveRequest struct { - Request fuse.Request - cancel func() -} - -type serveNode struct { - inode uint64 - generation uint64 - node Node - refs uint64 - - // Delay freeing the NodeID until waitgroup is done. This allows - // using the NodeID for short periods of time without holding the - // Server.meta lock. - // - // Rules: - // - // - hold Server.meta while calling wg.Add, then unlock - // - do NOT try to reacquire Server.meta - wg sync.WaitGroup -} - -func (sn *serveNode) attr(ctx context.Context, attr *fuse.Attr) error { - err := nodeAttr(ctx, sn.node, attr) - if attr.Inode == 0 { - attr.Inode = sn.inode - } - return err -} - -type serveHandle struct { - handle Handle - readData []byte - nodeID fuse.NodeID -} - -// NodeRef is deprecated. It remains here to decrease code churn on -// FUSE library users. You may remove it from your program now; -// returning the same Node values are now recognized automatically, -// without needing NodeRef. -type NodeRef struct{} - -func (c *Server) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) { - c.meta.Lock() - defer c.meta.Unlock() - - if id, ok := c.nodeRef[node]; ok { - sn := c.node[id] - sn.refs++ - return id, sn.generation - } - - sn := &serveNode{inode: inode, node: node, refs: 1} - if n := len(c.freeNode); n > 0 { - id = c.freeNode[n-1] - c.freeNode = c.freeNode[:n-1] - c.node[id] = sn - c.nodeGen++ - } else { - id = fuse.NodeID(len(c.node)) - c.node = append(c.node, sn) - } - sn.generation = c.nodeGen - c.nodeRef[node] = id - return id, sn.generation -} - -func (c *Server) saveHandle(handle Handle, nodeID fuse.NodeID) (id fuse.HandleID) { - c.meta.Lock() - shandle := &serveHandle{handle: handle, nodeID: nodeID} - if n := len(c.freeHandle); n > 0 { - id = c.freeHandle[n-1] - c.freeHandle = c.freeHandle[:n-1] - c.handle[id] = shandle - } else { - id = fuse.HandleID(len(c.handle)) - c.handle = append(c.handle, shandle) - } - c.meta.Unlock() - return -} - -type nodeRefcountDropBug struct { - N uint64 - Refs uint64 - Node fuse.NodeID -} - -func (n *nodeRefcountDropBug) String() string { - return fmt.Sprintf("bug: trying to drop %d of %d references to %v", n.N, n.Refs, n.Node) -} - -func (c *Server) dropNode(id fuse.NodeID, n uint64) (forget bool) { - c.meta.Lock() - defer c.meta.Unlock() - snode := c.node[id] - - if snode == nil { - // this should only happen if refcounts kernel<->us disagree - // *and* two ForgetRequests for the same node race each other; - // this indicates a bug somewhere - c.debug(nodeRefcountDropBug{N: n, Node: id}) - - // we may end up triggering Forget twice, but that's better - // than not even once, and that's the best we can do - return true - } - - if n > snode.refs { - c.debug(nodeRefcountDropBug{N: n, Refs: snode.refs, Node: id}) - n = snode.refs - } - - snode.refs -= n - if snode.refs == 0 { - snode.wg.Wait() - c.node[id] = nil - delete(c.nodeRef, snode.node) - c.freeNode = append(c.freeNode, id) - return true - } - return false -} - -func (c *Server) dropHandle(id fuse.HandleID) { - c.meta.Lock() - c.handle[id] = nil - c.freeHandle = append(c.freeHandle, id) - c.meta.Unlock() -} - -type missingHandle struct { - Handle fuse.HandleID - MaxHandle fuse.HandleID -} - -func (m missingHandle) String() string { - return fmt.Sprint("missing handle: ", m.Handle, m.MaxHandle) -} - -// Returns nil for invalid handles. -func (c *Server) getHandle(id fuse.HandleID) (shandle *serveHandle) { - c.meta.Lock() - defer c.meta.Unlock() - if id < fuse.HandleID(len(c.handle)) { - shandle = c.handle[uint(id)] - } - if shandle == nil { - c.debug(missingHandle{ - Handle: id, - MaxHandle: fuse.HandleID(len(c.handle)), - }) - } - return -} - -type request struct { - Op string - Request *fuse.Header - In interface{} `json:",omitempty"` -} - -func (r request) String() string { - return fmt.Sprintf("<- %s", r.In) -} - -type logResponseHeader struct { - ID fuse.RequestID -} - -func (m logResponseHeader) String() string { - return fmt.Sprintf("ID=%v", m.ID) -} - -type response struct { - Op string - Request logResponseHeader - Out interface{} `json:",omitempty"` - // Errno contains the errno value as a string, for example "EPERM". - Errno string `json:",omitempty"` - // Error may contain a free form error message. - Error string `json:",omitempty"` -} - -func (r response) errstr() string { - s := r.Errno - if r.Error != "" { - // prefix the errno constant to the long form message - s = s + ": " + r.Error - } - return s -} - -func (r response) String() string { - switch { - case r.Errno != "" && r.Out != nil: - return fmt.Sprintf("-> [%v] %v error=%s", r.Request, r.Out, r.errstr()) - case r.Errno != "": - return fmt.Sprintf("-> [%v] %s error=%s", r.Request, r.Op, r.errstr()) - case r.Out != nil: - // make sure (seemingly) empty values are readable - switch r.Out.(type) { - case string: - return fmt.Sprintf("-> [%v] %s %q", r.Request, r.Op, r.Out) - case []byte: - return fmt.Sprintf("-> [%v] %s [% x]", r.Request, r.Op, r.Out) - default: - return fmt.Sprintf("-> [%v] %v", r.Request, r.Out) - } - default: - return fmt.Sprintf("-> [%v] %s", r.Request, r.Op) - } -} - -type notification struct { - Op string - Node fuse.NodeID - Out interface{} `json:",omitempty"` - Err string `json:",omitempty"` -} - -func (n notification) String() string { - var buf bytes.Buffer - fmt.Fprintf(&buf, "=> %s %v", n.Op, n.Node) - if n.Out != nil { - // make sure (seemingly) empty values are readable - switch n.Out.(type) { - case string: - fmt.Fprintf(&buf, " %q", n.Out) - case []byte: - fmt.Fprintf(&buf, " [% x]", n.Out) - default: - fmt.Fprintf(&buf, " %s", n.Out) - } - } - if n.Err != "" { - fmt.Fprintf(&buf, " Err:%v", n.Err) - } - return buf.String() -} - -type logMissingNode struct { - MaxNode fuse.NodeID -} - -func opName(req fuse.Request) string { - t := reflect.Indirect(reflect.ValueOf(req)).Type() - s := t.Name() - s = strings.TrimSuffix(s, "Request") - return s -} - -type logLinkRequestOldNodeNotFound struct { - Request *fuse.Header - In *fuse.LinkRequest -} - -func (m *logLinkRequestOldNodeNotFound) String() string { - return fmt.Sprintf("In LinkRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.OldNode) -} - -type renameNewDirNodeNotFound struct { - Request *fuse.Header - In *fuse.RenameRequest -} - -func (m *renameNewDirNodeNotFound) String() string { - return fmt.Sprintf("In RenameRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.NewDir) -} - -type handlerPanickedError struct { - Request interface{} - Err interface{} -} - -var _ error = handlerPanickedError{} - -func (h handlerPanickedError) Error() string { - return fmt.Sprintf("handler panicked: %v", h.Err) -} - -var _ fuse.ErrorNumber = handlerPanickedError{} - -func (h handlerPanickedError) Errno() fuse.Errno { - if err, ok := h.Err.(fuse.ErrorNumber); ok { - return err.Errno() - } - return fuse.DefaultErrno -} - -// handlerTerminatedError happens when a handler terminates itself -// with runtime.Goexit. This is most commonly because of incorrect use -// of testing.TB.FailNow, typically via t.Fatal. -type handlerTerminatedError struct { - Request interface{} -} - -var _ error = handlerTerminatedError{} - -func (h handlerTerminatedError) Error() string { - return fmt.Sprintf("handler terminated (called runtime.Goexit)") -} - -var _ fuse.ErrorNumber = handlerTerminatedError{} - -func (h handlerTerminatedError) Errno() fuse.Errno { - return fuse.DefaultErrno -} - -type handleNotReaderError struct { - handle Handle -} - -var _ error = handleNotReaderError{} - -func (e handleNotReaderError) Error() string { - return fmt.Sprintf("handle has no Read: %T", e.handle) -} - -var _ fuse.ErrorNumber = handleNotReaderError{} - -func (e handleNotReaderError) Errno() fuse.Errno { - return fuse.ENOTSUP -} - -func initLookupResponse(s *fuse.LookupResponse) { - s.EntryValid = entryValidTime -} - -func (c *Server) serve(r fuse.Request) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - parentCtx := ctx - if c.context != nil { - ctx = c.context(ctx, r) - } - - req := &serveRequest{Request: r, cancel: cancel} - - c.debug(request{ - Op: opName(r), - Request: r.Hdr(), - In: r, - }) - var node Node - var snode *serveNode - c.meta.Lock() - hdr := r.Hdr() - if id := hdr.Node; id != 0 { - if id < fuse.NodeID(len(c.node)) { - snode = c.node[uint(id)] - } - if snode == nil { - c.meta.Unlock() - c.debug(response{ - Op: opName(r), - Request: logResponseHeader{ID: hdr.ID}, - Error: fuse.ESTALE.ErrnoName(), - // this is the only place that sets both Error and - // Out; not sure if i want to do that; might get rid - // of len(c.node) things altogether - Out: logMissingNode{ - MaxNode: fuse.NodeID(len(c.node)), - }, - }) - r.RespondError(fuse.ESTALE) - return - } - node = snode.node - } - if c.req[hdr.ID] != nil { - // This happens with OSXFUSE. Assume it's okay and - // that we'll never see an interrupt for this one. - // Otherwise everything wedges. TODO: Report to OSXFUSE? - // - // TODO this might have been because of missing done() calls - } else { - c.req[hdr.ID] = req - } - c.meta.Unlock() - - // Call this before responding. - // After responding is too late: we might get another request - // with the same ID and be very confused. - done := func(resp interface{}) { - msg := response{ - Op: opName(r), - Request: logResponseHeader{ID: hdr.ID}, - } - if err, ok := resp.(error); ok { - msg.Error = err.Error() - if ferr, ok := err.(fuse.ErrorNumber); ok { - errno := ferr.Errno() - msg.Errno = errno.ErrnoName() - if errno == err { - // it's just a fuse.Errno with no extra detail; - // skip the textual message for log readability - msg.Error = "" - } - } else { - msg.Errno = fuse.DefaultErrno.ErrnoName() - } - } else { - msg.Out = resp - } - c.debug(msg) - - c.meta.Lock() - delete(c.req, hdr.ID) - c.meta.Unlock() - } - - var responded bool - defer func() { - if rec := recover(); rec != nil { - const size = 1 << 16 - buf := make([]byte, size) - n := runtime.Stack(buf, false) - buf = buf[:n] - log.Printf("fuse: panic in handler for %v: %v\n%s", r, rec, buf) - err := handlerPanickedError{ - Request: r, - Err: rec, - } - done(err) - r.RespondError(err) - return - } - - if !responded { - err := handlerTerminatedError{ - Request: r, - } - done(err) - r.RespondError(err) - } - }() - - if err := c.handleRequest(ctx, node, snode, r, done); err != nil { - if err == context.Canceled { - select { - case <-parentCtx.Done(): - // We canceled the parent context because of an - // incoming interrupt request, so return EINTR - // to trigger the right behavior in the client app. - // - // Only do this when it's the parent context that was - // canceled, not a context controlled by the program - // using this library, so we don't return EINTR too - // eagerly -- it might cause busy loops. - // - // Decent write-up on role of EINTR: - // http://250bpm.com/blog:12 - err = fuse.EINTR - default: - // nothing - } - } - done(err) - r.RespondError(err) - } - - // disarm runtime.Goexit protection - responded = true -} - -// handleRequest will either a) call done(s) and r.Respond(s) OR b) return an error. -func (c *Server) handleRequest(ctx context.Context, node Node, snode *serveNode, r fuse.Request, done func(resp interface{})) error { - switch r := r.(type) { - default: - // Note: To FUSE, ENOSYS means "this server never implements this request." - // It would be inappropriate to return ENOSYS for other operations in this - // switch that might only be unavailable in some contexts, not all. - return fuse.ENOSYS - - case *fuse.StatfsRequest: - s := &fuse.StatfsResponse{} - if fs, ok := c.fs.(FSStatfser); ok { - if err := fs.Statfs(ctx, r, s); err != nil { - return err - } - } - done(s) - r.Respond(s) - return nil - - // Node operations. - case *fuse.GetattrRequest: - s := &fuse.GetattrResponse{} - if n, ok := node.(NodeGetattrer); ok { - if err := n.Getattr(ctx, r, s); err != nil { - return err - } - } else { - if err := snode.attr(ctx, &s.Attr); err != nil { - return err - } - } - done(s) - r.Respond(s) - return nil - - case *fuse.SetattrRequest: - s := &fuse.SetattrResponse{} - if n, ok := node.(NodeSetattrer); ok { - if err := n.Setattr(ctx, r, s); err != nil { - return err - } - } - - if err := snode.attr(ctx, &s.Attr); err != nil { - return err - } - done(s) - r.Respond(s) - return nil - - case *fuse.SymlinkRequest: - s := &fuse.SymlinkResponse{} - initLookupResponse(&s.LookupResponse) - n, ok := node.(NodeSymlinker) - if !ok { - return fuse.EIO // XXX or EPERM like Mkdir? - } - n2, err := n.Symlink(ctx, r) - if err != nil { - return err - } - if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.NewName, n2); err != nil { - return err - } - done(s) - r.Respond(s) - return nil - - case *fuse.ReadlinkRequest: - n, ok := node.(NodeReadlinker) - if !ok { - return fuse.EIO /// XXX or EPERM? - } - target, err := n.Readlink(ctx, r) - if err != nil { - return err - } - done(target) - r.Respond(target) - return nil - - case *fuse.LinkRequest: - n, ok := node.(NodeLinker) - if !ok { - return fuse.EIO /// XXX or EPERM? - } - c.meta.Lock() - var oldNode *serveNode - if int(r.OldNode) < len(c.node) { - oldNode = c.node[r.OldNode] - } - c.meta.Unlock() - if oldNode == nil { - c.debug(logLinkRequestOldNodeNotFound{ - Request: r.Hdr(), - In: r, - }) - return fuse.EIO - } - n2, err := n.Link(ctx, r, oldNode.node) - if err != nil { - return err - } - s := &fuse.LookupResponse{} - initLookupResponse(s) - if err := c.saveLookup(ctx, s, snode, r.NewName, n2); err != nil { - return err - } - done(s) - r.Respond(s) - return nil - - case *fuse.RemoveRequest: - n, ok := node.(NodeRemover) - if !ok { - return fuse.EIO /// XXX or EPERM? - } - err := n.Remove(ctx, r) - if err != nil { - return err - } - done(nil) - r.Respond() - return nil - - case *fuse.AccessRequest: - if n, ok := node.(NodeAccesser); ok { - if err := n.Access(ctx, r); err != nil { - return err - } - } - done(nil) - r.Respond() - return nil - - case *fuse.LookupRequest: - var n2 Node - var err error - s := &fuse.LookupResponse{} - initLookupResponse(s) - if n, ok := node.(NodeStringLookuper); ok { - n2, err = n.Lookup(ctx, r.Name) - } else if n, ok := node.(NodeRequestLookuper); ok { - n2, err = n.Lookup(ctx, r, s) - } else { - return fuse.ENOENT - } - if err != nil { - return err - } - if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil { - return err - } - done(s) - r.Respond(s) - return nil - - case *fuse.MkdirRequest: - s := &fuse.MkdirResponse{} - initLookupResponse(&s.LookupResponse) - n, ok := node.(NodeMkdirer) - if !ok { - return fuse.EPERM - } - n2, err := n.Mkdir(ctx, r) - if err != nil { - return err - } - if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil { - return err - } - done(s) - r.Respond(s) - return nil - - case *fuse.OpenRequest: - s := &fuse.OpenResponse{} - var h2 Handle - if n, ok := node.(NodeOpener); ok { - hh, err := n.Open(ctx, r, s) - if err != nil { - return err - } - h2 = hh - } else { - h2 = node - } - s.Handle = c.saveHandle(h2, r.Hdr().Node) - done(s) - r.Respond(s) - return nil - - case *fuse.CreateRequest: - n, ok := node.(NodeCreater) - if !ok { - // If we send back ENOSYS, FUSE will try mknod+open. - return fuse.EPERM - } - s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}} - initLookupResponse(&s.LookupResponse) - n2, h2, err := n.Create(ctx, r, s) - if err != nil { - return err - } - if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil { - return err - } - s.Handle = c.saveHandle(h2, r.Hdr().Node) - done(s) - r.Respond(s) - return nil - - case *fuse.GetxattrRequest: - n, ok := node.(NodeGetxattrer) - if !ok { - return fuse.ENOTSUP - } - s := &fuse.GetxattrResponse{} - err := n.Getxattr(ctx, r, s) - if err != nil { - return err - } - if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) { - return fuse.ERANGE - } - done(s) - r.Respond(s) - return nil - - case *fuse.ListxattrRequest: - n, ok := node.(NodeListxattrer) - if !ok { - return fuse.ENOTSUP - } - s := &fuse.ListxattrResponse{} - err := n.Listxattr(ctx, r, s) - if err != nil { - return err - } - if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) { - return fuse.ERANGE - } - done(s) - r.Respond(s) - return nil - - case *fuse.SetxattrRequest: - n, ok := node.(NodeSetxattrer) - if !ok { - return fuse.ENOTSUP - } - err := n.Setxattr(ctx, r) - if err != nil { - return err - } - done(nil) - r.Respond() - return nil - - case *fuse.RemovexattrRequest: - n, ok := node.(NodeRemovexattrer) - if !ok { - return fuse.ENOTSUP - } - err := n.Removexattr(ctx, r) - if err != nil { - return err - } - done(nil) - r.Respond() - return nil - - case *fuse.ForgetRequest: - forget := c.dropNode(r.Hdr().Node, r.N) - if forget { - n, ok := node.(NodeForgetter) - if ok { - n.Forget() - } - } - done(nil) - r.Respond() - return nil - - // Handle operations. - case *fuse.ReadRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - return fuse.ESTALE - } - handle := shandle.handle - - s := &fuse.ReadResponse{Data: make([]byte, 0, r.Size)} - if r.Dir { - if h, ok := handle.(HandleReadDirAller); ok { - // detect rewinddir(3) or similar seek and refresh - // contents - if r.Offset == 0 { - shandle.readData = nil - } - - if shandle.readData == nil { - dirs, err := h.ReadDirAll(ctx) - if err != nil { - return err - } - var data []byte - for _, dir := range dirs { - if dir.Inode == 0 { - dir.Inode = c.dynamicInode(snode.inode, dir.Name) - } - data = fuse.AppendDirent(data, dir) - } - shandle.readData = data - } - fuseutil.HandleRead(r, s, shandle.readData) - done(s) - r.Respond(s) - return nil - } - } else { - if h, ok := handle.(HandleReadAller); ok { - if shandle.readData == nil { - data, err := h.ReadAll(ctx) - if err != nil { - return err - } - if data == nil { - data = []byte{} - } - shandle.readData = data - } - fuseutil.HandleRead(r, s, shandle.readData) - done(s) - r.Respond(s) - return nil - } - h, ok := handle.(HandleReader) - if !ok { - err := handleNotReaderError{handle: handle} - return err - } - if err := h.Read(ctx, r, s); err != nil { - return err - } - } - done(s) - r.Respond(s) - return nil - - case *fuse.WriteRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - return fuse.ESTALE - } - - s := &fuse.WriteResponse{} - if h, ok := shandle.handle.(HandleWriter); ok { - if err := h.Write(ctx, r, s); err != nil { - return err - } - done(s) - r.Respond(s) - return nil - } - return fuse.EIO - - case *fuse.FlushRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - return fuse.ESTALE - } - handle := shandle.handle - - if h, ok := handle.(HandleFlusher); ok { - if err := h.Flush(ctx, r); err != nil { - return err - } - } - done(nil) - r.Respond() - return nil - - case *fuse.ReleaseRequest: - shandle := c.getHandle(r.Handle) - if shandle == nil { - return fuse.ESTALE - } - handle := shandle.handle - - // No matter what, release the handle. - c.dropHandle(r.Handle) - - if h, ok := handle.(HandleReleaser); ok { - if err := h.Release(ctx, r); err != nil { - return err - } - } - done(nil) - r.Respond() - return nil - - case *fuse.DestroyRequest: - if fs, ok := c.fs.(FSDestroyer); ok { - fs.Destroy() - } - done(nil) - r.Respond() - return nil - - case *fuse.RenameRequest: - c.meta.Lock() - var newDirNode *serveNode - if int(r.NewDir) < len(c.node) { - newDirNode = c.node[r.NewDir] - } - c.meta.Unlock() - if newDirNode == nil { - c.debug(renameNewDirNodeNotFound{ - Request: r.Hdr(), - In: r, - }) - return fuse.EIO - } - n, ok := node.(NodeRenamer) - if !ok { - return fuse.EIO // XXX or EPERM like Mkdir? - } - err := n.Rename(ctx, r, newDirNode.node) - if err != nil { - return err - } - done(nil) - r.Respond() - return nil - - case *fuse.MknodRequest: - n, ok := node.(NodeMknoder) - if !ok { - return fuse.EIO - } - n2, err := n.Mknod(ctx, r) - if err != nil { - return err - } - s := &fuse.LookupResponse{} - initLookupResponse(s) - if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil { - return err - } - done(s) - r.Respond(s) - return nil - - case *fuse.FsyncRequest: - n, ok := node.(NodeFsyncer) - if !ok { - return fuse.EIO - } - err := n.Fsync(ctx, r) - if err != nil { - return err - } - done(nil) - r.Respond() - return nil - - case *fuse.InterruptRequest: - c.meta.Lock() - ireq := c.req[r.IntrID] - if ireq != nil && ireq.cancel != nil { - ireq.cancel() - ireq.cancel = nil - } - c.meta.Unlock() - done(nil) - r.Respond() - return nil - - /* case *FsyncdirRequest: - return ENOSYS - - case *GetlkRequest, *SetlkRequest, *SetlkwRequest: - return ENOSYS - - case *BmapRequest: - return ENOSYS - - case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest: - return ENOSYS - */ - } - - panic("not reached") -} - -func (c *Server) saveLookup(ctx context.Context, s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) error { - if err := nodeAttr(ctx, n2, &s.Attr); err != nil { - return err - } - if s.Attr.Inode == 0 { - s.Attr.Inode = c.dynamicInode(snode.inode, elem) - } - - s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2) - return nil -} - -type invalidateNodeDetail struct { - Off int64 - Size int64 -} - -func (i invalidateNodeDetail) String() string { - return fmt.Sprintf("Off:%d Size:%d", i.Off, i.Size) -} - -func errstr(err error) string { - if err == nil { - return "" - } - return err.Error() -} - -func (s *Server) invalidateNode(node Node, off int64, size int64) error { - s.meta.Lock() - id, ok := s.nodeRef[node] - if ok { - snode := s.node[id] - snode.wg.Add(1) - defer snode.wg.Done() - } - s.meta.Unlock() - if !ok { - // This is what the kernel would have said, if we had been - // able to send this message; it's not cached. - return fuse.ErrNotCached - } - // Delay logging until after we can record the error too. We - // consider a /dev/fuse write to be instantaneous enough to not - // need separate before and after messages. - err := s.conn.InvalidateNode(id, off, size) - s.debug(notification{ - Op: "InvalidateNode", - Node: id, - Out: invalidateNodeDetail{ - Off: off, - Size: size, - }, - Err: errstr(err), - }) - return err -} - -// InvalidateNodeAttr invalidates the kernel cache of the attributes -// of node. -// -// Returns fuse.ErrNotCached if the kernel is not currently caching -// the node. -func (s *Server) InvalidateNodeAttr(node Node) error { - return s.invalidateNode(node, 0, 0) -} - -// InvalidateNodeData invalidates the kernel cache of the attributes -// and data of node. -// -// Returns fuse.ErrNotCached if the kernel is not currently caching -// the node. -func (s *Server) InvalidateNodeData(node Node) error { - return s.invalidateNode(node, 0, -1) -} - -// InvalidateNodeDataRange invalidates the kernel cache of the -// attributes and a range of the data of node. -// -// Returns fuse.ErrNotCached if the kernel is not currently caching -// the node. -func (s *Server) InvalidateNodeDataRange(node Node, off int64, size int64) error { - return s.invalidateNode(node, off, size) -} - -type invalidateEntryDetail struct { - Name string -} - -func (i invalidateEntryDetail) String() string { - return fmt.Sprintf("%q", i.Name) -} - -// InvalidateEntry invalidates the kernel cache of the directory entry -// identified by parent node and entry basename. -// -// Kernel may or may not cache directory listings. To invalidate -// those, use InvalidateNode to invalidate all of the data for a -// directory. (As of 2015-06, Linux FUSE does not cache directory -// listings.) -// -// Returns ErrNotCached if the kernel is not currently caching the -// node. -func (s *Server) InvalidateEntry(parent Node, name string) error { - s.meta.Lock() - id, ok := s.nodeRef[parent] - if ok { - snode := s.node[id] - snode.wg.Add(1) - defer snode.wg.Done() - } - s.meta.Unlock() - if !ok { - // This is what the kernel would have said, if we had been - // able to send this message; it's not cached. - return fuse.ErrNotCached - } - err := s.conn.InvalidateEntry(id, name) - s.debug(notification{ - Op: "InvalidateEntry", - Node: id, - Out: invalidateEntryDetail{ - Name: name, - }, - Err: errstr(err), - }) - return err -} - -// DataHandle returns a read-only Handle that satisfies reads -// using the given data. -func DataHandle(data []byte) Handle { - return &dataHandle{data} -} - -type dataHandle struct { - data []byte -} - -func (d *dataHandle) ReadAll(ctx context.Context) ([]byte, error) { - return d.data, nil -} - -// GenerateDynamicInode returns a dynamic inode. -// -// The parent inode and current entry name are used as the criteria -// for choosing a pseudorandom inode. This makes it likely the same -// entry will get the same inode on multiple runs. -func GenerateDynamicInode(parent uint64, name string) uint64 { - h := fnv.New64a() - var buf [8]byte - binary.LittleEndian.PutUint64(buf[:], parent) - _, _ = h.Write(buf[:]) - _, _ = h.Write([]byte(name)) - var inode uint64 - for { - inode = h.Sum64() - if inode != 0 { - break - } - // there's a tiny probability that result is zero; change the - // input a little and try again - _, _ = h.Write([]byte{'x'}) - } - return inode -} diff --git a/vendor/bazil.org/fuse/fs/tree.go b/vendor/bazil.org/fuse/fs/tree.go deleted file mode 100644 index 7e078045a5..0000000000 --- a/vendor/bazil.org/fuse/fs/tree.go +++ /dev/null @@ -1,99 +0,0 @@ -// FUSE directory tree, for servers that wish to use it with the service loop. - -package fs - -import ( - "os" - pathpkg "path" - "strings" - - "golang.org/x/net/context" -) - -import ( - "bazil.org/fuse" -) - -// A Tree implements a basic read-only directory tree for FUSE. -// The Nodes contained in it may still be writable. -type Tree struct { - tree -} - -func (t *Tree) Root() (Node, error) { - return &t.tree, nil -} - -// Add adds the path to the tree, resolving to the given node. -// If path or a prefix of path has already been added to the tree, -// Add panics. -// -// Add is only safe to call before starting to serve requests. -func (t *Tree) Add(path string, node Node) { - path = pathpkg.Clean("/" + path)[1:] - elems := strings.Split(path, "/") - dir := Node(&t.tree) - for i, elem := range elems { - dt, ok := dir.(*tree) - if !ok { - panic("fuse: Tree.Add for " + strings.Join(elems[:i], "/") + " and " + path) - } - n := dt.lookup(elem) - if n != nil { - if i+1 == len(elems) { - panic("fuse: Tree.Add for " + path + " conflicts with " + elem) - } - dir = n - } else { - if i+1 == len(elems) { - dt.add(elem, node) - } else { - dir = &tree{} - dt.add(elem, dir) - } - } - } -} - -type treeDir struct { - name string - node Node -} - -type tree struct { - dir []treeDir -} - -func (t *tree) lookup(name string) Node { - for _, d := range t.dir { - if d.name == name { - return d.node - } - } - return nil -} - -func (t *tree) add(name string, n Node) { - t.dir = append(t.dir, treeDir{name, n}) -} - -func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error { - a.Mode = os.ModeDir | 0555 - return nil -} - -func (t *tree) Lookup(ctx context.Context, name string) (Node, error) { - n := t.lookup(name) - if n != nil { - return n, nil - } - return nil, fuse.ENOENT -} - -func (t *tree) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - var out []fuse.Dirent - for _, d := range t.dir { - out = append(out, fuse.Dirent{Name: d.name}) - } - return out, nil -} diff --git a/vendor/bazil.org/fuse/fuse.go b/vendor/bazil.org/fuse/fuse.go deleted file mode 100644 index 6db0ef2935..0000000000 --- a/vendor/bazil.org/fuse/fuse.go +++ /dev/null @@ -1,2303 +0,0 @@ -// See the file LICENSE for copyright and licensing information. - -// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c, -// which carries this notice: -// -// The files in this directory are subject to the following license. -// -// The author of this software is Russ Cox. -// -// Copyright (c) 2006 Russ Cox -// -// Permission to use, copy, modify, and distribute this software for any -// purpose without fee is hereby granted, provided that this entire notice -// is included in all copies of any software which is or includes a copy -// or modification of this software and in all copies of the supporting -// documentation for such software. -// -// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY -// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS -// FITNESS FOR ANY PARTICULAR PURPOSE. - -// Package fuse enables writing FUSE file systems on Linux, OS X, and FreeBSD. -// -// On OS X, it requires OSXFUSE (http://osxfuse.github.com/). -// -// There are two approaches to writing a FUSE file system. The first is to speak -// the low-level message protocol, reading from a Conn using ReadRequest and -// writing using the various Respond methods. This approach is closest to -// the actual interaction with the kernel and can be the simplest one in contexts -// such as protocol translators. -// -// Servers of synthesized file systems tend to share common -// bookkeeping abstracted away by the second approach, which is to -// call fs.Serve to serve the FUSE protocol using an implementation of -// the service methods in the interfaces FS* (file system), Node* (file -// or directory), and Handle* (opened file or directory). -// There are a daunting number of such methods that can be written, -// but few are required. -// The specific methods are described in the documentation for those interfaces. -// -// The hellofs subdirectory contains a simple illustration of the fs.Serve approach. -// -// Service Methods -// -// The required and optional methods for the FS, Node, and Handle interfaces -// have the general form -// -// Op(ctx context.Context, req *OpRequest, resp *OpResponse) error -// -// where Op is the name of a FUSE operation. Op reads request -// parameters from req and writes results to resp. An operation whose -// only result is the error result omits the resp parameter. -// -// Multiple goroutines may call service methods simultaneously; the -// methods being called are responsible for appropriate -// synchronization. -// -// The operation must not hold on to the request or response, -// including any []byte fields such as WriteRequest.Data or -// SetxattrRequest.Xattr. -// -// Errors -// -// Operations can return errors. The FUSE interface can only -// communicate POSIX errno error numbers to file system clients, the -// message is not visible to file system clients. The returned error -// can implement ErrorNumber to control the errno returned. Without -// ErrorNumber, a generic errno (EIO) is returned. -// -// Error messages will be visible in the debug log as part of the -// response. -// -// Interrupted Operations -// -// In some file systems, some operations -// may take an undetermined amount of time. For example, a Read waiting for -// a network message or a matching Write might wait indefinitely. If the request -// is cancelled and no longer needed, the context will be cancelled. -// Blocking operations should select on a receive from ctx.Done() and attempt to -// abort the operation early if the receive succeeds (meaning the channel is closed). -// To indicate that the operation failed because it was aborted, return fuse.EINTR. -// -// If an operation does not block for an indefinite amount of time, supporting -// cancellation is not necessary. -// -// Authentication -// -// All requests types embed a Header, meaning that the method can -// inspect req.Pid, req.Uid, and req.Gid as necessary to implement -// permission checking. The kernel FUSE layer normally prevents other -// users from accessing the FUSE file system (to change this, see -// AllowOther, AllowRoot), but does not enforce access modes (to -// change this, see DefaultPermissions). -// -// Mount Options -// -// Behavior and metadata of the mounted file system can be changed by -// passing MountOption values to Mount. -// -package fuse // import "bazil.org/fuse" - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "os" - "sync" - "syscall" - "time" - "unsafe" -) - -// A Conn represents a connection to a mounted FUSE file system. -type Conn struct { - // Ready is closed when the mount is complete or has failed. - Ready <-chan struct{} - - // MountError stores any error from the mount process. Only valid - // after Ready is closed. - MountError error - - // File handle for kernel communication. Only safe to access if - // rio or wio is held. - dev *os.File - wio sync.RWMutex - rio sync.RWMutex - - // Protocol version negotiated with InitRequest/InitResponse. - proto Protocol -} - -// MountpointDoesNotExistError is an error returned when the -// mountpoint does not exist. -type MountpointDoesNotExistError struct { - Path string -} - -var _ error = (*MountpointDoesNotExistError)(nil) - -func (e *MountpointDoesNotExistError) Error() string { - return fmt.Sprintf("mountpoint does not exist: %v", e.Path) -} - -// Mount mounts a new FUSE connection on the named directory -// and returns a connection for reading and writing FUSE messages. -// -// After a successful return, caller must call Close to free -// resources. -// -// Even on successful return, the new mount is not guaranteed to be -// visible until after Conn.Ready is closed. See Conn.MountError for -// possible errors. Incoming requests on Conn must be served to make -// progress. -func Mount(dir string, options ...MountOption) (*Conn, error) { - conf := mountConfig{ - options: make(map[string]string), - } - for _, option := range options { - if err := option(&conf); err != nil { - return nil, err - } - } - - ready := make(chan struct{}, 1) - c := &Conn{ - Ready: ready, - } - f, err := mount(dir, &conf, ready, &c.MountError) - if err != nil { - return nil, err - } - c.dev = f - - if err := initMount(c, &conf); err != nil { - c.Close() - if err == ErrClosedWithoutInit { - // see if we can provide a better error - <-c.Ready - if err := c.MountError; err != nil { - return nil, err - } - } - return nil, err - } - - return c, nil -} - -type OldVersionError struct { - Kernel Protocol - LibraryMin Protocol -} - -func (e *OldVersionError) Error() string { - return fmt.Sprintf("kernel FUSE version is too old: %v < %v", e.Kernel, e.LibraryMin) -} - -var ( - ErrClosedWithoutInit = errors.New("fuse connection closed without init") -) - -func initMount(c *Conn, conf *mountConfig) error { - req, err := c.ReadRequest() - if err != nil { - if err == io.EOF { - return ErrClosedWithoutInit - } - return err - } - r, ok := req.(*InitRequest) - if !ok { - return fmt.Errorf("missing init, got: %T", req) - } - - min := Protocol{protoVersionMinMajor, protoVersionMinMinor} - if r.Kernel.LT(min) { - req.RespondError(Errno(syscall.EPROTO)) - c.Close() - return &OldVersionError{ - Kernel: r.Kernel, - LibraryMin: min, - } - } - - proto := Protocol{protoVersionMaxMajor, protoVersionMaxMinor} - if r.Kernel.LT(proto) { - // Kernel doesn't support the latest version we have. - proto = r.Kernel - } - c.proto = proto - - s := &InitResponse{ - Library: proto, - MaxReadahead: conf.maxReadahead, - MaxWrite: maxWrite, - Flags: InitBigWrites | conf.initFlags, - } - r.Respond(s) - return nil -} - -// A Request represents a single FUSE request received from the kernel. -// Use a type switch to determine the specific kind. -// A request of unrecognized type will have concrete type *Header. -type Request interface { - // Hdr returns the Header associated with this request. - Hdr() *Header - - // RespondError responds to the request with the given error. - RespondError(error) - - String() string -} - -// A RequestID identifies an active FUSE request. -type RequestID uint64 - -func (r RequestID) String() string { - return fmt.Sprintf("%#x", uint64(r)) -} - -// A NodeID is a number identifying a directory or file. -// It must be unique among IDs returned in LookupResponses -// that have not yet been forgotten by ForgetRequests. -type NodeID uint64 - -func (n NodeID) String() string { - return fmt.Sprintf("%#x", uint64(n)) -} - -// A HandleID is a number identifying an open directory or file. -// It only needs to be unique while the directory or file is open. -type HandleID uint64 - -func (h HandleID) String() string { - return fmt.Sprintf("%#x", uint64(h)) -} - -// The RootID identifies the root directory of a FUSE file system. -const RootID NodeID = rootID - -// A Header describes the basic information sent in every request. -type Header struct { - Conn *Conn `json:"-"` // connection this request was received on - ID RequestID // unique ID for request - Node NodeID // file or directory the request is about - Uid uint32 // user ID of process making request - Gid uint32 // group ID of process making request - Pid uint32 // process ID of process making request - - // for returning to reqPool - msg *message -} - -func (h *Header) String() string { - return fmt.Sprintf("ID=%v Node=%v Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid) -} - -func (h *Header) Hdr() *Header { - return h -} - -func (h *Header) noResponse() { - putMessage(h.msg) -} - -func (h *Header) respond(msg []byte) { - out := (*outHeader)(unsafe.Pointer(&msg[0])) - out.Unique = uint64(h.ID) - h.Conn.respond(msg) - putMessage(h.msg) -} - -// An ErrorNumber is an error with a specific error number. -// -// Operations may return an error value that implements ErrorNumber to -// control what specific error number (errno) to return. -type ErrorNumber interface { - // Errno returns the the error number (errno) for this error. - Errno() Errno -} - -const ( - // ENOSYS indicates that the call is not supported. - ENOSYS = Errno(syscall.ENOSYS) - - // ESTALE is used by Serve to respond to violations of the FUSE protocol. - ESTALE = Errno(syscall.ESTALE) - - ENOENT = Errno(syscall.ENOENT) - EIO = Errno(syscall.EIO) - EPERM = Errno(syscall.EPERM) - - // EINTR indicates request was interrupted by an InterruptRequest. - // See also fs.Intr. - EINTR = Errno(syscall.EINTR) - - ERANGE = Errno(syscall.ERANGE) - ENOTSUP = Errno(syscall.ENOTSUP) - EEXIST = Errno(syscall.EEXIST) -) - -// DefaultErrno is the errno used when error returned does not -// implement ErrorNumber. -const DefaultErrno = EIO - -var errnoNames = map[Errno]string{ - ENOSYS: "ENOSYS", - ESTALE: "ESTALE", - ENOENT: "ENOENT", - EIO: "EIO", - EPERM: "EPERM", - EINTR: "EINTR", - EEXIST: "EEXIST", -} - -// Errno implements Error and ErrorNumber using a syscall.Errno. -type Errno syscall.Errno - -var _ = ErrorNumber(Errno(0)) -var _ = error(Errno(0)) - -func (e Errno) Errno() Errno { - return e -} - -func (e Errno) String() string { - return syscall.Errno(e).Error() -} - -func (e Errno) Error() string { - return syscall.Errno(e).Error() -} - -// ErrnoName returns the short non-numeric identifier for this errno. -// For example, "EIO". -func (e Errno) ErrnoName() string { - s := errnoNames[e] - if s == "" { - s = fmt.Sprint(e.Errno()) - } - return s -} - -func (e Errno) MarshalText() ([]byte, error) { - s := e.ErrnoName() - return []byte(s), nil -} - -func (h *Header) RespondError(err error) { - errno := DefaultErrno - if ferr, ok := err.(ErrorNumber); ok { - errno = ferr.Errno() - } - // FUSE uses negative errors! - // TODO: File bug report against OSXFUSE: positive error causes kernel panic. - buf := newBuffer(0) - hOut := (*outHeader)(unsafe.Pointer(&buf[0])) - hOut.Error = -int32(errno) - h.respond(buf) -} - -// All requests read from the kernel, without data, are shorter than -// this. -var maxRequestSize = syscall.Getpagesize() -var bufSize = maxRequestSize + maxWrite - -// reqPool is a pool of messages. -// -// Lifetime of a logical message is from getMessage to putMessage. -// getMessage is called by ReadRequest. putMessage is called by -// Conn.ReadRequest, Request.Respond, or Request.RespondError. -// -// Messages in the pool are guaranteed to have conn and off zeroed, -// buf allocated and len==bufSize, and hdr set. -var reqPool = sync.Pool{ - New: allocMessage, -} - -func allocMessage() interface{} { - m := &message{buf: make([]byte, bufSize)} - m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0])) - return m -} - -func getMessage(c *Conn) *message { - m := reqPool.Get().(*message) - m.conn = c - return m -} - -func putMessage(m *message) { - m.buf = m.buf[:bufSize] - m.conn = nil - m.off = 0 - reqPool.Put(m) -} - -// a message represents the bytes of a single FUSE message -type message struct { - conn *Conn - buf []byte // all bytes - hdr *inHeader // header - off int // offset for reading additional fields -} - -func (m *message) len() uintptr { - return uintptr(len(m.buf) - m.off) -} - -func (m *message) data() unsafe.Pointer { - var p unsafe.Pointer - if m.off < len(m.buf) { - p = unsafe.Pointer(&m.buf[m.off]) - } - return p -} - -func (m *message) bytes() []byte { - return m.buf[m.off:] -} - -func (m *message) Header() Header { - h := m.hdr - return Header{ - Conn: m.conn, - ID: RequestID(h.Unique), - Node: NodeID(h.Nodeid), - Uid: h.Uid, - Gid: h.Gid, - Pid: h.Pid, - - msg: m, - } -} - -// fileMode returns a Go os.FileMode from a Unix mode. -func fileMode(unixMode uint32) os.FileMode { - mode := os.FileMode(unixMode & 0777) - switch unixMode & syscall.S_IFMT { - case syscall.S_IFREG: - // nothing - case syscall.S_IFDIR: - mode |= os.ModeDir - case syscall.S_IFCHR: - mode |= os.ModeCharDevice | os.ModeDevice - case syscall.S_IFBLK: - mode |= os.ModeDevice - case syscall.S_IFIFO: - mode |= os.ModeNamedPipe - case syscall.S_IFLNK: - mode |= os.ModeSymlink - case syscall.S_IFSOCK: - mode |= os.ModeSocket - default: - // no idea - mode |= os.ModeDevice - } - if unixMode&syscall.S_ISUID != 0 { - mode |= os.ModeSetuid - } - if unixMode&syscall.S_ISGID != 0 { - mode |= os.ModeSetgid - } - return mode -} - -type noOpcode struct { - Opcode uint32 -} - -func (m noOpcode) String() string { - return fmt.Sprintf("No opcode %v", m.Opcode) -} - -type malformedMessage struct { -} - -func (malformedMessage) String() string { - return "malformed message" -} - -// Close closes the FUSE connection. -func (c *Conn) Close() error { - c.wio.Lock() - defer c.wio.Unlock() - c.rio.Lock() - defer c.rio.Unlock() - return c.dev.Close() -} - -// caller must hold wio or rio -func (c *Conn) fd() int { - return int(c.dev.Fd()) -} - -func (c *Conn) Protocol() Protocol { - return c.proto -} - -// ReadRequest returns the next FUSE request from the kernel. -// -// Caller must call either Request.Respond or Request.RespondError in -// a reasonable time. Caller must not retain Request after that call. -func (c *Conn) ReadRequest() (Request, error) { - m := getMessage(c) -loop: - c.rio.RLock() - n, err := syscall.Read(c.fd(), m.buf) - c.rio.RUnlock() - if err == syscall.EINTR { - // OSXFUSE sends EINTR to userspace when a request interrupt - // completed before it got sent to userspace? - goto loop - } - if err != nil && err != syscall.ENODEV { - putMessage(m) - return nil, err - } - if n <= 0 { - putMessage(m) - return nil, io.EOF - } - m.buf = m.buf[:n] - - if n < inHeaderSize { - putMessage(m) - return nil, errors.New("fuse: message too short") - } - - // FreeBSD FUSE sends a short length in the header - // for FUSE_INIT even though the actual read length is correct. - if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) { - m.hdr.Len = uint32(n) - } - - // OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message. - if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite { - m.hdr.Len = uint32(n) - } - - if m.hdr.Len != uint32(n) { - // prepare error message before returning m to pool - err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len) - putMessage(m) - return nil, err - } - - m.off = inHeaderSize - - // Convert to data structures. - // Do not trust kernel to hand us well-formed data. - var req Request - switch m.hdr.Opcode { - default: - Debug(noOpcode{Opcode: m.hdr.Opcode}) - goto unrecognized - - case opLookup: - buf := m.bytes() - n := len(buf) - if n == 0 || buf[n-1] != '\x00' { - goto corrupt - } - req = &LookupRequest{ - Header: m.Header(), - Name: string(buf[:n-1]), - } - - case opForget: - in := (*forgetIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &ForgetRequest{ - Header: m.Header(), - N: in.Nlookup, - } - - case opGetattr: - switch { - case c.proto.LT(Protocol{7, 9}): - req = &GetattrRequest{ - Header: m.Header(), - } - - default: - in := (*getattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &GetattrRequest{ - Header: m.Header(), - Flags: GetattrFlags(in.GetattrFlags), - Handle: HandleID(in.Fh), - } - } - - case opSetattr: - in := (*setattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &SetattrRequest{ - Header: m.Header(), - Valid: SetattrValid(in.Valid), - Handle: HandleID(in.Fh), - Size: in.Size, - Atime: time.Unix(int64(in.Atime), int64(in.AtimeNsec)), - Mtime: time.Unix(int64(in.Mtime), int64(in.MtimeNsec)), - Mode: fileMode(in.Mode), - Uid: in.Uid, - Gid: in.Gid, - Bkuptime: in.BkupTime(), - Chgtime: in.Chgtime(), - Flags: in.Flags(), - } - - case opReadlink: - if len(m.bytes()) > 0 { - goto corrupt - } - req = &ReadlinkRequest{ - Header: m.Header(), - } - - case opSymlink: - // m.bytes() is "newName\0target\0" - names := m.bytes() - if len(names) == 0 || names[len(names)-1] != 0 { - goto corrupt - } - i := bytes.IndexByte(names, '\x00') - if i < 0 { - goto corrupt - } - newName, target := names[0:i], names[i+1:len(names)-1] - req = &SymlinkRequest{ - Header: m.Header(), - NewName: string(newName), - Target: string(target), - } - - case opLink: - in := (*linkIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - newName := m.bytes()[unsafe.Sizeof(*in):] - if len(newName) < 2 || newName[len(newName)-1] != 0 { - goto corrupt - } - newName = newName[:len(newName)-1] - req = &LinkRequest{ - Header: m.Header(), - OldNode: NodeID(in.Oldnodeid), - NewName: string(newName), - } - - case opMknod: - size := mknodInSize(c.proto) - if m.len() < size { - goto corrupt - } - in := (*mknodIn)(m.data()) - name := m.bytes()[size:] - if len(name) < 2 || name[len(name)-1] != '\x00' { - goto corrupt - } - name = name[:len(name)-1] - r := &MknodRequest{ - Header: m.Header(), - Mode: fileMode(in.Mode), - Rdev: in.Rdev, - Name: string(name), - } - if c.proto.GE(Protocol{7, 12}) { - r.Umask = fileMode(in.Umask) & os.ModePerm - } - req = r - - case opMkdir: - size := mkdirInSize(c.proto) - if m.len() < size { - goto corrupt - } - in := (*mkdirIn)(m.data()) - name := m.bytes()[size:] - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - r := &MkdirRequest{ - Header: m.Header(), - Name: string(name[:i]), - // observed on Linux: mkdirIn.Mode & syscall.S_IFMT == 0, - // and this causes fileMode to go into it's "no idea" - // code branch; enforce type to directory - Mode: fileMode((in.Mode &^ syscall.S_IFMT) | syscall.S_IFDIR), - } - if c.proto.GE(Protocol{7, 12}) { - r.Umask = fileMode(in.Umask) & os.ModePerm - } - req = r - - case opUnlink, opRmdir: - buf := m.bytes() - n := len(buf) - if n == 0 || buf[n-1] != '\x00' { - goto corrupt - } - req = &RemoveRequest{ - Header: m.Header(), - Name: string(buf[:n-1]), - Dir: m.hdr.Opcode == opRmdir, - } - - case opRename: - in := (*renameIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - newDirNodeID := NodeID(in.Newdir) - oldNew := m.bytes()[unsafe.Sizeof(*in):] - // oldNew should be "old\x00new\x00" - if len(oldNew) < 4 { - goto corrupt - } - if oldNew[len(oldNew)-1] != '\x00' { - goto corrupt - } - i := bytes.IndexByte(oldNew, '\x00') - if i < 0 { - goto corrupt - } - oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1]) - req = &RenameRequest{ - Header: m.Header(), - NewDir: newDirNodeID, - OldName: oldName, - NewName: newName, - } - - case opOpendir, opOpen: - in := (*openIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &OpenRequest{ - Header: m.Header(), - Dir: m.hdr.Opcode == opOpendir, - Flags: openFlags(in.Flags), - } - - case opRead, opReaddir: - in := (*readIn)(m.data()) - if m.len() < readInSize(c.proto) { - goto corrupt - } - r := &ReadRequest{ - Header: m.Header(), - Dir: m.hdr.Opcode == opReaddir, - Handle: HandleID(in.Fh), - Offset: int64(in.Offset), - Size: int(in.Size), - } - if c.proto.GE(Protocol{7, 9}) { - r.Flags = ReadFlags(in.ReadFlags) - r.LockOwner = in.LockOwner - r.FileFlags = openFlags(in.Flags) - } - req = r - - case opWrite: - in := (*writeIn)(m.data()) - if m.len() < writeInSize(c.proto) { - goto corrupt - } - r := &WriteRequest{ - Header: m.Header(), - Handle: HandleID(in.Fh), - Offset: int64(in.Offset), - Flags: WriteFlags(in.WriteFlags), - } - if c.proto.GE(Protocol{7, 9}) { - r.LockOwner = in.LockOwner - r.FileFlags = openFlags(in.Flags) - } - buf := m.bytes()[writeInSize(c.proto):] - if uint32(len(buf)) < in.Size { - goto corrupt - } - r.Data = buf - req = r - - case opStatfs: - req = &StatfsRequest{ - Header: m.Header(), - } - - case opRelease, opReleasedir: - in := (*releaseIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &ReleaseRequest{ - Header: m.Header(), - Dir: m.hdr.Opcode == opReleasedir, - Handle: HandleID(in.Fh), - Flags: openFlags(in.Flags), - ReleaseFlags: ReleaseFlags(in.ReleaseFlags), - LockOwner: in.LockOwner, - } - - case opFsync, opFsyncdir: - in := (*fsyncIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &FsyncRequest{ - Dir: m.hdr.Opcode == opFsyncdir, - Header: m.Header(), - Handle: HandleID(in.Fh), - Flags: in.FsyncFlags, - } - - case opSetxattr: - in := (*setxattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - m.off += int(unsafe.Sizeof(*in)) - name := m.bytes() - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - xattr := name[i+1:] - if uint32(len(xattr)) < in.Size { - goto corrupt - } - xattr = xattr[:in.Size] - req = &SetxattrRequest{ - Header: m.Header(), - Flags: in.Flags, - Position: in.position(), - Name: string(name[:i]), - Xattr: xattr, - } - - case opGetxattr: - in := (*getxattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - name := m.bytes()[unsafe.Sizeof(*in):] - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - req = &GetxattrRequest{ - Header: m.Header(), - Name: string(name[:i]), - Size: in.Size, - Position: in.position(), - } - - case opListxattr: - in := (*getxattrIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &ListxattrRequest{ - Header: m.Header(), - Size: in.Size, - Position: in.position(), - } - - case opRemovexattr: - buf := m.bytes() - n := len(buf) - if n == 0 || buf[n-1] != '\x00' { - goto corrupt - } - req = &RemovexattrRequest{ - Header: m.Header(), - Name: string(buf[:n-1]), - } - - case opFlush: - in := (*flushIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &FlushRequest{ - Header: m.Header(), - Handle: HandleID(in.Fh), - Flags: in.FlushFlags, - LockOwner: in.LockOwner, - } - - case opInit: - in := (*initIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &InitRequest{ - Header: m.Header(), - Kernel: Protocol{in.Major, in.Minor}, - MaxReadahead: in.MaxReadahead, - Flags: InitFlags(in.Flags), - } - - case opGetlk: - panic("opGetlk") - case opSetlk: - panic("opSetlk") - case opSetlkw: - panic("opSetlkw") - - case opAccess: - in := (*accessIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &AccessRequest{ - Header: m.Header(), - Mask: in.Mask, - } - - case opCreate: - size := createInSize(c.proto) - if m.len() < size { - goto corrupt - } - in := (*createIn)(m.data()) - name := m.bytes()[size:] - i := bytes.IndexByte(name, '\x00') - if i < 0 { - goto corrupt - } - r := &CreateRequest{ - Header: m.Header(), - Flags: openFlags(in.Flags), - Mode: fileMode(in.Mode), - Name: string(name[:i]), - } - if c.proto.GE(Protocol{7, 12}) { - r.Umask = fileMode(in.Umask) & os.ModePerm - } - req = r - - case opInterrupt: - in := (*interruptIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - req = &InterruptRequest{ - Header: m.Header(), - IntrID: RequestID(in.Unique), - } - - case opBmap: - panic("opBmap") - - case opDestroy: - req = &DestroyRequest{ - Header: m.Header(), - } - - // OS X - case opSetvolname: - panic("opSetvolname") - case opGetxtimes: - panic("opGetxtimes") - case opExchange: - in := (*exchangeIn)(m.data()) - if m.len() < unsafe.Sizeof(*in) { - goto corrupt - } - oldDirNodeID := NodeID(in.Olddir) - newDirNodeID := NodeID(in.Newdir) - oldNew := m.bytes()[unsafe.Sizeof(*in):] - // oldNew should be "oldname\x00newname\x00" - if len(oldNew) < 4 { - goto corrupt - } - if oldNew[len(oldNew)-1] != '\x00' { - goto corrupt - } - i := bytes.IndexByte(oldNew, '\x00') - if i < 0 { - goto corrupt - } - oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1]) - req = &ExchangeDataRequest{ - Header: m.Header(), - OldDir: oldDirNodeID, - NewDir: newDirNodeID, - OldName: oldName, - NewName: newName, - // TODO options - } - } - - return req, nil - -corrupt: - Debug(malformedMessage{}) - putMessage(m) - return nil, fmt.Errorf("fuse: malformed message") - -unrecognized: - // Unrecognized message. - // Assume higher-level code will send a "no idea what you mean" error. - h := m.Header() - return &h, nil -} - -type bugShortKernelWrite struct { - Written int64 - Length int64 - Error string - Stack string -} - -func (b bugShortKernelWrite) String() string { - return fmt.Sprintf("short kernel write: written=%d/%d error=%q stack=\n%s", b.Written, b.Length, b.Error, b.Stack) -} - -type bugKernelWriteError struct { - Error string - Stack string -} - -func (b bugKernelWriteError) String() string { - return fmt.Sprintf("kernel write error: error=%q stack=\n%s", b.Error, b.Stack) -} - -// safe to call even with nil error -func errorString(err error) string { - if err == nil { - return "" - } - return err.Error() -} - -func (c *Conn) writeToKernel(msg []byte) error { - out := (*outHeader)(unsafe.Pointer(&msg[0])) - out.Len = uint32(len(msg)) - - c.wio.RLock() - defer c.wio.RUnlock() - nn, err := syscall.Write(c.fd(), msg) - if err == nil && nn != len(msg) { - Debug(bugShortKernelWrite{ - Written: int64(nn), - Length: int64(len(msg)), - Error: errorString(err), - Stack: stack(), - }) - } - return err -} - -func (c *Conn) respond(msg []byte) { - if err := c.writeToKernel(msg); err != nil { - Debug(bugKernelWriteError{ - Error: errorString(err), - Stack: stack(), - }) - } -} - -type notCachedError struct{} - -func (notCachedError) Error() string { - return "node not cached" -} - -var _ ErrorNumber = notCachedError{} - -func (notCachedError) Errno() Errno { - // Behave just like if the original syscall.ENOENT had been passed - // straight through. - return ENOENT -} - -var ( - ErrNotCached = notCachedError{} -) - -// sendInvalidate sends an invalidate notification to kernel. -// -// A returned ENOENT is translated to a friendlier error. -func (c *Conn) sendInvalidate(msg []byte) error { - switch err := c.writeToKernel(msg); err { - case syscall.ENOENT: - return ErrNotCached - default: - return err - } -} - -// InvalidateNode invalidates the kernel cache of the attributes and a -// range of the data of a node. -// -// Giving offset 0 and size -1 means all data. To invalidate just the -// attributes, give offset 0 and size 0. -// -// Returns ErrNotCached if the kernel is not currently caching the -// node. -func (c *Conn) InvalidateNode(nodeID NodeID, off int64, size int64) error { - buf := newBuffer(unsafe.Sizeof(notifyInvalInodeOut{})) - h := (*outHeader)(unsafe.Pointer(&buf[0])) - // h.Unique is 0 - h.Error = notifyCodeInvalInode - out := (*notifyInvalInodeOut)(buf.alloc(unsafe.Sizeof(notifyInvalInodeOut{}))) - out.Ino = uint64(nodeID) - out.Off = off - out.Len = size - return c.sendInvalidate(buf) -} - -// InvalidateEntry invalidates the kernel cache of the directory entry -// identified by parent directory node ID and entry basename. -// -// Kernel may or may not cache directory listings. To invalidate -// those, use InvalidateNode to invalidate all of the data for a -// directory. (As of 2015-06, Linux FUSE does not cache directory -// listings.) -// -// Returns ErrNotCached if the kernel is not currently caching the -// node. -func (c *Conn) InvalidateEntry(parent NodeID, name string) error { - const maxUint32 = ^uint32(0) - if uint64(len(name)) > uint64(maxUint32) { - // very unlikely, but we don't want to silently truncate - return syscall.ENAMETOOLONG - } - buf := newBuffer(unsafe.Sizeof(notifyInvalEntryOut{}) + uintptr(len(name)) + 1) - h := (*outHeader)(unsafe.Pointer(&buf[0])) - // h.Unique is 0 - h.Error = notifyCodeInvalEntry - out := (*notifyInvalEntryOut)(buf.alloc(unsafe.Sizeof(notifyInvalEntryOut{}))) - out.Parent = uint64(parent) - out.Namelen = uint32(len(name)) - buf = append(buf, name...) - buf = append(buf, '\x00') - return c.sendInvalidate(buf) -} - -// An InitRequest is the first request sent on a FUSE file system. -type InitRequest struct { - Header `json:"-"` - Kernel Protocol - // Maximum readahead in bytes that the kernel plans to use. - MaxReadahead uint32 - Flags InitFlags -} - -var _ = Request(&InitRequest{}) - -func (r *InitRequest) String() string { - return fmt.Sprintf("Init [%v] %v ra=%d fl=%v", &r.Header, r.Kernel, r.MaxReadahead, r.Flags) -} - -// An InitResponse is the response to an InitRequest. -type InitResponse struct { - Library Protocol - // Maximum readahead in bytes that the kernel can use. Ignored if - // greater than InitRequest.MaxReadahead. - MaxReadahead uint32 - Flags InitFlags - // Maximum size of a single write operation. - // Linux enforces a minimum of 4 KiB. - MaxWrite uint32 -} - -func (r *InitResponse) String() string { - return fmt.Sprintf("Init %v ra=%d fl=%v w=%d", r.Library, r.MaxReadahead, r.Flags, r.MaxWrite) -} - -// Respond replies to the request with the given response. -func (r *InitRequest) Respond(resp *InitResponse) { - buf := newBuffer(unsafe.Sizeof(initOut{})) - out := (*initOut)(buf.alloc(unsafe.Sizeof(initOut{}))) - out.Major = resp.Library.Major - out.Minor = resp.Library.Minor - out.MaxReadahead = resp.MaxReadahead - out.Flags = uint32(resp.Flags) - out.MaxWrite = resp.MaxWrite - - // MaxWrite larger than our receive buffer would just lead to - // errors on large writes. - if out.MaxWrite > maxWrite { - out.MaxWrite = maxWrite - } - r.respond(buf) -} - -// A StatfsRequest requests information about the mounted file system. -type StatfsRequest struct { - Header `json:"-"` -} - -var _ = Request(&StatfsRequest{}) - -func (r *StatfsRequest) String() string { - return fmt.Sprintf("Statfs [%s]", &r.Header) -} - -// Respond replies to the request with the given response. -func (r *StatfsRequest) Respond(resp *StatfsResponse) { - buf := newBuffer(unsafe.Sizeof(statfsOut{})) - out := (*statfsOut)(buf.alloc(unsafe.Sizeof(statfsOut{}))) - out.St = kstatfs{ - Blocks: resp.Blocks, - Bfree: resp.Bfree, - Bavail: resp.Bavail, - Files: resp.Files, - Bsize: resp.Bsize, - Namelen: resp.Namelen, - Frsize: resp.Frsize, - } - r.respond(buf) -} - -// A StatfsResponse is the response to a StatfsRequest. -type StatfsResponse struct { - Blocks uint64 // Total data blocks in file system. - Bfree uint64 // Free blocks in file system. - Bavail uint64 // Free blocks in file system if you're not root. - Files uint64 // Total files in file system. - Ffree uint64 // Free files in file system. - Bsize uint32 // Block size - Namelen uint32 // Maximum file name length? - Frsize uint32 // Fragment size, smallest addressable data size in the file system. -} - -func (r *StatfsResponse) String() string { - return fmt.Sprintf("Statfs blocks=%d/%d/%d files=%d/%d bsize=%d frsize=%d namelen=%d", - r.Bavail, r.Bfree, r.Blocks, - r.Ffree, r.Files, - r.Bsize, - r.Frsize, - r.Namelen, - ) -} - -// An AccessRequest asks whether the file can be accessed -// for the purpose specified by the mask. -type AccessRequest struct { - Header `json:"-"` - Mask uint32 -} - -var _ = Request(&AccessRequest{}) - -func (r *AccessRequest) String() string { - return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask) -} - -// Respond replies to the request indicating that access is allowed. -// To deny access, use RespondError. -func (r *AccessRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// An Attr is the metadata for a single file or directory. -type Attr struct { - Valid time.Duration // how long Attr can be cached - - Inode uint64 // inode number - Size uint64 // size in bytes - Blocks uint64 // size in 512-byte units - Atime time.Time // time of last access - Mtime time.Time // time of last modification - Ctime time.Time // time of last inode change - Crtime time.Time // time of creation (OS X only) - Mode os.FileMode // file mode - Nlink uint32 // number of links (usually 1) - Uid uint32 // owner uid - Gid uint32 // group gid - Rdev uint32 // device numbers - Flags uint32 // chflags(2) flags (OS X only) - BlockSize uint32 // preferred blocksize for filesystem I/O -} - -func (a Attr) String() string { - return fmt.Sprintf("valid=%v ino=%v size=%d mode=%v", a.Valid, a.Inode, a.Size, a.Mode) -} - -func unix(t time.Time) (sec uint64, nsec uint32) { - nano := t.UnixNano() - sec = uint64(nano / 1e9) - nsec = uint32(nano % 1e9) - return -} - -func (a *Attr) attr(out *attr, proto Protocol) { - out.Ino = a.Inode - out.Size = a.Size - out.Blocks = a.Blocks - out.Atime, out.AtimeNsec = unix(a.Atime) - out.Mtime, out.MtimeNsec = unix(a.Mtime) - out.Ctime, out.CtimeNsec = unix(a.Ctime) - out.SetCrtime(unix(a.Crtime)) - out.Mode = uint32(a.Mode) & 0777 - switch { - default: - out.Mode |= syscall.S_IFREG - case a.Mode&os.ModeDir != 0: - out.Mode |= syscall.S_IFDIR - case a.Mode&os.ModeDevice != 0: - if a.Mode&os.ModeCharDevice != 0 { - out.Mode |= syscall.S_IFCHR - } else { - out.Mode |= syscall.S_IFBLK - } - case a.Mode&os.ModeNamedPipe != 0: - out.Mode |= syscall.S_IFIFO - case a.Mode&os.ModeSymlink != 0: - out.Mode |= syscall.S_IFLNK - case a.Mode&os.ModeSocket != 0: - out.Mode |= syscall.S_IFSOCK - } - if a.Mode&os.ModeSetuid != 0 { - out.Mode |= syscall.S_ISUID - } - if a.Mode&os.ModeSetgid != 0 { - out.Mode |= syscall.S_ISGID - } - out.Nlink = a.Nlink - out.Uid = a.Uid - out.Gid = a.Gid - out.Rdev = a.Rdev - out.SetFlags(a.Flags) - if proto.GE(Protocol{7, 9}) { - out.Blksize = a.BlockSize - } - - return -} - -// A GetattrRequest asks for the metadata for the file denoted by r.Node. -type GetattrRequest struct { - Header `json:"-"` - Flags GetattrFlags - Handle HandleID -} - -var _ = Request(&GetattrRequest{}) - -func (r *GetattrRequest) String() string { - return fmt.Sprintf("Getattr [%s] %v fl=%v", &r.Header, r.Handle, r.Flags) -} - -// Respond replies to the request with the given response. -func (r *GetattrRequest) Respond(resp *GetattrResponse) { - size := attrOutSize(r.Header.Conn.proto) - buf := newBuffer(size) - out := (*attrOut)(buf.alloc(size)) - out.AttrValid = uint64(resp.Attr.Valid / time.Second) - out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&out.Attr, r.Header.Conn.proto) - r.respond(buf) -} - -// A GetattrResponse is the response to a GetattrRequest. -type GetattrResponse struct { - Attr Attr // file attributes -} - -func (r *GetattrResponse) String() string { - return fmt.Sprintf("Getattr %v", r.Attr) -} - -// A GetxattrRequest asks for the extended attributes associated with r.Node. -type GetxattrRequest struct { - Header `json:"-"` - - // Maximum size to return. - Size uint32 - - // Name of the attribute requested. - Name string - - // Offset within extended attributes. - // - // Only valid for OS X, and then only with the resource fork - // attribute. - Position uint32 -} - -var _ = Request(&GetxattrRequest{}) - -func (r *GetxattrRequest) String() string { - return fmt.Sprintf("Getxattr [%s] %q %d @%d", &r.Header, r.Name, r.Size, r.Position) -} - -// Respond replies to the request with the given response. -func (r *GetxattrRequest) Respond(resp *GetxattrResponse) { - if r.Size == 0 { - buf := newBuffer(unsafe.Sizeof(getxattrOut{})) - out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{}))) - out.Size = uint32(len(resp.Xattr)) - r.respond(buf) - } else { - buf := newBuffer(uintptr(len(resp.Xattr))) - buf = append(buf, resp.Xattr...) - r.respond(buf) - } -} - -// A GetxattrResponse is the response to a GetxattrRequest. -type GetxattrResponse struct { - Xattr []byte -} - -func (r *GetxattrResponse) String() string { - return fmt.Sprintf("Getxattr %x", r.Xattr) -} - -// A ListxattrRequest asks to list the extended attributes associated with r.Node. -type ListxattrRequest struct { - Header `json:"-"` - Size uint32 // maximum size to return - Position uint32 // offset within attribute list -} - -var _ = Request(&ListxattrRequest{}) - -func (r *ListxattrRequest) String() string { - return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position) -} - -// Respond replies to the request with the given response. -func (r *ListxattrRequest) Respond(resp *ListxattrResponse) { - if r.Size == 0 { - buf := newBuffer(unsafe.Sizeof(getxattrOut{})) - out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{}))) - out.Size = uint32(len(resp.Xattr)) - r.respond(buf) - } else { - buf := newBuffer(uintptr(len(resp.Xattr))) - buf = append(buf, resp.Xattr...) - r.respond(buf) - } -} - -// A ListxattrResponse is the response to a ListxattrRequest. -type ListxattrResponse struct { - Xattr []byte -} - -func (r *ListxattrResponse) String() string { - return fmt.Sprintf("Listxattr %x", r.Xattr) -} - -// Append adds an extended attribute name to the response. -func (r *ListxattrResponse) Append(names ...string) { - for _, name := range names { - r.Xattr = append(r.Xattr, name...) - r.Xattr = append(r.Xattr, '\x00') - } -} - -// A RemovexattrRequest asks to remove an extended attribute associated with r.Node. -type RemovexattrRequest struct { - Header `json:"-"` - Name string // name of extended attribute -} - -var _ = Request(&RemovexattrRequest{}) - -func (r *RemovexattrRequest) String() string { - return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name) -} - -// Respond replies to the request, indicating that the attribute was removed. -func (r *RemovexattrRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// A SetxattrRequest asks to set an extended attribute associated with a file. -type SetxattrRequest struct { - Header `json:"-"` - - // Flags can make the request fail if attribute does/not already - // exist. Unfortunately, the constants are platform-specific and - // not exposed by Go1.2. Look for XATTR_CREATE, XATTR_REPLACE. - // - // TODO improve this later - // - // TODO XATTR_CREATE and exist -> EEXIST - // - // TODO XATTR_REPLACE and not exist -> ENODATA - Flags uint32 - - // Offset within extended attributes. - // - // Only valid for OS X, and then only with the resource fork - // attribute. - Position uint32 - - Name string - Xattr []byte -} - -var _ = Request(&SetxattrRequest{}) - -func trunc(b []byte, max int) ([]byte, string) { - if len(b) > max { - return b[:max], "..." - } - return b, "" -} - -func (r *SetxattrRequest) String() string { - xattr, tail := trunc(r.Xattr, 16) - return fmt.Sprintf("Setxattr [%s] %q %x%s fl=%v @%#x", &r.Header, r.Name, xattr, tail, r.Flags, r.Position) -} - -// Respond replies to the request, indicating that the extended attribute was set. -func (r *SetxattrRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// A LookupRequest asks to look up the given name in the directory named by r.Node. -type LookupRequest struct { - Header `json:"-"` - Name string -} - -var _ = Request(&LookupRequest{}) - -func (r *LookupRequest) String() string { - return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name) -} - -// Respond replies to the request with the given response. -func (r *LookupRequest) Respond(resp *LookupResponse) { - size := entryOutSize(r.Header.Conn.proto) - buf := newBuffer(size) - out := (*entryOut)(buf.alloc(size)) - out.Nodeid = uint64(resp.Node) - out.Generation = resp.Generation - out.EntryValid = uint64(resp.EntryValid / time.Second) - out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond) - out.AttrValid = uint64(resp.Attr.Valid / time.Second) - out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&out.Attr, r.Header.Conn.proto) - r.respond(buf) -} - -// A LookupResponse is the response to a LookupRequest. -type LookupResponse struct { - Node NodeID - Generation uint64 - EntryValid time.Duration - Attr Attr -} - -func (r *LookupResponse) string() string { - return fmt.Sprintf("%v gen=%d valid=%v attr={%v}", r.Node, r.Generation, r.EntryValid, r.Attr) -} - -func (r *LookupResponse) String() string { - return fmt.Sprintf("Lookup %s", r.string()) -} - -// An OpenRequest asks to open a file or directory -type OpenRequest struct { - Header `json:"-"` - Dir bool // is this Opendir? - Flags OpenFlags -} - -var _ = Request(&OpenRequest{}) - -func (r *OpenRequest) String() string { - return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags) -} - -// Respond replies to the request with the given response. -func (r *OpenRequest) Respond(resp *OpenResponse) { - buf := newBuffer(unsafe.Sizeof(openOut{})) - out := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{}))) - out.Fh = uint64(resp.Handle) - out.OpenFlags = uint32(resp.Flags) - r.respond(buf) -} - -// A OpenResponse is the response to a OpenRequest. -type OpenResponse struct { - Handle HandleID - Flags OpenResponseFlags -} - -func (r *OpenResponse) string() string { - return fmt.Sprintf("%v fl=%v", r.Handle, r.Flags) -} - -func (r *OpenResponse) String() string { - return fmt.Sprintf("Open %s", r.string()) -} - -// A CreateRequest asks to create and open a file (not a directory). -type CreateRequest struct { - Header `json:"-"` - Name string - Flags OpenFlags - Mode os.FileMode - // Umask of the request. Not supported on OS X. - Umask os.FileMode -} - -var _ = Request(&CreateRequest{}) - -func (r *CreateRequest) String() string { - return fmt.Sprintf("Create [%s] %q fl=%v mode=%v umask=%v", &r.Header, r.Name, r.Flags, r.Mode, r.Umask) -} - -// Respond replies to the request with the given response. -func (r *CreateRequest) Respond(resp *CreateResponse) { - eSize := entryOutSize(r.Header.Conn.proto) - buf := newBuffer(eSize + unsafe.Sizeof(openOut{})) - - e := (*entryOut)(buf.alloc(eSize)) - e.Nodeid = uint64(resp.Node) - e.Generation = resp.Generation - e.EntryValid = uint64(resp.EntryValid / time.Second) - e.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond) - e.AttrValid = uint64(resp.Attr.Valid / time.Second) - e.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&e.Attr, r.Header.Conn.proto) - - o := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{}))) - o.Fh = uint64(resp.Handle) - o.OpenFlags = uint32(resp.Flags) - - r.respond(buf) -} - -// A CreateResponse is the response to a CreateRequest. -// It describes the created node and opened handle. -type CreateResponse struct { - LookupResponse - OpenResponse -} - -func (r *CreateResponse) String() string { - return fmt.Sprintf("Create {%s} {%s}", r.LookupResponse.string(), r.OpenResponse.string()) -} - -// A MkdirRequest asks to create (but not open) a directory. -type MkdirRequest struct { - Header `json:"-"` - Name string - Mode os.FileMode - // Umask of the request. Not supported on OS X. - Umask os.FileMode -} - -var _ = Request(&MkdirRequest{}) - -func (r *MkdirRequest) String() string { - return fmt.Sprintf("Mkdir [%s] %q mode=%v umask=%v", &r.Header, r.Name, r.Mode, r.Umask) -} - -// Respond replies to the request with the given response. -func (r *MkdirRequest) Respond(resp *MkdirResponse) { - size := entryOutSize(r.Header.Conn.proto) - buf := newBuffer(size) - out := (*entryOut)(buf.alloc(size)) - out.Nodeid = uint64(resp.Node) - out.Generation = resp.Generation - out.EntryValid = uint64(resp.EntryValid / time.Second) - out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond) - out.AttrValid = uint64(resp.Attr.Valid / time.Second) - out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&out.Attr, r.Header.Conn.proto) - r.respond(buf) -} - -// A MkdirResponse is the response to a MkdirRequest. -type MkdirResponse struct { - LookupResponse -} - -func (r *MkdirResponse) String() string { - return fmt.Sprintf("Mkdir %v", r.LookupResponse.string()) -} - -// A ReadRequest asks to read from an open file. -type ReadRequest struct { - Header `json:"-"` - Dir bool // is this Readdir? - Handle HandleID - Offset int64 - Size int - Flags ReadFlags - LockOwner uint64 - FileFlags OpenFlags -} - -var _ = Request(&ReadRequest{}) - -func (r *ReadRequest) String() string { - return fmt.Sprintf("Read [%s] %v %d @%#x dir=%v fl=%v lock=%d ffl=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir, r.Flags, r.LockOwner, r.FileFlags) -} - -// Respond replies to the request with the given response. -func (r *ReadRequest) Respond(resp *ReadResponse) { - buf := newBuffer(uintptr(len(resp.Data))) - buf = append(buf, resp.Data...) - r.respond(buf) -} - -// A ReadResponse is the response to a ReadRequest. -type ReadResponse struct { - Data []byte -} - -func (r *ReadResponse) String() string { - return fmt.Sprintf("Read %d", len(r.Data)) -} - -type jsonReadResponse struct { - Len uint64 -} - -func (r *ReadResponse) MarshalJSON() ([]byte, error) { - j := jsonReadResponse{ - Len: uint64(len(r.Data)), - } - return json.Marshal(j) -} - -// A ReleaseRequest asks to release (close) an open file handle. -type ReleaseRequest struct { - Header `json:"-"` - Dir bool // is this Releasedir? - Handle HandleID - Flags OpenFlags // flags from OpenRequest - ReleaseFlags ReleaseFlags - LockOwner uint32 -} - -var _ = Request(&ReleaseRequest{}) - -func (r *ReleaseRequest) String() string { - return fmt.Sprintf("Release [%s] %v fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner) -} - -// Respond replies to the request, indicating that the handle has been released. -func (r *ReleaseRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// A DestroyRequest is sent by the kernel when unmounting the file system. -// No more requests will be received after this one, but it should still be -// responded to. -type DestroyRequest struct { - Header `json:"-"` -} - -var _ = Request(&DestroyRequest{}) - -func (r *DestroyRequest) String() string { - return fmt.Sprintf("Destroy [%s]", &r.Header) -} - -// Respond replies to the request. -func (r *DestroyRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// A ForgetRequest is sent by the kernel when forgetting about r.Node -// as returned by r.N lookup requests. -type ForgetRequest struct { - Header `json:"-"` - N uint64 -} - -var _ = Request(&ForgetRequest{}) - -func (r *ForgetRequest) String() string { - return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N) -} - -// Respond replies to the request, indicating that the forgetfulness has been recorded. -func (r *ForgetRequest) Respond() { - // Don't reply to forget messages. - r.noResponse() -} - -// A Dirent represents a single directory entry. -type Dirent struct { - // Inode this entry names. - Inode uint64 - - // Type of the entry, for example DT_File. - // - // Setting this is optional. The zero value (DT_Unknown) means - // callers will just need to do a Getattr when the type is - // needed. Providing a type can speed up operations - // significantly. - Type DirentType - - // Name of the entry - Name string -} - -// Type of an entry in a directory listing. -type DirentType uint32 - -const ( - // These don't quite match os.FileMode; especially there's an - // explicit unknown, instead of zero value meaning file. They - // are also not quite syscall.DT_*; nothing says the FUSE - // protocol follows those, and even if they were, we don't - // want each fs to fiddle with syscall. - - // The shift by 12 is hardcoded in the FUSE userspace - // low-level C library, so it's safe here. - - DT_Unknown DirentType = 0 - DT_Socket DirentType = syscall.S_IFSOCK >> 12 - DT_Link DirentType = syscall.S_IFLNK >> 12 - DT_File DirentType = syscall.S_IFREG >> 12 - DT_Block DirentType = syscall.S_IFBLK >> 12 - DT_Dir DirentType = syscall.S_IFDIR >> 12 - DT_Char DirentType = syscall.S_IFCHR >> 12 - DT_FIFO DirentType = syscall.S_IFIFO >> 12 -) - -func (t DirentType) String() string { - switch t { - case DT_Unknown: - return "unknown" - case DT_Socket: - return "socket" - case DT_Link: - return "link" - case DT_File: - return "file" - case DT_Block: - return "block" - case DT_Dir: - return "dir" - case DT_Char: - return "char" - case DT_FIFO: - return "fifo" - } - return "invalid" -} - -// AppendDirent appends the encoded form of a directory entry to data -// and returns the resulting slice. -func AppendDirent(data []byte, dir Dirent) []byte { - de := dirent{ - Ino: dir.Inode, - Namelen: uint32(len(dir.Name)), - Type: uint32(dir.Type), - } - de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7) - data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...) - data = append(data, dir.Name...) - n := direntSize + uintptr(len(dir.Name)) - if n%8 != 0 { - var pad [8]byte - data = append(data, pad[:8-n%8]...) - } - return data -} - -// A WriteRequest asks to write to an open file. -type WriteRequest struct { - Header - Handle HandleID - Offset int64 - Data []byte - Flags WriteFlags - LockOwner uint64 - FileFlags OpenFlags -} - -var _ = Request(&WriteRequest{}) - -func (r *WriteRequest) String() string { - return fmt.Sprintf("Write [%s] %v %d @%d fl=%v lock=%d ffl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags, r.LockOwner, r.FileFlags) -} - -type jsonWriteRequest struct { - Handle HandleID - Offset int64 - Len uint64 - Flags WriteFlags -} - -func (r *WriteRequest) MarshalJSON() ([]byte, error) { - j := jsonWriteRequest{ - Handle: r.Handle, - Offset: r.Offset, - Len: uint64(len(r.Data)), - Flags: r.Flags, - } - return json.Marshal(j) -} - -// Respond replies to the request with the given response. -func (r *WriteRequest) Respond(resp *WriteResponse) { - buf := newBuffer(unsafe.Sizeof(writeOut{})) - out := (*writeOut)(buf.alloc(unsafe.Sizeof(writeOut{}))) - out.Size = uint32(resp.Size) - r.respond(buf) -} - -// A WriteResponse replies to a write indicating how many bytes were written. -type WriteResponse struct { - Size int -} - -func (r *WriteResponse) String() string { - return fmt.Sprintf("Write %d", r.Size) -} - -// A SetattrRequest asks to change one or more attributes associated with a file, -// as indicated by Valid. -type SetattrRequest struct { - Header `json:"-"` - Valid SetattrValid - Handle HandleID - Size uint64 - Atime time.Time - Mtime time.Time - Mode os.FileMode - Uid uint32 - Gid uint32 - - // OS X only - Bkuptime time.Time - Chgtime time.Time - Crtime time.Time - Flags uint32 // see chflags(2) -} - -var _ = Request(&SetattrRequest{}) - -func (r *SetattrRequest) String() string { - var buf bytes.Buffer - fmt.Fprintf(&buf, "Setattr [%s]", &r.Header) - if r.Valid.Mode() { - fmt.Fprintf(&buf, " mode=%v", r.Mode) - } - if r.Valid.Uid() { - fmt.Fprintf(&buf, " uid=%d", r.Uid) - } - if r.Valid.Gid() { - fmt.Fprintf(&buf, " gid=%d", r.Gid) - } - if r.Valid.Size() { - fmt.Fprintf(&buf, " size=%d", r.Size) - } - if r.Valid.Atime() { - fmt.Fprintf(&buf, " atime=%v", r.Atime) - } - if r.Valid.AtimeNow() { - fmt.Fprintf(&buf, " atime=now") - } - if r.Valid.Mtime() { - fmt.Fprintf(&buf, " mtime=%v", r.Mtime) - } - if r.Valid.MtimeNow() { - fmt.Fprintf(&buf, " mtime=now") - } - if r.Valid.Handle() { - fmt.Fprintf(&buf, " handle=%v", r.Handle) - } else { - fmt.Fprintf(&buf, " handle=INVALID-%v", r.Handle) - } - if r.Valid.LockOwner() { - fmt.Fprintf(&buf, " lockowner") - } - if r.Valid.Crtime() { - fmt.Fprintf(&buf, " crtime=%v", r.Crtime) - } - if r.Valid.Chgtime() { - fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime) - } - if r.Valid.Bkuptime() { - fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime) - } - if r.Valid.Flags() { - fmt.Fprintf(&buf, " flags=%v", r.Flags) - } - return buf.String() -} - -// Respond replies to the request with the given response, -// giving the updated attributes. -func (r *SetattrRequest) Respond(resp *SetattrResponse) { - size := attrOutSize(r.Header.Conn.proto) - buf := newBuffer(size) - out := (*attrOut)(buf.alloc(size)) - out.AttrValid = uint64(resp.Attr.Valid / time.Second) - out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&out.Attr, r.Header.Conn.proto) - r.respond(buf) -} - -// A SetattrResponse is the response to a SetattrRequest. -type SetattrResponse struct { - Attr Attr // file attributes -} - -func (r *SetattrResponse) String() string { - return fmt.Sprintf("Setattr %v", r.Attr) -} - -// A FlushRequest asks for the current state of an open file to be flushed -// to storage, as when a file descriptor is being closed. A single opened Handle -// may receive multiple FlushRequests over its lifetime. -type FlushRequest struct { - Header `json:"-"` - Handle HandleID - Flags uint32 - LockOwner uint64 -} - -var _ = Request(&FlushRequest{}) - -func (r *FlushRequest) String() string { - return fmt.Sprintf("Flush [%s] %v fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner) -} - -// Respond replies to the request, indicating that the flush succeeded. -func (r *FlushRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// A RemoveRequest asks to remove a file or directory from the -// directory r.Node. -type RemoveRequest struct { - Header `json:"-"` - Name string // name of the entry to remove - Dir bool // is this rmdir? -} - -var _ = Request(&RemoveRequest{}) - -func (r *RemoveRequest) String() string { - return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir) -} - -// Respond replies to the request, indicating that the file was removed. -func (r *RemoveRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// A SymlinkRequest is a request to create a symlink making NewName point to Target. -type SymlinkRequest struct { - Header `json:"-"` - NewName, Target string -} - -var _ = Request(&SymlinkRequest{}) - -func (r *SymlinkRequest) String() string { - return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target) -} - -// Respond replies to the request, indicating that the symlink was created. -func (r *SymlinkRequest) Respond(resp *SymlinkResponse) { - size := entryOutSize(r.Header.Conn.proto) - buf := newBuffer(size) - out := (*entryOut)(buf.alloc(size)) - out.Nodeid = uint64(resp.Node) - out.Generation = resp.Generation - out.EntryValid = uint64(resp.EntryValid / time.Second) - out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond) - out.AttrValid = uint64(resp.Attr.Valid / time.Second) - out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&out.Attr, r.Header.Conn.proto) - r.respond(buf) -} - -// A SymlinkResponse is the response to a SymlinkRequest. -type SymlinkResponse struct { - LookupResponse -} - -func (r *SymlinkResponse) String() string { - return fmt.Sprintf("Symlink %v", r.LookupResponse.string()) -} - -// A ReadlinkRequest is a request to read a symlink's target. -type ReadlinkRequest struct { - Header `json:"-"` -} - -var _ = Request(&ReadlinkRequest{}) - -func (r *ReadlinkRequest) String() string { - return fmt.Sprintf("Readlink [%s]", &r.Header) -} - -func (r *ReadlinkRequest) Respond(target string) { - buf := newBuffer(uintptr(len(target))) - buf = append(buf, target...) - r.respond(buf) -} - -// A LinkRequest is a request to create a hard link. -type LinkRequest struct { - Header `json:"-"` - OldNode NodeID - NewName string -} - -var _ = Request(&LinkRequest{}) - -func (r *LinkRequest) String() string { - return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName) -} - -func (r *LinkRequest) Respond(resp *LookupResponse) { - size := entryOutSize(r.Header.Conn.proto) - buf := newBuffer(size) - out := (*entryOut)(buf.alloc(size)) - out.Nodeid = uint64(resp.Node) - out.Generation = resp.Generation - out.EntryValid = uint64(resp.EntryValid / time.Second) - out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond) - out.AttrValid = uint64(resp.Attr.Valid / time.Second) - out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&out.Attr, r.Header.Conn.proto) - r.respond(buf) -} - -// A RenameRequest is a request to rename a file. -type RenameRequest struct { - Header `json:"-"` - NewDir NodeID - OldName, NewName string -} - -var _ = Request(&RenameRequest{}) - -func (r *RenameRequest) String() string { - return fmt.Sprintf("Rename [%s] from %q to dirnode %v %q", &r.Header, r.OldName, r.NewDir, r.NewName) -} - -func (r *RenameRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -type MknodRequest struct { - Header `json:"-"` - Name string - Mode os.FileMode - Rdev uint32 - // Umask of the request. Not supported on OS X. - Umask os.FileMode -} - -var _ = Request(&MknodRequest{}) - -func (r *MknodRequest) String() string { - return fmt.Sprintf("Mknod [%s] Name %q mode=%v umask=%v rdev=%d", &r.Header, r.Name, r.Mode, r.Umask, r.Rdev) -} - -func (r *MknodRequest) Respond(resp *LookupResponse) { - size := entryOutSize(r.Header.Conn.proto) - buf := newBuffer(size) - out := (*entryOut)(buf.alloc(size)) - out.Nodeid = uint64(resp.Node) - out.Generation = resp.Generation - out.EntryValid = uint64(resp.EntryValid / time.Second) - out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond) - out.AttrValid = uint64(resp.Attr.Valid / time.Second) - out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond) - resp.Attr.attr(&out.Attr, r.Header.Conn.proto) - r.respond(buf) -} - -type FsyncRequest struct { - Header `json:"-"` - Handle HandleID - // TODO bit 1 is datasync, not well documented upstream - Flags uint32 - Dir bool -} - -var _ = Request(&FsyncRequest{}) - -func (r *FsyncRequest) String() string { - return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags) -} - -func (r *FsyncRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} - -// An InterruptRequest is a request to interrupt another pending request. The -// response to that request should return an error status of EINTR. -type InterruptRequest struct { - Header `json:"-"` - IntrID RequestID // ID of the request to be interrupt. -} - -var _ = Request(&InterruptRequest{}) - -func (r *InterruptRequest) Respond() { - // nothing to do here - r.noResponse() -} - -func (r *InterruptRequest) String() string { - return fmt.Sprintf("Interrupt [%s] ID %v", &r.Header, r.IntrID) -} - -// An ExchangeDataRequest is a request to exchange the contents of two -// files, while leaving most metadata untouched. -// -// This request comes from OS X exchangedata(2) and represents its -// specific semantics. Crucially, it is very different from Linux -// renameat(2) RENAME_EXCHANGE. -// -// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html -type ExchangeDataRequest struct { - Header `json:"-"` - OldDir, NewDir NodeID - OldName, NewName string - // TODO options -} - -var _ = Request(&ExchangeDataRequest{}) - -func (r *ExchangeDataRequest) String() string { - // TODO options - return fmt.Sprintf("ExchangeData [%s] %v %q and %v %q", &r.Header, r.OldDir, r.OldName, r.NewDir, r.NewName) -} - -func (r *ExchangeDataRequest) Respond() { - buf := newBuffer(0) - r.respond(buf) -} diff --git a/vendor/bazil.org/fuse/fuse.iml b/vendor/bazil.org/fuse/fuse.iml deleted file mode 100644 index 792ad4c30c..0000000000 --- a/vendor/bazil.org/fuse/fuse.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/vendor/bazil.org/fuse/fuse_darwin.go b/vendor/bazil.org/fuse/fuse_darwin.go deleted file mode 100644 index b58dca97d6..0000000000 --- a/vendor/bazil.org/fuse/fuse_darwin.go +++ /dev/null @@ -1,9 +0,0 @@ -package fuse - -// Maximum file write size we are prepared to receive from the kernel. -// -// This value has to be >=16MB or OSXFUSE (3.4.0 observed) will -// forcibly close the /dev/fuse file descriptor on a Setxattr with a -// 16MB value. See TestSetxattr16MB and -// https://github.com/bazil/fuse/issues/42 -const maxWrite = 16 * 1024 * 1024 diff --git a/vendor/bazil.org/fuse/fuse_freebsd.go b/vendor/bazil.org/fuse/fuse_freebsd.go deleted file mode 100644 index 4aa83a0d41..0000000000 --- a/vendor/bazil.org/fuse/fuse_freebsd.go +++ /dev/null @@ -1,6 +0,0 @@ -package fuse - -// Maximum file write size we are prepared to receive from the kernel. -// -// This number is just a guess. -const maxWrite = 128 * 1024 diff --git a/vendor/bazil.org/fuse/fuse_kernel.go b/vendor/bazil.org/fuse/fuse_kernel.go deleted file mode 100644 index 87c5ca1dc6..0000000000 --- a/vendor/bazil.org/fuse/fuse_kernel.go +++ /dev/null @@ -1,774 +0,0 @@ -// See the file LICENSE for copyright and licensing information. - -// Derived from FUSE's fuse_kernel.h, which carries this notice: -/* - This file defines the kernel interface of FUSE - Copyright (C) 2001-2007 Miklos Szeredi - - - This -- and only this -- header file may also be distributed under - the terms of the BSD Licence as follows: - - Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. -*/ - -package fuse - -import ( - "fmt" - "syscall" - "unsafe" -) - -// The FUSE version implemented by the package. -const ( - protoVersionMinMajor = 7 - protoVersionMinMinor = 8 - protoVersionMaxMajor = 7 - protoVersionMaxMinor = 12 -) - -const ( - rootID = 1 -) - -type kstatfs struct { - Blocks uint64 - Bfree uint64 - Bavail uint64 - Files uint64 - Ffree uint64 - Bsize uint32 - Namelen uint32 - Frsize uint32 - _ uint32 - Spare [6]uint32 -} - -type fileLock struct { - Start uint64 - End uint64 - Type uint32 - Pid uint32 -} - -// GetattrFlags are bit flags that can be seen in GetattrRequest. -type GetattrFlags uint32 - -const ( - // Indicates the handle is valid. - GetattrFh GetattrFlags = 1 << 0 -) - -var getattrFlagsNames = []flagName{ - {uint32(GetattrFh), "GetattrFh"}, -} - -func (fl GetattrFlags) String() string { - return flagString(uint32(fl), getattrFlagsNames) -} - -// The SetattrValid are bit flags describing which fields in the SetattrRequest -// are included in the change. -type SetattrValid uint32 - -const ( - SetattrMode SetattrValid = 1 << 0 - SetattrUid SetattrValid = 1 << 1 - SetattrGid SetattrValid = 1 << 2 - SetattrSize SetattrValid = 1 << 3 - SetattrAtime SetattrValid = 1 << 4 - SetattrMtime SetattrValid = 1 << 5 - SetattrHandle SetattrValid = 1 << 6 - - // Linux only(?) - SetattrAtimeNow SetattrValid = 1 << 7 - SetattrMtimeNow SetattrValid = 1 << 8 - SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html - - // OS X only - SetattrCrtime SetattrValid = 1 << 28 - SetattrChgtime SetattrValid = 1 << 29 - SetattrBkuptime SetattrValid = 1 << 30 - SetattrFlags SetattrValid = 1 << 31 -) - -func (fl SetattrValid) Mode() bool { return fl&SetattrMode != 0 } -func (fl SetattrValid) Uid() bool { return fl&SetattrUid != 0 } -func (fl SetattrValid) Gid() bool { return fl&SetattrGid != 0 } -func (fl SetattrValid) Size() bool { return fl&SetattrSize != 0 } -func (fl SetattrValid) Atime() bool { return fl&SetattrAtime != 0 } -func (fl SetattrValid) Mtime() bool { return fl&SetattrMtime != 0 } -func (fl SetattrValid) Handle() bool { return fl&SetattrHandle != 0 } -func (fl SetattrValid) AtimeNow() bool { return fl&SetattrAtimeNow != 0 } -func (fl SetattrValid) MtimeNow() bool { return fl&SetattrMtimeNow != 0 } -func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 } -func (fl SetattrValid) Crtime() bool { return fl&SetattrCrtime != 0 } -func (fl SetattrValid) Chgtime() bool { return fl&SetattrChgtime != 0 } -func (fl SetattrValid) Bkuptime() bool { return fl&SetattrBkuptime != 0 } -func (fl SetattrValid) Flags() bool { return fl&SetattrFlags != 0 } - -func (fl SetattrValid) String() string { - return flagString(uint32(fl), setattrValidNames) -} - -var setattrValidNames = []flagName{ - {uint32(SetattrMode), "SetattrMode"}, - {uint32(SetattrUid), "SetattrUid"}, - {uint32(SetattrGid), "SetattrGid"}, - {uint32(SetattrSize), "SetattrSize"}, - {uint32(SetattrAtime), "SetattrAtime"}, - {uint32(SetattrMtime), "SetattrMtime"}, - {uint32(SetattrHandle), "SetattrHandle"}, - {uint32(SetattrAtimeNow), "SetattrAtimeNow"}, - {uint32(SetattrMtimeNow), "SetattrMtimeNow"}, - {uint32(SetattrLockOwner), "SetattrLockOwner"}, - {uint32(SetattrCrtime), "SetattrCrtime"}, - {uint32(SetattrChgtime), "SetattrChgtime"}, - {uint32(SetattrBkuptime), "SetattrBkuptime"}, - {uint32(SetattrFlags), "SetattrFlags"}, -} - -// Flags that can be seen in OpenRequest.Flags. -const ( - // Access modes. These are not 1-bit flags, but alternatives where - // only one can be chosen. See the IsReadOnly etc convenience - // methods. - OpenReadOnly OpenFlags = syscall.O_RDONLY - OpenWriteOnly OpenFlags = syscall.O_WRONLY - OpenReadWrite OpenFlags = syscall.O_RDWR - - // File was opened in append-only mode, all writes will go to end - // of file. OS X does not provide this information. - OpenAppend OpenFlags = syscall.O_APPEND - OpenCreate OpenFlags = syscall.O_CREAT - OpenDirectory OpenFlags = syscall.O_DIRECTORY - OpenExclusive OpenFlags = syscall.O_EXCL - OpenNonblock OpenFlags = syscall.O_NONBLOCK - OpenSync OpenFlags = syscall.O_SYNC - OpenTruncate OpenFlags = syscall.O_TRUNC -) - -// OpenAccessModeMask is a bitmask that separates the access mode -// from the other flags in OpenFlags. -const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE - -// OpenFlags are the O_FOO flags passed to open/create/etc calls. For -// example, os.O_WRONLY | os.O_APPEND. -type OpenFlags uint32 - -func (fl OpenFlags) String() string { - // O_RDONLY, O_RWONLY, O_RDWR are not flags - s := accModeName(fl & OpenAccessModeMask) - flags := uint32(fl &^ OpenAccessModeMask) - if flags != 0 { - s = s + "+" + flagString(flags, openFlagNames) - } - return s -} - -// Return true if OpenReadOnly is set. -func (fl OpenFlags) IsReadOnly() bool { - return fl&OpenAccessModeMask == OpenReadOnly -} - -// Return true if OpenWriteOnly is set. -func (fl OpenFlags) IsWriteOnly() bool { - return fl&OpenAccessModeMask == OpenWriteOnly -} - -// Return true if OpenReadWrite is set. -func (fl OpenFlags) IsReadWrite() bool { - return fl&OpenAccessModeMask == OpenReadWrite -} - -func accModeName(flags OpenFlags) string { - switch flags { - case OpenReadOnly: - return "OpenReadOnly" - case OpenWriteOnly: - return "OpenWriteOnly" - case OpenReadWrite: - return "OpenReadWrite" - default: - return "" - } -} - -var openFlagNames = []flagName{ - {uint32(OpenAppend), "OpenAppend"}, - {uint32(OpenCreate), "OpenCreate"}, - {uint32(OpenDirectory), "OpenDirectory"}, - {uint32(OpenExclusive), "OpenExclusive"}, - {uint32(OpenNonblock), "OpenNonblock"}, - {uint32(OpenSync), "OpenSync"}, - {uint32(OpenTruncate), "OpenTruncate"}, -} - -// The OpenResponseFlags are returned in the OpenResponse. -type OpenResponseFlags uint32 - -const ( - OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file - OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open - OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X) - - OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X - OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X -) - -func (fl OpenResponseFlags) String() string { - return flagString(uint32(fl), openResponseFlagNames) -} - -var openResponseFlagNames = []flagName{ - {uint32(OpenDirectIO), "OpenDirectIO"}, - {uint32(OpenKeepCache), "OpenKeepCache"}, - {uint32(OpenNonSeekable), "OpenNonSeekable"}, - {uint32(OpenPurgeAttr), "OpenPurgeAttr"}, - {uint32(OpenPurgeUBC), "OpenPurgeUBC"}, -} - -// The InitFlags are used in the Init exchange. -type InitFlags uint32 - -const ( - InitAsyncRead InitFlags = 1 << 0 - InitPosixLocks InitFlags = 1 << 1 - InitFileOps InitFlags = 1 << 2 - InitAtomicTrunc InitFlags = 1 << 3 - InitExportSupport InitFlags = 1 << 4 - InitBigWrites InitFlags = 1 << 5 - // Do not mask file access modes with umask. Not supported on OS X. - InitDontMask InitFlags = 1 << 6 - InitSpliceWrite InitFlags = 1 << 7 - InitSpliceMove InitFlags = 1 << 8 - InitSpliceRead InitFlags = 1 << 9 - InitFlockLocks InitFlags = 1 << 10 - InitHasIoctlDir InitFlags = 1 << 11 - InitAutoInvalData InitFlags = 1 << 12 - InitDoReaddirplus InitFlags = 1 << 13 - InitReaddirplusAuto InitFlags = 1 << 14 - InitAsyncDIO InitFlags = 1 << 15 - InitWritebackCache InitFlags = 1 << 16 - InitNoOpenSupport InitFlags = 1 << 17 - - InitCaseSensitive InitFlags = 1 << 29 // OS X only - InitVolRename InitFlags = 1 << 30 // OS X only - InitXtimes InitFlags = 1 << 31 // OS X only -) - -type flagName struct { - bit uint32 - name string -} - -var initFlagNames = []flagName{ - {uint32(InitAsyncRead), "InitAsyncRead"}, - {uint32(InitPosixLocks), "InitPosixLocks"}, - {uint32(InitFileOps), "InitFileOps"}, - {uint32(InitAtomicTrunc), "InitAtomicTrunc"}, - {uint32(InitExportSupport), "InitExportSupport"}, - {uint32(InitBigWrites), "InitBigWrites"}, - {uint32(InitDontMask), "InitDontMask"}, - {uint32(InitSpliceWrite), "InitSpliceWrite"}, - {uint32(InitSpliceMove), "InitSpliceMove"}, - {uint32(InitSpliceRead), "InitSpliceRead"}, - {uint32(InitFlockLocks), "InitFlockLocks"}, - {uint32(InitHasIoctlDir), "InitHasIoctlDir"}, - {uint32(InitAutoInvalData), "InitAutoInvalData"}, - {uint32(InitDoReaddirplus), "InitDoReaddirplus"}, - {uint32(InitReaddirplusAuto), "InitReaddirplusAuto"}, - {uint32(InitAsyncDIO), "InitAsyncDIO"}, - {uint32(InitWritebackCache), "InitWritebackCache"}, - {uint32(InitNoOpenSupport), "InitNoOpenSupport"}, - - {uint32(InitCaseSensitive), "InitCaseSensitive"}, - {uint32(InitVolRename), "InitVolRename"}, - {uint32(InitXtimes), "InitXtimes"}, -} - -func (fl InitFlags) String() string { - return flagString(uint32(fl), initFlagNames) -} - -func flagString(f uint32, names []flagName) string { - var s string - - if f == 0 { - return "0" - } - - for _, n := range names { - if f&n.bit != 0 { - s += "+" + n.name - f &^= n.bit - } - } - if f != 0 { - s += fmt.Sprintf("%+#x", f) - } - return s[1:] -} - -// The ReleaseFlags are used in the Release exchange. -type ReleaseFlags uint32 - -const ( - ReleaseFlush ReleaseFlags = 1 << 0 -) - -func (fl ReleaseFlags) String() string { - return flagString(uint32(fl), releaseFlagNames) -} - -var releaseFlagNames = []flagName{ - {uint32(ReleaseFlush), "ReleaseFlush"}, -} - -// Opcodes -const ( - opLookup = 1 - opForget = 2 // no reply - opGetattr = 3 - opSetattr = 4 - opReadlink = 5 - opSymlink = 6 - opMknod = 8 - opMkdir = 9 - opUnlink = 10 - opRmdir = 11 - opRename = 12 - opLink = 13 - opOpen = 14 - opRead = 15 - opWrite = 16 - opStatfs = 17 - opRelease = 18 - opFsync = 20 - opSetxattr = 21 - opGetxattr = 22 - opListxattr = 23 - opRemovexattr = 24 - opFlush = 25 - opInit = 26 - opOpendir = 27 - opReaddir = 28 - opReleasedir = 29 - opFsyncdir = 30 - opGetlk = 31 - opSetlk = 32 - opSetlkw = 33 - opAccess = 34 - opCreate = 35 - opInterrupt = 36 - opBmap = 37 - opDestroy = 38 - opIoctl = 39 // Linux? - opPoll = 40 // Linux? - - // OS X - opSetvolname = 61 - opGetxtimes = 62 - opExchange = 63 -) - -type entryOut struct { - Nodeid uint64 // Inode ID - Generation uint64 // Inode generation - EntryValid uint64 // Cache timeout for the name - AttrValid uint64 // Cache timeout for the attributes - EntryValidNsec uint32 - AttrValidNsec uint32 - Attr attr -} - -func entryOutSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 9}): - return unsafe.Offsetof(entryOut{}.Attr) + unsafe.Offsetof(entryOut{}.Attr.Blksize) - default: - return unsafe.Sizeof(entryOut{}) - } -} - -type forgetIn struct { - Nlookup uint64 -} - -type getattrIn struct { - GetattrFlags uint32 - _ uint32 - Fh uint64 -} - -type attrOut struct { - AttrValid uint64 // Cache timeout for the attributes - AttrValidNsec uint32 - _ uint32 - Attr attr -} - -func attrOutSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 9}): - return unsafe.Offsetof(attrOut{}.Attr) + unsafe.Offsetof(attrOut{}.Attr.Blksize) - default: - return unsafe.Sizeof(attrOut{}) - } -} - -// OS X -type getxtimesOut struct { - Bkuptime uint64 - Crtime uint64 - BkuptimeNsec uint32 - CrtimeNsec uint32 -} - -type mknodIn struct { - Mode uint32 - Rdev uint32 - Umask uint32 - _ uint32 - // "filename\x00" follows. -} - -func mknodInSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 12}): - return unsafe.Offsetof(mknodIn{}.Umask) - default: - return unsafe.Sizeof(mknodIn{}) - } -} - -type mkdirIn struct { - Mode uint32 - Umask uint32 - // filename follows -} - -func mkdirInSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 12}): - return unsafe.Offsetof(mkdirIn{}.Umask) + 4 - default: - return unsafe.Sizeof(mkdirIn{}) - } -} - -type renameIn struct { - Newdir uint64 - // "oldname\x00newname\x00" follows -} - -// OS X -type exchangeIn struct { - Olddir uint64 - Newdir uint64 - Options uint64 - // "oldname\x00newname\x00" follows -} - -type linkIn struct { - Oldnodeid uint64 -} - -type setattrInCommon struct { - Valid uint32 - _ uint32 - Fh uint64 - Size uint64 - LockOwner uint64 // unused on OS X? - Atime uint64 - Mtime uint64 - Unused2 uint64 - AtimeNsec uint32 - MtimeNsec uint32 - Unused3 uint32 - Mode uint32 - Unused4 uint32 - Uid uint32 - Gid uint32 - Unused5 uint32 -} - -type openIn struct { - Flags uint32 - Unused uint32 -} - -type openOut struct { - Fh uint64 - OpenFlags uint32 - _ uint32 -} - -type createIn struct { - Flags uint32 - Mode uint32 - Umask uint32 - _ uint32 -} - -func createInSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 12}): - return unsafe.Offsetof(createIn{}.Umask) - default: - return unsafe.Sizeof(createIn{}) - } -} - -type releaseIn struct { - Fh uint64 - Flags uint32 - ReleaseFlags uint32 - LockOwner uint32 -} - -type flushIn struct { - Fh uint64 - FlushFlags uint32 - _ uint32 - LockOwner uint64 -} - -type readIn struct { - Fh uint64 - Offset uint64 - Size uint32 - ReadFlags uint32 - LockOwner uint64 - Flags uint32 - _ uint32 -} - -func readInSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 9}): - return unsafe.Offsetof(readIn{}.ReadFlags) + 4 - default: - return unsafe.Sizeof(readIn{}) - } -} - -// The ReadFlags are passed in ReadRequest. -type ReadFlags uint32 - -const ( - // LockOwner field is valid. - ReadLockOwner ReadFlags = 1 << 1 -) - -var readFlagNames = []flagName{ - {uint32(ReadLockOwner), "ReadLockOwner"}, -} - -func (fl ReadFlags) String() string { - return flagString(uint32(fl), readFlagNames) -} - -type writeIn struct { - Fh uint64 - Offset uint64 - Size uint32 - WriteFlags uint32 - LockOwner uint64 - Flags uint32 - _ uint32 -} - -func writeInSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 9}): - return unsafe.Offsetof(writeIn{}.LockOwner) - default: - return unsafe.Sizeof(writeIn{}) - } -} - -type writeOut struct { - Size uint32 - _ uint32 -} - -// The WriteFlags are passed in WriteRequest. -type WriteFlags uint32 - -const ( - WriteCache WriteFlags = 1 << 0 - // LockOwner field is valid. - WriteLockOwner WriteFlags = 1 << 1 -) - -var writeFlagNames = []flagName{ - {uint32(WriteCache), "WriteCache"}, - {uint32(WriteLockOwner), "WriteLockOwner"}, -} - -func (fl WriteFlags) String() string { - return flagString(uint32(fl), writeFlagNames) -} - -const compatStatfsSize = 48 - -type statfsOut struct { - St kstatfs -} - -type fsyncIn struct { - Fh uint64 - FsyncFlags uint32 - _ uint32 -} - -type setxattrInCommon struct { - Size uint32 - Flags uint32 -} - -func (setxattrInCommon) position() uint32 { - return 0 -} - -type getxattrInCommon struct { - Size uint32 - _ uint32 -} - -func (getxattrInCommon) position() uint32 { - return 0 -} - -type getxattrOut struct { - Size uint32 - _ uint32 -} - -type lkIn struct { - Fh uint64 - Owner uint64 - Lk fileLock - LkFlags uint32 - _ uint32 -} - -func lkInSize(p Protocol) uintptr { - switch { - case p.LT(Protocol{7, 9}): - return unsafe.Offsetof(lkIn{}.LkFlags) - default: - return unsafe.Sizeof(lkIn{}) - } -} - -type lkOut struct { - Lk fileLock -} - -type accessIn struct { - Mask uint32 - _ uint32 -} - -type initIn struct { - Major uint32 - Minor uint32 - MaxReadahead uint32 - Flags uint32 -} - -const initInSize = int(unsafe.Sizeof(initIn{})) - -type initOut struct { - Major uint32 - Minor uint32 - MaxReadahead uint32 - Flags uint32 - Unused uint32 - MaxWrite uint32 -} - -type interruptIn struct { - Unique uint64 -} - -type bmapIn struct { - Block uint64 - BlockSize uint32 - _ uint32 -} - -type bmapOut struct { - Block uint64 -} - -type inHeader struct { - Len uint32 - Opcode uint32 - Unique uint64 - Nodeid uint64 - Uid uint32 - Gid uint32 - Pid uint32 - _ uint32 -} - -const inHeaderSize = int(unsafe.Sizeof(inHeader{})) - -type outHeader struct { - Len uint32 - Error int32 - Unique uint64 -} - -type dirent struct { - Ino uint64 - Off uint64 - Namelen uint32 - Type uint32 - Name [0]byte -} - -const direntSize = 8 + 8 + 4 + 4 - -const ( - notifyCodePoll int32 = 1 - notifyCodeInvalInode int32 = 2 - notifyCodeInvalEntry int32 = 3 -) - -type notifyInvalInodeOut struct { - Ino uint64 - Off int64 - Len int64 -} - -type notifyInvalEntryOut struct { - Parent uint64 - Namelen uint32 - _ uint32 -} diff --git a/vendor/bazil.org/fuse/fuse_kernel_darwin.go b/vendor/bazil.org/fuse/fuse_kernel_darwin.go deleted file mode 100644 index b9873fdf39..0000000000 --- a/vendor/bazil.org/fuse/fuse_kernel_darwin.go +++ /dev/null @@ -1,88 +0,0 @@ -package fuse - -import ( - "time" -) - -type attr struct { - Ino uint64 - Size uint64 - Blocks uint64 - Atime uint64 - Mtime uint64 - Ctime uint64 - Crtime_ uint64 // OS X only - AtimeNsec uint32 - MtimeNsec uint32 - CtimeNsec uint32 - CrtimeNsec uint32 // OS X only - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint32 - Flags_ uint32 // OS X only; see chflags(2) - Blksize uint32 - padding uint32 -} - -func (a *attr) SetCrtime(s uint64, ns uint32) { - a.Crtime_, a.CrtimeNsec = s, ns -} - -func (a *attr) SetFlags(f uint32) { - a.Flags_ = f -} - -type setattrIn struct { - setattrInCommon - - // OS X only - Bkuptime_ uint64 - Chgtime_ uint64 - Crtime uint64 - BkuptimeNsec uint32 - ChgtimeNsec uint32 - CrtimeNsec uint32 - Flags_ uint32 // see chflags(2) -} - -func (in *setattrIn) BkupTime() time.Time { - return time.Unix(int64(in.Bkuptime_), int64(in.BkuptimeNsec)) -} - -func (in *setattrIn) Chgtime() time.Time { - return time.Unix(int64(in.Chgtime_), int64(in.ChgtimeNsec)) -} - -func (in *setattrIn) Flags() uint32 { - return in.Flags_ -} - -func openFlags(flags uint32) OpenFlags { - return OpenFlags(flags) -} - -type getxattrIn struct { - getxattrInCommon - - // OS X only - Position uint32 - Padding uint32 -} - -func (g *getxattrIn) position() uint32 { - return g.Position -} - -type setxattrIn struct { - setxattrInCommon - - // OS X only - Position uint32 - Padding uint32 -} - -func (s *setxattrIn) position() uint32 { - return s.Position -} diff --git a/vendor/bazil.org/fuse/fuse_kernel_freebsd.go b/vendor/bazil.org/fuse/fuse_kernel_freebsd.go deleted file mode 100644 index b1141e41dc..0000000000 --- a/vendor/bazil.org/fuse/fuse_kernel_freebsd.go +++ /dev/null @@ -1,62 +0,0 @@ -package fuse - -import "time" - -type attr struct { - Ino uint64 - Size uint64 - Blocks uint64 - Atime uint64 - Mtime uint64 - Ctime uint64 - AtimeNsec uint32 - MtimeNsec uint32 - CtimeNsec uint32 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint32 - Blksize uint32 - padding uint32 -} - -func (a *attr) Crtime() time.Time { - return time.Time{} -} - -func (a *attr) SetCrtime(s uint64, ns uint32) { - // ignored on freebsd -} - -func (a *attr) SetFlags(f uint32) { - // ignored on freebsd -} - -type setattrIn struct { - setattrInCommon -} - -func (in *setattrIn) BkupTime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Chgtime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Flags() uint32 { - return 0 -} - -func openFlags(flags uint32) OpenFlags { - return OpenFlags(flags) -} - -type getxattrIn struct { - getxattrInCommon -} - -type setxattrIn struct { - setxattrInCommon -} diff --git a/vendor/bazil.org/fuse/fuse_kernel_linux.go b/vendor/bazil.org/fuse/fuse_kernel_linux.go deleted file mode 100644 index d3ba866178..0000000000 --- a/vendor/bazil.org/fuse/fuse_kernel_linux.go +++ /dev/null @@ -1,70 +0,0 @@ -package fuse - -import "time" - -type attr struct { - Ino uint64 - Size uint64 - Blocks uint64 - Atime uint64 - Mtime uint64 - Ctime uint64 - AtimeNsec uint32 - MtimeNsec uint32 - CtimeNsec uint32 - Mode uint32 - Nlink uint32 - Uid uint32 - Gid uint32 - Rdev uint32 - Blksize uint32 - padding uint32 -} - -func (a *attr) Crtime() time.Time { - return time.Time{} -} - -func (a *attr) SetCrtime(s uint64, ns uint32) { - // Ignored on Linux. -} - -func (a *attr) SetFlags(f uint32) { - // Ignored on Linux. -} - -type setattrIn struct { - setattrInCommon -} - -func (in *setattrIn) BkupTime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Chgtime() time.Time { - return time.Time{} -} - -func (in *setattrIn) Flags() uint32 { - return 0 -} - -func openFlags(flags uint32) OpenFlags { - // on amd64, the 32-bit O_LARGEFILE flag is always seen; - // on i386, the flag probably depends on the app - // requesting, but in any case should be utterly - // uninteresting to us here; our kernel protocol messages - // are not directly related to the client app's kernel - // API/ABI - flags &^= 0x8000 - - return OpenFlags(flags) -} - -type getxattrIn struct { - getxattrInCommon -} - -type setxattrIn struct { - setxattrInCommon -} diff --git a/vendor/bazil.org/fuse/fuse_kernel_std.go b/vendor/bazil.org/fuse/fuse_kernel_std.go deleted file mode 100644 index 074cfd3228..0000000000 --- a/vendor/bazil.org/fuse/fuse_kernel_std.go +++ /dev/null @@ -1 +0,0 @@ -package fuse diff --git a/vendor/bazil.org/fuse/fuse_linux.go b/vendor/bazil.org/fuse/fuse_linux.go deleted file mode 100644 index 5fb96f9ae9..0000000000 --- a/vendor/bazil.org/fuse/fuse_linux.go +++ /dev/null @@ -1,7 +0,0 @@ -package fuse - -// Maximum file write size we are prepared to receive from the kernel. -// -// Linux 4.2.0 has been observed to cap this value at 128kB -// (FUSE_MAX_PAGES_PER_REQ=32, 4kB pages). -const maxWrite = 128 * 1024 diff --git a/vendor/bazil.org/fuse/fuseutil/fuseutil.go b/vendor/bazil.org/fuse/fuseutil/fuseutil.go deleted file mode 100644 index b3f52b73b2..0000000000 --- a/vendor/bazil.org/fuse/fuseutil/fuseutil.go +++ /dev/null @@ -1,20 +0,0 @@ -package fuseutil // import "bazil.org/fuse/fuseutil" - -import ( - "bazil.org/fuse" -) - -// HandleRead handles a read request assuming that data is the entire file content. -// It adjusts the amount returned in resp according to req.Offset and req.Size. -func HandleRead(req *fuse.ReadRequest, resp *fuse.ReadResponse, data []byte) { - if req.Offset >= int64(len(data)) { - data = nil - } else { - data = data[req.Offset:] - } - if len(data) > req.Size { - data = data[:req.Size] - } - n := copy(resp.Data[:req.Size], data) - resp.Data = resp.Data[:n] -} diff --git a/vendor/bazil.org/fuse/mount.go b/vendor/bazil.org/fuse/mount.go deleted file mode 100644 index 8054e9021c..0000000000 --- a/vendor/bazil.org/fuse/mount.go +++ /dev/null @@ -1,38 +0,0 @@ -package fuse - -import ( - "bufio" - "errors" - "io" - "log" - "sync" -) - -var ( - // ErrOSXFUSENotFound is returned from Mount when the OSXFUSE - // installation is not detected. - // - // Only happens on OS X. Make sure OSXFUSE is installed, or see - // OSXFUSELocations for customization. - ErrOSXFUSENotFound = errors.New("cannot locate OSXFUSE") -) - -func neverIgnoreLine(line string) bool { - return false -} - -func lineLogger(wg *sync.WaitGroup, prefix string, ignore func(line string) bool, r io.ReadCloser) { - defer wg.Done() - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - line := scanner.Text() - if ignore(line) { - continue - } - log.Printf("%s: %s", prefix, line) - } - if err := scanner.Err(); err != nil { - log.Printf("%s, error reading: %v", prefix, err) - } -} diff --git a/vendor/bazil.org/fuse/mount_darwin.go b/vendor/bazil.org/fuse/mount_darwin.go deleted file mode 100644 index c1c36e62b5..0000000000 --- a/vendor/bazil.org/fuse/mount_darwin.go +++ /dev/null @@ -1,208 +0,0 @@ -package fuse - -import ( - "errors" - "fmt" - "log" - "os" - "os/exec" - "path" - "strconv" - "strings" - "sync" - "syscall" -) - -var ( - errNoAvail = errors.New("no available fuse devices") - errNotLoaded = errors.New("osxfuse is not loaded") -) - -func loadOSXFUSE(bin string) error { - cmd := exec.Command(bin) - cmd.Dir = "/" - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - return err -} - -func openOSXFUSEDev(devPrefix string) (*os.File, error) { - var f *os.File - var err error - for i := uint64(0); ; i++ { - path := devPrefix + strconv.FormatUint(i, 10) - f, err = os.OpenFile(path, os.O_RDWR, 0000) - if os.IsNotExist(err) { - if i == 0 { - // not even the first device was found -> fuse is not loaded - return nil, errNotLoaded - } - - // we've run out of kernel-provided devices - return nil, errNoAvail - } - - if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY { - // try the next one - continue - } - - if err != nil { - return nil, err - } - return f, nil - } -} - -func handleMountOSXFUSE(helperName string, errCh chan<- error) func(line string) (ignore bool) { - var noMountpointPrefix = helperName + `: ` - const noMountpointSuffix = `: No such file or directory` - return func(line string) (ignore bool) { - if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) { - // re-extract it from the error message in case some layer - // changed the path - mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)] - err := &MountpointDoesNotExistError{ - Path: mountpoint, - } - select { - case errCh <- err: - return true - default: - // not the first error; fall back to logging it - return false - } - } - - return false - } -} - -// isBoringMountOSXFUSEError returns whether the Wait error is -// uninteresting; exit status 64 is. -func isBoringMountOSXFUSEError(err error) bool { - if err, ok := err.(*exec.ExitError); ok && err.Exited() { - if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 64 { - return true - } - } - return false -} - -func callMount(bin string, daemonVar string, dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) error { - for k, v := range conf.options { - if strings.Contains(k, ",") || strings.Contains(v, ",") { - // Silly limitation but the mount helper does not - // understand any escaping. See TestMountOptionCommaError. - return fmt.Errorf("mount options cannot contain commas on darwin: %q=%q", k, v) - } - } - cmd := exec.Command( - bin, - "-o", conf.getOptions(), - // Tell osxfuse-kext how large our buffer is. It must split - // writes larger than this into multiple writes. - // - // OSXFUSE seems to ignore InitResponse.MaxWrite, and uses - // this instead. - "-o", "iosize="+strconv.FormatUint(maxWrite, 10), - // refers to fd passed in cmd.ExtraFiles - "3", - dir, - ) - cmd.ExtraFiles = []*os.File{f} - cmd.Env = os.Environ() - // OSXFUSE <3.3.0 - cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=") - // OSXFUSE >=3.3.0 - cmd.Env = append(cmd.Env, "MOUNT_OSXFUSE_CALL_BY_LIB=") - - daemon := os.Args[0] - if daemonVar != "" { - cmd.Env = append(cmd.Env, daemonVar+"="+daemon) - } - - stdout, err := cmd.StdoutPipe() - if err != nil { - return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err) - } - stderr, err := cmd.StderrPipe() - if err != nil { - return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err) - } - - if err := cmd.Start(); err != nil { - return fmt.Errorf("mount_osxfusefs: %v", err) - } - helperErrCh := make(chan error, 1) - go func() { - var wg sync.WaitGroup - wg.Add(2) - go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout) - helperName := path.Base(bin) - go lineLogger(&wg, "mount helper error", handleMountOSXFUSE(helperName, helperErrCh), stderr) - wg.Wait() - if err := cmd.Wait(); err != nil { - // see if we have a better error to report - select { - case helperErr := <-helperErrCh: - // log the Wait error if it's not what we expected - if !isBoringMountOSXFUSEError(err) { - log.Printf("mount helper failed: %v", err) - } - // and now return what we grabbed from stderr as the real - // error - *errp = helperErr - close(ready) - return - default: - // nope, fall back to generic message - } - - *errp = fmt.Errorf("mount_osxfusefs: %v", err) - close(ready) - return - } - - *errp = nil - close(ready) - }() - return nil -} - -func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) { - locations := conf.osxfuseLocations - if locations == nil { - locations = []OSXFUSEPaths{ - OSXFUSELocationV3, - OSXFUSELocationV2, - } - } - for _, loc := range locations { - if _, err := os.Stat(loc.Mount); os.IsNotExist(err) { - // try the other locations - continue - } - - f, err := openOSXFUSEDev(loc.DevicePrefix) - if err == errNotLoaded { - err = loadOSXFUSE(loc.Load) - if err != nil { - return nil, err - } - // try again - f, err = openOSXFUSEDev(loc.DevicePrefix) - } - if err != nil { - return nil, err - } - err = callMount(loc.Mount, loc.DaemonVar, dir, conf, f, ready, errp) - if err != nil { - f.Close() - return nil, err - } - return f, nil - } - return nil, ErrOSXFUSENotFound -} diff --git a/vendor/bazil.org/fuse/mount_freebsd.go b/vendor/bazil.org/fuse/mount_freebsd.go deleted file mode 100644 index 70bb410249..0000000000 --- a/vendor/bazil.org/fuse/mount_freebsd.go +++ /dev/null @@ -1,111 +0,0 @@ -package fuse - -import ( - "fmt" - "log" - "os" - "os/exec" - "strings" - "sync" - "syscall" -) - -func handleMountFusefsStderr(errCh chan<- error) func(line string) (ignore bool) { - return func(line string) (ignore bool) { - const ( - noMountpointPrefix = `mount_fusefs: ` - noMountpointSuffix = `: No such file or directory` - ) - if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) { - // re-extract it from the error message in case some layer - // changed the path - mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)] - err := &MountpointDoesNotExistError{ - Path: mountpoint, - } - select { - case errCh <- err: - return true - default: - // not the first error; fall back to logging it - return false - } - } - - return false - } -} - -// isBoringMountFusefsError returns whether the Wait error is -// uninteresting; exit status 1 is. -func isBoringMountFusefsError(err error) bool { - if err, ok := err.(*exec.ExitError); ok && err.Exited() { - if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 { - return true - } - } - return false -} - -func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) { - for k, v := range conf.options { - if strings.Contains(k, ",") || strings.Contains(v, ",") { - // Silly limitation but the mount helper does not - // understand any escaping. See TestMountOptionCommaError. - return nil, fmt.Errorf("mount options cannot contain commas on FreeBSD: %q=%q", k, v) - } - } - - f, err := os.OpenFile("/dev/fuse", os.O_RDWR, 0000) - if err != nil { - *errp = err - return nil, err - } - - cmd := exec.Command( - "/sbin/mount_fusefs", - "--safe", - "-o", conf.getOptions(), - "3", - dir, - ) - cmd.ExtraFiles = []*os.File{f} - - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err) - } - stderr, err := cmd.StderrPipe() - if err != nil { - return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err) - } - - if err := cmd.Start(); err != nil { - return nil, fmt.Errorf("mount_fusefs: %v", err) - } - helperErrCh := make(chan error, 1) - var wg sync.WaitGroup - wg.Add(2) - go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout) - go lineLogger(&wg, "mount helper error", handleMountFusefsStderr(helperErrCh), stderr) - wg.Wait() - if err := cmd.Wait(); err != nil { - // see if we have a better error to report - select { - case helperErr := <-helperErrCh: - // log the Wait error if it's not what we expected - if !isBoringMountFusefsError(err) { - log.Printf("mount helper failed: %v", err) - } - // and now return what we grabbed from stderr as the real - // error - return nil, helperErr - default: - // nope, fall back to generic message - } - return nil, fmt.Errorf("mount_fusefs: %v", err) - } - - close(ready) - return f, nil -} diff --git a/vendor/bazil.org/fuse/mount_linux.go b/vendor/bazil.org/fuse/mount_linux.go deleted file mode 100644 index 197d1044e9..0000000000 --- a/vendor/bazil.org/fuse/mount_linux.go +++ /dev/null @@ -1,150 +0,0 @@ -package fuse - -import ( - "fmt" - "log" - "net" - "os" - "os/exec" - "strings" - "sync" - "syscall" -) - -func handleFusermountStderr(errCh chan<- error) func(line string) (ignore bool) { - return func(line string) (ignore bool) { - if line == `fusermount: failed to open /etc/fuse.conf: Permission denied` { - // Silence this particular message, it occurs way too - // commonly and isn't very relevant to whether the mount - // succeeds or not. - return true - } - - const ( - noMountpointPrefix = `fusermount: failed to access mountpoint ` - noMountpointSuffix = `: No such file or directory` - ) - if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) { - // re-extract it from the error message in case some layer - // changed the path - mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)] - err := &MountpointDoesNotExistError{ - Path: mountpoint, - } - select { - case errCh <- err: - return true - default: - // not the first error; fall back to logging it - return false - } - } - - return false - } -} - -// isBoringFusermountError returns whether the Wait error is -// uninteresting; exit status 1 is. -func isBoringFusermountError(err error) bool { - if err, ok := err.(*exec.ExitError); ok && err.Exited() { - if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 { - return true - } - } - return false -} - -func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) { - // linux mount is never delayed - close(ready) - - fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0) - if err != nil { - return nil, fmt.Errorf("socketpair error: %v", err) - } - - writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes") - defer writeFile.Close() - - readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads") - defer readFile.Close() - - cmd := exec.Command( - "fusermount", - "-o", conf.getOptions(), - "--", - dir, - ) - cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3") - - cmd.ExtraFiles = []*os.File{writeFile} - - var wg sync.WaitGroup - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, fmt.Errorf("setting up fusermount stderr: %v", err) - } - stderr, err := cmd.StderrPipe() - if err != nil { - return nil, fmt.Errorf("setting up fusermount stderr: %v", err) - } - - if err := cmd.Start(); err != nil { - return nil, fmt.Errorf("fusermount: %v", err) - } - helperErrCh := make(chan error, 1) - wg.Add(2) - go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout) - go lineLogger(&wg, "mount helper error", handleFusermountStderr(helperErrCh), stderr) - wg.Wait() - if err := cmd.Wait(); err != nil { - // see if we have a better error to report - select { - case helperErr := <-helperErrCh: - // log the Wait error if it's not what we expected - if !isBoringFusermountError(err) { - log.Printf("mount helper failed: %v", err) - } - // and now return what we grabbed from stderr as the real - // error - return nil, helperErr - default: - // nope, fall back to generic message - } - - return nil, fmt.Errorf("fusermount: %v", err) - } - - c, err := net.FileConn(readFile) - if err != nil { - return nil, fmt.Errorf("FileConn from fusermount socket: %v", err) - } - defer c.Close() - - uc, ok := c.(*net.UnixConn) - if !ok { - return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c) - } - - buf := make([]byte, 32) // expect 1 byte - oob := make([]byte, 32) // expect 24 bytes - _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) - scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) - if err != nil { - return nil, fmt.Errorf("ParseSocketControlMessage: %v", err) - } - if len(scms) != 1 { - return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms) - } - scm := scms[0] - gotFds, err := syscall.ParseUnixRights(&scm) - if err != nil { - return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err) - } - if len(gotFds) != 1 { - return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds) - } - f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse") - return f, nil -} diff --git a/vendor/bazil.org/fuse/options.go b/vendor/bazil.org/fuse/options.go deleted file mode 100644 index 65ce8a5410..0000000000 --- a/vendor/bazil.org/fuse/options.go +++ /dev/null @@ -1,310 +0,0 @@ -package fuse - -import ( - "errors" - "strings" -) - -func dummyOption(conf *mountConfig) error { - return nil -} - -// mountConfig holds the configuration for a mount operation. -// Use it by passing MountOption values to Mount. -type mountConfig struct { - options map[string]string - maxReadahead uint32 - initFlags InitFlags - osxfuseLocations []OSXFUSEPaths -} - -func escapeComma(s string) string { - s = strings.Replace(s, `\`, `\\`, -1) - s = strings.Replace(s, `,`, `\,`, -1) - return s -} - -// getOptions makes a string of options suitable for passing to FUSE -// mount flag `-o`. Returns an empty string if no options were set. -// Any platform specific adjustments should happen before the call. -func (m *mountConfig) getOptions() string { - var opts []string - for k, v := range m.options { - k = escapeComma(k) - if v != "" { - k += "=" + escapeComma(v) - } - opts = append(opts, k) - } - return strings.Join(opts, ",") -} - -type mountOption func(*mountConfig) error - -// MountOption is passed to Mount to change the behavior of the mount. -type MountOption mountOption - -// FSName sets the file system name (also called source) that is -// visible in the list of mounted file systems. -// -// FreeBSD ignores this option. -func FSName(name string) MountOption { - return func(conf *mountConfig) error { - conf.options["fsname"] = name - return nil - } -} - -// Subtype sets the subtype of the mount. The main type is always -// `fuse`. The type in a list of mounted file systems will look like -// `fuse.foo`. -// -// OS X ignores this option. -// FreeBSD ignores this option. -func Subtype(fstype string) MountOption { - return func(conf *mountConfig) error { - conf.options["subtype"] = fstype - return nil - } -} - -// LocalVolume sets the volume to be local (instead of network), -// changing the behavior of Finder, Spotlight, and such. -// -// OS X only. Others ignore this option. -func LocalVolume() MountOption { - return localVolume -} - -// VolumeName sets the volume name shown in Finder. -// -// OS X only. Others ignore this option. -func VolumeName(name string) MountOption { - return volumeName(name) -} - -// NoAppleDouble makes OSXFUSE disallow files with names used by OS X -// to store extended attributes on file systems that do not support -// them natively. -// -// Such file names are: -// -// ._* -// .DS_Store -// -// OS X only. Others ignore this option. -func NoAppleDouble() MountOption { - return noAppleDouble -} - -// NoAppleXattr makes OSXFUSE disallow extended attributes with the -// prefix "com.apple.". This disables persistent Finder state and -// other such information. -// -// OS X only. Others ignore this option. -func NoAppleXattr() MountOption { - return noAppleXattr -} - -// ExclCreate causes O_EXCL flag to be set for only "truly" exclusive creates, -// i.e. create calls for which the initiator explicitly set the O_EXCL flag. -// -// OSXFUSE expects all create calls to return EEXIST in case the file -// already exists, regardless of whether O_EXCL was specified or not. -// To ensure this behavior, it normally sets OpenExclusive for all -// Create calls, regardless of whether the original call had it set. -// For distributed filesystems, that may force every file create to be -// a distributed consensus action, causing undesirable delays. -// -// This option makes the FUSE filesystem see the original flag value, -// and better decide when to ensure global consensus. -// -// Note that returning EEXIST on existing file create is still -// expected with OSXFUSE, regardless of the presence of the -// OpenExclusive flag. -// -// For more information, see -// https://github.com/osxfuse/osxfuse/issues/209 -// -// OS X only. Others ignore this options. -// Requires OSXFUSE 3.4.1 or newer. -func ExclCreate() MountOption { - return exclCreate -} - -// DaemonTimeout sets the time in seconds between a request and a reply before -// the FUSE mount is declared dead. -// -// OS X and FreeBSD only. Others ignore this option. -func DaemonTimeout(name string) MountOption { - return daemonTimeout(name) -} - -var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot") - -// AllowOther allows other users to access the file system. -// -// Only one of AllowOther or AllowRoot can be used. -func AllowOther() MountOption { - return func(conf *mountConfig) error { - if _, ok := conf.options["allow_root"]; ok { - return ErrCannotCombineAllowOtherAndAllowRoot - } - conf.options["allow_other"] = "" - return nil - } -} - -// AllowRoot allows other users to access the file system. -// -// Only one of AllowOther or AllowRoot can be used. -// -// FreeBSD ignores this option. -func AllowRoot() MountOption { - return func(conf *mountConfig) error { - if _, ok := conf.options["allow_other"]; ok { - return ErrCannotCombineAllowOtherAndAllowRoot - } - conf.options["allow_root"] = "" - return nil - } -} - -// AllowDev enables interpreting character or block special devices on the -// filesystem. -func AllowDev() MountOption { - return func(conf *mountConfig) error { - conf.options["dev"] = "" - return nil - } -} - -// AllowSUID allows set-user-identifier or set-group-identifier bits to take -// effect. -func AllowSUID() MountOption { - return func(conf *mountConfig) error { - conf.options["suid"] = "" - return nil - } -} - -// DefaultPermissions makes the kernel enforce access control based on -// the file mode (as in chmod). -// -// Without this option, the Node itself decides what is and is not -// allowed. This is normally ok because FUSE file systems cannot be -// accessed by other users without AllowOther/AllowRoot. -// -// FreeBSD ignores this option. -func DefaultPermissions() MountOption { - return func(conf *mountConfig) error { - conf.options["default_permissions"] = "" - return nil - } -} - -// ReadOnly makes the mount read-only. -func ReadOnly() MountOption { - return func(conf *mountConfig) error { - conf.options["ro"] = "" - return nil - } -} - -// MaxReadahead sets the number of bytes that can be prefetched for -// sequential reads. The kernel can enforce a maximum value lower than -// this. -// -// This setting makes the kernel perform speculative reads that do not -// originate from any client process. This usually tremendously -// improves read performance. -func MaxReadahead(n uint32) MountOption { - return func(conf *mountConfig) error { - conf.maxReadahead = n - return nil - } -} - -// AsyncRead enables multiple outstanding read requests for the same -// handle. Without this, there is at most one request in flight at a -// time. -func AsyncRead() MountOption { - return func(conf *mountConfig) error { - conf.initFlags |= InitAsyncRead - return nil - } -} - -// WritebackCache enables the kernel to buffer writes before sending -// them to the FUSE server. Without this, writethrough caching is -// used. -func WritebackCache() MountOption { - return func(conf *mountConfig) error { - conf.initFlags |= InitWritebackCache - return nil - } -} - -// OSXFUSEPaths describes the paths used by an installed OSXFUSE -// version. See OSXFUSELocationV3 for typical values. -type OSXFUSEPaths struct { - // Prefix for the device file. At mount time, an incrementing - // number is suffixed until a free FUSE device is found. - DevicePrefix string - // Path of the load helper, used to load the kernel extension if - // no device files are found. - Load string - // Path of the mount helper, used for the actual mount operation. - Mount string - // Environment variable used to pass the path to the executable - // calling the mount helper. - DaemonVar string -} - -// Default paths for OSXFUSE. See OSXFUSELocations. -var ( - OSXFUSELocationV3 = OSXFUSEPaths{ - DevicePrefix: "/dev/osxfuse", - Load: "/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse", - Mount: "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse", - DaemonVar: "MOUNT_OSXFUSE_DAEMON_PATH", - } - OSXFUSELocationV2 = OSXFUSEPaths{ - DevicePrefix: "/dev/osxfuse", - Load: "/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs", - Mount: "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", - DaemonVar: "MOUNT_FUSEFS_DAEMON_PATH", - } -) - -// OSXFUSELocations sets where to look for OSXFUSE files. The -// arguments are all the possible locations. The previous locations -// are replaced. -// -// Without this option, OSXFUSELocationV3 and OSXFUSELocationV2 are -// used. -// -// OS X only. Others ignore this option. -func OSXFUSELocations(paths ...OSXFUSEPaths) MountOption { - return func(conf *mountConfig) error { - if len(paths) == 0 { - return errors.New("must specify at least one location for OSXFUSELocations") - } - // replace previous values, but make a copy so there's no - // worries about caller mutating their slice - conf.osxfuseLocations = append(conf.osxfuseLocations[:0], paths...) - return nil - } -} - -// AllowNonEmptyMount allows the mounting over a non-empty directory. -// -// The files in it will be shadowed by the freshly created mount. By -// default these mounts are rejected to prevent accidental covering up -// of data, which could for example prevent automatic backup. -func AllowNonEmptyMount() MountOption { - return func(conf *mountConfig) error { - conf.options["nonempty"] = "" - return nil - } -} diff --git a/vendor/bazil.org/fuse/options_darwin.go b/vendor/bazil.org/fuse/options_darwin.go deleted file mode 100644 index faa9d78e74..0000000000 --- a/vendor/bazil.org/fuse/options_darwin.go +++ /dev/null @@ -1,35 +0,0 @@ -package fuse - -func localVolume(conf *mountConfig) error { - conf.options["local"] = "" - return nil -} - -func volumeName(name string) MountOption { - return func(conf *mountConfig) error { - conf.options["volname"] = name - return nil - } -} - -func daemonTimeout(name string) MountOption { - return func(conf *mountConfig) error { - conf.options["daemon_timeout"] = name - return nil - } -} - -func noAppleXattr(conf *mountConfig) error { - conf.options["noapplexattr"] = "" - return nil -} - -func noAppleDouble(conf *mountConfig) error { - conf.options["noappledouble"] = "" - return nil -} - -func exclCreate(conf *mountConfig) error { - conf.options["excl_create"] = "" - return nil -} diff --git a/vendor/bazil.org/fuse/options_freebsd.go b/vendor/bazil.org/fuse/options_freebsd.go deleted file mode 100644 index 7c164b1368..0000000000 --- a/vendor/bazil.org/fuse/options_freebsd.go +++ /dev/null @@ -1,28 +0,0 @@ -package fuse - -func localVolume(conf *mountConfig) error { - return nil -} - -func volumeName(name string) MountOption { - return dummyOption -} - -func daemonTimeout(name string) MountOption { - return func(conf *mountConfig) error { - conf.options["timeout"] = name - return nil - } -} - -func noAppleXattr(conf *mountConfig) error { - return nil -} - -func noAppleDouble(conf *mountConfig) error { - return nil -} - -func exclCreate(conf *mountConfig) error { - return nil -} diff --git a/vendor/bazil.org/fuse/options_linux.go b/vendor/bazil.org/fuse/options_linux.go deleted file mode 100644 index 13f0896d58..0000000000 --- a/vendor/bazil.org/fuse/options_linux.go +++ /dev/null @@ -1,25 +0,0 @@ -package fuse - -func localVolume(conf *mountConfig) error { - return nil -} - -func volumeName(name string) MountOption { - return dummyOption -} - -func daemonTimeout(name string) MountOption { - return dummyOption -} - -func noAppleXattr(conf *mountConfig) error { - return nil -} - -func noAppleDouble(conf *mountConfig) error { - return nil -} - -func exclCreate(conf *mountConfig) error { - return nil -} diff --git a/vendor/bazil.org/fuse/protocol.go b/vendor/bazil.org/fuse/protocol.go deleted file mode 100644 index a77bbf72f1..0000000000 --- a/vendor/bazil.org/fuse/protocol.go +++ /dev/null @@ -1,75 +0,0 @@ -package fuse - -import ( - "fmt" -) - -// Protocol is a FUSE protocol version number. -type Protocol struct { - Major uint32 - Minor uint32 -} - -func (p Protocol) String() string { - return fmt.Sprintf("%d.%d", p.Major, p.Minor) -} - -// LT returns whether a is less than b. -func (a Protocol) LT(b Protocol) bool { - return a.Major < b.Major || - (a.Major == b.Major && a.Minor < b.Minor) -} - -// GE returns whether a is greater than or equal to b. -func (a Protocol) GE(b Protocol) bool { - return a.Major > b.Major || - (a.Major == b.Major && a.Minor >= b.Minor) -} - -func (a Protocol) is79() bool { - return a.GE(Protocol{7, 9}) -} - -// HasAttrBlockSize returns whether Attr.BlockSize is respected by the -// kernel. -func (a Protocol) HasAttrBlockSize() bool { - return a.is79() -} - -// HasReadWriteFlags returns whether ReadRequest/WriteRequest -// fields Flags and FileFlags are valid. -func (a Protocol) HasReadWriteFlags() bool { - return a.is79() -} - -// HasGetattrFlags returns whether GetattrRequest field Flags is -// valid. -func (a Protocol) HasGetattrFlags() bool { - return a.is79() -} - -func (a Protocol) is710() bool { - return a.GE(Protocol{7, 10}) -} - -// HasOpenNonSeekable returns whether OpenResponse field Flags flag -// OpenNonSeekable is supported. -func (a Protocol) HasOpenNonSeekable() bool { - return a.is710() -} - -func (a Protocol) is712() bool { - return a.GE(Protocol{7, 12}) -} - -// HasUmask returns whether CreateRequest/MkdirRequest/MknodRequest -// field Umask is valid. -func (a Protocol) HasUmask() bool { - return a.is712() -} - -// HasInvalidate returns whether InvalidateNode/InvalidateEntry are -// supported. -func (a Protocol) HasInvalidate() bool { - return a.is712() -} diff --git a/vendor/bazil.org/fuse/unmount.go b/vendor/bazil.org/fuse/unmount.go deleted file mode 100644 index ffe3f155c4..0000000000 --- a/vendor/bazil.org/fuse/unmount.go +++ /dev/null @@ -1,6 +0,0 @@ -package fuse - -// Unmount tries to unmount the filesystem mounted at dir. -func Unmount(dir string) error { - return unmount(dir) -} diff --git a/vendor/bazil.org/fuse/unmount_linux.go b/vendor/bazil.org/fuse/unmount_linux.go deleted file mode 100644 index 088f0cfeee..0000000000 --- a/vendor/bazil.org/fuse/unmount_linux.go +++ /dev/null @@ -1,21 +0,0 @@ -package fuse - -import ( - "bytes" - "errors" - "os/exec" -) - -func unmount(dir string) error { - cmd := exec.Command("fusermount", "-u", dir) - output, err := cmd.CombinedOutput() - if err != nil { - if len(output) > 0 { - output = bytes.TrimRight(output, "\n") - msg := err.Error() + ": " + string(output) - err = errors.New(msg) - } - return err - } - return nil -} diff --git a/vendor/bazil.org/fuse/unmount_std.go b/vendor/bazil.org/fuse/unmount_std.go deleted file mode 100644 index d6efe276f6..0000000000 --- a/vendor/bazil.org/fuse/unmount_std.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build !linux - -package fuse - -import ( - "os" - "syscall" -) - -func unmount(dir string) error { - err := syscall.Unmount(dir, 0) - if err != nil { - err = &os.PathError{Op: "unmount", Path: dir, Err: err} - return err - } - return nil -} diff --git a/vendor/github.com/codahale/hdrhistogram/LICENSE b/vendor/github.com/codahale/hdrhistogram/LICENSE deleted file mode 100644 index f9835c241f..0000000000 --- a/vendor/github.com/codahale/hdrhistogram/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Coda Hale - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/codahale/hdrhistogram/README.md b/vendor/github.com/codahale/hdrhistogram/README.md deleted file mode 100644 index 614b197c3d..0000000000 --- a/vendor/github.com/codahale/hdrhistogram/README.md +++ /dev/null @@ -1,15 +0,0 @@ -hdrhistogram -============ - -[![Build Status](https://travis-ci.org/codahale/hdrhistogram.png?branch=master)](https://travis-ci.org/codahale/hdrhistogram) - -A pure Go implementation of the [HDR Histogram](https://github.com/HdrHistogram/HdrHistogram). - -> A Histogram that supports recording and analyzing sampled data value counts -> across a configurable integer value range with configurable value precision -> within the range. Value precision is expressed as the number of significant -> digits in the value recording, and provides control over value quantization -> behavior across the value range and the subsequent value resolution at any -> given level. - -For documentation, check [godoc](http://godoc.org/github.com/codahale/hdrhistogram). diff --git a/vendor/github.com/codahale/hdrhistogram/hdr.go b/vendor/github.com/codahale/hdrhistogram/hdr.go deleted file mode 100644 index c97842926d..0000000000 --- a/vendor/github.com/codahale/hdrhistogram/hdr.go +++ /dev/null @@ -1,564 +0,0 @@ -// Package hdrhistogram provides an implementation of Gil Tene's HDR Histogram -// data structure. The HDR Histogram allows for fast and accurate analysis of -// the extreme ranges of data with non-normal distributions, like latency. -package hdrhistogram - -import ( - "fmt" - "math" -) - -// A Bracket is a part of a cumulative distribution. -type Bracket struct { - Quantile float64 - Count, ValueAt int64 -} - -// A Snapshot is an exported view of a Histogram, useful for serializing them. -// A Histogram can be constructed from it by passing it to Import. -type Snapshot struct { - LowestTrackableValue int64 - HighestTrackableValue int64 - SignificantFigures int64 - Counts []int64 -} - -// A Histogram is a lossy data structure used to record the distribution of -// non-normally distributed data (like latency) with a high degree of accuracy -// and a bounded degree of precision. -type Histogram struct { - lowestTrackableValue int64 - highestTrackableValue int64 - unitMagnitude int64 - significantFigures int64 - subBucketHalfCountMagnitude int32 - subBucketHalfCount int32 - subBucketMask int64 - subBucketCount int32 - bucketCount int32 - countsLen int32 - totalCount int64 - counts []int64 -} - -// New returns a new Histogram instance capable of tracking values in the given -// range and with the given amount of precision. -func New(minValue, maxValue int64, sigfigs int) *Histogram { - if sigfigs < 1 || 5 < sigfigs { - panic(fmt.Errorf("sigfigs must be [1,5] (was %d)", sigfigs)) - } - - largestValueWithSingleUnitResolution := 2 * math.Pow10(sigfigs) - subBucketCountMagnitude := int32(math.Ceil(math.Log2(float64(largestValueWithSingleUnitResolution)))) - - subBucketHalfCountMagnitude := subBucketCountMagnitude - if subBucketHalfCountMagnitude < 1 { - subBucketHalfCountMagnitude = 1 - } - subBucketHalfCountMagnitude-- - - unitMagnitude := int32(math.Floor(math.Log2(float64(minValue)))) - if unitMagnitude < 0 { - unitMagnitude = 0 - } - - subBucketCount := int32(math.Pow(2, float64(subBucketHalfCountMagnitude)+1)) - - subBucketHalfCount := subBucketCount / 2 - subBucketMask := int64(subBucketCount-1) << uint(unitMagnitude) - - // determine exponent range needed to support the trackable value with no - // overflow: - smallestUntrackableValue := int64(subBucketCount) << uint(unitMagnitude) - bucketsNeeded := int32(1) - for smallestUntrackableValue < maxValue { - smallestUntrackableValue <<= 1 - bucketsNeeded++ - } - - bucketCount := bucketsNeeded - countsLen := (bucketCount + 1) * (subBucketCount / 2) - - return &Histogram{ - lowestTrackableValue: minValue, - highestTrackableValue: maxValue, - unitMagnitude: int64(unitMagnitude), - significantFigures: int64(sigfigs), - subBucketHalfCountMagnitude: subBucketHalfCountMagnitude, - subBucketHalfCount: subBucketHalfCount, - subBucketMask: subBucketMask, - subBucketCount: subBucketCount, - bucketCount: bucketCount, - countsLen: countsLen, - totalCount: 0, - counts: make([]int64, countsLen), - } -} - -// ByteSize returns an estimate of the amount of memory allocated to the -// histogram in bytes. -// -// N.B.: This does not take into account the overhead for slices, which are -// small, constant, and specific to the compiler version. -func (h *Histogram) ByteSize() int { - return 6*8 + 5*4 + len(h.counts)*8 -} - -// Merge merges the data stored in the given histogram with the receiver, -// returning the number of recorded values which had to be dropped. -func (h *Histogram) Merge(from *Histogram) (dropped int64) { - i := from.rIterator() - for i.next() { - v := i.valueFromIdx - c := i.countAtIdx - - if h.RecordValues(v, c) != nil { - dropped += c - } - } - - return -} - -// TotalCount returns total number of values recorded. -func (h *Histogram) TotalCount() int64 { - return h.totalCount -} - -// Max returns the approximate maximum recorded value. -func (h *Histogram) Max() int64 { - var max int64 - i := h.iterator() - for i.next() { - if i.countAtIdx != 0 { - max = i.highestEquivalentValue - } - } - return h.highestEquivalentValue(max) -} - -// Min returns the approximate minimum recorded value. -func (h *Histogram) Min() int64 { - var min int64 - i := h.iterator() - for i.next() { - if i.countAtIdx != 0 && min == 0 { - min = i.highestEquivalentValue - break - } - } - return h.lowestEquivalentValue(min) -} - -// Mean returns the approximate arithmetic mean of the recorded values. -func (h *Histogram) Mean() float64 { - if h.totalCount == 0 { - return 0 - } - var total int64 - i := h.iterator() - for i.next() { - if i.countAtIdx != 0 { - total += i.countAtIdx * h.medianEquivalentValue(i.valueFromIdx) - } - } - return float64(total) / float64(h.totalCount) -} - -// StdDev returns the approximate standard deviation of the recorded values. -func (h *Histogram) StdDev() float64 { - if h.totalCount == 0 { - return 0 - } - - mean := h.Mean() - geometricDevTotal := 0.0 - - i := h.iterator() - for i.next() { - if i.countAtIdx != 0 { - dev := float64(h.medianEquivalentValue(i.valueFromIdx)) - mean - geometricDevTotal += (dev * dev) * float64(i.countAtIdx) - } - } - - return math.Sqrt(geometricDevTotal / float64(h.totalCount)) -} - -// Reset deletes all recorded values and restores the histogram to its original -// state. -func (h *Histogram) Reset() { - h.totalCount = 0 - for i := range h.counts { - h.counts[i] = 0 - } -} - -// RecordValue records the given value, returning an error if the value is out -// of range. -func (h *Histogram) RecordValue(v int64) error { - return h.RecordValues(v, 1) -} - -// RecordCorrectedValue records the given value, correcting for stalls in the -// recording process. This only works for processes which are recording values -// at an expected interval (e.g., doing jitter analysis). Processes which are -// recording ad-hoc values (e.g., latency for incoming requests) can't take -// advantage of this. -func (h *Histogram) RecordCorrectedValue(v, expectedInterval int64) error { - if err := h.RecordValue(v); err != nil { - return err - } - - if expectedInterval <= 0 || v <= expectedInterval { - return nil - } - - missingValue := v - expectedInterval - for missingValue >= expectedInterval { - if err := h.RecordValue(missingValue); err != nil { - return err - } - missingValue -= expectedInterval - } - - return nil -} - -// RecordValues records n occurrences of the given value, returning an error if -// the value is out of range. -func (h *Histogram) RecordValues(v, n int64) error { - idx := h.countsIndexFor(v) - if idx < 0 || int(h.countsLen) <= idx { - return fmt.Errorf("value %d is too large to be recorded", v) - } - h.counts[idx] += n - h.totalCount += n - - return nil -} - -// ValueAtQuantile returns the recorded value at the given quantile (0..100). -func (h *Histogram) ValueAtQuantile(q float64) int64 { - if q > 100 { - q = 100 - } - - total := int64(0) - countAtPercentile := int64(((q / 100) * float64(h.totalCount)) + 0.5) - - i := h.iterator() - for i.next() { - total += i.countAtIdx - if total >= countAtPercentile { - return h.highestEquivalentValue(i.valueFromIdx) - } - } - - return 0 -} - -// CumulativeDistribution returns an ordered list of brackets of the -// distribution of recorded values. -func (h *Histogram) CumulativeDistribution() []Bracket { - var result []Bracket - - i := h.pIterator(1) - for i.next() { - result = append(result, Bracket{ - Quantile: i.percentile, - Count: i.countToIdx, - ValueAt: i.highestEquivalentValue, - }) - } - - return result -} - -// SignificantFigures returns the significant figures used to create the -// histogram -func (h *Histogram) SignificantFigures() int64 { - return h.significantFigures -} - -// LowestTrackableValue returns the lower bound on values that will be added -// to the histogram -func (h *Histogram) LowestTrackableValue() int64 { - return h.lowestTrackableValue -} - -// HighestTrackableValue returns the upper bound on values that will be added -// to the histogram -func (h *Histogram) HighestTrackableValue() int64 { - return h.highestTrackableValue -} - -// Histogram bar for plotting -type Bar struct { - From, To, Count int64 -} - -// Pretty print as csv for easy plotting -func (b Bar) String() string { - return fmt.Sprintf("%v, %v, %v\n", b.From, b.To, b.Count) -} - -// Distribution returns an ordered list of bars of the -// distribution of recorded values, counts can be normalized to a probability -func (h *Histogram) Distribution() (result []Bar) { - i := h.iterator() - for i.next() { - result = append(result, Bar{ - Count: i.countAtIdx, - From: h.lowestEquivalentValue(i.valueFromIdx), - To: i.highestEquivalentValue, - }) - } - - return result -} - -// Equals returns true if the two Histograms are equivalent, false if not. -func (h *Histogram) Equals(other *Histogram) bool { - switch { - case - h.lowestTrackableValue != other.lowestTrackableValue, - h.highestTrackableValue != other.highestTrackableValue, - h.unitMagnitude != other.unitMagnitude, - h.significantFigures != other.significantFigures, - h.subBucketHalfCountMagnitude != other.subBucketHalfCountMagnitude, - h.subBucketHalfCount != other.subBucketHalfCount, - h.subBucketMask != other.subBucketMask, - h.subBucketCount != other.subBucketCount, - h.bucketCount != other.bucketCount, - h.countsLen != other.countsLen, - h.totalCount != other.totalCount: - return false - default: - for i, c := range h.counts { - if c != other.counts[i] { - return false - } - } - } - return true -} - -// Export returns a snapshot view of the Histogram. This can be later passed to -// Import to construct a new Histogram with the same state. -func (h *Histogram) Export() *Snapshot { - return &Snapshot{ - LowestTrackableValue: h.lowestTrackableValue, - HighestTrackableValue: h.highestTrackableValue, - SignificantFigures: h.significantFigures, - Counts: append([]int64(nil), h.counts...), // copy - } -} - -// Import returns a new Histogram populated from the Snapshot data (which the -// caller must stop accessing). -func Import(s *Snapshot) *Histogram { - h := New(s.LowestTrackableValue, s.HighestTrackableValue, int(s.SignificantFigures)) - h.counts = s.Counts - totalCount := int64(0) - for i := int32(0); i < h.countsLen; i++ { - countAtIndex := h.counts[i] - if countAtIndex > 0 { - totalCount += countAtIndex - } - } - h.totalCount = totalCount - return h -} - -func (h *Histogram) iterator() *iterator { - return &iterator{ - h: h, - subBucketIdx: -1, - } -} - -func (h *Histogram) rIterator() *rIterator { - return &rIterator{ - iterator: iterator{ - h: h, - subBucketIdx: -1, - }, - } -} - -func (h *Histogram) pIterator(ticksPerHalfDistance int32) *pIterator { - return &pIterator{ - iterator: iterator{ - h: h, - subBucketIdx: -1, - }, - ticksPerHalfDistance: ticksPerHalfDistance, - } -} - -func (h *Histogram) sizeOfEquivalentValueRange(v int64) int64 { - bucketIdx := h.getBucketIndex(v) - subBucketIdx := h.getSubBucketIdx(v, bucketIdx) - adjustedBucket := bucketIdx - if subBucketIdx >= h.subBucketCount { - adjustedBucket++ - } - return int64(1) << uint(h.unitMagnitude+int64(adjustedBucket)) -} - -func (h *Histogram) valueFromIndex(bucketIdx, subBucketIdx int32) int64 { - return int64(subBucketIdx) << uint(int64(bucketIdx)+h.unitMagnitude) -} - -func (h *Histogram) lowestEquivalentValue(v int64) int64 { - bucketIdx := h.getBucketIndex(v) - subBucketIdx := h.getSubBucketIdx(v, bucketIdx) - return h.valueFromIndex(bucketIdx, subBucketIdx) -} - -func (h *Histogram) nextNonEquivalentValue(v int64) int64 { - return h.lowestEquivalentValue(v) + h.sizeOfEquivalentValueRange(v) -} - -func (h *Histogram) highestEquivalentValue(v int64) int64 { - return h.nextNonEquivalentValue(v) - 1 -} - -func (h *Histogram) medianEquivalentValue(v int64) int64 { - return h.lowestEquivalentValue(v) + (h.sizeOfEquivalentValueRange(v) >> 1) -} - -func (h *Histogram) getCountAtIndex(bucketIdx, subBucketIdx int32) int64 { - return h.counts[h.countsIndex(bucketIdx, subBucketIdx)] -} - -func (h *Histogram) countsIndex(bucketIdx, subBucketIdx int32) int32 { - bucketBaseIdx := (bucketIdx + 1) << uint(h.subBucketHalfCountMagnitude) - offsetInBucket := subBucketIdx - h.subBucketHalfCount - return bucketBaseIdx + offsetInBucket -} - -func (h *Histogram) getBucketIndex(v int64) int32 { - pow2Ceiling := bitLen(v | h.subBucketMask) - return int32(pow2Ceiling - int64(h.unitMagnitude) - - int64(h.subBucketHalfCountMagnitude+1)) -} - -func (h *Histogram) getSubBucketIdx(v int64, idx int32) int32 { - return int32(v >> uint(int64(idx)+int64(h.unitMagnitude))) -} - -func (h *Histogram) countsIndexFor(v int64) int { - bucketIdx := h.getBucketIndex(v) - subBucketIdx := h.getSubBucketIdx(v, bucketIdx) - return int(h.countsIndex(bucketIdx, subBucketIdx)) -} - -type iterator struct { - h *Histogram - bucketIdx, subBucketIdx int32 - countAtIdx, countToIdx, valueFromIdx int64 - highestEquivalentValue int64 -} - -func (i *iterator) next() bool { - if i.countToIdx >= i.h.totalCount { - return false - } - - // increment bucket - i.subBucketIdx++ - if i.subBucketIdx >= i.h.subBucketCount { - i.subBucketIdx = i.h.subBucketHalfCount - i.bucketIdx++ - } - - if i.bucketIdx >= i.h.bucketCount { - return false - } - - i.countAtIdx = i.h.getCountAtIndex(i.bucketIdx, i.subBucketIdx) - i.countToIdx += i.countAtIdx - i.valueFromIdx = i.h.valueFromIndex(i.bucketIdx, i.subBucketIdx) - i.highestEquivalentValue = i.h.highestEquivalentValue(i.valueFromIdx) - - return true -} - -type rIterator struct { - iterator - countAddedThisStep int64 -} - -func (r *rIterator) next() bool { - for r.iterator.next() { - if r.countAtIdx != 0 { - r.countAddedThisStep = r.countAtIdx - return true - } - } - return false -} - -type pIterator struct { - iterator - seenLastValue bool - ticksPerHalfDistance int32 - percentileToIteratorTo float64 - percentile float64 -} - -func (p *pIterator) next() bool { - if !(p.countToIdx < p.h.totalCount) { - if p.seenLastValue { - return false - } - - p.seenLastValue = true - p.percentile = 100 - - return true - } - - if p.subBucketIdx == -1 && !p.iterator.next() { - return false - } - - var done = false - for !done { - currentPercentile := (100.0 * float64(p.countToIdx)) / float64(p.h.totalCount) - if p.countAtIdx != 0 && p.percentileToIteratorTo <= currentPercentile { - p.percentile = p.percentileToIteratorTo - halfDistance := math.Trunc(math.Pow(2, math.Trunc(math.Log2(100.0/(100.0-p.percentileToIteratorTo)))+1)) - percentileReportingTicks := float64(p.ticksPerHalfDistance) * halfDistance - p.percentileToIteratorTo += 100.0 / percentileReportingTicks - return true - } - done = !p.iterator.next() - } - - return true -} - -func bitLen(x int64) (n int64) { - for ; x >= 0x8000; x >>= 16 { - n += 16 - } - if x >= 0x80 { - x >>= 8 - n += 8 - } - if x >= 0x8 { - x >>= 4 - n += 4 - } - if x >= 0x2 { - x >>= 2 - n += 2 - } - if x >= 0x1 { - n++ - } - return -} diff --git a/vendor/github.com/codahale/hdrhistogram/window.go b/vendor/github.com/codahale/hdrhistogram/window.go deleted file mode 100644 index dc43612a4b..0000000000 --- a/vendor/github.com/codahale/hdrhistogram/window.go +++ /dev/null @@ -1,45 +0,0 @@ -package hdrhistogram - -// A WindowedHistogram combines histograms to provide windowed statistics. -type WindowedHistogram struct { - idx int - h []Histogram - m *Histogram - - Current *Histogram -} - -// NewWindowed creates a new WindowedHistogram with N underlying histograms with -// the given parameters. -func NewWindowed(n int, minValue, maxValue int64, sigfigs int) *WindowedHistogram { - w := WindowedHistogram{ - idx: -1, - h: make([]Histogram, n), - m: New(minValue, maxValue, sigfigs), - } - - for i := range w.h { - w.h[i] = *New(minValue, maxValue, sigfigs) - } - w.Rotate() - - return &w -} - -// Merge returns a histogram which includes the recorded values from all the -// sections of the window. -func (w *WindowedHistogram) Merge() *Histogram { - w.m.Reset() - for _, h := range w.h { - w.m.Merge(&h) - } - return w.m -} - -// Rotate resets the oldest histogram and rotates it to be used as the current -// histogram. -func (w *WindowedHistogram) Rotate() { - w.idx++ - w.Current = &w.h[w.idx%len(w.h)] - w.Current.Reset() -} diff --git a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md deleted file mode 100644 index 28e2c24255..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md +++ /dev/null @@ -1,186 +0,0 @@ -Changes by Version -================== - -2.15.0 (unreleased) -------------------- - -- nothing yet - - -2.14.0 (2018-04-30) -------------------- - -- Support throttling for debug traces (#274) -- Remove dependency on Apache Thrift (#303) -- Remove dependency on tchannel (#295) (#294) -- Test with Go 1.9 (#298) - - -2.13.0 (2018-04-15) -------------------- - -- Use value receiver for config.NewTracer() (#283) -- Lock span during jaeger thrift conversion (#273) -- Fix the RemotelyControlledSampler so that it terminates go-routine on Close() (#260) -- Added support for client configuration via env vars (#275) -- Allow overriding sampler in the Config (#270) - - -2.12.0 (2018-03-14) -------------------- - -- Use lock when retrieving span.Context() (#268) -- Add Configuration support for custom Injector and Extractor (#263) - - -2.11.2 (2018-01-12) -------------------- - -- Add Gopkg.toml to allow using the lib with `dep` - - -2.11.1 (2018-01-03) -------------------- - -- Do not enqueue spans after Reporter is closed (#235, #245) -- Change default flush interval to 1sec (#243) - - -2.11.0 (2017-11-27) -------------------- - -- Normalize metric names and tags to be compatible with Prometheus (#222) - - -2.10.0 (2017-11-14) -------------------- - -- Support custom tracing headers (#176) -- Add BaggageRestrictionManager (#178) and RemoteBaggageRestrictionManager (#182) -- Do not coerce baggage keys to lower case (#196) -- Log span name when span cannot be reported (#198) -- Add option to enable gen128Bit for tracer (#193) and allow custom generator for high bits of trace ID (#219) - - -2.9.0 (2017-07-29) ------------------- - -- Pin thrift <= 0.10 (#179) -- Introduce a parallel interface ContribObserver (#159) - - -2.8.0 (2017-07-05) ------------------- - -- Drop `jaeger.` prefix from `jaeger.hostname` process-level tag -- Add options to set tracer tags - - -2.7.0 (2017-06-21) ------------------- - -- Fix rate limiter balance [#135](https://github.com/uber/jaeger-client-go/pull/135) [#140](https://github.com/uber/jaeger-client-go/pull/140) -- Default client to send Jaeger.thrift [#147](https://github.com/uber/jaeger-client-go/pull/147) -- Save baggage in span [#153](https://github.com/uber/jaeger-client-go/pull/153) -- Move reporter.queueLength to the top of the struct to guarantee 64bit alignment [#158](https://github.com/uber/jaeger-client-go/pull/158) -- Support HTTP transport with jaeger.thrift [#161](https://github.com/uber/jaeger-client-go/pull/161) - - -2.6.0 (2017-03-28) ------------------- - -- Add config option to initialize RPC Metrics feature - - -2.5.0 (2017-03-23) ------------------- - -- Split request latency metric by success/failure [#123](https://github.com/uber/jaeger-client-go/pull/123) -- Add mutex to adaptive sampler and fix race condition [#124](https://github.com/uber/jaeger-client-go/pull/124) -- Fix rate limiter panic [#125](https://github.com/uber/jaeger-client-go/pull/125) - - -2.4.0 (2017-03-21) ------------------- - -- Remove `_ms` suffix from request latency metric name [#121](https://github.com/uber/jaeger-client-go/pull/121) -- Rename all metrics to "request" and "http_request" and use tags for other dimensions [#121](https://github.com/uber/jaeger-client-go/pull/121) - - -2.3.0 (2017-03-20) ------------------- - -- Make Span type public to allow access to non-std methods for testing [#117](https://github.com/uber/jaeger-client-go/pull/117) -- Add a structured way to extract traces for logging with zap [#118](https://github.com/uber/jaeger-client-go/pull/118) - - -2.2.1 (2017-03-14) ------------------- - -- Fix panic caused by updating the remote sampler from adaptive sampler to any other sampler type (https://github.com/uber/jaeger-client-go/pull/111) - - -2.2.0 (2017-03-10) ------------------- - -- Introduce Observer and SpanObserver (https://github.com/uber/jaeger-client-go/pull/94) -- Add RPC metrics emitter as Observer/SpanObserver (https://github.com/uber/jaeger-client-go/pull/103) - - -2.1.2 (2017-02-27) -------------------- - -- Fix leaky bucket bug (https://github.com/uber/jaeger-client-go/pull/99) -- Fix zap logger Infof (https://github.com/uber/jaeger-client-go/pull/100) -- Add tracer initialization godoc examples - - -2.1.1 (2017-02-21) -------------------- - -- Fix inefficient usage of zap.Logger - - -2.1.0 (2017-02-17) -------------------- - -- Add adapter for zap.Logger (https://github.com/uber-go/zap) -- Move logging API to ./log/ package - - -2.0.0 (2017-02-08) -------------------- - -- Support Adaptive Sampling -- Support 128bit Trace IDs -- Change trace/span IDs from uint64 to strong types TraceID and SpanID -- Add Zipkin HTTP B3 Propagation format support #72 -- Rip out existing metrics and use github.com/uber/jaeger-lib/metrics -- Change API for tracer, reporter, sampler initialization - - -1.6.0 (2016-10-14) -------------------- - -- Add Zipkin HTTP transport -- Support external baggage via jaeger-baggage header -- Unpin Thrift version, keep to master - - -1.5.1 (2016-09-27) -------------------- - -- Relax dependency on opentracing to ^1 - - -1.5.0 (2016-09-27) -------------------- - -- Upgrade to opentracing-go 1.0 -- Support KV logging for Spans - - -1.4.0 (2016-09-14) -------------------- - -- Support debug traces via HTTP header "jaeger-debug-id" diff --git a/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md b/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md deleted file mode 100644 index 7cf014a51e..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md +++ /dev/null @@ -1,170 +0,0 @@ -# How to Contribute to Jaeger - -We'd love your help! - -Jaeger is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub -pull requests. This document outlines some of the conventions on development -workflow, commit message formatting, contact points and other resources to make -it easier to get your contribution accepted. - -We gratefully welcome improvements to documentation as well as to code. - -# Certificate of Origin - -By contributing to this project you agree to the [Developer Certificate of -Origin](https://developercertificate.org/) (DCO). This document was created -by the Linux Kernel community and is a simple statement that you, as a -contributor, have the legal right to make the contribution. See the [DCO](DCO) -file for details. - -## Getting Started - -This library uses [glide](https://github.com/Masterminds/glide) to manage dependencies. - -To get started, make sure you clone the Git repository into the correct location -`github.com/uber/jaeger-client-go` relative to `$GOPATH`: - -``` -mkdir -p $GOPATH/src/github.com/uber -cd $GOPATH/src/github.com/uber -git clone git@github.com:jaegertracing/jaeger-client-go.git jaeger-client-go -cd jaeger-client-go -``` - -Then install dependencies and run the tests: - -``` -git submodule update --init --recursive -glide install -make test -``` - -## Imports grouping - -This projects follows the following pattern for grouping imports in Go files: - * imports from standard library - * imports from other projects - * imports from `jaeger-client-go` project - -For example: - -```go -import ( - "fmt" - - "github.com/uber/jaeger-lib/metrics" - "go.uber.org/zap" - - "github.com/uber/jaeger-client-go/config" -) -``` - -## Making A Change - -*Before making any significant changes, please [open an -issue](https://github.com/jaegertracing/jaeger-client-go/issues).* Discussing your proposed -changes ahead of time will make the contribution process smooth for everyone. - -Once we've discussed your changes and you've got your code ready, make sure -that tests are passing (`make test` or `make cover`) and open your PR. Your -pull request is most likely to be accepted if it: - -* Includes tests for new functionality. -* Follows the guidelines in [Effective - Go](https://golang.org/doc/effective_go.html) and the [Go team's common code - review comments](https://github.com/golang/go/wiki/CodeReviewComments). -* Has a [good commit message](https://chris.beams.io/posts/git-commit/): - * Separate subject from body with a blank line - * Limit the subject line to 50 characters - * Capitalize the subject line - * Do not end the subject line with a period - * Use the imperative mood in the subject line - * Wrap the body at 72 characters - * Use the body to explain _what_ and _why_ instead of _how_ -* Each commit must be signed by the author ([see below](#sign-your-work)). - -## License - -By contributing your code, you agree to license your contribution under the terms -of the [Apache License](LICENSE). - -If you are adding a new file it should have a header like below. The easiest -way to add such header is to run `make fmt`. - -``` -// Copyright (c) 2017 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -``` - -## Sign your work - -The sign-off is a simple line at the end of the explanation for the -patch, which certifies that you wrote it or otherwise have the right to -pass it on as an open-source patch. The rules are pretty simple: if you -can certify the below (from -[developercertificate.org](http://developercertificate.org/)): - -``` -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. -``` - -then you just add a line to every git commit message: - - Signed-off-by: Joe Smith - -using your real name (sorry, no pseudonyms or anonymous contributions.) - -You can add the sign off when creating the git commit via `git commit -s`. - -If you want this to be automatic you can set up some aliases: - -``` -git config --add alias.amend "commit -s --amend" -git config --add alias.c "commit -s" -``` diff --git a/vendor/github.com/uber/jaeger-client-go/DCO b/vendor/github.com/uber/jaeger-client-go/DCO deleted file mode 100644 index 068953d4bd..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/DCO +++ /dev/null @@ -1,37 +0,0 @@ -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. - diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.lock b/vendor/github.com/uber/jaeger-client-go/Gopkg.lock deleted file mode 100644 index ec054c6ed6..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/Gopkg.lock +++ /dev/null @@ -1,164 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - branch = "master" - name = "github.com/beorn7/perks" - packages = ["quantile"] - revision = "3a771d992973f24aa725d07868b467d1ddfceafb" - -[[projects]] - branch = "master" - name = "github.com/codahale/hdrhistogram" - packages = ["."] - revision = "3a0bb77429bd3a61596f5e8a3172445844342120" - -[[projects]] - branch = "master" - name = "github.com/crossdock/crossdock-go" - packages = [ - ".", - "assert", - "require" - ] - revision = "049aabb0122b03bc9bd30cab8f3f91fb60166361" - -[[projects]] - name = "github.com/davecgh/go-spew" - packages = ["spew"] - revision = "346938d642f2ec3594ed81d874461961cd0faa76" - version = "v1.1.0" - -[[projects]] - name = "github.com/golang/protobuf" - packages = ["proto"] - revision = "925541529c1fa6821df4e44ce2723319eb2be768" - version = "v1.0.0" - -[[projects]] - name = "github.com/matttproud/golang_protobuf_extensions" - packages = ["pbutil"] - revision = "3247c84500bff8d9fb6d579d800f20b3e091582c" - version = "v1.0.0" - -[[projects]] - name = "github.com/opentracing/opentracing-go" - packages = [ - ".", - "ext", - "log" - ] - revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" - version = "v1.0.2" - -[[projects]] - name = "github.com/pkg/errors" - packages = ["."] - revision = "645ef00459ed84a119197bfb8d8205042c6df63d" - version = "v0.8.0" - -[[projects]] - name = "github.com/pmezard/go-difflib" - packages = ["difflib"] - revision = "792786c7400a136282c1664665ae0a8db921c6c2" - version = "v1.0.0" - -[[projects]] - name = "github.com/prometheus/client_golang" - packages = ["prometheus"] - revision = "c5b7fccd204277076155f10851dad72b76a49317" - version = "v0.8.0" - -[[projects]] - branch = "master" - name = "github.com/prometheus/client_model" - packages = ["go"] - revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" - -[[projects]] - branch = "master" - name = "github.com/prometheus/common" - packages = [ - "expfmt", - "internal/bitbucket.org/ww/goautoneg", - "model" - ] - revision = "d811d2e9bf898806ecfb6ef6296774b13ffc314c" - -[[projects]] - branch = "master" - name = "github.com/prometheus/procfs" - packages = [ - ".", - "internal/util", - "nfs", - "xfs" - ] - revision = "8b1c2da0d56deffdbb9e48d4414b4e674bd8083e" - -[[projects]] - name = "github.com/stretchr/testify" - packages = [ - "assert", - "require", - "suite" - ] - revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" - version = "v1.2.1" - -[[projects]] - name = "github.com/uber-go/atomic" - packages = ["."] - revision = "8474b86a5a6f79c443ce4b2992817ff32cf208b8" - version = "v1.3.1" - -[[projects]] - name = "github.com/uber/jaeger-lib" - packages = [ - "metrics", - "metrics/prometheus", - "metrics/testutils" - ] - revision = "4267858c0679cd4e47cefed8d7f70fd386cfb567" - version = "v1.4.0" - -[[projects]] - name = "go.uber.org/atomic" - packages = ["."] - revision = "54f72d32435d760d5604f17a82e2435b28dc4ba5" - version = "v1.3.0" - -[[projects]] - name = "go.uber.org/multierr" - packages = ["."] - revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" - version = "v1.1.0" - -[[projects]] - name = "go.uber.org/zap" - packages = [ - ".", - "buffer", - "internal/bufferpool", - "internal/color", - "internal/exit", - "zapcore" - ] - revision = "eeedf312bc6c57391d84767a4cd413f02a917974" - version = "v1.8.0" - -[[projects]] - branch = "master" - name = "golang.org/x/net" - packages = [ - "context", - "context/ctxhttp" - ] - revision = "5f9ae10d9af5b1c89ae6904293b14b064d4ada23" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "f9dcfaf37a785c5dac1e20c29605eda29a83ba9c6f8842e92960dc94c8c4ff80" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.toml b/vendor/github.com/uber/jaeger-client-go/Gopkg.toml deleted file mode 100644 index baf7a6bdf7..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/Gopkg.toml +++ /dev/null @@ -1,27 +0,0 @@ -[[constraint]] - name = "github.com/crossdock/crossdock-go" - branch = "master" - -[[constraint]] - name = "github.com/opentracing/opentracing-go" - version = "^1" - -[[constraint]] - name = "github.com/prometheus/client_golang" - version = "0.8.0" - -[[constraint]] - name = "github.com/stretchr/testify" - version = "^1.1.3" - -[[constraint]] - name = "github.com/uber-go/atomic" - version = "^1" - -[[constraint]] - name = "github.com/uber/jaeger-lib" - version = "^1.3" - -[[constraint]] - name = "go.uber.org/zap" - version = "^1" diff --git a/vendor/github.com/uber/jaeger-client-go/LICENSE b/vendor/github.com/uber/jaeger-client-go/LICENSE deleted file mode 100644 index 261eeb9e9f..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/uber/jaeger-client-go/Makefile b/vendor/github.com/uber/jaeger-client-go/Makefile deleted file mode 100644 index 601cc65148..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/Makefile +++ /dev/null @@ -1,117 +0,0 @@ -PROJECT_ROOT=github.com/uber/jaeger-client-go -PACKAGES := $(shell glide novendor | grep -v -e ./thrift-gen/... -e ./thrift/...) -# all .go files that don't exist in hidden directories -ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen -e ./thrift/ \ - -e ".*/\..*" \ - -e ".*/_.*" \ - -e ".*/mocks.*") - --include crossdock/rules.mk - -export GO15VENDOREXPERIMENT=1 - -RACE=-race -GOTEST=go test -v $(RACE) -GOLINT=golint -GOVET=go vet -GOFMT=gofmt -FMT_LOG=fmt.log -LINT_LOG=lint.log - -THRIFT_VER=0.9.3 -THRIFT_IMG=thrift:$(THRIFT_VER) -THRIFT=docker run -v "${PWD}:/data" $(THRIFT_IMG) thrift -THRIFT_GO_ARGS=thrift_import="github.com/apache/thrift/lib/go/thrift" -THRIFT_GEN_DIR=thrift-gen - -PASS=$(shell printf "\033[32mPASS\033[0m") -FAIL=$(shell printf "\033[31mFAIL\033[0m") -COLORIZE=sed ''/PASS/s//$(PASS)/'' | sed ''/FAIL/s//$(FAIL)/'' - -.DEFAULT_GOAL := test-and-lint - -.PHONY: test-and-lint -test-and-lint: test fmt lint - -.PHONY: test -test: - bash -c "set -e; set -o pipefail; $(GOTEST) $(PACKAGES) | $(COLORIZE)" - -.PHONY: fmt -fmt: - $(GOFMT) -e -s -l -w $(ALL_SRC) - ./scripts/updateLicenses.sh - -.PHONY: lint -lint: - $(GOVET) $(PACKAGES) - @cat /dev/null > $(LINT_LOG) - @$(foreach pkg, $(PACKAGES), $(GOLINT) $(pkg) | grep -v crossdock/thrift >> $(LINT_LOG) || true;) - @[ ! -s "$(LINT_LOG)" ] || (echo "Lint Failures" | cat - $(LINT_LOG) && false) - @$(GOFMT) -e -s -l $(ALL_SRC) > $(FMT_LOG) - ./scripts/updateLicenses.sh >> $(FMT_LOG) - @[ ! -s "$(FMT_LOG)" ] || (echo "go fmt or license check failures, run 'make fmt'" | cat - $(FMT_LOG) && false) - - -.PHONY: install -install: - glide --version || go get github.com/Masterminds/glide -ifeq ($(USE_DEP),true) - dep ensure -else - glide install -endif - - -.PHONY: cover -cover: - ./scripts/cover.sh $(shell go list $(PACKAGES)) - go tool cover -html=cover.out -o cover.html - - -# This is not part of the regular test target because we don't want to slow it -# down. -.PHONY: test-examples -test-examples: - make -C examples - -# TODO at the moment we're not generating tchan_*.go files -thrift: idl-submodule thrift-image - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/agent.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/sampling.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/jaeger.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/zipkincore.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/baggage.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/crossdock/thrift/ /data/idl/thrift/crossdock/tracetest.thrift - sed -i '' 's|"zipkincore"|"$(PROJECT_ROOT)/thrift-gen/zipkincore"|g' $(THRIFT_GEN_DIR)/agent/*.go - sed -i '' 's|"jaeger"|"$(PROJECT_ROOT)/thrift-gen/jaeger"|g' $(THRIFT_GEN_DIR)/agent/*.go - sed -i '' 's|"github.com/apache/thrift/lib/go/thrift"|"github.com/uber/jaeger-client-go/thrift"|g' \ - $(THRIFT_GEN_DIR)/*/*.go crossdock/thrift/tracetest/*.go - rm -rf thrift-gen/*/*-remote - rm -rf crossdock/thrift/*/*-remote - rm -rf thrift-gen/jaeger/collector.go - -idl-submodule: - git submodule init - git submodule update - -thrift-image: - $(THRIFT) -version - -.PHONY: install-dep-ci -install-dep-ci: - - curl -L -s https://github.com/golang/dep/releases/download/v0.3.2/dep-linux-amd64 -o $$GOPATH/bin/dep - - chmod +x $$GOPATH/bin/dep - -.PHONY: install-ci -install-ci: install-dep-ci install - go get github.com/wadey/gocovmerge - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover - go get github.com/golang/lint/golint - -.PHONY: test-ci -test-ci: - @./scripts/cover.sh $(shell go list $(PACKAGES)) - make lint - diff --git a/vendor/github.com/uber/jaeger-client-go/README.md b/vendor/github.com/uber/jaeger-client-go/README.md deleted file mode 100644 index 16b04454e1..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/README.md +++ /dev/null @@ -1,260 +0,0 @@ -[![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![OpenTracing 1.0 Enabled][ot-img]][ot-url] - -# Jaeger Bindings for Go OpenTracing API - -Instrumentation library that implements an -[OpenTracing](http://opentracing.io) Tracer for Jaeger (https://jaegertracing.io). - -**IMPORTANT**: The library's import path is based on its original location under `github.com/uber`. Do not try to import it as `github.com/jaegertracing`, it will not compile. We might revisit this in the next major release. - * :white_check_mark: `import "github.com/uber/jaeger-client-go"` - * :x: `import "github.com/jaegertracing/jaeger-client-go"` - -## How to Contribute - -Please see [CONTRIBUTING.md](CONTRIBUTING.md). - -## Installation - -We recommended using a dependency manager like [glide](https://github.com/Masterminds/glide) -and [semantic versioning](http://semver.org/) when including this library into an application. -For example, Jaeger backend imports this library like this: - -```yaml -- package: github.com/uber/jaeger-client-go - version: ^2.7.0 -``` - -If you instead want to use the latest version in `master`, you can pull it via `go get`. -Note that during `go get` you may see build errors due to incompatible dependencies, which is why -we recommend using semantic versions for dependencies. The error may be fixed by running -`make install` (it will install `glide` if you don't have it): - -```shell -go get -u github.com/uber/jaeger-client-go/ -cd $GOPATH/src/github.com/uber/jaeger-client-go/ -git submodule update --init --recursive -make install -``` - -## Initialization - -See tracer initialization examples in [godoc](https://godoc.org/github.com/uber/jaeger-client-go/config#pkg-examples) -and [config/example_test.go](./config/example_test.go). - -### Environment variables - -The tracer can be initialized with values coming from environment variables. None of the env vars are required -and all of them can be overriden via direct setting of the property on the configuration object. - -Property| Description ---- | --- -JAEGER_SERVICE_NAME | The service name -JAEGER_AGENT_HOST | The hostname for communicating with agent via UDP -JAEGER_AGENT_PORT | The port for communicating with agent via UDP -JAEGER_REPORTER_LOG_SPANS | Whether the reporter should also log the spans -JAEGER_REPORTER_MAX_QUEUE_SIZE | The reporter's maximum queue size -JAEGER_REPORTER_FLUSH_INTERVAL | The reporter's flush interval (ms) -JAEGER_SAMPLER_TYPE | The sampler type -JAEGER_SAMPLER_PARAM | The sampler parameter (number) -JAEGER_SAMPLER_MANAGER_HOST_PORT | The host name and port when using the remote controlled sampler -JAEGER_SAMPLER_MAX_OPERATIONS | The maximum number of operations that the sampler will keep track of -JAEGER_SAMPLER_REFRESH_INTERVAL | How often the remotely controlled sampler will poll jaeger-agent for the appropriate sampling strategy -JAEGER_TAGS | A comma separated list of `name = value` tracer level tags, which get added to all reported spans. The value can also refer to an environment variable using the format `${envVarName:default}`, where the `:default` is optional, and identifies a value to be used if the environment variable cannot be found -JAEGER_DISABLED | Whether the tracer is disabled or not. If true, the default `opentracing.NoopTracer` is used. -JAEGER_RPC_METRICS | Whether to store RPC metrics - -### Closing the tracer via `io.Closer` - -The constructor function for Jaeger Tracer returns the tracer itself and an `io.Closer` instance. -It is recommended to structure your `main()` so that it calls the `Close()` function on the closer -before exiting, e.g. - -```go -tracer, closer, err := cfg.NewTracer(...) -defer closer.Close() -``` - -This is especially useful for command-line tools that enable tracing, as well as -for the long-running apps that support graceful shutdown. For example, if your deployment -system sends SIGTERM instead of killing the process and you trap that signal to do a graceful -exit, then having `defer closer.Closer()` ensures that all buffered spans are flushed. - -### Metrics & Monitoring - -The tracer emits a number of different metrics, defined in -[metrics.go](metrics.go). The monitoring backend is expected to support -tag-based metric names, e.g. instead of `statsd`-style string names -like `counters.my-service.jaeger.spans.started.sampled`, the metrics -are defined by a short name and a collection of key/value tags, for -example: `name:jaeger.traces, state:started, sampled:y`. See [metrics.go](./metrics.go) -file for the full list and descriptions of emitted metrics. - -The monitoring backend is represented by the `metrics.Factory` interface from package -[`"github.com/uber/jaeger-lib/metrics"`](https://github.com/jaegertracing/jaeger-lib/tree/master/metrics). An implementation -of that interface can be passed as an option to either the Configuration object or the Tracer -constructor, for example: - -```go -import ( - "github.com/uber/jaeger-client-go/config" - "github.com/uber/jaeger-lib/metrics/prometheus" -) - - metricsFactory := prometheus.New() - tracer, closer, err := config.Configuration{ - ServiceName: "your-service-name", - }.NewTracer( - config.Metrics(metricsFactory), - ) -``` - -By default, a no-op `metrics.NullFactory` is used. - -### Logging - -The tracer can be configured with an optional logger, which will be -used to log communication errors, or log spans if a logging reporter -option is specified in the configuration. The logging API is abstracted -by the [Logger](logger.go) interface. A logger instance implementing -this interface can be set on the `Config` object before calling the -`New` method. - -Besides the [zap](https://github.com/uber-go/zap) implementation -bundled with this package there is also a [go-kit](https://github.com/go-kit/kit) -one in the [jaeger-lib](https://github.com/jaegertracing/jaeger-lib) repository. - -## Instrumentation for Tracing - -Since this tracer is fully compliant with OpenTracing API 1.0, -all code instrumentation should only use the API itself, as described -in the [opentracing-go](https://github.com/opentracing/opentracing-go) documentation. - -## Features - -### Reporters - -A "reporter" is a component that receives the finished spans and reports -them to somewhere. Under normal circumstances, the Tracer -should use the default `RemoteReporter`, which sends the spans out of -process via configurable "transport". For testing purposes, one can -use an `InMemoryReporter` that accumulates spans in a buffer and -allows to retrieve them for later verification. Also available are -`NullReporter`, a no-op reporter that does nothing, a `LoggingReporter` -which logs all finished spans using their `String()` method, and a -`CompositeReporter` that can be used to combine more than one reporter -into one, e.g. to attach a logging reporter to the main remote reporter. - -### Span Reporting Transports - -The remote reporter uses "transports" to actually send the spans out -of process. Currently the supported transports include: - * [Jaeger Thrift](https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/agent.thrift) over UDP or HTTP, - * [Zipkin Thrift](https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/zipkincore.thrift) over HTTP. - -### Sampling - -The tracer does not record all spans, but only those that have the -sampling bit set in the `flags`. When a new trace is started and a new -unique ID is generated, a sampling decision is made whether this trace -should be sampled. The sampling decision is propagated to all downstream -calls via the `flags` field of the trace context. The following samplers -are available: - 1. `RemotelyControlledSampler` uses one of the other simpler samplers - and periodically updates it by polling an external server. This - allows dynamic control of the sampling strategies. - 1. `ConstSampler` always makes the same sampling decision for all - trace IDs. it can be configured to either sample all traces, or - to sample none. - 1. `ProbabilisticSampler` uses a fixed sampling rate as a probability - for a given trace to be sampled. The actual decision is made by - comparing the trace ID with a random number multiplied by the - sampling rate. - 1. `RateLimitingSampler` can be used to allow only a certain fixed - number of traces to be sampled per second. - -### Baggage Injection - -The OpenTracing spec allows for [baggage][baggage], which are key value pairs that are added -to the span context and propagated throughout the trace. An external process can inject baggage -by setting the special HTTP Header `jaeger-baggage` on a request: - -```sh -curl -H "jaeger-baggage: key1=value1, key2=value2" http://myhost.com -``` - -Baggage can also be programatically set inside your service: - -```go -if span := opentracing.SpanFromContext(ctx); span != nil { - span.SetBaggageItem("key", "value") -} -``` - -Another service downstream of that can retrieve the baggage in a similar way: - -```go -if span := opentracing.SpanFromContext(ctx); span != nil { - val := span.BaggageItem("key") - println(val) -} -``` - -### Debug Traces (Forced Sampling) - -#### Programmatically - -The OpenTracing API defines a `sampling.priority` standard tag that -can be used to affect the sampling of a span and its children: - -```go -import ( - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" -) - -span := opentracing.SpanFromContext(ctx) -ext.SamplingPriority.Set(span, 1) -``` - -#### Via HTTP Headers - -Jaeger Tracer also understands a special HTTP Header `jaeger-debug-id`, -which can be set in the incoming request, e.g. - -```sh -curl -H "jaeger-debug-id: some-correlation-id" http://myhost.com -``` - -When Jaeger sees this header in the request that otherwise has no -tracing context, it ensures that the new trace started for this -request will be sampled in the "debug" mode (meaning it should survive -all downsampling that might happen in the collection pipeline), and the -root span will have a tag as if this statement was executed: - -```go -span.SetTag("jaeger-debug-id", "some-correlation-id") -``` - -This allows using Jaeger UI to find the trace by this tag. - -### Zipkin HTTP B3 compatible header propagation - -Jaeger Tracer supports Zipkin B3 Propagation HTTP headers, which are used -by a lot of Zipkin tracers. This means that you can use Jaeger in conjunction with e.g. [these OpenZipkin tracers](https://github.com/openzipkin). - -However it is not the default propagation format, see [here](zipkin/README.md#NewZipkinB3HTTPHeaderPropagator) how to set it up. - -## License - -[Apache 2.0 License](LICENSE). - - -[doc-img]: https://godoc.org/github.com/uber/jaeger-client-go?status.svg -[doc]: https://godoc.org/github.com/uber/jaeger-client-go -[ci-img]: https://travis-ci.org/jaegertracing/jaeger-client-go.svg?branch=master -[ci]: https://travis-ci.org/jaegertracing/jaeger-client-go -[cov-img]: https://codecov.io/gh/jaegertracing/jaeger-client-go/branch/master/graph/badge.svg -[cov]: https://codecov.io/gh/jaegertracing/jaeger-client-go -[ot-img]: https://img.shields.io/badge/OpenTracing--1.0-enabled-blue.svg -[ot-url]: http://opentracing.io -[baggage]: https://github.com/opentracing/specification/blob/master/specification.md#set-a-baggage-item diff --git a/vendor/github.com/uber/jaeger-client-go/RELEASE.md b/vendor/github.com/uber/jaeger-client-go/RELEASE.md deleted file mode 100644 index 115e49ab8a..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/RELEASE.md +++ /dev/null @@ -1,11 +0,0 @@ -# Release Process - -1. Create a PR "Preparing for release X.Y.Z" against master branch - * Alter CHANGELOG.md from ` (unreleased)` to ` (YYYY-MM-DD)` - * Update `JaegerClientVersion` in constants.go to `Go-X.Y.Z` -2. Create a release "Release X.Y.Z" on Github - * Create Tag `vX.Y.Z` - * Copy CHANGELOG.md into the release notes -3. Create a PR "Back to development" against master branch - * Add ` (unreleased)` to CHANGELOG.md - * Update `JaegerClientVersion` in constants.go to `Go-dev` diff --git a/vendor/github.com/uber/jaeger-client-go/baggage_setter.go b/vendor/github.com/uber/jaeger-client-go/baggage_setter.go deleted file mode 100644 index 1037ca0e86..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/baggage_setter.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "github.com/opentracing/opentracing-go/log" - - "github.com/uber/jaeger-client-go/internal/baggage" -) - -// baggageSetter is an actor that can set a baggage value on a Span given certain -// restrictions (eg. maxValueLength). -type baggageSetter struct { - restrictionManager baggage.RestrictionManager - metrics *Metrics -} - -func newBaggageSetter(restrictionManager baggage.RestrictionManager, metrics *Metrics) *baggageSetter { - return &baggageSetter{ - restrictionManager: restrictionManager, - metrics: metrics, - } -} - -// (NB) span should hold the lock before making this call -func (s *baggageSetter) setBaggage(span *Span, key, value string) { - var truncated bool - var prevItem string - restriction := s.restrictionManager.GetRestriction(span.serviceName(), key) - if !restriction.KeyAllowed() { - s.logFields(span, key, value, prevItem, truncated, restriction.KeyAllowed()) - s.metrics.BaggageUpdateFailure.Inc(1) - return - } - if len(value) > restriction.MaxValueLength() { - truncated = true - value = value[:restriction.MaxValueLength()] - s.metrics.BaggageTruncate.Inc(1) - } - prevItem = span.context.baggage[key] - s.logFields(span, key, value, prevItem, truncated, restriction.KeyAllowed()) - span.context = span.context.WithBaggageItem(key, value) - s.metrics.BaggageUpdateSuccess.Inc(1) -} - -func (s *baggageSetter) logFields(span *Span, key, value, prevItem string, truncated, valid bool) { - if !span.context.IsSampled() { - return - } - fields := []log.Field{ - log.String("event", "baggage"), - log.String("key", key), - log.String("value", value), - } - if prevItem != "" { - fields = append(fields, log.String("override", "true")) - } - if truncated { - fields = append(fields, log.String("truncated", "true")) - } - if !valid { - fields = append(fields, log.String("invalid", "true")) - } - span.logFieldsNoLocking(fields...) -} diff --git a/vendor/github.com/uber/jaeger-client-go/config/config.go b/vendor/github.com/uber/jaeger-client-go/config/config.go deleted file mode 100644 index 1eb2967785..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/config/config.go +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright (c) 2017-2018 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/opentracing/opentracing-go" - - "github.com/uber/jaeger-client-go" - "github.com/uber/jaeger-client-go/internal/baggage/remote" - throttler "github.com/uber/jaeger-client-go/internal/throttler/remote" - "github.com/uber/jaeger-client-go/rpcmetrics" -) - -const defaultSamplingProbability = 0.001 - -// Configuration configures and creates Jaeger Tracer -type Configuration struct { - // ServiceName specifies the service name to use on the tracer. - // Can be provided via environment variable named JAEGER_SERVICE_NAME - ServiceName string `yaml:"serviceName"` - - // Disabled can be provided via environment variable named JAEGER_DISABLED - Disabled bool `yaml:"disabled"` - - // RPCMetrics can be provided via environment variable named JAEGER_RPC_METRICS - RPCMetrics bool `yaml:"rpc_metrics"` - - // Tags can be provided via environment variable named JAEGER_TAGS - Tags []opentracing.Tag `yaml:"tags"` - - Sampler *SamplerConfig `yaml:"sampler"` - Reporter *ReporterConfig `yaml:"reporter"` - Headers *jaeger.HeadersConfig `yaml:"headers"` - BaggageRestrictions *BaggageRestrictionsConfig `yaml:"baggage_restrictions"` - Throttler *ThrottlerConfig `yaml:"throttler"` -} - -// SamplerConfig allows initializing a non-default sampler. All fields are optional. -type SamplerConfig struct { - // Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote - // Can be set by exporting an environment variable named JAEGER_SAMPLER_TYPE - Type string `yaml:"type"` - - // Param is a value passed to the sampler. - // Valid values for Param field are: - // - for "const" sampler, 0 or 1 for always false/true respectively - // - for "probabilistic" sampler, a probability between 0 and 1 - // - for "rateLimiting" sampler, the number of spans per second - // - for "remote" sampler, param is the same as for "probabilistic" - // and indicates the initial sampling rate before the actual one - // is received from the mothership. - // Can be set by exporting an environment variable named JAEGER_SAMPLER_PARAM - Param float64 `yaml:"param"` - - // SamplingServerURL is the address of jaeger-agent's HTTP sampling server - // Can be set by exporting an environment variable named JAEGER_SAMPLER_MANAGER_HOST_PORT - SamplingServerURL string `yaml:"samplingServerURL"` - - // MaxOperations is the maximum number of operations that the sampler - // will keep track of. If an operation is not tracked, a default probabilistic - // sampler will be used rather than the per operation specific sampler. - // Can be set by exporting an environment variable named JAEGER_SAMPLER_MAX_OPERATIONS - MaxOperations int `yaml:"maxOperations"` - - // SamplingRefreshInterval controls how often the remotely controlled sampler will poll - // jaeger-agent for the appropriate sampling strategy. - // Can be set by exporting an environment variable named JAEGER_SAMPLER_REFRESH_INTERVAL - SamplingRefreshInterval time.Duration `yaml:"samplingRefreshInterval"` -} - -// ReporterConfig configures the reporter. All fields are optional. -type ReporterConfig struct { - // QueueSize controls how many spans the reporter can keep in memory before it starts dropping - // new spans. The queue is continuously drained by a background go-routine, as fast as spans - // can be sent out of process. - // Can be set by exporting an environment variable named JAEGER_REPORTER_MAX_QUEUE_SIZE - QueueSize int `yaml:"queueSize"` - - // BufferFlushInterval controls how often the buffer is force-flushed, even if it's not full. - // It is generally not useful, as it only matters for very low traffic services. - // Can be set by exporting an environment variable named JAEGER_REPORTER_FLUSH_INTERVAL - BufferFlushInterval time.Duration - - // LogSpans, when true, enables LoggingReporter that runs in parallel with the main reporter - // and logs all submitted spans. Main Configuration.Logger must be initialized in the code - // for this option to have any effect. - // Can be set by exporting an environment variable named JAEGER_REPORTER_LOG_SPANS - LogSpans bool `yaml:"logSpans"` - - // LocalAgentHostPort instructs reporter to send spans to jaeger-agent at this address - // Can be set by exporting an environment variable named JAEGER_AGENT_HOST / JAEGER_AGENT_PORT - LocalAgentHostPort string `yaml:"localAgentHostPort"` -} - -// BaggageRestrictionsConfig configures the baggage restrictions manager which can be used to whitelist -// certain baggage keys. All fields are optional. -type BaggageRestrictionsConfig struct { - // DenyBaggageOnInitializationFailure controls the startup failure mode of the baggage restriction - // manager. If true, the manager will not allow any baggage to be written until baggage restrictions have - // been retrieved from jaeger-agent. If false, the manager wil allow any baggage to be written until baggage - // restrictions have been retrieved from jaeger-agent. - DenyBaggageOnInitializationFailure bool `yaml:"denyBaggageOnInitializationFailure"` - - // HostPort is the hostPort of jaeger-agent's baggage restrictions server - HostPort string `yaml:"hostPort"` - - // RefreshInterval controls how often the baggage restriction manager will poll - // jaeger-agent for the most recent baggage restrictions. - RefreshInterval time.Duration `yaml:"refreshInterval"` -} - -// ThrottlerConfig configures the throttler which can be used to throttle the -// rate at which the client may send debug requests. -type ThrottlerConfig struct { - // HostPort of jaeger-agent's credit server. - HostPort string `yaml:"hostPort"` - - // RefreshInterval controls how often the throttler will poll jaeger-agent - // for more throttling credits. - RefreshInterval time.Duration `yaml:"refreshInterval"` - - // SynchronousInitialization determines whether or not the throttler should - // synchronously fetch credits from the agent when an operation is seen for - // the first time. This should be set to true if the client will be used by - // a short lived service that needs to ensure that credits are fetched - // upfront such that sampling or throttling occurs. - SynchronousInitialization bool `yaml:"synchronousInitialization"` -} - -type nullCloser struct{} - -func (*nullCloser) Close() error { return nil } - -// New creates a new Jaeger Tracer, and a closer func that can be used to flush buffers -// before shutdown. -// -// Deprecated: use NewTracer() function -func (c Configuration) New( - serviceName string, - options ...Option, -) (opentracing.Tracer, io.Closer, error) { - if serviceName != "" { - c.ServiceName = serviceName - } - - return c.NewTracer(options...) -} - -// NewTracer returns a new tracer based on the current configuration, using the given options, -// and a closer func that can be used to flush buffers before shutdown. -func (c Configuration) NewTracer(options ...Option) (opentracing.Tracer, io.Closer, error) { - if c.ServiceName == "" { - return nil, nil, errors.New("no service name provided") - } - - if c.Disabled { - return &opentracing.NoopTracer{}, &nullCloser{}, nil - } - opts := applyOptions(options...) - tracerMetrics := jaeger.NewMetrics(opts.metrics, nil) - if c.RPCMetrics { - Observer( - rpcmetrics.NewObserver( - opts.metrics.Namespace("jaeger-rpc", map[string]string{"component": "jaeger"}), - rpcmetrics.DefaultNameNormalizer, - ), - )(&opts) // adds to c.observers - } - if c.Sampler == nil { - c.Sampler = &SamplerConfig{ - Type: jaeger.SamplerTypeRemote, - Param: defaultSamplingProbability, - } - } - if c.Reporter == nil { - c.Reporter = &ReporterConfig{} - } - - sampler := opts.sampler - if sampler == nil { - s, err := c.Sampler.NewSampler(c.ServiceName, tracerMetrics) - if err != nil { - return nil, nil, err - } - sampler = s - } - - reporter := opts.reporter - if reporter == nil { - r, err := c.Reporter.NewReporter(c.ServiceName, tracerMetrics, opts.logger) - if err != nil { - return nil, nil, err - } - reporter = r - } - - tracerOptions := []jaeger.TracerOption{ - jaeger.TracerOptions.Metrics(tracerMetrics), - jaeger.TracerOptions.Logger(opts.logger), - jaeger.TracerOptions.CustomHeaderKeys(c.Headers), - jaeger.TracerOptions.Gen128Bit(opts.gen128Bit), - jaeger.TracerOptions.ZipkinSharedRPCSpan(opts.zipkinSharedRPCSpan), - jaeger.TracerOptions.MaxTagValueLength(opts.maxTagValueLength), - } - - for _, tag := range opts.tags { - tracerOptions = append(tracerOptions, jaeger.TracerOptions.Tag(tag.Key, tag.Value)) - } - - for _, tag := range c.Tags { - tracerOptions = append(tracerOptions, jaeger.TracerOptions.Tag(tag.Key, tag.Value)) - } - - for _, obs := range opts.observers { - tracerOptions = append(tracerOptions, jaeger.TracerOptions.Observer(obs)) - } - - for _, cobs := range opts.contribObservers { - tracerOptions = append(tracerOptions, jaeger.TracerOptions.ContribObserver(cobs)) - } - - for format, injector := range opts.injectors { - tracerOptions = append(tracerOptions, jaeger.TracerOptions.Injector(format, injector)) - } - - for format, extractor := range opts.extractors { - tracerOptions = append(tracerOptions, jaeger.TracerOptions.Extractor(format, extractor)) - } - - if c.BaggageRestrictions != nil { - mgr := remote.NewRestrictionManager( - c.ServiceName, - remote.Options.Metrics(tracerMetrics), - remote.Options.Logger(opts.logger), - remote.Options.HostPort(c.BaggageRestrictions.HostPort), - remote.Options.RefreshInterval(c.BaggageRestrictions.RefreshInterval), - remote.Options.DenyBaggageOnInitializationFailure( - c.BaggageRestrictions.DenyBaggageOnInitializationFailure, - ), - ) - tracerOptions = append(tracerOptions, jaeger.TracerOptions.BaggageRestrictionManager(mgr)) - } - - if c.Throttler != nil { - debugThrottler := throttler.NewThrottler( - c.ServiceName, - throttler.Options.Metrics(tracerMetrics), - throttler.Options.Logger(opts.logger), - throttler.Options.HostPort(c.Throttler.HostPort), - throttler.Options.RefreshInterval(c.Throttler.RefreshInterval), - throttler.Options.SynchronousInitialization( - c.Throttler.SynchronousInitialization, - ), - ) - - tracerOptions = append(tracerOptions, jaeger.TracerOptions.DebugThrottler(debugThrottler)) - } - - tracer, closer := jaeger.NewTracer( - c.ServiceName, - sampler, - reporter, - tracerOptions..., - ) - - return tracer, closer, nil -} - -// InitGlobalTracer creates a new Jaeger Tracer, and sets it as global OpenTracing Tracer. -// It returns a closer func that can be used to flush buffers before shutdown. -func (c Configuration) InitGlobalTracer( - serviceName string, - options ...Option, -) (io.Closer, error) { - if c.Disabled { - return &nullCloser{}, nil - } - tracer, closer, err := c.New(serviceName, options...) - if err != nil { - return nil, err - } - opentracing.SetGlobalTracer(tracer) - return closer, nil -} - -// NewSampler creates a new sampler based on the configuration -func (sc *SamplerConfig) NewSampler( - serviceName string, - metrics *jaeger.Metrics, -) (jaeger.Sampler, error) { - samplerType := strings.ToLower(sc.Type) - if samplerType == jaeger.SamplerTypeConst { - return jaeger.NewConstSampler(sc.Param != 0), nil - } - if samplerType == jaeger.SamplerTypeProbabilistic { - if sc.Param >= 0 && sc.Param <= 1.0 { - return jaeger.NewProbabilisticSampler(sc.Param) - } - return nil, fmt.Errorf( - "Invalid Param for probabilistic sampler: %v. Expecting value between 0 and 1", - sc.Param, - ) - } - if samplerType == jaeger.SamplerTypeRateLimiting { - return jaeger.NewRateLimitingSampler(sc.Param), nil - } - if samplerType == jaeger.SamplerTypeRemote || sc.Type == "" { - sc2 := *sc - sc2.Type = jaeger.SamplerTypeProbabilistic - initSampler, err := sc2.NewSampler(serviceName, nil) - if err != nil { - return nil, err - } - options := []jaeger.SamplerOption{ - jaeger.SamplerOptions.Metrics(metrics), - jaeger.SamplerOptions.InitialSampler(initSampler), - jaeger.SamplerOptions.SamplingServerURL(sc.SamplingServerURL), - } - if sc.MaxOperations != 0 { - options = append(options, jaeger.SamplerOptions.MaxOperations(sc.MaxOperations)) - } - if sc.SamplingRefreshInterval != 0 { - options = append(options, jaeger.SamplerOptions.SamplingRefreshInterval(sc.SamplingRefreshInterval)) - } - return jaeger.NewRemotelyControlledSampler(serviceName, options...), nil - } - return nil, fmt.Errorf("Unknown sampler type %v", sc.Type) -} - -// NewReporter instantiates a new reporter that submits spans to tcollector -func (rc *ReporterConfig) NewReporter( - serviceName string, - metrics *jaeger.Metrics, - logger jaeger.Logger, -) (jaeger.Reporter, error) { - sender, err := rc.newTransport() - if err != nil { - return nil, err - } - reporter := jaeger.NewRemoteReporter( - sender, - jaeger.ReporterOptions.QueueSize(rc.QueueSize), - jaeger.ReporterOptions.BufferFlushInterval(rc.BufferFlushInterval), - jaeger.ReporterOptions.Logger(logger), - jaeger.ReporterOptions.Metrics(metrics)) - if rc.LogSpans && logger != nil { - logger.Infof("Initializing logging reporter\n") - reporter = jaeger.NewCompositeReporter(jaeger.NewLoggingReporter(logger), reporter) - } - return reporter, err -} - -func (rc *ReporterConfig) newTransport() (jaeger.Transport, error) { - return jaeger.NewUDPTransport(rc.LocalAgentHostPort, 0) -} diff --git a/vendor/github.com/uber/jaeger-client-go/config/config_env.go b/vendor/github.com/uber/jaeger-client-go/config/config_env.go deleted file mode 100644 index 96f170c539..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/config/config_env.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2018 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "fmt" - "os" - "strconv" - "strings" - "time" - - opentracing "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" - - "github.com/uber/jaeger-client-go" -) - -const ( - // environment variable names - envServiceName = "JAEGER_SERVICE_NAME" - envDisabled = "JAEGER_DISABLED" - envRPCMetrics = "JAEGER_RPC_METRICS" - envTags = "JAEGER_TAGS" - envSamplerType = "JAEGER_SAMPLER_TYPE" - envSamplerParam = "JAEGER_SAMPLER_PARAM" - envSamplerManagerHostPort = "JAEGER_SAMPLER_MANAGER_HOST_PORT" - envSamplerMaxOperations = "JAEGER_SAMPLER_MAX_OPERATIONS" - envSamplerRefreshInterval = "JAEGER_SAMPLER_REFRESH_INTERVAL" - envReporterMaxQueueSize = "JAEGER_REPORTER_MAX_QUEUE_SIZE" - envReporterFlushInterval = "JAEGER_REPORTER_FLUSH_INTERVAL" - envReporterLogSpans = "JAEGER_REPORTER_LOG_SPANS" - envAgentHost = "JAEGER_AGENT_HOST" - envAgentPort = "JAEGER_AGENT_PORT" -) - -// FromEnv uses environment variables to set the tracer's Configuration -func FromEnv() (*Configuration, error) { - c := &Configuration{} - - if e := os.Getenv(envServiceName); e != "" { - c.ServiceName = e - } - - if e := os.Getenv(envRPCMetrics); e != "" { - if value, err := strconv.ParseBool(e); err == nil { - c.RPCMetrics = value - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envRPCMetrics, e) - } - } - - if e := os.Getenv(envDisabled); e != "" { - if value, err := strconv.ParseBool(e); err == nil { - c.Disabled = value - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envDisabled, e) - } - } - - if e := os.Getenv(envTags); e != "" { - c.Tags = parseTags(e) - } - - if s, err := samplerConfigFromEnv(); err == nil { - c.Sampler = s - } else { - return nil, errors.Wrap(err, "cannot obtain sampler config from env") - } - - if r, err := reporterConfigFromEnv(); err == nil { - c.Reporter = r - } else { - return nil, errors.Wrap(err, "cannot obtain reporter config from env") - } - - return c, nil -} - -// samplerConfigFromEnv creates a new SamplerConfig based on the environment variables -func samplerConfigFromEnv() (*SamplerConfig, error) { - sc := &SamplerConfig{} - - if e := os.Getenv(envSamplerType); e != "" { - sc.Type = e - } - - if e := os.Getenv(envSamplerParam); e != "" { - if value, err := strconv.ParseFloat(e, 64); err == nil { - sc.Param = value - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerParam, e) - } - } - - if e := os.Getenv(envSamplerManagerHostPort); e != "" { - sc.SamplingServerURL = e - } - - if e := os.Getenv(envSamplerMaxOperations); e != "" { - if value, err := strconv.ParseInt(e, 10, 0); err == nil { - sc.MaxOperations = int(value) - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerMaxOperations, e) - } - } - - if e := os.Getenv(envSamplerRefreshInterval); e != "" { - if value, err := time.ParseDuration(e); err == nil { - sc.SamplingRefreshInterval = value - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerRefreshInterval, e) - } - } - - return sc, nil -} - -// reporterConfigFromEnv creates a new ReporterConfig based on the environment variables -func reporterConfigFromEnv() (*ReporterConfig, error) { - rc := &ReporterConfig{} - - if e := os.Getenv(envReporterMaxQueueSize); e != "" { - if value, err := strconv.ParseInt(e, 10, 0); err == nil { - rc.QueueSize = int(value) - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterMaxQueueSize, e) - } - } - - if e := os.Getenv(envReporterFlushInterval); e != "" { - if value, err := time.ParseDuration(e); err == nil { - rc.BufferFlushInterval = value - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterFlushInterval, e) - } - } - - if e := os.Getenv(envReporterLogSpans); e != "" { - if value, err := strconv.ParseBool(e); err == nil { - rc.LogSpans = value - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterLogSpans, e) - } - } - - host := jaeger.DefaultUDPSpanServerHost - if e := os.Getenv(envAgentHost); e != "" { - host = e - } - - port := jaeger.DefaultUDPSpanServerPort - if e := os.Getenv(envAgentPort); e != "" { - if value, err := strconv.ParseInt(e, 10, 0); err == nil { - port = int(value) - } else { - return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envAgentPort, e) - } - } - - // the side effect of this is that we are building the default value, even if none of the env vars - // were not explicitly passed - rc.LocalAgentHostPort = fmt.Sprintf("%s:%d", host, port) - - return rc, nil -} - -// parseTags parses the given string into a collection of Tags. -// Spec for this value: -// - comma separated list of key=value -// - value can be specified using the notation ${envVar:defaultValue}, where `envVar` -// is an environment variable and `defaultValue` is the value to use in case the env var is not set -func parseTags(sTags string) []opentracing.Tag { - pairs := strings.Split(sTags, ",") - tags := make([]opentracing.Tag, 0) - for _, p := range pairs { - kv := strings.SplitN(p, "=", 2) - k, v := strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]) - - if strings.HasPrefix(v, "${") && strings.HasSuffix(v, "}") { - ed := strings.SplitN(v[2:len(v)-1], ":", 2) - e, d := ed[0], ed[1] - v = os.Getenv(e) - if v == "" && d != "" { - v = d - } - } - - tag := opentracing.Tag{Key: k, Value: v} - tags = append(tags, tag) - } - - return tags -} diff --git a/vendor/github.com/uber/jaeger-client-go/config/options.go b/vendor/github.com/uber/jaeger-client-go/config/options.go deleted file mode 100644 index d14f1f8a9b..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/config/options.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - opentracing "github.com/opentracing/opentracing-go" - "github.com/uber/jaeger-lib/metrics" - - "github.com/uber/jaeger-client-go" -) - -// Option is a function that sets some option on the client. -type Option func(c *Options) - -// Options control behavior of the client. -type Options struct { - metrics metrics.Factory - logger jaeger.Logger - reporter jaeger.Reporter - sampler jaeger.Sampler - contribObservers []jaeger.ContribObserver - observers []jaeger.Observer - gen128Bit bool - zipkinSharedRPCSpan bool - maxTagValueLength int - tags []opentracing.Tag - injectors map[interface{}]jaeger.Injector - extractors map[interface{}]jaeger.Extractor -} - -// Metrics creates an Option that initializes Metrics in the tracer, -// which is used to emit statistics about spans. -func Metrics(factory metrics.Factory) Option { - return func(c *Options) { - c.metrics = factory - } -} - -// Logger can be provided to log Reporter errors, as well as to log spans -// if Reporter.LogSpans is set to true. -func Logger(logger jaeger.Logger) Option { - return func(c *Options) { - c.logger = logger - } -} - -// Reporter can be provided explicitly to override the configuration. -// Useful for testing, e.g. by passing InMemoryReporter. -func Reporter(reporter jaeger.Reporter) Option { - return func(c *Options) { - c.reporter = reporter - } -} - -// Sampler can be provided explicitly to override the configuration. -func Sampler(sampler jaeger.Sampler) Option { - return func(c *Options) { - c.sampler = sampler - } -} - -// Observer can be registered with the Tracer to receive notifications about new Spans. -func Observer(observer jaeger.Observer) Option { - return func(c *Options) { - c.observers = append(c.observers, observer) - } -} - -// ContribObserver can be registered with the Tracer to recieve notifications -// about new spans. -func ContribObserver(observer jaeger.ContribObserver) Option { - return func(c *Options) { - c.contribObservers = append(c.contribObservers, observer) - } -} - -// Gen128Bit specifies whether to generate 128bit trace IDs. -func Gen128Bit(gen128Bit bool) Option { - return func(c *Options) { - c.gen128Bit = gen128Bit - } -} - -// ZipkinSharedRPCSpan creates an option that enables sharing span ID between client -// and server spans a la zipkin. If false, client and server spans will be assigned -// different IDs. -func ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) Option { - return func(c *Options) { - c.zipkinSharedRPCSpan = zipkinSharedRPCSpan - } -} - -// MaxTagValueLength can be provided to override the default max tag value length. -func MaxTagValueLength(maxTagValueLength int) Option { - return func(c *Options) { - c.maxTagValueLength = maxTagValueLength - } -} - -// Tag creates an option that adds a tracer-level tag. -func Tag(key string, value interface{}) Option { - return func(c *Options) { - c.tags = append(c.tags, opentracing.Tag{Key: key, Value: value}) - } -} - -// Injector registers an Injector with the given format. -func Injector(format interface{}, injector jaeger.Injector) Option { - return func(c *Options) { - c.injectors[format] = injector - } -} - -// Extractor registers an Extractor with the given format. -func Extractor(format interface{}, extractor jaeger.Extractor) Option { - return func(c *Options) { - c.extractors[format] = extractor - } -} - -func applyOptions(options ...Option) Options { - opts := Options{ - injectors: make(map[interface{}]jaeger.Injector), - extractors: make(map[interface{}]jaeger.Extractor), - } - for _, option := range options { - option(&opts) - } - if opts.metrics == nil { - opts.metrics = metrics.NullFactory - } - if opts.logger == nil { - opts.logger = jaeger.NullLogger - } - return opts -} diff --git a/vendor/github.com/uber/jaeger-client-go/constants.go b/vendor/github.com/uber/jaeger-client-go/constants.go deleted file mode 100644 index b5368ff381..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/constants.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -const ( - // JaegerClientVersion is the version of the client library reported as Span tag. - JaegerClientVersion = "Go-2.15.0-dev" - - // JaegerClientVersionTagKey is the name of the tag used to report client version. - JaegerClientVersionTagKey = "jaeger.version" - - // JaegerDebugHeader is the name of HTTP header or a TextMap carrier key which, - // if found in the carrier, forces the trace to be sampled as "debug" trace. - // The value of the header is recorded as the tag on the root span, so that the - // trace can be found in the UI using this value as a correlation ID. - JaegerDebugHeader = "jaeger-debug-id" - - // JaegerBaggageHeader is the name of the HTTP header that is used to submit baggage. - // It differs from TraceBaggageHeaderPrefix in that it can be used only in cases where - // a root span does not exist. - JaegerBaggageHeader = "jaeger-baggage" - - // TracerHostnameTagKey used to report host name of the process. - TracerHostnameTagKey = "hostname" - - // TracerIPTagKey used to report ip of the process. - TracerIPTagKey = "ip" - - // TracerUUIDTagKey used to report UUID of the client process. - TracerUUIDTagKey = "client-uuid" - - // SamplerTypeTagKey reports which sampler was used on the root span. - SamplerTypeTagKey = "sampler.type" - - // SamplerParamTagKey reports the parameter of the sampler, like sampling probability. - SamplerParamTagKey = "sampler.param" - - // TraceContextHeaderName is the http header name used to propagate tracing context. - // This must be in lower-case to avoid mismatches when decoding incoming headers. - TraceContextHeaderName = "uber-trace-id" - - // TracerStateHeaderName is deprecated. - // Deprecated: use TraceContextHeaderName - TracerStateHeaderName = TraceContextHeaderName - - // TraceBaggageHeaderPrefix is the prefix for http headers used to propagate baggage. - // This must be in lower-case to avoid mismatches when decoding incoming headers. - TraceBaggageHeaderPrefix = "uberctx-" - - // SamplerTypeConst is the type of sampler that always makes the same decision. - SamplerTypeConst = "const" - - // SamplerTypeRemote is the type of sampler that polls Jaeger agent for sampling strategy. - SamplerTypeRemote = "remote" - - // SamplerTypeProbabilistic is the type of sampler that samples traces - // with a certain fixed probability. - SamplerTypeProbabilistic = "probabilistic" - - // SamplerTypeRateLimiting is the type of sampler that samples - // only up to a fixed number of traces per second. - SamplerTypeRateLimiting = "ratelimiting" - - // SamplerTypeLowerBound is the type of sampler that samples - // at least a fixed number of traces per second. - SamplerTypeLowerBound = "lowerbound" - - // DefaultUDPSpanServerHost is the default host to send the spans to, via UDP - DefaultUDPSpanServerHost = "localhost" - - // DefaultUDPSpanServerPort is the default port to send the spans to, via UDP - DefaultUDPSpanServerPort = 6831 - - // DefaultMaxTagValueLength is the default max length of byte array or string allowed in the tag value. - DefaultMaxTagValueLength = 256 -) diff --git a/vendor/github.com/uber/jaeger-client-go/context.go b/vendor/github.com/uber/jaeger-client-go/context.go deleted file mode 100644 index 8b06173d98..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/context.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "errors" - "fmt" - "strconv" - "strings" -) - -const ( - flagSampled = byte(1) - flagDebug = byte(2) -) - -var ( - errEmptyTracerStateString = errors.New("Cannot convert empty string to tracer state") - errMalformedTracerStateString = errors.New("String does not match tracer state format") - - emptyContext = SpanContext{} -) - -// TraceID represents unique 128bit identifier of a trace -type TraceID struct { - High, Low uint64 -} - -// SpanID represents unique 64bit identifier of a span -type SpanID uint64 - -// SpanContext represents propagated span identity and state -type SpanContext struct { - // traceID represents globally unique ID of the trace. - // Usually generated as a random number. - traceID TraceID - - // spanID represents span ID that must be unique within its trace, - // but does not have to be globally unique. - spanID SpanID - - // parentID refers to the ID of the parent span. - // Should be 0 if the current span is a root span. - parentID SpanID - - // flags is a bitmap containing such bits as 'sampled' and 'debug'. - flags byte - - // Distributed Context baggage. The is a snapshot in time. - baggage map[string]string - - // debugID can be set to some correlation ID when the context is being - // extracted from a TextMap carrier. - // - // See JaegerDebugHeader in constants.go - debugID string -} - -// ForeachBaggageItem implements ForeachBaggageItem() of opentracing.SpanContext -func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool) { - for k, v := range c.baggage { - if !handler(k, v) { - break - } - } -} - -// IsSampled returns whether this trace was chosen for permanent storage -// by the sampling mechanism of the tracer. -func (c SpanContext) IsSampled() bool { - return (c.flags & flagSampled) == flagSampled -} - -// IsDebug indicates whether sampling was explicitly requested by the service. -func (c SpanContext) IsDebug() bool { - return (c.flags & flagDebug) == flagDebug -} - -// IsValid indicates whether this context actually represents a valid trace. -func (c SpanContext) IsValid() bool { - return c.traceID.IsValid() && c.spanID != 0 -} - -func (c SpanContext) String() string { - if c.traceID.High == 0 { - return fmt.Sprintf("%x:%x:%x:%x", c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.flags) - } - return fmt.Sprintf("%x%016x:%x:%x:%x", c.traceID.High, c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.flags) -} - -// ContextFromString reconstructs the Context encoded in a string -func ContextFromString(value string) (SpanContext, error) { - var context SpanContext - if value == "" { - return emptyContext, errEmptyTracerStateString - } - parts := strings.Split(value, ":") - if len(parts) != 4 { - return emptyContext, errMalformedTracerStateString - } - var err error - if context.traceID, err = TraceIDFromString(parts[0]); err != nil { - return emptyContext, err - } - if context.spanID, err = SpanIDFromString(parts[1]); err != nil { - return emptyContext, err - } - if context.parentID, err = SpanIDFromString(parts[2]); err != nil { - return emptyContext, err - } - flags, err := strconv.ParseUint(parts[3], 10, 8) - if err != nil { - return emptyContext, err - } - context.flags = byte(flags) - return context, nil -} - -// TraceID returns the trace ID of this span context -func (c SpanContext) TraceID() TraceID { - return c.traceID -} - -// SpanID returns the span ID of this span context -func (c SpanContext) SpanID() SpanID { - return c.spanID -} - -// ParentID returns the parent span ID of this span context -func (c SpanContext) ParentID() SpanID { - return c.parentID -} - -// NewSpanContext creates a new instance of SpanContext -func NewSpanContext(traceID TraceID, spanID, parentID SpanID, sampled bool, baggage map[string]string) SpanContext { - flags := byte(0) - if sampled { - flags = flagSampled - } - return SpanContext{ - traceID: traceID, - spanID: spanID, - parentID: parentID, - flags: flags, - baggage: baggage} -} - -// CopyFrom copies data from ctx into this context, including span identity and baggage. -// TODO This is only used by interop.go. Remove once TChannel Go supports OpenTracing. -func (c *SpanContext) CopyFrom(ctx *SpanContext) { - c.traceID = ctx.traceID - c.spanID = ctx.spanID - c.parentID = ctx.parentID - c.flags = ctx.flags - if l := len(ctx.baggage); l > 0 { - c.baggage = make(map[string]string, l) - for k, v := range ctx.baggage { - c.baggage[k] = v - } - } else { - c.baggage = nil - } -} - -// WithBaggageItem creates a new context with an extra baggage item. -func (c SpanContext) WithBaggageItem(key, value string) SpanContext { - var newBaggage map[string]string - if c.baggage == nil { - newBaggage = map[string]string{key: value} - } else { - newBaggage = make(map[string]string, len(c.baggage)+1) - for k, v := range c.baggage { - newBaggage[k] = v - } - newBaggage[key] = value - } - // Use positional parameters so the compiler will help catch new fields. - return SpanContext{c.traceID, c.spanID, c.parentID, c.flags, newBaggage, ""} -} - -// isDebugIDContainerOnly returns true when the instance of the context is only -// used to return the debug/correlation ID from extract() method. This happens -// in the situation when "jaeger-debug-id" header is passed in the carrier to -// the extract() method, but the request otherwise has no span context in it. -// Previously this would've returned opentracing.ErrSpanContextNotFound from the -// extract method, but now it returns a dummy context with only debugID filled in. -// -// See JaegerDebugHeader in constants.go -// See textMapPropagator#Extract -func (c *SpanContext) isDebugIDContainerOnly() bool { - return !c.traceID.IsValid() && c.debugID != "" -} - -// ------- TraceID ------- - -func (t TraceID) String() string { - if t.High == 0 { - return fmt.Sprintf("%x", t.Low) - } - return fmt.Sprintf("%x%016x", t.High, t.Low) -} - -// TraceIDFromString creates a TraceID from a hexadecimal string -func TraceIDFromString(s string) (TraceID, error) { - var hi, lo uint64 - var err error - if len(s) > 32 { - return TraceID{}, fmt.Errorf("TraceID cannot be longer than 32 hex characters: %s", s) - } else if len(s) > 16 { - hiLen := len(s) - 16 - if hi, err = strconv.ParseUint(s[0:hiLen], 16, 64); err != nil { - return TraceID{}, err - } - if lo, err = strconv.ParseUint(s[hiLen:], 16, 64); err != nil { - return TraceID{}, err - } - } else { - if lo, err = strconv.ParseUint(s, 16, 64); err != nil { - return TraceID{}, err - } - } - return TraceID{High: hi, Low: lo}, nil -} - -// IsValid checks if the trace ID is valid, i.e. not zero. -func (t TraceID) IsValid() bool { - return t.High != 0 || t.Low != 0 -} - -// ------- SpanID ------- - -func (s SpanID) String() string { - return fmt.Sprintf("%x", uint64(s)) -} - -// SpanIDFromString creates a SpanID from a hexadecimal string -func SpanIDFromString(s string) (SpanID, error) { - if len(s) > 16 { - return SpanID(0), fmt.Errorf("SpanID cannot be longer than 16 hex characters: %s", s) - } - id, err := strconv.ParseUint(s, 16, 64) - if err != nil { - return SpanID(0), err - } - return SpanID(id), nil -} diff --git a/vendor/github.com/uber/jaeger-client-go/contrib_observer.go b/vendor/github.com/uber/jaeger-client-go/contrib_observer.go deleted file mode 100644 index 4ce1881f3b..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/contrib_observer.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - opentracing "github.com/opentracing/opentracing-go" -) - -// ContribObserver can be registered with the Tracer to receive notifications -// about new Spans. Modelled after github.com/opentracing-contrib/go-observer. -type ContribObserver interface { - // Create and return a span observer. Called when a span starts. - // If the Observer is not interested in the given span, it must return (nil, false). - // E.g : - // func StartSpan(opName string, opts ...opentracing.StartSpanOption) { - // var sp opentracing.Span - // sso := opentracing.StartSpanOptions{} - // if spanObserver, ok := Observer.OnStartSpan(span, opName, sso); ok { - // // we have a valid SpanObserver - // } - // ... - // } - OnStartSpan(sp opentracing.Span, operationName string, options opentracing.StartSpanOptions) (ContribSpanObserver, bool) -} - -// ContribSpanObserver is created by the Observer and receives notifications -// about other Span events. This interface is meant to match -// github.com/opentracing-contrib/go-observer, via duck typing, without -// directly importing the go-observer package. -type ContribSpanObserver interface { - OnSetOperationName(operationName string) - OnSetTag(key string, value interface{}) - OnFinish(options opentracing.FinishOptions) -} - -// wrapper observer for the old observers (see observer.go) -type oldObserver struct { - obs Observer -} - -func (o *oldObserver) OnStartSpan(sp opentracing.Span, operationName string, options opentracing.StartSpanOptions) (ContribSpanObserver, bool) { - spanObserver := o.obs.OnStartSpan(operationName, options) - return spanObserver, spanObserver != nil -} diff --git a/vendor/github.com/uber/jaeger-client-go/doc.go b/vendor/github.com/uber/jaeger-client-go/doc.go deleted file mode 100644 index 4f5549033d..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/doc.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* -Package jaeger implements an OpenTracing (http://opentracing.io) Tracer. -It is currently using Zipkin-compatible data model and can be directly -itegrated with Zipkin backend (http://zipkin.io). - -For integration instructions please refer to the README: - -https://github.com/uber/jaeger-client-go/blob/master/README.md -*/ -package jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/glide.lock b/vendor/github.com/uber/jaeger-client-go/glide.lock deleted file mode 100644 index d76b153617..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/glide.lock +++ /dev/null @@ -1,89 +0,0 @@ -hash: 3accf84f97bff4a91162736104c0e9b9790820712bd86db6fec5e665f7196a82 -updated: 2018-04-30T11:46:43.804556-04:00 -imports: -- name: github.com/beorn7/perks - version: 3a771d992973f24aa725d07868b467d1ddfceafb - subpackages: - - quantile -- name: github.com/codahale/hdrhistogram - version: 3a0bb77429bd3a61596f5e8a3172445844342120 -- name: github.com/crossdock/crossdock-go - version: 049aabb0122b03bc9bd30cab8f3f91fb60166361 - subpackages: - - assert - - require -- name: github.com/davecgh/go-spew - version: 8991bc29aa16c548c550c7ff78260e27b9ab7c73 - subpackages: - - spew -- name: github.com/golang/protobuf - version: bbd03ef6da3a115852eaf24c8a1c46aeb39aa175 - subpackages: - - proto -- name: github.com/matttproud/golang_protobuf_extensions - version: c12348ce28de40eed0136aa2b644d0ee0650e56c - subpackages: - - pbutil -- name: github.com/opentracing/opentracing-go - version: 1949ddbfd147afd4d964a9f00b24eb291e0e7c38 - subpackages: - - ext - - log -- name: github.com/pkg/errors - version: 645ef00459ed84a119197bfb8d8205042c6df63d -- name: github.com/pmezard/go-difflib - version: 792786c7400a136282c1664665ae0a8db921c6c2 - subpackages: - - difflib -- name: github.com/prometheus/client_golang - version: c5b7fccd204277076155f10851dad72b76a49317 - subpackages: - - prometheus -- name: github.com/prometheus/client_model - version: 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c - subpackages: - - go -- name: github.com/prometheus/common - version: 38c53a9f4bfcd932d1b00bfc65e256a7fba6b37a - subpackages: - - expfmt - - internal/bitbucket.org/ww/goautoneg - - model -- name: github.com/prometheus/procfs - version: 780932d4fbbe0e69b84c34c20f5c8d0981e109ea - subpackages: - - internal/util - - nfs - - xfs -- name: github.com/stretchr/testify - version: 12b6f73e6084dad08a7c6e575284b177ecafbc71 - subpackages: - - assert - - require - - suite -- name: github.com/uber/jaeger-lib - version: 4267858c0679cd4e47cefed8d7f70fd386cfb567 - subpackages: - - metrics - - metrics/prometheus - - metrics/testutils -- name: go.uber.org/atomic - version: 8474b86a5a6f79c443ce4b2992817ff32cf208b8 -- name: go.uber.org/multierr - version: 3c4937480c32f4c13a875a1829af76c98ca3d40a -- name: go.uber.org/zap - version: eeedf312bc6c57391d84767a4cd413f02a917974 - subpackages: - - buffer - - internal/bufferpool - - internal/color - - internal/exit - - zapcore -- name: golang.org/x/net - version: 6078986fec03a1dcc236c34816c71b0e05018fda - subpackages: - - context - - context/ctxhttp -testImports: -- name: github.com/uber-go/atomic - version: 8474b86a5a6f79c443ce4b2992817ff32cf208b8 diff --git a/vendor/github.com/uber/jaeger-client-go/glide.yaml b/vendor/github.com/uber/jaeger-client-go/glide.yaml deleted file mode 100644 index 6637da2152..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/glide.yaml +++ /dev/null @@ -1,22 +0,0 @@ -package: github.com/uber/jaeger-client-go -import: -- package: github.com/opentracing/opentracing-go - version: ^1 - subpackages: - - ext - - log -- package: github.com/crossdock/crossdock-go -- package: github.com/uber/jaeger-lib - version: ^1.2.1 - subpackages: - - metrics -- package: github.com/pkg/errors - version: ~0.8.0 -testImport: -- package: github.com/stretchr/testify - subpackages: - - assert - - require - - suite -- package: github.com/prometheus/client_golang - version: v0.8.0 diff --git a/vendor/github.com/uber/jaeger-client-go/header.go b/vendor/github.com/uber/jaeger-client-go/header.go deleted file mode 100644 index 19c2c055b8..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/header.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -// HeadersConfig contains the values for the header keys that Jaeger will use. -// These values may be either custom or default depending on whether custom -// values were provided via a configuration. -type HeadersConfig struct { - // JaegerDebugHeader is the name of HTTP header or a TextMap carrier key which, - // if found in the carrier, forces the trace to be sampled as "debug" trace. - // The value of the header is recorded as the tag on the root span, so that the - // trace can be found in the UI using this value as a correlation ID. - JaegerDebugHeader string `yaml:"jaegerDebugHeader"` - - // JaegerBaggageHeader is the name of the HTTP header that is used to submit baggage. - // It differs from TraceBaggageHeaderPrefix in that it can be used only in cases where - // a root span does not exist. - JaegerBaggageHeader string `yaml:"jaegerBaggageHeader"` - - // TraceContextHeaderName is the http header name used to propagate tracing context. - // This must be in lower-case to avoid mismatches when decoding incoming headers. - TraceContextHeaderName string `yaml:"TraceContextHeaderName"` - - // TraceBaggageHeaderPrefix is the prefix for http headers used to propagate baggage. - // This must be in lower-case to avoid mismatches when decoding incoming headers. - TraceBaggageHeaderPrefix string `yaml:"traceBaggageHeaderPrefix"` -} - -func (c *HeadersConfig) applyDefaults() *HeadersConfig { - if c.JaegerBaggageHeader == "" { - c.JaegerBaggageHeader = JaegerBaggageHeader - } - if c.JaegerDebugHeader == "" { - c.JaegerDebugHeader = JaegerDebugHeader - } - if c.TraceBaggageHeaderPrefix == "" { - c.TraceBaggageHeaderPrefix = TraceBaggageHeaderPrefix - } - if c.TraceContextHeaderName == "" { - c.TraceContextHeaderName = TraceContextHeaderName - } - return c -} - -func getDefaultHeadersConfig() *HeadersConfig { - return &HeadersConfig{ - JaegerDebugHeader: JaegerDebugHeader, - JaegerBaggageHeader: JaegerBaggageHeader, - TraceContextHeaderName: TraceContextHeaderName, - TraceBaggageHeaderPrefix: TraceBaggageHeaderPrefix, - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go deleted file mode 100644 index 745729319f..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package remote - -import ( - "time" - - "github.com/uber/jaeger-client-go" -) - -const ( - defaultMaxValueLength = 2048 - defaultRefreshInterval = time.Minute - defaultHostPort = "localhost:5778" -) - -// Option is a function that sets some option on the RestrictionManager -type Option func(options *options) - -// Options is a factory for all available options -var Options options - -type options struct { - denyBaggageOnInitializationFailure bool - metrics *jaeger.Metrics - logger jaeger.Logger - hostPort string - refreshInterval time.Duration -} - -// DenyBaggageOnInitializationFailure creates an Option that determines the startup failure mode of RestrictionManager. -// If DenyBaggageOnInitializationFailure is true, RestrictionManager will not allow any baggage to be written until baggage -// restrictions have been retrieved from agent. -// If DenyBaggageOnInitializationFailure is false, RestrictionManager will allow any baggage to be written until baggage -// restrictions have been retrieved from agent. -func (options) DenyBaggageOnInitializationFailure(b bool) Option { - return func(o *options) { - o.denyBaggageOnInitializationFailure = b - } -} - -// Metrics creates an Option that initializes Metrics on the RestrictionManager, which is used to emit statistics. -func (options) Metrics(m *jaeger.Metrics) Option { - return func(o *options) { - o.metrics = m - } -} - -// Logger creates an Option that sets the logger used by the RestrictionManager. -func (options) Logger(logger jaeger.Logger) Option { - return func(o *options) { - o.logger = logger - } -} - -// HostPort creates an Option that sets the hostPort of the local agent that contains the baggage restrictions. -func (options) HostPort(hostPort string) Option { - return func(o *options) { - o.hostPort = hostPort - } -} - -// RefreshInterval creates an Option that sets how often the RestrictionManager will poll local agent for -// the baggage restrictions. -func (options) RefreshInterval(refreshInterval time.Duration) Option { - return func(o *options) { - o.refreshInterval = refreshInterval - } -} - -func applyOptions(o ...Option) options { - opts := options{} - for _, option := range o { - option(&opts) - } - if opts.metrics == nil { - opts.metrics = jaeger.NewNullMetrics() - } - if opts.logger == nil { - opts.logger = jaeger.NullLogger - } - if opts.hostPort == "" { - opts.hostPort = defaultHostPort - } - if opts.refreshInterval == 0 { - opts.refreshInterval = defaultRefreshInterval - } - return opts -} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go deleted file mode 100644 index a56515acab..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package remote - -import ( - "fmt" - "net/url" - "sync" - "time" - - "github.com/uber/jaeger-client-go/internal/baggage" - thrift "github.com/uber/jaeger-client-go/thrift-gen/baggage" - "github.com/uber/jaeger-client-go/utils" -) - -type httpBaggageRestrictionManagerProxy struct { - url string -} - -func newHTTPBaggageRestrictionManagerProxy(hostPort, serviceName string) *httpBaggageRestrictionManagerProxy { - v := url.Values{} - v.Set("service", serviceName) - return &httpBaggageRestrictionManagerProxy{ - url: fmt.Sprintf("http://%s/baggageRestrictions?%s", hostPort, v.Encode()), - } -} - -func (s *httpBaggageRestrictionManagerProxy) GetBaggageRestrictions(serviceName string) ([]*thrift.BaggageRestriction, error) { - var out []*thrift.BaggageRestriction - if err := utils.GetJSON(s.url, &out); err != nil { - return nil, err - } - return out, nil -} - -// RestrictionManager manages baggage restrictions by retrieving baggage restrictions from agent -type RestrictionManager struct { - options - - mux sync.RWMutex - serviceName string - restrictions map[string]*baggage.Restriction - thriftProxy thrift.BaggageRestrictionManager - pollStopped sync.WaitGroup - stopPoll chan struct{} - invalidRestriction *baggage.Restriction - validRestriction *baggage.Restriction - - // Determines if the manager has successfully retrieved baggage restrictions from agent - initialized bool -} - -// NewRestrictionManager returns a BaggageRestrictionManager that polls the agent for the latest -// baggage restrictions. -func NewRestrictionManager(serviceName string, options ...Option) *RestrictionManager { - // TODO there is a developing use case where a single tracer can generate traces on behalf of many services. - // restrictionsMap will need to exist per service - opts := applyOptions(options...) - m := &RestrictionManager{ - serviceName: serviceName, - options: opts, - restrictions: make(map[string]*baggage.Restriction), - thriftProxy: newHTTPBaggageRestrictionManagerProxy(opts.hostPort, serviceName), - stopPoll: make(chan struct{}), - invalidRestriction: baggage.NewRestriction(false, 0), - validRestriction: baggage.NewRestriction(true, defaultMaxValueLength), - } - m.pollStopped.Add(1) - go m.pollManager() - return m -} - -// isReady returns true if the manager has retrieved baggage restrictions from the remote source. -func (m *RestrictionManager) isReady() bool { - m.mux.RLock() - defer m.mux.RUnlock() - return m.initialized -} - -// GetRestriction implements RestrictionManager#GetRestriction. -func (m *RestrictionManager) GetRestriction(service, key string) *baggage.Restriction { - m.mux.RLock() - defer m.mux.RUnlock() - if !m.initialized { - if m.denyBaggageOnInitializationFailure { - return m.invalidRestriction - } - return m.validRestriction - } - if restriction, ok := m.restrictions[key]; ok { - return restriction - } - return m.invalidRestriction -} - -// Close stops remote polling and closes the RemoteRestrictionManager. -func (m *RestrictionManager) Close() error { - close(m.stopPoll) - m.pollStopped.Wait() - return nil -} - -func (m *RestrictionManager) pollManager() { - defer m.pollStopped.Done() - // attempt to initialize baggage restrictions - if err := m.updateRestrictions(); err != nil { - m.logger.Error(fmt.Sprintf("Failed to initialize baggage restrictions: %s", err.Error())) - } - ticker := time.NewTicker(m.refreshInterval) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - if err := m.updateRestrictions(); err != nil { - m.logger.Error(fmt.Sprintf("Failed to update baggage restrictions: %s", err.Error())) - } - case <-m.stopPoll: - return - } - } -} - -func (m *RestrictionManager) updateRestrictions() error { - restrictions, err := m.thriftProxy.GetBaggageRestrictions(m.serviceName) - if err != nil { - m.metrics.BaggageRestrictionsUpdateFailure.Inc(1) - return err - } - newRestrictions := m.parseRestrictions(restrictions) - m.metrics.BaggageRestrictionsUpdateSuccess.Inc(1) - m.mux.Lock() - defer m.mux.Unlock() - m.initialized = true - m.restrictions = newRestrictions - return nil -} - -func (m *RestrictionManager) parseRestrictions(restrictions []*thrift.BaggageRestriction) map[string]*baggage.Restriction { - setters := make(map[string]*baggage.Restriction, len(restrictions)) - for _, restriction := range restrictions { - setters[restriction.BaggageKey] = baggage.NewRestriction(true, int(restriction.MaxValueLength)) - } - return setters -} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go deleted file mode 100644 index c16a5c5662..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package baggage - -const ( - defaultMaxValueLength = 2048 -) - -// Restriction determines whether a baggage key is allowed and contains any restrictions on the baggage value. -type Restriction struct { - keyAllowed bool - maxValueLength int -} - -// NewRestriction returns a new Restriction. -func NewRestriction(keyAllowed bool, maxValueLength int) *Restriction { - return &Restriction{ - keyAllowed: keyAllowed, - maxValueLength: maxValueLength, - } -} - -// KeyAllowed returns whether the baggage key for this restriction is allowed. -func (r *Restriction) KeyAllowed() bool { - return r.keyAllowed -} - -// MaxValueLength returns the max length for the baggage value. -func (r *Restriction) MaxValueLength() int { - return r.maxValueLength -} - -// RestrictionManager keeps track of valid baggage keys and their restrictions. The manager -// will return a Restriction for a specific baggage key which will determine whether the baggage -// key is allowed for the current service and any other applicable restrictions on the baggage -// value. -type RestrictionManager interface { - GetRestriction(service, key string) *Restriction -} - -// DefaultRestrictionManager allows any baggage key. -type DefaultRestrictionManager struct { - defaultRestriction *Restriction -} - -// NewDefaultRestrictionManager returns a DefaultRestrictionManager. -func NewDefaultRestrictionManager(maxValueLength int) *DefaultRestrictionManager { - if maxValueLength == 0 { - maxValueLength = defaultMaxValueLength - } - return &DefaultRestrictionManager{ - defaultRestriction: &Restriction{keyAllowed: true, maxValueLength: maxValueLength}, - } -} - -// GetRestriction implements RestrictionManager#GetRestriction. -func (m *DefaultRestrictionManager) GetRestriction(service, key string) *Restriction { - return m.defaultRestriction -} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go b/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go deleted file mode 100644 index 0e10b8a5aa..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package spanlog - -import ( - "encoding/json" - "fmt" - - "github.com/opentracing/opentracing-go/log" -) - -type fieldsAsMap map[string]string - -// MaterializeWithJSON converts log Fields into JSON string -// TODO refactor into pluggable materializer -func MaterializeWithJSON(logFields []log.Field) ([]byte, error) { - fields := fieldsAsMap(make(map[string]string, len(logFields))) - for _, field := range logFields { - field.Marshal(fields) - } - if event, ok := fields["event"]; ok && len(fields) == 1 { - return []byte(event), nil - } - return json.Marshal(fields) -} - -func (ml fieldsAsMap) EmitString(key, value string) { - ml[key] = value -} - -func (ml fieldsAsMap) EmitBool(key string, value bool) { - ml[key] = fmt.Sprintf("%t", value) -} - -func (ml fieldsAsMap) EmitInt(key string, value int) { - ml[key] = fmt.Sprintf("%d", value) -} - -func (ml fieldsAsMap) EmitInt32(key string, value int32) { - ml[key] = fmt.Sprintf("%d", value) -} - -func (ml fieldsAsMap) EmitInt64(key string, value int64) { - ml[key] = fmt.Sprintf("%d", value) -} - -func (ml fieldsAsMap) EmitUint32(key string, value uint32) { - ml[key] = fmt.Sprintf("%d", value) -} - -func (ml fieldsAsMap) EmitUint64(key string, value uint64) { - ml[key] = fmt.Sprintf("%d", value) -} - -func (ml fieldsAsMap) EmitFloat32(key string, value float32) { - ml[key] = fmt.Sprintf("%f", value) -} - -func (ml fieldsAsMap) EmitFloat64(key string, value float64) { - ml[key] = fmt.Sprintf("%f", value) -} - -func (ml fieldsAsMap) EmitObject(key string, value interface{}) { - ml[key] = fmt.Sprintf("%+v", value) -} - -func (ml fieldsAsMap) EmitLazyLogger(value log.LazyLogger) { - value(ml) -} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/options.go b/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/options.go deleted file mode 100644 index f52c322fb6..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/options.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2018 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package remote - -import ( - "time" - - "github.com/uber/jaeger-client-go" -) - -const ( - defaultHostPort = "localhost:5778" - defaultRefreshInterval = time.Second * 5 -) - -// Option is a function that sets some option on the Throttler -type Option func(options *options) - -// Options is a factory for all available options -var Options options - -type options struct { - metrics *jaeger.Metrics - logger jaeger.Logger - hostPort string - refreshInterval time.Duration - synchronousInitialization bool -} - -// Metrics creates an Option that initializes Metrics on the Throttler, which is used to emit statistics. -func (options) Metrics(m *jaeger.Metrics) Option { - return func(o *options) { - o.metrics = m - } -} - -// Logger creates an Option that sets the logger used by the Throttler. -func (options) Logger(logger jaeger.Logger) Option { - return func(o *options) { - o.logger = logger - } -} - -// HostPort creates an Option that sets the hostPort of the local agent that keeps track of credits. -func (options) HostPort(hostPort string) Option { - return func(o *options) { - o.hostPort = hostPort - } -} - -// RefreshInterval creates an Option that sets how often the Throttler will poll local agent for -// credits. -func (options) RefreshInterval(refreshInterval time.Duration) Option { - return func(o *options) { - o.refreshInterval = refreshInterval - } -} - -// SynchronousInitialization creates an Option that determines whether the throttler should synchronously -// fetch credits from the agent when an operation is seen for the first time. This should be set to true -// if the client will be used by a short lived service that needs to ensure that credits are fetched upfront -// such that sampling or throttling occurs. -func (options) SynchronousInitialization(b bool) Option { - return func(o *options) { - o.synchronousInitialization = b - } -} - -func applyOptions(o ...Option) options { - opts := options{} - for _, option := range o { - option(&opts) - } - if opts.metrics == nil { - opts.metrics = jaeger.NewNullMetrics() - } - if opts.logger == nil { - opts.logger = jaeger.NullLogger - } - if opts.hostPort == "" { - opts.hostPort = defaultHostPort - } - if opts.refreshInterval == 0 { - opts.refreshInterval = defaultRefreshInterval - } - return opts -} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/throttler.go b/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/throttler.go deleted file mode 100644 index 20f434fe49..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/internal/throttler/remote/throttler.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2018 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package remote - -import ( - "fmt" - "net/url" - "sync" - "sync/atomic" - "time" - - "github.com/pkg/errors" - - "github.com/uber/jaeger-client-go" - "github.com/uber/jaeger-client-go/utils" -) - -const ( - // minimumCredits is the minimum amount of credits necessary to not be throttled. - // i.e. if currentCredits > minimumCredits, then the operation will not be throttled. - minimumCredits = 1.0 -) - -var ( - errorUUIDNotSet = errors.New("Throttler UUID must be set") -) - -type operationBalance struct { - Operation string `json:"operation"` - Balance float64 `json:"balance"` -} - -type creditResponse struct { - Balances []operationBalance `json:"balances"` -} - -type httpCreditManagerProxy struct { - hostPort string -} - -func newHTTPCreditManagerProxy(hostPort string) *httpCreditManagerProxy { - return &httpCreditManagerProxy{ - hostPort: hostPort, - } -} - -// N.B. Operations list must not be empty. -func (m *httpCreditManagerProxy) FetchCredits(uuid, serviceName string, operations []string) (*creditResponse, error) { - params := url.Values{} - params.Set("service", serviceName) - params.Set("uuid", uuid) - for _, op := range operations { - params.Add("operations", op) - } - var resp creditResponse - if err := utils.GetJSON(fmt.Sprintf("http://%s/credits?%s", m.hostPort, params.Encode()), &resp); err != nil { - return nil, errors.Wrap(err, "Failed to receive credits from agent") - } - return &resp, nil -} - -// Throttler retrieves credits from agent and uses it to throttle operations. -type Throttler struct { - options - - mux sync.RWMutex - service string - uuid atomic.Value - creditManager *httpCreditManagerProxy - credits map[string]float64 // map of operation->credits - close chan struct{} - stopped sync.WaitGroup -} - -// NewThrottler returns a Throttler that polls agent for credits and uses them to throttle -// the service. -func NewThrottler(service string, options ...Option) *Throttler { - opts := applyOptions(options...) - creditManager := newHTTPCreditManagerProxy(opts.hostPort) - t := &Throttler{ - options: opts, - creditManager: creditManager, - service: service, - credits: make(map[string]float64), - close: make(chan struct{}), - } - t.stopped.Add(1) - go t.pollManager() - return t -} - -// IsAllowed implements Throttler#IsAllowed. -func (t *Throttler) IsAllowed(operation string) bool { - t.mux.Lock() - defer t.mux.Unlock() - value, ok := t.credits[operation] - if !ok || value == 0 { - if !ok { - // NOTE: This appears to be a no-op at first glance, but it stores - // the operation key in the map. Necessary for functionality of - // Throttler#operations method. - t.credits[operation] = 0 - } - if !t.synchronousInitialization { - t.metrics.ThrottledDebugSpans.Inc(1) - return false - } - // If it is the first time this operation is being checked, synchronously fetch - // the credits. - credits, err := t.fetchCredits([]string{operation}) - if err != nil { - // Failed to receive credits from agent, try again next time - t.logger.Error("Failed to fetch credits: " + err.Error()) - return false - } - if len(credits.Balances) == 0 { - // This shouldn't happen but just in case - return false - } - for _, opBalance := range credits.Balances { - t.credits[opBalance.Operation] += opBalance.Balance - } - } - return t.isAllowed(operation) -} - -// Close stops the throttler from fetching credits from remote. -func (t *Throttler) Close() error { - close(t.close) - t.stopped.Wait() - return nil -} - -// SetProcess implements ProcessSetter#SetProcess. It's imperative that the UUID is set before any remote -// requests are made. -func (t *Throttler) SetProcess(process jaeger.Process) { - if process.UUID != "" { - t.uuid.Store(process.UUID) - } -} - -// N.B. This function must be called with the Write Lock -func (t *Throttler) isAllowed(operation string) bool { - credits := t.credits[operation] - if credits < minimumCredits { - t.metrics.ThrottledDebugSpans.Inc(1) - return false - } - t.credits[operation] = credits - minimumCredits - return true -} - -func (t *Throttler) pollManager() { - defer t.stopped.Done() - ticker := time.NewTicker(t.refreshInterval) - defer ticker.Stop() - for { - select { - case <-ticker.C: - t.refreshCredits() - case <-t.close: - return - } - } -} - -func (t *Throttler) operations() []string { - t.mux.RLock() - defer t.mux.RUnlock() - operations := make([]string, 0, len(t.credits)) - for op := range t.credits { - operations = append(operations, op) - } - return operations -} - -func (t *Throttler) refreshCredits() { - operations := t.operations() - if len(operations) == 0 { - return - } - newCredits, err := t.fetchCredits(operations) - if err != nil { - t.metrics.ThrottlerUpdateFailure.Inc(1) - t.logger.Error("Failed to fetch credits: " + err.Error()) - return - } - t.metrics.ThrottlerUpdateSuccess.Inc(1) - - t.mux.Lock() - defer t.mux.Unlock() - for _, opBalance := range newCredits.Balances { - t.credits[opBalance.Operation] += opBalance.Balance - } -} - -func (t *Throttler) fetchCredits(operations []string) (*creditResponse, error) { - uuid := t.uuid.Load() - uuidStr, _ := uuid.(string) - if uuid == nil || uuidStr == "" { - return nil, errorUUIDNotSet - } - return t.creditManager.FetchCredits(uuidStr, t.service, operations) -} diff --git a/vendor/github.com/uber/jaeger-client-go/internal/throttler/throttler.go b/vendor/github.com/uber/jaeger-client-go/internal/throttler/throttler.go deleted file mode 100644 index 196ed69cac..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/internal/throttler/throttler.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2018 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package throttler - -// Throttler is used to rate limits operations. For example, given how debug spans -// are always sampled, a throttler can be enabled per client to rate limit the amount -// of debug spans a client can start. -type Throttler interface { - // IsAllowed determines whether the operation should be allowed and not be - // throttled. - IsAllowed(operation string) bool -} - -// DefaultThrottler doesn't throttle at all. -type DefaultThrottler struct{} - -// IsAllowed implements Throttler#IsAllowed. -func (t DefaultThrottler) IsAllowed(operation string) bool { - return true -} diff --git a/vendor/github.com/uber/jaeger-client-go/interop.go b/vendor/github.com/uber/jaeger-client-go/interop.go deleted file mode 100644 index 8402d087c2..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/interop.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "github.com/opentracing/opentracing-go" -) - -// TODO this file should not be needed after TChannel PR. - -type formatKey int - -// SpanContextFormat is a constant used as OpenTracing Format. -// Requires *SpanContext as carrier. -// This format is intended for interop with TChannel or other Zipkin-like tracers. -const SpanContextFormat formatKey = iota - -type jaegerTraceContextPropagator struct { - tracer *Tracer -} - -func (p *jaegerTraceContextPropagator) Inject( - ctx SpanContext, - abstractCarrier interface{}, -) error { - carrier, ok := abstractCarrier.(*SpanContext) - if !ok { - return opentracing.ErrInvalidCarrier - } - - carrier.CopyFrom(&ctx) - return nil -} - -func (p *jaegerTraceContextPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { - carrier, ok := abstractCarrier.(*SpanContext) - if !ok { - return emptyContext, opentracing.ErrInvalidCarrier - } - ctx := new(SpanContext) - ctx.CopyFrom(carrier) - return *ctx, nil -} diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go b/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go deleted file mode 100644 index 868b2a5b54..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "fmt" - - "github.com/opentracing/opentracing-go/log" - - j "github.com/uber/jaeger-client-go/thrift-gen/jaeger" -) - -type tags []*j.Tag - -// ConvertLogsToJaegerTags converts log Fields into jaeger tags. -func ConvertLogsToJaegerTags(logFields []log.Field) []*j.Tag { - fields := tags(make([]*j.Tag, 0, len(logFields))) - for _, field := range logFields { - field.Marshal(&fields) - } - return fields -} - -func (t *tags) EmitString(key, value string) { - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_STRING, VStr: &value}) -} - -func (t *tags) EmitBool(key string, value bool) { - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_BOOL, VBool: &value}) -} - -func (t *tags) EmitInt(key string, value int) { - vLong := int64(value) - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) -} - -func (t *tags) EmitInt32(key string, value int32) { - vLong := int64(value) - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) -} - -func (t *tags) EmitInt64(key string, value int64) { - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &value}) -} - -func (t *tags) EmitUint32(key string, value uint32) { - vLong := int64(value) - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) -} - -func (t *tags) EmitUint64(key string, value uint64) { - vLong := int64(value) - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_LONG, VLong: &vLong}) -} - -func (t *tags) EmitFloat32(key string, value float32) { - vDouble := float64(value) - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_DOUBLE, VDouble: &vDouble}) -} - -func (t *tags) EmitFloat64(key string, value float64) { - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_DOUBLE, VDouble: &value}) -} - -func (t *tags) EmitObject(key string, value interface{}) { - vStr := fmt.Sprintf("%+v", value) - *t = append(*t, &j.Tag{Key: key, VType: j.TagType_STRING, VStr: &vStr}) -} - -func (t *tags) EmitLazyLogger(value log.LazyLogger) { - value(t) -} diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go deleted file mode 100644 index 6ce1caf873..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "time" - - "github.com/opentracing/opentracing-go" - - j "github.com/uber/jaeger-client-go/thrift-gen/jaeger" - "github.com/uber/jaeger-client-go/utils" -) - -// BuildJaegerThrift builds jaeger span based on internal span. -func BuildJaegerThrift(span *Span) *j.Span { - span.Lock() - defer span.Unlock() - startTime := utils.TimeToMicrosecondsSinceEpochInt64(span.startTime) - duration := span.duration.Nanoseconds() / int64(time.Microsecond) - jaegerSpan := &j.Span{ - TraceIdLow: int64(span.context.traceID.Low), - TraceIdHigh: int64(span.context.traceID.High), - SpanId: int64(span.context.spanID), - ParentSpanId: int64(span.context.parentID), - OperationName: span.operationName, - Flags: int32(span.context.flags), - StartTime: startTime, - Duration: duration, - Tags: buildTags(span.tags, span.tracer.options.maxTagValueLength), - Logs: buildLogs(span.logs), - References: buildReferences(span.references), - } - return jaegerSpan -} - -// BuildJaegerProcessThrift creates a thrift Process type. -func BuildJaegerProcessThrift(span *Span) *j.Process { - span.Lock() - defer span.Unlock() - return buildJaegerProcessThrift(span.tracer) -} - -func buildJaegerProcessThrift(tracer *Tracer) *j.Process { - process := &j.Process{ - ServiceName: tracer.serviceName, - Tags: buildTags(tracer.tags, tracer.options.maxTagValueLength), - } - if tracer.process.UUID != "" { - process.Tags = append(process.Tags, &j.Tag{Key: TracerUUIDTagKey, VStr: &tracer.process.UUID, VType: j.TagType_STRING}) - } - return process -} - -func buildTags(tags []Tag, maxTagValueLength int) []*j.Tag { - jTags := make([]*j.Tag, 0, len(tags)) - for _, tag := range tags { - jTag := buildTag(&tag, maxTagValueLength) - jTags = append(jTags, jTag) - } - return jTags -} - -func buildLogs(logs []opentracing.LogRecord) []*j.Log { - jLogs := make([]*j.Log, 0, len(logs)) - for _, log := range logs { - jLog := &j.Log{ - Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(log.Timestamp), - Fields: ConvertLogsToJaegerTags(log.Fields), - } - jLogs = append(jLogs, jLog) - } - return jLogs -} - -func buildTag(tag *Tag, maxTagValueLength int) *j.Tag { - jTag := &j.Tag{Key: tag.key} - switch value := tag.value.(type) { - case string: - vStr := truncateString(value, maxTagValueLength) - jTag.VStr = &vStr - jTag.VType = j.TagType_STRING - case []byte: - if len(value) > maxTagValueLength { - value = value[:maxTagValueLength] - } - jTag.VBinary = value - jTag.VType = j.TagType_BINARY - case int: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case uint: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case int8: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case uint8: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case int16: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case uint16: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case int32: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case uint32: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case int64: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case uint64: - vLong := int64(value) - jTag.VLong = &vLong - jTag.VType = j.TagType_LONG - case float32: - vDouble := float64(value) - jTag.VDouble = &vDouble - jTag.VType = j.TagType_DOUBLE - case float64: - vDouble := float64(value) - jTag.VDouble = &vDouble - jTag.VType = j.TagType_DOUBLE - case bool: - vBool := value - jTag.VBool = &vBool - jTag.VType = j.TagType_BOOL - default: - vStr := truncateString(stringify(value), maxTagValueLength) - jTag.VStr = &vStr - jTag.VType = j.TagType_STRING - } - return jTag -} - -func buildReferences(references []Reference) []*j.SpanRef { - retMe := make([]*j.SpanRef, 0, len(references)) - for _, ref := range references { - if ref.Type == opentracing.ChildOfRef { - retMe = append(retMe, spanRef(ref.Context, j.SpanRefType_CHILD_OF)) - } else if ref.Type == opentracing.FollowsFromRef { - retMe = append(retMe, spanRef(ref.Context, j.SpanRefType_FOLLOWS_FROM)) - } - } - return retMe -} - -func spanRef(ctx SpanContext, refType j.SpanRefType) *j.SpanRef { - return &j.SpanRef{ - RefType: refType, - TraceIdLow: int64(ctx.traceID.Low), - TraceIdHigh: int64(ctx.traceID.High), - SpanId: int64(ctx.spanID), - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/log/logger.go b/vendor/github.com/uber/jaeger-client-go/log/logger.go deleted file mode 100644 index 894bb3dbf7..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/log/logger.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package log - -import ( - "bytes" - "fmt" - "log" - "sync" -) - -// Logger provides an abstract interface for logging from Reporters. -// Applications can provide their own implementation of this interface to adapt -// reporters logging to whatever logging library they prefer (stdlib log, -// logrus, go-logging, etc). -type Logger interface { - // Error logs a message at error priority - Error(msg string) - - // Infof logs a message at info priority - Infof(msg string, args ...interface{}) -} - -// StdLogger is implementation of the Logger interface that delegates to default `log` package -var StdLogger = &stdLogger{} - -type stdLogger struct{} - -func (l *stdLogger) Error(msg string) { - log.Printf("ERROR: %s", msg) -} - -// Infof logs a message at info priority -func (l *stdLogger) Infof(msg string, args ...interface{}) { - log.Printf(msg, args...) -} - -// NullLogger is implementation of the Logger interface that is no-op -var NullLogger = &nullLogger{} - -type nullLogger struct{} - -func (l *nullLogger) Error(msg string) {} -func (l *nullLogger) Infof(msg string, args ...interface{}) {} - -// BytesBufferLogger implements Logger backed by a bytes.Buffer. -type BytesBufferLogger struct { - mux sync.Mutex - buf bytes.Buffer -} - -// Error implements Logger. -func (l *BytesBufferLogger) Error(msg string) { - l.mux.Lock() - l.buf.WriteString(fmt.Sprintf("ERROR: %s\n", msg)) - l.mux.Unlock() -} - -// Infof implements Logger. -func (l *BytesBufferLogger) Infof(msg string, args ...interface{}) { - l.mux.Lock() - l.buf.WriteString("INFO: " + fmt.Sprintf(msg, args...) + "\n") - l.mux.Unlock() -} - -// String returns string representation of the underlying buffer. -func (l *BytesBufferLogger) String() string { - l.mux.Lock() - defer l.mux.Unlock() - return l.buf.String() -} - -// Flush empties the underlying buffer. -func (l *BytesBufferLogger) Flush() { - l.mux.Lock() - defer l.mux.Unlock() - l.buf.Reset() -} diff --git a/vendor/github.com/uber/jaeger-client-go/logger.go b/vendor/github.com/uber/jaeger-client-go/logger.go deleted file mode 100644 index d4f0b50192..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/logger.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import "log" - -// NB This will be deprecated in 3.0.0, please use jaeger-client-go/log/logger instead. - -// Logger provides an abstract interface for logging from Reporters. -// Applications can provide their own implementation of this interface to adapt -// reporters logging to whatever logging library they prefer (stdlib log, -// logrus, go-logging, etc). -type Logger interface { - // Error logs a message at error priority - Error(msg string) - - // Infof logs a message at info priority - Infof(msg string, args ...interface{}) -} - -// StdLogger is implementation of the Logger interface that delegates to default `log` package -var StdLogger = &stdLogger{} - -type stdLogger struct{} - -func (l *stdLogger) Error(msg string) { - log.Printf("ERROR: %s", msg) -} - -// Infof logs a message at info priority -func (l *stdLogger) Infof(msg string, args ...interface{}) { - log.Printf(msg, args...) -} - -// NullLogger is implementation of the Logger interface that delegates to default `log` package -var NullLogger = &nullLogger{} - -type nullLogger struct{} - -func (l *nullLogger) Error(msg string) {} -func (l *nullLogger) Infof(msg string, args ...interface{}) {} diff --git a/vendor/github.com/uber/jaeger-client-go/metrics.go b/vendor/github.com/uber/jaeger-client-go/metrics.go deleted file mode 100644 index cadb2b9c0f..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/metrics.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2017-2018 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "github.com/uber/jaeger-lib/metrics" -) - -// Metrics is a container of all stats emitted by Jaeger tracer. -type Metrics struct { - // Number of traces started by this tracer as sampled - TracesStartedSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=y"` - - // Number of traces started by this tracer as not sampled - TracesStartedNotSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=n"` - - // Number of externally started sampled traces this tracer joined - TracesJoinedSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=y"` - - // Number of externally started not-sampled traces this tracer joined - TracesJoinedNotSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=n"` - - // Number of sampled spans started by this tracer - SpansStartedSampled metrics.Counter `metric:"started_spans" tags:"sampled=y"` - - // Number of unsampled spans started by this tracer - SpansStartedNotSampled metrics.Counter `metric:"started_spans" tags:"sampled=n"` - - // Number of spans finished by this tracer - SpansFinished metrics.Counter `metric:"finished_spans"` - - // Number of errors decoding tracing context - DecodingErrors metrics.Counter `metric:"span_context_decoding_errors"` - - // Number of spans successfully reported - ReporterSuccess metrics.Counter `metric:"reporter_spans" tags:"result=ok"` - - // Number of spans not reported due to a Sender failure - ReporterFailure metrics.Counter `metric:"reporter_spans" tags:"result=err"` - - // Number of spans dropped due to internal queue overflow - ReporterDropped metrics.Counter `metric:"reporter_spans" tags:"result=dropped"` - - // Current number of spans in the reporter queue - ReporterQueueLength metrics.Gauge `metric:"reporter_queue_length"` - - // Number of times the Sampler succeeded to retrieve sampling strategy - SamplerRetrieved metrics.Counter `metric:"sampler_queries" tags:"result=ok"` - - // Number of times the Sampler failed to retrieve sampling strategy - SamplerQueryFailure metrics.Counter `metric:"sampler_queries" tags:"result=err"` - - // Number of times the Sampler succeeded to retrieve and update sampling strategy - SamplerUpdated metrics.Counter `metric:"sampler_updates" tags:"result=ok"` - - // Number of times the Sampler failed to update sampling strategy - SamplerUpdateFailure metrics.Counter `metric:"sampler_updates" tags:"result=err"` - - // Number of times baggage was successfully written or updated on spans. - BaggageUpdateSuccess metrics.Counter `metric:"baggage_updates" tags:"result=ok"` - - // Number of times baggage failed to write or update on spans. - BaggageUpdateFailure metrics.Counter `metric:"baggage_updates" tags:"result=err"` - - // Number of times baggage was truncated as per baggage restrictions. - BaggageTruncate metrics.Counter `metric:"baggage_truncations"` - - // Number of times baggage restrictions were successfully updated. - BaggageRestrictionsUpdateSuccess metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=ok"` - - // Number of times baggage restrictions failed to update. - BaggageRestrictionsUpdateFailure metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=err"` - - // Number of times debug spans were throttled. - ThrottledDebugSpans metrics.Counter `metric:"throttled_debug_spans"` - - // Number of times throttler successfully updated. - ThrottlerUpdateSuccess metrics.Counter `metric:"throttler_updates" tags:"result=ok"` - - // Number of times throttler failed to update. - ThrottlerUpdateFailure metrics.Counter `metric:"throttler_updates" tags:"result=err"` -} - -// NewMetrics creates a new Metrics struct and initializes it. -func NewMetrics(factory metrics.Factory, globalTags map[string]string) *Metrics { - m := &Metrics{} - // TODO the namespace "jaeger" should be configurable (e.g. in all-in-one "jaeger-client" would make more sense) - metrics.Init(m, factory.Namespace("jaeger", nil), globalTags) - return m -} - -// NewNullMetrics creates a new Metrics struct that won't report any metrics. -func NewNullMetrics() *Metrics { - return NewMetrics(metrics.NullFactory, nil) -} diff --git a/vendor/github.com/uber/jaeger-client-go/observer.go b/vendor/github.com/uber/jaeger-client-go/observer.go deleted file mode 100644 index 7bbd028897..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/observer.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import opentracing "github.com/opentracing/opentracing-go" - -// Observer can be registered with the Tracer to receive notifications about -// new Spans. -// -// Deprecated: use jaeger.ContribObserver instead. -type Observer interface { - OnStartSpan(operationName string, options opentracing.StartSpanOptions) SpanObserver -} - -// SpanObserver is created by the Observer and receives notifications about -// other Span events. -// -// Deprecated: use jaeger.ContribSpanObserver instead. -type SpanObserver interface { - OnSetOperationName(operationName string) - OnSetTag(key string, value interface{}) - OnFinish(options opentracing.FinishOptions) -} - -// compositeObserver is a dispatcher to other observers -type compositeObserver struct { - observers []ContribObserver -} - -// compositeSpanObserver is a dispatcher to other span observers -type compositeSpanObserver struct { - observers []ContribSpanObserver -} - -// noopSpanObserver is used when there are no observers registered -// on the Tracer or none of them returns span observers from OnStartSpan. -var noopSpanObserver = &compositeSpanObserver{} - -func (o *compositeObserver) append(contribObserver ContribObserver) { - o.observers = append(o.observers, contribObserver) -} - -func (o *compositeObserver) OnStartSpan(sp opentracing.Span, operationName string, options opentracing.StartSpanOptions) ContribSpanObserver { - var spanObservers []ContribSpanObserver - for _, obs := range o.observers { - spanObs, ok := obs.OnStartSpan(sp, operationName, options) - if ok { - if spanObservers == nil { - spanObservers = make([]ContribSpanObserver, 0, len(o.observers)) - } - spanObservers = append(spanObservers, spanObs) - } - } - if len(spanObservers) == 0 { - return noopSpanObserver - } - return &compositeSpanObserver{observers: spanObservers} -} - -func (o *compositeSpanObserver) OnSetOperationName(operationName string) { - for _, obs := range o.observers { - obs.OnSetOperationName(operationName) - } -} - -func (o *compositeSpanObserver) OnSetTag(key string, value interface{}) { - for _, obs := range o.observers { - obs.OnSetTag(key, value) - } -} - -func (o *compositeSpanObserver) OnFinish(options opentracing.FinishOptions) { - for _, obs := range o.observers { - obs.OnFinish(options) - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/process.go b/vendor/github.com/uber/jaeger-client-go/process.go deleted file mode 100644 index 30cbf99624..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/process.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2018 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -// Process holds process specific metadata that's relevant to this client. -type Process struct { - Service string - UUID string - Tags []Tag -} - -// ProcessSetter sets a process. This can be used by any class that requires -// the process to be set as part of initialization. -// See internal/throttler/remote/throttler.go for an example. -type ProcessSetter interface { - SetProcess(process Process) -} diff --git a/vendor/github.com/uber/jaeger-client-go/propagation.go b/vendor/github.com/uber/jaeger-client-go/propagation.go deleted file mode 100644 index abca67a3c9..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/propagation.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" - "log" - "net/url" - "strings" - "sync" - - opentracing "github.com/opentracing/opentracing-go" -) - -// Injector is responsible for injecting SpanContext instances in a manner suitable -// for propagation via a format-specific "carrier" object. Typically the -// injection will take place across an RPC boundary, but message queues and -// other IPC mechanisms are also reasonable places to use an Injector. -type Injector interface { - // Inject takes `SpanContext` and injects it into `carrier`. The actual type - // of `carrier` depends on the `format` passed to `Tracer.Inject()`. - // - // Implementations may return opentracing.ErrInvalidCarrier or any other - // implementation-specific error if injection fails. - Inject(ctx SpanContext, carrier interface{}) error -} - -// Extractor is responsible for extracting SpanContext instances from a -// format-specific "carrier" object. Typically the extraction will take place -// on the server side of an RPC boundary, but message queues and other IPC -// mechanisms are also reasonable places to use an Extractor. -type Extractor interface { - // Extract decodes a SpanContext instance from the given `carrier`, - // or (nil, opentracing.ErrSpanContextNotFound) if no context could - // be found in the `carrier`. - Extract(carrier interface{}) (SpanContext, error) -} - -type textMapPropagator struct { - headerKeys *HeadersConfig - metrics Metrics - encodeValue func(string) string - decodeValue func(string) string -} - -func newTextMapPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMapPropagator { - return &textMapPropagator{ - headerKeys: headerKeys, - metrics: metrics, - encodeValue: func(val string) string { - return val - }, - decodeValue: func(val string) string { - return val - }, - } -} - -func newHTTPHeaderPropagator(headerKeys *HeadersConfig, metrics Metrics) *textMapPropagator { - return &textMapPropagator{ - headerKeys: headerKeys, - metrics: metrics, - encodeValue: func(val string) string { - return url.QueryEscape(val) - }, - decodeValue: func(val string) string { - // ignore decoding errors, cannot do anything about them - if v, err := url.QueryUnescape(val); err == nil { - return v - } - return val - }, - } -} - -type binaryPropagator struct { - tracer *Tracer - buffers sync.Pool -} - -func newBinaryPropagator(tracer *Tracer) *binaryPropagator { - return &binaryPropagator{ - tracer: tracer, - buffers: sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}, - } -} - -func (p *textMapPropagator) Inject( - sc SpanContext, - abstractCarrier interface{}, -) error { - textMapWriter, ok := abstractCarrier.(opentracing.TextMapWriter) - if !ok { - return opentracing.ErrInvalidCarrier - } - - // Do not encode the string with trace context to avoid accidental double-encoding - // if people are using opentracing < 0.10.0. Our colon-separated representation - // of the trace context is already safe for HTTP headers. - textMapWriter.Set(p.headerKeys.TraceContextHeaderName, sc.String()) - for k, v := range sc.baggage { - safeKey := p.addBaggageKeyPrefix(k) - safeVal := p.encodeValue(v) - textMapWriter.Set(safeKey, safeVal) - } - return nil -} - -func (p *textMapPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { - textMapReader, ok := abstractCarrier.(opentracing.TextMapReader) - if !ok { - return emptyContext, opentracing.ErrInvalidCarrier - } - var ctx SpanContext - var baggage map[string]string - err := textMapReader.ForeachKey(func(rawKey, value string) error { - key := strings.ToLower(rawKey) // TODO not necessary for plain TextMap - if key == p.headerKeys.TraceContextHeaderName { - var err error - safeVal := p.decodeValue(value) - if ctx, err = ContextFromString(safeVal); err != nil { - return err - } - } else if key == p.headerKeys.JaegerDebugHeader { - ctx.debugID = p.decodeValue(value) - } else if key == p.headerKeys.JaegerBaggageHeader { - if baggage == nil { - baggage = make(map[string]string) - } - for k, v := range p.parseCommaSeparatedMap(value) { - baggage[k] = v - } - } else if strings.HasPrefix(key, p.headerKeys.TraceBaggageHeaderPrefix) { - if baggage == nil { - baggage = make(map[string]string) - } - safeKey := p.removeBaggageKeyPrefix(key) - safeVal := p.decodeValue(value) - baggage[safeKey] = safeVal - } - return nil - }) - if err != nil { - p.metrics.DecodingErrors.Inc(1) - return emptyContext, err - } - if !ctx.traceID.IsValid() && ctx.debugID == "" && len(baggage) == 0 { - return emptyContext, opentracing.ErrSpanContextNotFound - } - ctx.baggage = baggage - return ctx, nil -} - -func (p *binaryPropagator) Inject( - sc SpanContext, - abstractCarrier interface{}, -) error { - carrier, ok := abstractCarrier.(io.Writer) - if !ok { - return opentracing.ErrInvalidCarrier - } - - // Handle the tracer context - if err := binary.Write(carrier, binary.BigEndian, sc.traceID); err != nil { - return err - } - if err := binary.Write(carrier, binary.BigEndian, sc.spanID); err != nil { - return err - } - if err := binary.Write(carrier, binary.BigEndian, sc.parentID); err != nil { - return err - } - if err := binary.Write(carrier, binary.BigEndian, sc.flags); err != nil { - return err - } - - // Handle the baggage items - if err := binary.Write(carrier, binary.BigEndian, int32(len(sc.baggage))); err != nil { - return err - } - for k, v := range sc.baggage { - if err := binary.Write(carrier, binary.BigEndian, int32(len(k))); err != nil { - return err - } - io.WriteString(carrier, k) - if err := binary.Write(carrier, binary.BigEndian, int32(len(v))); err != nil { - return err - } - io.WriteString(carrier, v) - } - - return nil -} - -func (p *binaryPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { - carrier, ok := abstractCarrier.(io.Reader) - if !ok { - return emptyContext, opentracing.ErrInvalidCarrier - } - var ctx SpanContext - - if err := binary.Read(carrier, binary.BigEndian, &ctx.traceID); err != nil { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - if err := binary.Read(carrier, binary.BigEndian, &ctx.spanID); err != nil { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - if err := binary.Read(carrier, binary.BigEndian, &ctx.parentID); err != nil { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - if err := binary.Read(carrier, binary.BigEndian, &ctx.flags); err != nil { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - - // Handle the baggage items - var numBaggage int32 - if err := binary.Read(carrier, binary.BigEndian, &numBaggage); err != nil { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - if iNumBaggage := int(numBaggage); iNumBaggage > 0 { - ctx.baggage = make(map[string]string, iNumBaggage) - buf := p.buffers.Get().(*bytes.Buffer) - defer p.buffers.Put(buf) - - var keyLen, valLen int32 - for i := 0; i < iNumBaggage; i++ { - if err := binary.Read(carrier, binary.BigEndian, &keyLen); err != nil { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - buf.Reset() - buf.Grow(int(keyLen)) - if n, err := io.CopyN(buf, carrier, int64(keyLen)); err != nil || int32(n) != keyLen { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - key := buf.String() - - if err := binary.Read(carrier, binary.BigEndian, &valLen); err != nil { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - buf.Reset() - buf.Grow(int(valLen)) - if n, err := io.CopyN(buf, carrier, int64(valLen)); err != nil || int32(n) != valLen { - return emptyContext, opentracing.ErrSpanContextCorrupted - } - ctx.baggage[key] = buf.String() - } - } - - return ctx, nil -} - -// Converts a comma separated key value pair list into a map -// e.g. key1=value1, key2=value2, key3 = value3 -// is converted to map[string]string { "key1" : "value1", -// "key2" : "value2", -// "key3" : "value3" } -func (p *textMapPropagator) parseCommaSeparatedMap(value string) map[string]string { - baggage := make(map[string]string) - value, err := url.QueryUnescape(value) - if err != nil { - log.Printf("Unable to unescape %s, %v", value, err) - return baggage - } - for _, kvpair := range strings.Split(value, ",") { - kv := strings.Split(strings.TrimSpace(kvpair), "=") - if len(kv) == 2 { - baggage[kv[0]] = kv[1] - } else { - log.Printf("Malformed value passed in for %s", p.headerKeys.JaegerBaggageHeader) - } - } - return baggage -} - -// Converts a baggage item key into an http header format, -// by prepending TraceBaggageHeaderPrefix and encoding the key string -func (p *textMapPropagator) addBaggageKeyPrefix(key string) string { - // TODO encodeBaggageKeyAsHeader add caching and escaping - return fmt.Sprintf("%v%v", p.headerKeys.TraceBaggageHeaderPrefix, key) -} - -func (p *textMapPropagator) removeBaggageKeyPrefix(key string) string { - // TODO decodeBaggageHeaderKey add caching and escaping - return key[len(p.headerKeys.TraceBaggageHeaderPrefix):] -} diff --git a/vendor/github.com/uber/jaeger-client-go/reference.go b/vendor/github.com/uber/jaeger-client-go/reference.go deleted file mode 100644 index 5646e78bb2..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/reference.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import "github.com/opentracing/opentracing-go" - -// Reference represents a causal reference to other Spans (via their SpanContext). -type Reference struct { - Type opentracing.SpanReferenceType - Context SpanContext -} diff --git a/vendor/github.com/uber/jaeger-client-go/reporter.go b/vendor/github.com/uber/jaeger-client-go/reporter.go deleted file mode 100644 index fe6288c4b9..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/reporter.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "fmt" - "sync" - "sync/atomic" - "time" - - "github.com/opentracing/opentracing-go" - - "github.com/uber/jaeger-client-go/log" -) - -// Reporter is called by the tracer when a span is completed to report the span to the tracing collector. -type Reporter interface { - // Report submits a new span to collectors, possibly asynchronously and/or with buffering. - Report(span *Span) - - // Close does a clean shutdown of the reporter, flushing any traces that may be buffered in memory. - Close() -} - -// ------------------------------ - -type nullReporter struct{} - -// NewNullReporter creates a no-op reporter that ignores all reported spans. -func NewNullReporter() Reporter { - return &nullReporter{} -} - -// Report implements Report() method of Reporter by doing nothing. -func (r *nullReporter) Report(span *Span) { - // no-op -} - -// Close implements Close() method of Reporter by doing nothing. -func (r *nullReporter) Close() { - // no-op -} - -// ------------------------------ - -type loggingReporter struct { - logger Logger -} - -// NewLoggingReporter creates a reporter that logs all reported spans to provided logger. -func NewLoggingReporter(logger Logger) Reporter { - return &loggingReporter{logger} -} - -// Report implements Report() method of Reporter by logging the span to the logger. -func (r *loggingReporter) Report(span *Span) { - r.logger.Infof("Reporting span %+v", span) -} - -// Close implements Close() method of Reporter by doing nothing. -func (r *loggingReporter) Close() { - // no-op -} - -// ------------------------------ - -// InMemoryReporter is used for testing, and simply collects spans in memory. -type InMemoryReporter struct { - spans []opentracing.Span - lock sync.Mutex -} - -// NewInMemoryReporter creates a reporter that stores spans in memory. -// NOTE: the Tracer should be created with options.PoolSpans = false. -func NewInMemoryReporter() *InMemoryReporter { - return &InMemoryReporter{ - spans: make([]opentracing.Span, 0, 10), - } -} - -// Report implements Report() method of Reporter by storing the span in the buffer. -func (r *InMemoryReporter) Report(span *Span) { - r.lock.Lock() - r.spans = append(r.spans, span) - r.lock.Unlock() -} - -// Close implements Close() method of Reporter by doing nothing. -func (r *InMemoryReporter) Close() { - // no-op -} - -// SpansSubmitted returns the number of spans accumulated in the buffer. -func (r *InMemoryReporter) SpansSubmitted() int { - r.lock.Lock() - defer r.lock.Unlock() - return len(r.spans) -} - -// GetSpans returns accumulated spans as a copy of the buffer. -func (r *InMemoryReporter) GetSpans() []opentracing.Span { - r.lock.Lock() - defer r.lock.Unlock() - copied := make([]opentracing.Span, len(r.spans)) - copy(copied, r.spans) - return copied -} - -// Reset clears all accumulated spans. -func (r *InMemoryReporter) Reset() { - r.lock.Lock() - defer r.lock.Unlock() - r.spans = nil -} - -// ------------------------------ - -type compositeReporter struct { - reporters []Reporter -} - -// NewCompositeReporter creates a reporter that ignores all reported spans. -func NewCompositeReporter(reporters ...Reporter) Reporter { - return &compositeReporter{reporters: reporters} -} - -// Report implements Report() method of Reporter by delegating to each underlying reporter. -func (r *compositeReporter) Report(span *Span) { - for _, reporter := range r.reporters { - reporter.Report(span) - } -} - -// Close implements Close() method of Reporter by closing each underlying reporter. -func (r *compositeReporter) Close() { - for _, reporter := range r.reporters { - reporter.Close() - } -} - -// ------------- REMOTE REPORTER ----------------- - -type reporterQueueItemType int - -const ( - defaultQueueSize = 100 - defaultBufferFlushInterval = 1 * time.Second - - reporterQueueItemSpan reporterQueueItemType = iota - reporterQueueItemClose -) - -type reporterQueueItem struct { - itemType reporterQueueItemType - span *Span - close *sync.WaitGroup -} - -type remoteReporter struct { - // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment. - // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq - queueLength int64 - closed int64 // 0 - not closed, 1 - closed - - reporterOptions - - sender Transport - queue chan reporterQueueItem -} - -// NewRemoteReporter creates a new reporter that sends spans out of process by means of Sender. -// Calls to Report(Span) return immediately (side effect: if internal buffer is full the span is dropped). -// Periodically the transport buffer is flushed even if it hasn't reached max packet size. -// Calls to Close() block until all spans reported prior to the call to Close are flushed. -func NewRemoteReporter(sender Transport, opts ...ReporterOption) Reporter { - options := reporterOptions{} - for _, option := range opts { - option(&options) - } - if options.bufferFlushInterval <= 0 { - options.bufferFlushInterval = defaultBufferFlushInterval - } - if options.logger == nil { - options.logger = log.NullLogger - } - if options.metrics == nil { - options.metrics = NewNullMetrics() - } - if options.queueSize <= 0 { - options.queueSize = defaultQueueSize - } - reporter := &remoteReporter{ - reporterOptions: options, - sender: sender, - queue: make(chan reporterQueueItem, options.queueSize), - } - go reporter.processQueue() - return reporter -} - -// Report implements Report() method of Reporter. -// It passes the span to a background go-routine for submission to Jaeger backend. -// If the internal queue is full, the span is dropped and metrics.ReporterDropped counter is incremented. -// If Report() is called after the reporter has been Close()-ed, the additional spans will not be -// sent to the backend, but the metrics.ReporterDropped counter may not reflect them correctly, -// because some of them may still be successfully added to the queue. -func (r *remoteReporter) Report(span *Span) { - select { - case r.queue <- reporterQueueItem{itemType: reporterQueueItemSpan, span: span}: - atomic.AddInt64(&r.queueLength, 1) - default: - r.metrics.ReporterDropped.Inc(1) - } -} - -// Close implements Close() method of Reporter by waiting for the queue to be drained. -func (r *remoteReporter) Close() { - if swapped := atomic.CompareAndSwapInt64(&r.closed, 0, 1); !swapped { - r.logger.Error("Repeated attempt to close the reporter is ignored") - return - } - r.sendCloseEvent() - r.sender.Close() -} - -func (r *remoteReporter) sendCloseEvent() { - wg := &sync.WaitGroup{} - wg.Add(1) - item := reporterQueueItem{itemType: reporterQueueItemClose, close: wg} - - r.queue <- item // if the queue is full we will block until there is space - atomic.AddInt64(&r.queueLength, 1) - wg.Wait() -} - -// processQueue reads spans from the queue, converts them to Thrift, and stores them in an internal buffer. -// When the buffer length reaches batchSize, it is flushed by submitting the accumulated spans to Jaeger. -// Buffer also gets flushed automatically every batchFlushInterval seconds, just in case the tracer stopped -// reporting new spans. -func (r *remoteReporter) processQueue() { - // flush causes the Sender to flush its accumulated spans and clear the buffer - flush := func() { - if flushed, err := r.sender.Flush(); err != nil { - r.metrics.ReporterFailure.Inc(int64(flushed)) - r.logger.Error(fmt.Sprintf("error when flushing the buffer: %s", err.Error())) - } else if flushed > 0 { - r.metrics.ReporterSuccess.Inc(int64(flushed)) - } - } - - timer := time.NewTicker(r.bufferFlushInterval) - for { - select { - case <-timer.C: - flush() - case item := <-r.queue: - atomic.AddInt64(&r.queueLength, -1) - switch item.itemType { - case reporterQueueItemSpan: - span := item.span - if flushed, err := r.sender.Append(span); err != nil { - r.metrics.ReporterFailure.Inc(int64(flushed)) - r.logger.Error(fmt.Sprintf("error reporting span %q: %s", span.OperationName(), err.Error())) - } else if flushed > 0 { - r.metrics.ReporterSuccess.Inc(int64(flushed)) - // to reduce the number of gauge stats, we only emit queue length on flush - r.metrics.ReporterQueueLength.Update(atomic.LoadInt64(&r.queueLength)) - } - case reporterQueueItemClose: - timer.Stop() - flush() - item.close.Done() - return - } - } - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/reporter_options.go b/vendor/github.com/uber/jaeger-client-go/reporter_options.go deleted file mode 100644 index 65012d7015..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/reporter_options.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "time" -) - -// ReporterOption is a function that sets some option on the reporter. -type ReporterOption func(c *reporterOptions) - -// ReporterOptions is a factory for all available ReporterOption's -var ReporterOptions reporterOptions - -// reporterOptions control behavior of the reporter. -type reporterOptions struct { - // queueSize is the size of internal queue where reported spans are stored before they are processed in the background - queueSize int - // bufferFlushInterval is how often the buffer is force-flushed, even if it's not full - bufferFlushInterval time.Duration - // logger is used to log errors of span submissions - logger Logger - // metrics is used to record runtime stats - metrics *Metrics -} - -// QueueSize creates a ReporterOption that sets the size of the internal queue where -// spans are stored before they are processed. -func (reporterOptions) QueueSize(queueSize int) ReporterOption { - return func(r *reporterOptions) { - r.queueSize = queueSize - } -} - -// Metrics creates a ReporterOption that initializes Metrics in the reporter, -// which is used to record runtime statistics. -func (reporterOptions) Metrics(metrics *Metrics) ReporterOption { - return func(r *reporterOptions) { - r.metrics = metrics - } -} - -// BufferFlushInterval creates a ReporterOption that sets how often the queue -// is force-flushed. -func (reporterOptions) BufferFlushInterval(bufferFlushInterval time.Duration) ReporterOption { - return func(r *reporterOptions) { - r.bufferFlushInterval = bufferFlushInterval - } -} - -// Logger creates a ReporterOption that initializes the logger used to log -// errors of span submissions. -func (reporterOptions) Logger(logger Logger) ReporterOption { - return func(r *reporterOptions) { - r.logger = logger - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md deleted file mode 100644 index 879948e9c9..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md +++ /dev/null @@ -1,5 +0,0 @@ -An Observer that can be used to emit RPC metrics -================================================ - -It can be attached to the tracer during tracer construction. -See `ExampleObserver` function in [observer_test.go](./observer_test.go). diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go deleted file mode 100644 index 51aa11b350..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package rpcmetrics implements an Observer that can be used to emit RPC metrics. -package rpcmetrics diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go deleted file mode 100644 index 30555243d0..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rpcmetrics - -import "sync" - -// normalizedEndpoints is a cache for endpointName -> safeName mappings. -type normalizedEndpoints struct { - names map[string]string - maxSize int - defaultName string - normalizer NameNormalizer - mux sync.RWMutex -} - -func newNormalizedEndpoints(maxSize int, normalizer NameNormalizer) *normalizedEndpoints { - return &normalizedEndpoints{ - maxSize: maxSize, - normalizer: normalizer, - names: make(map[string]string, maxSize), - } -} - -// normalize looks up the name in the cache, if not found it uses normalizer -// to convert the name to a safe name. If called with more than maxSize unique -// names it returns "" for all other names beyond those already cached. -func (n *normalizedEndpoints) normalize(name string) string { - n.mux.RLock() - norm, ok := n.names[name] - l := len(n.names) - n.mux.RUnlock() - if ok { - return norm - } - if l >= n.maxSize { - return "" - } - return n.normalizeWithLock(name) -} - -func (n *normalizedEndpoints) normalizeWithLock(name string) string { - norm := n.normalizer.Normalize(name) - n.mux.Lock() - defer n.mux.Unlock() - // cache may have grown while we were not holding the lock - if len(n.names) >= n.maxSize { - return "" - } - n.names[name] = norm - return norm -} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go deleted file mode 100644 index ab8d74c291..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rpcmetrics - -import ( - "sync" - - "github.com/uber/jaeger-lib/metrics" -) - -const ( - otherEndpointsPlaceholder = "other" - endpointNameMetricTag = "endpoint" -) - -// Metrics is a collection of metrics for an endpoint describing -// throughput, success, errors, and performance. -type Metrics struct { - // RequestCountSuccess is a counter of the total number of successes. - RequestCountSuccess metrics.Counter `metric:"requests" tags:"error=false"` - - // RequestCountFailures is a counter of the number of times any failure has been observed. - RequestCountFailures metrics.Counter `metric:"requests" tags:"error=true"` - - // RequestLatencySuccess is a latency histogram of succesful requests. - RequestLatencySuccess metrics.Timer `metric:"request_latency" tags:"error=false"` - - // RequestLatencyFailures is a latency histogram of failed requests. - RequestLatencyFailures metrics.Timer `metric:"request_latency" tags:"error=true"` - - // HTTPStatusCode2xx is a counter of the total number of requests with HTTP status code 200-299 - HTTPStatusCode2xx metrics.Counter `metric:"http_requests" tags:"status_code=2xx"` - - // HTTPStatusCode3xx is a counter of the total number of requests with HTTP status code 300-399 - HTTPStatusCode3xx metrics.Counter `metric:"http_requests" tags:"status_code=3xx"` - - // HTTPStatusCode4xx is a counter of the total number of requests with HTTP status code 400-499 - HTTPStatusCode4xx metrics.Counter `metric:"http_requests" tags:"status_code=4xx"` - - // HTTPStatusCode5xx is a counter of the total number of requests with HTTP status code 500-599 - HTTPStatusCode5xx metrics.Counter `metric:"http_requests" tags:"status_code=5xx"` -} - -func (m *Metrics) recordHTTPStatusCode(statusCode uint16) { - if statusCode >= 200 && statusCode < 300 { - m.HTTPStatusCode2xx.Inc(1) - } else if statusCode >= 300 && statusCode < 400 { - m.HTTPStatusCode3xx.Inc(1) - } else if statusCode >= 400 && statusCode < 500 { - m.HTTPStatusCode4xx.Inc(1) - } else if statusCode >= 500 && statusCode < 600 { - m.HTTPStatusCode5xx.Inc(1) - } -} - -// MetricsByEndpoint is a registry/cache of metrics for each unique endpoint name. -// Only maxNumberOfEndpoints Metrics are stored, all other endpoint names are mapped -// to a generic endpoint name "other". -type MetricsByEndpoint struct { - metricsFactory metrics.Factory - endpoints *normalizedEndpoints - metricsByEndpoint map[string]*Metrics - mux sync.RWMutex -} - -func newMetricsByEndpoint( - metricsFactory metrics.Factory, - normalizer NameNormalizer, - maxNumberOfEndpoints int, -) *MetricsByEndpoint { - return &MetricsByEndpoint{ - metricsFactory: metricsFactory, - endpoints: newNormalizedEndpoints(maxNumberOfEndpoints, normalizer), - metricsByEndpoint: make(map[string]*Metrics, maxNumberOfEndpoints+1), // +1 for "other" - } -} - -func (m *MetricsByEndpoint) get(endpoint string) *Metrics { - safeName := m.endpoints.normalize(endpoint) - if safeName == "" { - safeName = otherEndpointsPlaceholder - } - m.mux.RLock() - met := m.metricsByEndpoint[safeName] - m.mux.RUnlock() - if met != nil { - return met - } - - return m.getWithWriteLock(safeName) -} - -// split to make easier to test -func (m *MetricsByEndpoint) getWithWriteLock(safeName string) *Metrics { - m.mux.Lock() - defer m.mux.Unlock() - - // it is possible that the name has been already registered after we released - // the read lock and before we grabbed the write lock, so check for that. - if met, ok := m.metricsByEndpoint[safeName]; ok { - return met - } - - // it would be nice to create the struct before locking, since Init() is somewhat - // expensive, however some metrics backends (e.g. expvar) may not like duplicate metrics. - met := &Metrics{} - tags := map[string]string{endpointNameMetricTag: safeName} - metrics.Init(met, m.metricsFactory, tags) - - m.metricsByEndpoint[safeName] = met - return met -} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go deleted file mode 100644 index 148d84b3a1..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rpcmetrics - -// NameNormalizer is used to convert the endpoint names to strings -// that can be safely used as tags in the metrics. -type NameNormalizer interface { - Normalize(name string) string -} - -// DefaultNameNormalizer converts endpoint names so that they contain only characters -// from the safe charset [a-zA-Z0-9-./_]. All other characters are replaced with '-'. -var DefaultNameNormalizer = &SimpleNameNormalizer{ - SafeSets: []SafeCharacterSet{ - &Range{From: 'a', To: 'z'}, - &Range{From: 'A', To: 'Z'}, - &Range{From: '0', To: '9'}, - &Char{'-'}, - &Char{'_'}, - &Char{'/'}, - &Char{'.'}, - }, - Replacement: '-', -} - -// SimpleNameNormalizer uses a set of safe character sets. -type SimpleNameNormalizer struct { - SafeSets []SafeCharacterSet - Replacement byte -} - -// SafeCharacterSet determines if the given character is "safe" -type SafeCharacterSet interface { - IsSafe(c byte) bool -} - -// Range implements SafeCharacterSet -type Range struct { - From, To byte -} - -// IsSafe implements SafeCharacterSet -func (r *Range) IsSafe(c byte) bool { - return c >= r.From && c <= r.To -} - -// Char implements SafeCharacterSet -type Char struct { - Val byte -} - -// IsSafe implements SafeCharacterSet -func (ch *Char) IsSafe(c byte) bool { - return c == ch.Val -} - -// Normalize checks each character in the string against SafeSets, -// and if it's not safe substitutes it with Replacement. -func (n *SimpleNameNormalizer) Normalize(name string) string { - var retMe []byte - nameBytes := []byte(name) - for i, b := range nameBytes { - if n.safeByte(b) { - if retMe != nil { - retMe[i] = b - } - } else { - if retMe == nil { - retMe = make([]byte, len(nameBytes)) - copy(retMe[0:i], nameBytes[0:i]) - } - retMe[i] = n.Replacement - } - } - if retMe == nil { - return name - } - return string(retMe) -} - -// safeByte checks if b against all safe charsets. -func (n *SimpleNameNormalizer) safeByte(b byte) bool { - for i := range n.SafeSets { - if n.SafeSets[i].IsSafe(b) { - return true - } - } - return false -} diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go deleted file mode 100644 index eca5ff6f3b..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rpcmetrics - -import ( - "strconv" - "sync" - "time" - - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/uber/jaeger-lib/metrics" - - jaeger "github.com/uber/jaeger-client-go" -) - -const defaultMaxNumberOfEndpoints = 200 - -// Observer is an observer that can emit RPC metrics. -type Observer struct { - metricsByEndpoint *MetricsByEndpoint -} - -// NewObserver creates a new observer that can emit RPC metrics. -func NewObserver(metricsFactory metrics.Factory, normalizer NameNormalizer) *Observer { - return &Observer{ - metricsByEndpoint: newMetricsByEndpoint( - metricsFactory, - normalizer, - defaultMaxNumberOfEndpoints, - ), - } -} - -// OnStartSpan creates a new Observer for the span. -func (o *Observer) OnStartSpan( - operationName string, - options opentracing.StartSpanOptions, -) jaeger.SpanObserver { - return NewSpanObserver(o.metricsByEndpoint, operationName, options) -} - -// SpanKind identifies the span as inboud, outbound, or internal -type SpanKind int - -const ( - // Local span kind - Local SpanKind = iota - // Inbound span kind - Inbound - // Outbound span kind - Outbound -) - -// SpanObserver collects RPC metrics -type SpanObserver struct { - metricsByEndpoint *MetricsByEndpoint - operationName string - startTime time.Time - mux sync.Mutex - kind SpanKind - httpStatusCode uint16 - err bool -} - -// NewSpanObserver creates a new SpanObserver that can emit RPC metrics. -func NewSpanObserver( - metricsByEndpoint *MetricsByEndpoint, - operationName string, - options opentracing.StartSpanOptions, -) *SpanObserver { - so := &SpanObserver{ - metricsByEndpoint: metricsByEndpoint, - operationName: operationName, - startTime: options.StartTime, - } - for k, v := range options.Tags { - so.handleTagInLock(k, v) - } - return so -} - -// handleTags watches for special tags -// - SpanKind -// - HttpStatusCode -// - Error -func (so *SpanObserver) handleTagInLock(key string, value interface{}) { - if key == string(ext.SpanKind) { - if v, ok := value.(ext.SpanKindEnum); ok { - value = string(v) - } - if v, ok := value.(string); ok { - if v == string(ext.SpanKindRPCClientEnum) { - so.kind = Outbound - } else if v == string(ext.SpanKindRPCServerEnum) { - so.kind = Inbound - } - } - return - } - if key == string(ext.HTTPStatusCode) { - if v, ok := value.(uint16); ok { - so.httpStatusCode = v - } else if v, ok := value.(int); ok { - so.httpStatusCode = uint16(v) - } else if v, ok := value.(string); ok { - if vv, err := strconv.Atoi(v); err == nil { - so.httpStatusCode = uint16(vv) - } - } - return - } - if key == string(ext.Error) { - if v, ok := value.(bool); ok { - so.err = v - } else if v, ok := value.(string); ok { - if vv, err := strconv.ParseBool(v); err == nil { - so.err = vv - } - } - return - } -} - -// OnFinish emits the RPC metrics. It only has an effect when operation name -// is not blank, and the span kind is an RPC server. -func (so *SpanObserver) OnFinish(options opentracing.FinishOptions) { - so.mux.Lock() - defer so.mux.Unlock() - - if so.operationName == "" || so.kind != Inbound { - return - } - - mets := so.metricsByEndpoint.get(so.operationName) - latency := options.FinishTime.Sub(so.startTime) - if so.err { - mets.RequestCountFailures.Inc(1) - mets.RequestLatencyFailures.Record(latency) - } else { - mets.RequestCountSuccess.Inc(1) - mets.RequestLatencySuccess.Record(latency) - } - mets.recordHTTPStatusCode(so.httpStatusCode) -} - -// OnSetOperationName records new operation name. -func (so *SpanObserver) OnSetOperationName(operationName string) { - so.mux.Lock() - so.operationName = operationName - so.mux.Unlock() -} - -// OnSetTag implements SpanObserver -func (so *SpanObserver) OnSetTag(key string, value interface{}) { - so.mux.Lock() - so.handleTagInLock(key, value) - so.mux.Unlock() -} diff --git a/vendor/github.com/uber/jaeger-client-go/sampler.go b/vendor/github.com/uber/jaeger-client-go/sampler.go deleted file mode 100644 index e6a32b3837..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/sampler.go +++ /dev/null @@ -1,556 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "fmt" - "math" - "net/url" - "sync" - "sync/atomic" - "time" - - "github.com/uber/jaeger-client-go/log" - "github.com/uber/jaeger-client-go/thrift-gen/sampling" - "github.com/uber/jaeger-client-go/utils" -) - -const ( - defaultSamplingServerURL = "http://localhost:5778/sampling" - defaultSamplingRefreshInterval = time.Minute - defaultMaxOperations = 2000 -) - -// Sampler decides whether a new trace should be sampled or not. -type Sampler interface { - // IsSampled decides whether a trace with given `id` and `operation` - // should be sampled. This function will also return the tags that - // can be used to identify the type of sampling that was applied to - // the root span. Most simple samplers would return two tags, - // sampler.type and sampler.param, similar to those used in the Configuration - IsSampled(id TraceID, operation string) (sampled bool, tags []Tag) - - // Close does a clean shutdown of the sampler, stopping any background - // go-routines it may have started. - Close() - - // Equal checks if the `other` sampler is functionally equivalent - // to this sampler. - // TODO remove this function. This function is used to determine if 2 samplers are equivalent - // which does not bode well with the adaptive sampler which has to create all the composite samplers - // for the comparison to occur. This is expensive to do if only one sampler has changed. - Equal(other Sampler) bool -} - -// ----------------------- - -// ConstSampler is a sampler that always makes the same decision. -type ConstSampler struct { - Decision bool - tags []Tag -} - -// NewConstSampler creates a ConstSampler. -func NewConstSampler(sample bool) Sampler { - tags := []Tag{ - {key: SamplerTypeTagKey, value: SamplerTypeConst}, - {key: SamplerParamTagKey, value: sample}, - } - return &ConstSampler{Decision: sample, tags: tags} -} - -// IsSampled implements IsSampled() of Sampler. -func (s *ConstSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { - return s.Decision, s.tags -} - -// Close implements Close() of Sampler. -func (s *ConstSampler) Close() { - // nothing to do -} - -// Equal implements Equal() of Sampler. -func (s *ConstSampler) Equal(other Sampler) bool { - if o, ok := other.(*ConstSampler); ok { - return s.Decision == o.Decision - } - return false -} - -// ----------------------- - -// ProbabilisticSampler is a sampler that randomly samples a certain percentage -// of traces. -type ProbabilisticSampler struct { - samplingRate float64 - samplingBoundary uint64 - tags []Tag -} - -const maxRandomNumber = ^(uint64(1) << 63) // i.e. 0x7fffffffffffffff - -// NewProbabilisticSampler creates a sampler that randomly samples a certain percentage of traces specified by the -// samplingRate, in the range between 0.0 and 1.0. -// -// It relies on the fact that new trace IDs are 63bit random numbers themselves, thus making the sampling decision -// without generating a new random number, but simply calculating if traceID < (samplingRate * 2^63). -// TODO remove the error from this function for next major release -func NewProbabilisticSampler(samplingRate float64) (*ProbabilisticSampler, error) { - if samplingRate < 0.0 || samplingRate > 1.0 { - return nil, fmt.Errorf("Sampling Rate must be between 0.0 and 1.0, received %f", samplingRate) - } - return newProbabilisticSampler(samplingRate), nil -} - -func newProbabilisticSampler(samplingRate float64) *ProbabilisticSampler { - samplingRate = math.Max(0.0, math.Min(samplingRate, 1.0)) - tags := []Tag{ - {key: SamplerTypeTagKey, value: SamplerTypeProbabilistic}, - {key: SamplerParamTagKey, value: samplingRate}, - } - return &ProbabilisticSampler{ - samplingRate: samplingRate, - samplingBoundary: uint64(float64(maxRandomNumber) * samplingRate), - tags: tags, - } -} - -// SamplingRate returns the sampling probability this sampled was constructed with. -func (s *ProbabilisticSampler) SamplingRate() float64 { - return s.samplingRate -} - -// IsSampled implements IsSampled() of Sampler. -func (s *ProbabilisticSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { - return s.samplingBoundary >= id.Low, s.tags -} - -// Close implements Close() of Sampler. -func (s *ProbabilisticSampler) Close() { - // nothing to do -} - -// Equal implements Equal() of Sampler. -func (s *ProbabilisticSampler) Equal(other Sampler) bool { - if o, ok := other.(*ProbabilisticSampler); ok { - return s.samplingBoundary == o.samplingBoundary - } - return false -} - -// ----------------------- - -type rateLimitingSampler struct { - maxTracesPerSecond float64 - rateLimiter utils.RateLimiter - tags []Tag -} - -// NewRateLimitingSampler creates a sampler that samples at most maxTracesPerSecond. The distribution of sampled -// traces follows burstiness of the service, i.e. a service with uniformly distributed requests will have those -// requests sampled uniformly as well, but if requests are bursty, especially sub-second, then a number of -// sequential requests can be sampled each second. -func NewRateLimitingSampler(maxTracesPerSecond float64) Sampler { - tags := []Tag{ - {key: SamplerTypeTagKey, value: SamplerTypeRateLimiting}, - {key: SamplerParamTagKey, value: maxTracesPerSecond}, - } - return &rateLimitingSampler{ - maxTracesPerSecond: maxTracesPerSecond, - rateLimiter: utils.NewRateLimiter(maxTracesPerSecond, math.Max(maxTracesPerSecond, 1.0)), - tags: tags, - } -} - -// IsSampled implements IsSampled() of Sampler. -func (s *rateLimitingSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { - return s.rateLimiter.CheckCredit(1.0), s.tags -} - -func (s *rateLimitingSampler) Close() { - // nothing to do -} - -func (s *rateLimitingSampler) Equal(other Sampler) bool { - if o, ok := other.(*rateLimitingSampler); ok { - return s.maxTracesPerSecond == o.maxTracesPerSecond - } - return false -} - -// ----------------------- - -// GuaranteedThroughputProbabilisticSampler is a sampler that leverages both probabilisticSampler and -// rateLimitingSampler. The rateLimitingSampler is used as a guaranteed lower bound sampler such that -// every operation is sampled at least once in a time interval defined by the lowerBound. ie a lowerBound -// of 1.0 / (60 * 10) will sample an operation at least once every 10 minutes. -// -// The probabilisticSampler is given higher priority when tags are emitted, ie. if IsSampled() for both -// samplers return true, the tags for probabilisticSampler will be used. -type GuaranteedThroughputProbabilisticSampler struct { - probabilisticSampler *ProbabilisticSampler - lowerBoundSampler Sampler - tags []Tag - samplingRate float64 - lowerBound float64 -} - -// NewGuaranteedThroughputProbabilisticSampler returns a delegating sampler that applies both -// probabilisticSampler and rateLimitingSampler. -func NewGuaranteedThroughputProbabilisticSampler( - lowerBound, samplingRate float64, -) (*GuaranteedThroughputProbabilisticSampler, error) { - return newGuaranteedThroughputProbabilisticSampler(lowerBound, samplingRate), nil -} - -func newGuaranteedThroughputProbabilisticSampler(lowerBound, samplingRate float64) *GuaranteedThroughputProbabilisticSampler { - s := &GuaranteedThroughputProbabilisticSampler{ - lowerBoundSampler: NewRateLimitingSampler(lowerBound), - lowerBound: lowerBound, - } - s.setProbabilisticSampler(samplingRate) - return s -} - -func (s *GuaranteedThroughputProbabilisticSampler) setProbabilisticSampler(samplingRate float64) { - if s.probabilisticSampler == nil || s.samplingRate != samplingRate { - s.probabilisticSampler = newProbabilisticSampler(samplingRate) - s.samplingRate = s.probabilisticSampler.SamplingRate() - s.tags = []Tag{ - {key: SamplerTypeTagKey, value: SamplerTypeLowerBound}, - {key: SamplerParamTagKey, value: s.samplingRate}, - } - } -} - -// IsSampled implements IsSampled() of Sampler. -func (s *GuaranteedThroughputProbabilisticSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { - if sampled, tags := s.probabilisticSampler.IsSampled(id, operation); sampled { - s.lowerBoundSampler.IsSampled(id, operation) - return true, tags - } - sampled, _ := s.lowerBoundSampler.IsSampled(id, operation) - return sampled, s.tags -} - -// Close implements Close() of Sampler. -func (s *GuaranteedThroughputProbabilisticSampler) Close() { - s.probabilisticSampler.Close() - s.lowerBoundSampler.Close() -} - -// Equal implements Equal() of Sampler. -func (s *GuaranteedThroughputProbabilisticSampler) Equal(other Sampler) bool { - // NB The Equal() function is expensive and will be removed. See adaptiveSampler.Equal() for - // more information. - return false -} - -// this function should only be called while holding a Write lock -func (s *GuaranteedThroughputProbabilisticSampler) update(lowerBound, samplingRate float64) { - s.setProbabilisticSampler(samplingRate) - if s.lowerBound != lowerBound { - s.lowerBoundSampler = NewRateLimitingSampler(lowerBound) - s.lowerBound = lowerBound - } -} - -// ----------------------- - -type adaptiveSampler struct { - sync.RWMutex - - samplers map[string]*GuaranteedThroughputProbabilisticSampler - defaultSampler *ProbabilisticSampler - lowerBound float64 - maxOperations int -} - -// NewAdaptiveSampler returns a delegating sampler that applies both probabilisticSampler and -// rateLimitingSampler via the guaranteedThroughputProbabilisticSampler. This sampler keeps track of all -// operations and delegates calls to the respective guaranteedThroughputProbabilisticSampler. -func NewAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies, maxOperations int) (Sampler, error) { - return newAdaptiveSampler(strategies, maxOperations), nil -} - -func newAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies, maxOperations int) Sampler { - samplers := make(map[string]*GuaranteedThroughputProbabilisticSampler) - for _, strategy := range strategies.PerOperationStrategies { - sampler := newGuaranteedThroughputProbabilisticSampler( - strategies.DefaultLowerBoundTracesPerSecond, - strategy.ProbabilisticSampling.SamplingRate, - ) - samplers[strategy.Operation] = sampler - } - return &adaptiveSampler{ - samplers: samplers, - defaultSampler: newProbabilisticSampler(strategies.DefaultSamplingProbability), - lowerBound: strategies.DefaultLowerBoundTracesPerSecond, - maxOperations: maxOperations, - } -} - -func (s *adaptiveSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { - s.RLock() - sampler, ok := s.samplers[operation] - if ok { - defer s.RUnlock() - return sampler.IsSampled(id, operation) - } - s.RUnlock() - s.Lock() - defer s.Unlock() - - // Check if sampler has already been created - sampler, ok = s.samplers[operation] - if ok { - return sampler.IsSampled(id, operation) - } - // Store only up to maxOperations of unique ops. - if len(s.samplers) >= s.maxOperations { - return s.defaultSampler.IsSampled(id, operation) - } - newSampler := newGuaranteedThroughputProbabilisticSampler(s.lowerBound, s.defaultSampler.SamplingRate()) - s.samplers[operation] = newSampler - return newSampler.IsSampled(id, operation) -} - -func (s *adaptiveSampler) Close() { - s.Lock() - defer s.Unlock() - for _, sampler := range s.samplers { - sampler.Close() - } - s.defaultSampler.Close() -} - -func (s *adaptiveSampler) Equal(other Sampler) bool { - // NB The Equal() function is overly expensive for adaptiveSampler since it's composed of multiple - // samplers which all need to be initialized before this function can be called for a comparison. - // Therefore, adaptiveSampler uses the update() function to only alter the samplers that need - // changing. Hence this function always returns false so that the update function can be called. - // Once the Equal() function is removed from the Sampler API, this will no longer be needed. - return false -} - -func (s *adaptiveSampler) update(strategies *sampling.PerOperationSamplingStrategies) { - s.Lock() - defer s.Unlock() - for _, strategy := range strategies.PerOperationStrategies { - operation := strategy.Operation - samplingRate := strategy.ProbabilisticSampling.SamplingRate - lowerBound := strategies.DefaultLowerBoundTracesPerSecond - if sampler, ok := s.samplers[operation]; ok { - sampler.update(lowerBound, samplingRate) - } else { - sampler := newGuaranteedThroughputProbabilisticSampler( - lowerBound, - samplingRate, - ) - s.samplers[operation] = sampler - } - } - s.lowerBound = strategies.DefaultLowerBoundTracesPerSecond - if s.defaultSampler.SamplingRate() != strategies.DefaultSamplingProbability { - s.defaultSampler = newProbabilisticSampler(strategies.DefaultSamplingProbability) - } -} - -// ----------------------- - -// RemotelyControlledSampler is a delegating sampler that polls a remote server -// for the appropriate sampling strategy, constructs a corresponding sampler and -// delegates to it for sampling decisions. -type RemotelyControlledSampler struct { - // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment. - // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq - closed int64 // 0 - not closed, 1 - closed - - sync.RWMutex - samplerOptions - - serviceName string - manager sampling.SamplingManager - doneChan chan *sync.WaitGroup -} - -type httpSamplingManager struct { - serverURL string -} - -func (s *httpSamplingManager) GetSamplingStrategy(serviceName string) (*sampling.SamplingStrategyResponse, error) { - var out sampling.SamplingStrategyResponse - v := url.Values{} - v.Set("service", serviceName) - if err := utils.GetJSON(s.serverURL+"?"+v.Encode(), &out); err != nil { - return nil, err - } - return &out, nil -} - -// NewRemotelyControlledSampler creates a sampler that periodically pulls -// the sampling strategy from an HTTP sampling server (e.g. jaeger-agent). -func NewRemotelyControlledSampler( - serviceName string, - opts ...SamplerOption, -) *RemotelyControlledSampler { - options := applySamplerOptions(opts...) - sampler := &RemotelyControlledSampler{ - samplerOptions: options, - serviceName: serviceName, - manager: &httpSamplingManager{serverURL: options.samplingServerURL}, - doneChan: make(chan *sync.WaitGroup), - } - go sampler.pollController() - return sampler -} - -func applySamplerOptions(opts ...SamplerOption) samplerOptions { - options := samplerOptions{} - for _, option := range opts { - option(&options) - } - if options.sampler == nil { - options.sampler = newProbabilisticSampler(0.001) - } - if options.logger == nil { - options.logger = log.NullLogger - } - if options.maxOperations <= 0 { - options.maxOperations = defaultMaxOperations - } - if options.samplingServerURL == "" { - options.samplingServerURL = defaultSamplingServerURL - } - if options.metrics == nil { - options.metrics = NewNullMetrics() - } - if options.samplingRefreshInterval <= 0 { - options.samplingRefreshInterval = defaultSamplingRefreshInterval - } - return options -} - -// IsSampled implements IsSampled() of Sampler. -func (s *RemotelyControlledSampler) IsSampled(id TraceID, operation string) (bool, []Tag) { - s.RLock() - defer s.RUnlock() - return s.sampler.IsSampled(id, operation) -} - -// Close implements Close() of Sampler. -func (s *RemotelyControlledSampler) Close() { - if swapped := atomic.CompareAndSwapInt64(&s.closed, 0, 1); !swapped { - s.logger.Error("Repeated attempt to close the sampler is ignored") - return - } - - var wg sync.WaitGroup - wg.Add(1) - s.doneChan <- &wg - wg.Wait() -} - -// Equal implements Equal() of Sampler. -func (s *RemotelyControlledSampler) Equal(other Sampler) bool { - // NB The Equal() function is expensive and will be removed. See adaptiveSampler.Equal() for - // more information. - if o, ok := other.(*RemotelyControlledSampler); ok { - s.RLock() - o.RLock() - defer s.RUnlock() - defer o.RUnlock() - return s.sampler.Equal(o.sampler) - } - return false -} - -func (s *RemotelyControlledSampler) pollController() { - ticker := time.NewTicker(s.samplingRefreshInterval) - defer ticker.Stop() - s.pollControllerWithTicker(ticker) -} - -func (s *RemotelyControlledSampler) pollControllerWithTicker(ticker *time.Ticker) { - for { - select { - case <-ticker.C: - s.updateSampler() - case wg := <-s.doneChan: - wg.Done() - return - } - } -} - -func (s *RemotelyControlledSampler) getSampler() Sampler { - s.Lock() - defer s.Unlock() - return s.sampler -} - -func (s *RemotelyControlledSampler) setSampler(sampler Sampler) { - s.Lock() - defer s.Unlock() - s.sampler = sampler -} - -func (s *RemotelyControlledSampler) updateSampler() { - res, err := s.manager.GetSamplingStrategy(s.serviceName) - if err != nil { - s.metrics.SamplerQueryFailure.Inc(1) - return - } - s.Lock() - defer s.Unlock() - - s.metrics.SamplerRetrieved.Inc(1) - if strategies := res.GetOperationSampling(); strategies != nil { - s.updateAdaptiveSampler(strategies) - } else { - err = s.updateRateLimitingOrProbabilisticSampler(res) - } - if err != nil { - s.metrics.SamplerUpdateFailure.Inc(1) - s.logger.Infof("Unable to handle sampling strategy response %+v. Got error: %v", res, err) - return - } - s.metrics.SamplerUpdated.Inc(1) -} - -// NB: this function should only be called while holding a Write lock -func (s *RemotelyControlledSampler) updateAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies) { - if adaptiveSampler, ok := s.sampler.(*adaptiveSampler); ok { - adaptiveSampler.update(strategies) - } else { - s.sampler = newAdaptiveSampler(strategies, s.maxOperations) - } -} - -// NB: this function should only be called while holding a Write lock -func (s *RemotelyControlledSampler) updateRateLimitingOrProbabilisticSampler(res *sampling.SamplingStrategyResponse) error { - var newSampler Sampler - if probabilistic := res.GetProbabilisticSampling(); probabilistic != nil { - newSampler = newProbabilisticSampler(probabilistic.SamplingRate) - } else if rateLimiting := res.GetRateLimitingSampling(); rateLimiting != nil { - newSampler = NewRateLimitingSampler(float64(rateLimiting.MaxTracesPerSecond)) - } else { - return fmt.Errorf("Unsupported sampling strategy type %v", res.GetStrategyType()) - } - if !s.sampler.Equal(newSampler) { - s.sampler = newSampler - } - return nil -} diff --git a/vendor/github.com/uber/jaeger-client-go/sampler_options.go b/vendor/github.com/uber/jaeger-client-go/sampler_options.go deleted file mode 100644 index 75d28a5611..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/sampler_options.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "time" -) - -// SamplerOption is a function that sets some option on the sampler -type SamplerOption func(options *samplerOptions) - -// SamplerOptions is a factory for all available SamplerOption's -var SamplerOptions samplerOptions - -type samplerOptions struct { - metrics *Metrics - maxOperations int - sampler Sampler - logger Logger - samplingServerURL string - samplingRefreshInterval time.Duration -} - -// Metrics creates a SamplerOption that initializes Metrics on the sampler, -// which is used to emit statistics. -func (samplerOptions) Metrics(m *Metrics) SamplerOption { - return func(o *samplerOptions) { - o.metrics = m - } -} - -// MaxOperations creates a SamplerOption that sets the maximum number of -// operations the sampler will keep track of. -func (samplerOptions) MaxOperations(maxOperations int) SamplerOption { - return func(o *samplerOptions) { - o.maxOperations = maxOperations - } -} - -// InitialSampler creates a SamplerOption that sets the initial sampler -// to use before a remote sampler is created and used. -func (samplerOptions) InitialSampler(sampler Sampler) SamplerOption { - return func(o *samplerOptions) { - o.sampler = sampler - } -} - -// Logger creates a SamplerOption that sets the logger used by the sampler. -func (samplerOptions) Logger(logger Logger) SamplerOption { - return func(o *samplerOptions) { - o.logger = logger - } -} - -// SamplingServerURL creates a SamplerOption that sets the sampling server url -// of the local agent that contains the sampling strategies. -func (samplerOptions) SamplingServerURL(samplingServerURL string) SamplerOption { - return func(o *samplerOptions) { - o.samplingServerURL = samplingServerURL - } -} - -// SamplingRefreshInterval creates a SamplerOption that sets how often the -// sampler will poll local agent for the appropriate sampling strategy. -func (samplerOptions) SamplingRefreshInterval(samplingRefreshInterval time.Duration) SamplerOption { - return func(o *samplerOptions) { - o.samplingRefreshInterval = samplingRefreshInterval - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/span.go b/vendor/github.com/uber/jaeger-client-go/span.go deleted file mode 100644 index f0b497a90a..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/span.go +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2017-2018 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "sync" - "time" - - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/opentracing/opentracing-go/log" -) - -// Span implements opentracing.Span -type Span struct { - sync.RWMutex - - tracer *Tracer - - context SpanContext - - // The name of the "operation" this span is an instance of. - // Known as a "span name" in some implementations. - operationName string - - // firstInProcess, if true, indicates that this span is the root of the (sub)tree - // of spans in the current process. In other words it's true for the root spans, - // and the ingress spans when the process joins another trace. - firstInProcess bool - - // startTime is the timestamp indicating when the span began, with microseconds precision. - startTime time.Time - - // duration returns duration of the span with microseconds precision. - // Zero value means duration is unknown. - duration time.Duration - - // tags attached to this span - tags []Tag - - // The span's "micro-log" - logs []opentracing.LogRecord - - // references for this span - references []Reference - - observer ContribSpanObserver -} - -// Tag is a simple key value wrapper. -// TODO deprecate in the next major release, use opentracing.Tag instead. -type Tag struct { - key string - value interface{} -} - -// SetOperationName sets or changes the operation name. -func (s *Span) SetOperationName(operationName string) opentracing.Span { - s.Lock() - defer s.Unlock() - if s.context.IsSampled() { - s.operationName = operationName - } - s.observer.OnSetOperationName(operationName) - return s -} - -// SetTag implements SetTag() of opentracing.Span -func (s *Span) SetTag(key string, value interface{}) opentracing.Span { - s.observer.OnSetTag(key, value) - if key == string(ext.SamplingPriority) && !setSamplingPriority(s, value) { - return s - } - s.Lock() - defer s.Unlock() - if s.context.IsSampled() { - s.setTagNoLocking(key, value) - } - return s -} - -func (s *Span) setTagNoLocking(key string, value interface{}) { - s.tags = append(s.tags, Tag{key: key, value: value}) -} - -// LogFields implements opentracing.Span API -func (s *Span) LogFields(fields ...log.Field) { - s.Lock() - defer s.Unlock() - if !s.context.IsSampled() { - return - } - s.logFieldsNoLocking(fields...) -} - -// this function should only be called while holding a Write lock -func (s *Span) logFieldsNoLocking(fields ...log.Field) { - lr := opentracing.LogRecord{ - Fields: fields, - Timestamp: time.Now(), - } - s.appendLog(lr) -} - -// LogKV implements opentracing.Span API -func (s *Span) LogKV(alternatingKeyValues ...interface{}) { - s.RLock() - sampled := s.context.IsSampled() - s.RUnlock() - if !sampled { - return - } - fields, err := log.InterleavedKVToFields(alternatingKeyValues...) - if err != nil { - s.LogFields(log.Error(err), log.String("function", "LogKV")) - return - } - s.LogFields(fields...) -} - -// LogEvent implements opentracing.Span API -func (s *Span) LogEvent(event string) { - s.Log(opentracing.LogData{Event: event}) -} - -// LogEventWithPayload implements opentracing.Span API -func (s *Span) LogEventWithPayload(event string, payload interface{}) { - s.Log(opentracing.LogData{Event: event, Payload: payload}) -} - -// Log implements opentracing.Span API -func (s *Span) Log(ld opentracing.LogData) { - s.Lock() - defer s.Unlock() - if s.context.IsSampled() { - if ld.Timestamp.IsZero() { - ld.Timestamp = s.tracer.timeNow() - } - s.appendLog(ld.ToLogRecord()) - } -} - -// this function should only be called while holding a Write lock -func (s *Span) appendLog(lr opentracing.LogRecord) { - // TODO add logic to limit number of logs per span (issue #46) - s.logs = append(s.logs, lr) -} - -// SetBaggageItem implements SetBaggageItem() of opentracing.SpanContext -func (s *Span) SetBaggageItem(key, value string) opentracing.Span { - s.Lock() - defer s.Unlock() - s.tracer.setBaggage(s, key, value) - return s -} - -// BaggageItem implements BaggageItem() of opentracing.SpanContext -func (s *Span) BaggageItem(key string) string { - s.RLock() - defer s.RUnlock() - return s.context.baggage[key] -} - -// Finish implements opentracing.Span API -func (s *Span) Finish() { - s.FinishWithOptions(opentracing.FinishOptions{}) -} - -// FinishWithOptions implements opentracing.Span API -func (s *Span) FinishWithOptions(options opentracing.FinishOptions) { - if options.FinishTime.IsZero() { - options.FinishTime = s.tracer.timeNow() - } - s.observer.OnFinish(options) - s.Lock() - if s.context.IsSampled() { - s.duration = options.FinishTime.Sub(s.startTime) - // Note: bulk logs are not subject to maxLogsPerSpan limit - if options.LogRecords != nil { - s.logs = append(s.logs, options.LogRecords...) - } - for _, ld := range options.BulkLogData { - s.logs = append(s.logs, ld.ToLogRecord()) - } - } - s.Unlock() - // call reportSpan even for non-sampled traces, to return span to the pool - s.tracer.reportSpan(s) -} - -// Context implements opentracing.Span API -func (s *Span) Context() opentracing.SpanContext { - s.Lock() - defer s.Unlock() - return s.context -} - -// Tracer implements opentracing.Span API -func (s *Span) Tracer() opentracing.Tracer { - return s.tracer -} - -func (s *Span) String() string { - s.RLock() - defer s.RUnlock() - return s.context.String() -} - -// OperationName allows retrieving current operation name. -func (s *Span) OperationName() string { - s.RLock() - defer s.RUnlock() - return s.operationName -} - -func (s *Span) serviceName() string { - return s.tracer.serviceName -} - -// setSamplingPriority returns true if the flag was updated successfully, false otherwise. -func setSamplingPriority(s *Span, value interface{}) bool { - s.Lock() - defer s.Unlock() - val, ok := value.(uint16) - if !ok { - return false - } - if val == 0 { - s.context.flags = s.context.flags & (^flagSampled) - return true - } - if s.tracer.isDebugAllowed(s.operationName) { - s.context.flags = s.context.flags | flagDebug | flagSampled - return true - } - return false -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/agent.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/agent.go deleted file mode 100644 index e48811c500..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/agent.go +++ /dev/null @@ -1,411 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package agent - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" - "github.com/uber/jaeger-client-go/thrift-gen/jaeger" - "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -var _ = jaeger.GoUnusedProtection__ -var _ = zipkincore.GoUnusedProtection__ - -type Agent interface { - // Parameters: - // - Spans - EmitZipkinBatch(spans []*zipkincore.Span) (err error) - // Parameters: - // - Batch - EmitBatch(batch *jaeger.Batch) (err error) -} - -type AgentClient struct { - Transport thrift.TTransport - ProtocolFactory thrift.TProtocolFactory - InputProtocol thrift.TProtocol - OutputProtocol thrift.TProtocol - SeqId int32 -} - -func NewAgentClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *AgentClient { - return &AgentClient{Transport: t, - ProtocolFactory: f, - InputProtocol: f.GetProtocol(t), - OutputProtocol: f.GetProtocol(t), - SeqId: 0, - } -} - -func NewAgentClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *AgentClient { - return &AgentClient{Transport: t, - ProtocolFactory: nil, - InputProtocol: iprot, - OutputProtocol: oprot, - SeqId: 0, - } -} - -// Parameters: -// - Spans -func (p *AgentClient) EmitZipkinBatch(spans []*zipkincore.Span) (err error) { - if err = p.sendEmitZipkinBatch(spans); err != nil { - return - } - return -} - -func (p *AgentClient) sendEmitZipkinBatch(spans []*zipkincore.Span) (err error) { - oprot := p.OutputProtocol - if oprot == nil { - oprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.OutputProtocol = oprot - } - p.SeqId++ - if err = oprot.WriteMessageBegin("emitZipkinBatch", thrift.ONEWAY, p.SeqId); err != nil { - return - } - args := AgentEmitZipkinBatchArgs{ - Spans: spans, - } - if err = args.Write(oprot); err != nil { - return - } - if err = oprot.WriteMessageEnd(); err != nil { - return - } - return oprot.Flush() -} - -// Parameters: -// - Batch -func (p *AgentClient) EmitBatch(batch *jaeger.Batch) (err error) { - if err = p.sendEmitBatch(batch); err != nil { - return - } - return -} - -func (p *AgentClient) sendEmitBatch(batch *jaeger.Batch) (err error) { - oprot := p.OutputProtocol - if oprot == nil { - oprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.OutputProtocol = oprot - } - p.SeqId++ - if err = oprot.WriteMessageBegin("emitBatch", thrift.ONEWAY, p.SeqId); err != nil { - return - } - args := AgentEmitBatchArgs{ - Batch: batch, - } - if err = args.Write(oprot); err != nil { - return - } - if err = oprot.WriteMessageEnd(); err != nil { - return - } - return oprot.Flush() -} - -type AgentProcessor struct { - processorMap map[string]thrift.TProcessorFunction - handler Agent -} - -func (p *AgentProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { - p.processorMap[key] = processor -} - -func (p *AgentProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { - processor, ok = p.processorMap[key] - return processor, ok -} - -func (p *AgentProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { - return p.processorMap -} - -func NewAgentProcessor(handler Agent) *AgentProcessor { - - self0 := &AgentProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} - self0.processorMap["emitZipkinBatch"] = &agentProcessorEmitZipkinBatch{handler: handler} - self0.processorMap["emitBatch"] = &agentProcessorEmitBatch{handler: handler} - return self0 -} - -func (p *AgentProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - name, _, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return false, err - } - if processor, ok := p.GetProcessorFunction(name); ok { - return processor.Process(seqId, iprot, oprot) - } - iprot.Skip(thrift.STRUCT) - iprot.ReadMessageEnd() - x1 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) - oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) - x1.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, x1 - -} - -type agentProcessorEmitZipkinBatch struct { - handler Agent -} - -func (p *agentProcessorEmitZipkinBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - args := AgentEmitZipkinBatchArgs{} - if err = args.Read(iprot); err != nil { - iprot.ReadMessageEnd() - return false, err - } - - iprot.ReadMessageEnd() - var err2 error - if err2 = p.handler.EmitZipkinBatch(args.Spans); err2 != nil { - return true, err2 - } - return true, nil -} - -type agentProcessorEmitBatch struct { - handler Agent -} - -func (p *agentProcessorEmitBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - args := AgentEmitBatchArgs{} - if err = args.Read(iprot); err != nil { - iprot.ReadMessageEnd() - return false, err - } - - iprot.ReadMessageEnd() - var err2 error - if err2 = p.handler.EmitBatch(args.Batch); err2 != nil { - return true, err2 - } - return true, nil -} - -// HELPER FUNCTIONS AND STRUCTURES - -// Attributes: -// - Spans -type AgentEmitZipkinBatchArgs struct { - Spans []*zipkincore.Span `thrift:"spans,1" json:"spans"` -} - -func NewAgentEmitZipkinBatchArgs() *AgentEmitZipkinBatchArgs { - return &AgentEmitZipkinBatchArgs{} -} - -func (p *AgentEmitZipkinBatchArgs) GetSpans() []*zipkincore.Span { - return p.Spans -} -func (p *AgentEmitZipkinBatchArgs) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *AgentEmitZipkinBatchArgs) readField1(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*zipkincore.Span, 0, size) - p.Spans = tSlice - for i := 0; i < size; i++ { - _elem2 := &zipkincore.Span{} - if err := _elem2.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem2), err) - } - p.Spans = append(p.Spans, _elem2) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *AgentEmitZipkinBatchArgs) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("emitZipkinBatch_args"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *AgentEmitZipkinBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("spans", thrift.LIST, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:spans: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Spans)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Spans { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:spans: ", p), err) - } - return err -} - -func (p *AgentEmitZipkinBatchArgs) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("AgentEmitZipkinBatchArgs(%+v)", *p) -} - -// Attributes: -// - Batch -type AgentEmitBatchArgs struct { - Batch *jaeger.Batch `thrift:"batch,1" json:"batch"` -} - -func NewAgentEmitBatchArgs() *AgentEmitBatchArgs { - return &AgentEmitBatchArgs{} -} - -var AgentEmitBatchArgs_Batch_DEFAULT *jaeger.Batch - -func (p *AgentEmitBatchArgs) GetBatch() *jaeger.Batch { - if !p.IsSetBatch() { - return AgentEmitBatchArgs_Batch_DEFAULT - } - return p.Batch -} -func (p *AgentEmitBatchArgs) IsSetBatch() bool { - return p.Batch != nil -} - -func (p *AgentEmitBatchArgs) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *AgentEmitBatchArgs) readField1(iprot thrift.TProtocol) error { - p.Batch = &jaeger.Batch{} - if err := p.Batch.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Batch), err) - } - return nil -} - -func (p *AgentEmitBatchArgs) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("emitBatch_args"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *AgentEmitBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("batch", thrift.STRUCT, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:batch: ", p), err) - } - if err := p.Batch.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Batch), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:batch: ", p), err) - } - return err -} - -func (p *AgentEmitBatchArgs) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("AgentEmitBatchArgs(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/constants.go deleted file mode 100644 index aa9857bb82..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/constants.go +++ /dev/null @@ -1,23 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package agent - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" - "github.com/uber/jaeger-client-go/thrift-gen/jaeger" - "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -var _ = jaeger.GoUnusedProtection__ -var _ = zipkincore.GoUnusedProtection__ - -func init() { -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/ttypes.go deleted file mode 100644 index 9c28f11c1a..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/agent/ttypes.go +++ /dev/null @@ -1,21 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package agent - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" - "github.com/uber/jaeger-client-go/thrift-gen/jaeger" - "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -var _ = jaeger.GoUnusedProtection__ -var _ = zipkincore.GoUnusedProtection__ -var GoUnusedProtection__ int diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/baggagerestrictionmanager.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/baggagerestrictionmanager.go deleted file mode 100644 index 1f79c1255c..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/baggagerestrictionmanager.go +++ /dev/null @@ -1,435 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package baggage - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -type BaggageRestrictionManager interface { - // getBaggageRestrictions retrieves the baggage restrictions for a specific service. - // Usually, baggageRestrictions apply to all services however there may be situations - // where a baggageKey might only be allowed to be set by a specific service. - // - // Parameters: - // - ServiceName - GetBaggageRestrictions(serviceName string) (r []*BaggageRestriction, err error) -} - -type BaggageRestrictionManagerClient struct { - Transport thrift.TTransport - ProtocolFactory thrift.TProtocolFactory - InputProtocol thrift.TProtocol - OutputProtocol thrift.TProtocol - SeqId int32 -} - -func NewBaggageRestrictionManagerClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *BaggageRestrictionManagerClient { - return &BaggageRestrictionManagerClient{Transport: t, - ProtocolFactory: f, - InputProtocol: f.GetProtocol(t), - OutputProtocol: f.GetProtocol(t), - SeqId: 0, - } -} - -func NewBaggageRestrictionManagerClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *BaggageRestrictionManagerClient { - return &BaggageRestrictionManagerClient{Transport: t, - ProtocolFactory: nil, - InputProtocol: iprot, - OutputProtocol: oprot, - SeqId: 0, - } -} - -// getBaggageRestrictions retrieves the baggage restrictions for a specific service. -// Usually, baggageRestrictions apply to all services however there may be situations -// where a baggageKey might only be allowed to be set by a specific service. -// -// Parameters: -// - ServiceName -func (p *BaggageRestrictionManagerClient) GetBaggageRestrictions(serviceName string) (r []*BaggageRestriction, err error) { - if err = p.sendGetBaggageRestrictions(serviceName); err != nil { - return - } - return p.recvGetBaggageRestrictions() -} - -func (p *BaggageRestrictionManagerClient) sendGetBaggageRestrictions(serviceName string) (err error) { - oprot := p.OutputProtocol - if oprot == nil { - oprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.OutputProtocol = oprot - } - p.SeqId++ - if err = oprot.WriteMessageBegin("getBaggageRestrictions", thrift.CALL, p.SeqId); err != nil { - return - } - args := BaggageRestrictionManagerGetBaggageRestrictionsArgs{ - ServiceName: serviceName, - } - if err = args.Write(oprot); err != nil { - return - } - if err = oprot.WriteMessageEnd(); err != nil { - return - } - return oprot.Flush() -} - -func (p *BaggageRestrictionManagerClient) recvGetBaggageRestrictions() (value []*BaggageRestriction, err error) { - iprot := p.InputProtocol - if iprot == nil { - iprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.InputProtocol = iprot - } - method, mTypeId, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return - } - if method != "getBaggageRestrictions" { - err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "getBaggageRestrictions failed: wrong method name") - return - } - if p.SeqId != seqId { - err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "getBaggageRestrictions failed: out of sequence response") - return - } - if mTypeId == thrift.EXCEPTION { - error0 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception") - var error1 error - error1, err = error0.Read(iprot) - if err != nil { - return - } - if err = iprot.ReadMessageEnd(); err != nil { - return - } - err = error1 - return - } - if mTypeId != thrift.REPLY { - err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "getBaggageRestrictions failed: invalid message type") - return - } - result := BaggageRestrictionManagerGetBaggageRestrictionsResult{} - if err = result.Read(iprot); err != nil { - return - } - if err = iprot.ReadMessageEnd(); err != nil { - return - } - value = result.GetSuccess() - return -} - -type BaggageRestrictionManagerProcessor struct { - processorMap map[string]thrift.TProcessorFunction - handler BaggageRestrictionManager -} - -func (p *BaggageRestrictionManagerProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { - p.processorMap[key] = processor -} - -func (p *BaggageRestrictionManagerProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { - processor, ok = p.processorMap[key] - return processor, ok -} - -func (p *BaggageRestrictionManagerProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { - return p.processorMap -} - -func NewBaggageRestrictionManagerProcessor(handler BaggageRestrictionManager) *BaggageRestrictionManagerProcessor { - - self2 := &BaggageRestrictionManagerProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} - self2.processorMap["getBaggageRestrictions"] = &baggageRestrictionManagerProcessorGetBaggageRestrictions{handler: handler} - return self2 -} - -func (p *BaggageRestrictionManagerProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - name, _, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return false, err - } - if processor, ok := p.GetProcessorFunction(name); ok { - return processor.Process(seqId, iprot, oprot) - } - iprot.Skip(thrift.STRUCT) - iprot.ReadMessageEnd() - x3 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) - oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) - x3.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, x3 - -} - -type baggageRestrictionManagerProcessorGetBaggageRestrictions struct { - handler BaggageRestrictionManager -} - -func (p *baggageRestrictionManagerProcessorGetBaggageRestrictions) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - args := BaggageRestrictionManagerGetBaggageRestrictionsArgs{} - if err = args.Read(iprot); err != nil { - iprot.ReadMessageEnd() - x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) - oprot.WriteMessageBegin("getBaggageRestrictions", thrift.EXCEPTION, seqId) - x.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, err - } - - iprot.ReadMessageEnd() - result := BaggageRestrictionManagerGetBaggageRestrictionsResult{} - var retval []*BaggageRestriction - var err2 error - if retval, err2 = p.handler.GetBaggageRestrictions(args.ServiceName); err2 != nil { - x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing getBaggageRestrictions: "+err2.Error()) - oprot.WriteMessageBegin("getBaggageRestrictions", thrift.EXCEPTION, seqId) - x.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return true, err2 - } else { - result.Success = retval - } - if err2 = oprot.WriteMessageBegin("getBaggageRestrictions", thrift.REPLY, seqId); err2 != nil { - err = err2 - } - if err2 = result.Write(oprot); err == nil && err2 != nil { - err = err2 - } - if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { - err = err2 - } - if err2 = oprot.Flush(); err == nil && err2 != nil { - err = err2 - } - if err != nil { - return - } - return true, err -} - -// HELPER FUNCTIONS AND STRUCTURES - -// Attributes: -// - ServiceName -type BaggageRestrictionManagerGetBaggageRestrictionsArgs struct { - ServiceName string `thrift:"serviceName,1" json:"serviceName"` -} - -func NewBaggageRestrictionManagerGetBaggageRestrictionsArgs() *BaggageRestrictionManagerGetBaggageRestrictionsArgs { - return &BaggageRestrictionManagerGetBaggageRestrictionsArgs{} -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) GetServiceName() string { - return p.ServiceName -} -func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.ServiceName = v - } - return nil -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("getBaggageRestrictions_args"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("serviceName", thrift.STRING, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:serviceName: ", p), err) - } - if err := oprot.WriteString(string(p.ServiceName)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.serviceName (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:serviceName: ", p), err) - } - return err -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsArgs) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("BaggageRestrictionManagerGetBaggageRestrictionsArgs(%+v)", *p) -} - -// Attributes: -// - Success -type BaggageRestrictionManagerGetBaggageRestrictionsResult struct { - Success []*BaggageRestriction `thrift:"success,0" json:"success,omitempty"` -} - -func NewBaggageRestrictionManagerGetBaggageRestrictionsResult() *BaggageRestrictionManagerGetBaggageRestrictionsResult { - return &BaggageRestrictionManagerGetBaggageRestrictionsResult{} -} - -var BaggageRestrictionManagerGetBaggageRestrictionsResult_Success_DEFAULT []*BaggageRestriction - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) GetSuccess() []*BaggageRestriction { - return p.Success -} -func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) IsSetSuccess() bool { - return p.Success != nil -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 0: - if err := p.readField0(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) readField0(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*BaggageRestriction, 0, size) - p.Success = tSlice - for i := 0; i < size; i++ { - _elem4 := &BaggageRestriction{} - if err := _elem4.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem4), err) - } - p.Success = append(p.Success, _elem4) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("getBaggageRestrictions_result"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField0(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) writeField0(oprot thrift.TProtocol) (err error) { - if p.IsSetSuccess() { - if err := oprot.WriteFieldBegin("success", thrift.LIST, 0); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Success)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Success { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) - } - } - return err -} - -func (p *BaggageRestrictionManagerGetBaggageRestrictionsResult) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("BaggageRestrictionManagerGetBaggageRestrictionsResult(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/constants.go deleted file mode 100644 index ed35ce9ab5..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/constants.go +++ /dev/null @@ -1,18 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package baggage - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -func init() { -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/ttypes.go deleted file mode 100644 index 7888892f63..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/baggage/ttypes.go +++ /dev/null @@ -1,154 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package baggage - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -var GoUnusedProtection__ int - -// Attributes: -// - BaggageKey -// - MaxValueLength -type BaggageRestriction struct { - BaggageKey string `thrift:"baggageKey,1,required" json:"baggageKey"` - MaxValueLength int32 `thrift:"maxValueLength,2,required" json:"maxValueLength"` -} - -func NewBaggageRestriction() *BaggageRestriction { - return &BaggageRestriction{} -} - -func (p *BaggageRestriction) GetBaggageKey() string { - return p.BaggageKey -} - -func (p *BaggageRestriction) GetMaxValueLength() int32 { - return p.MaxValueLength -} -func (p *BaggageRestriction) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetBaggageKey bool = false - var issetMaxValueLength bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetBaggageKey = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetMaxValueLength = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetBaggageKey { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field BaggageKey is not set")) - } - if !issetMaxValueLength { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field MaxValueLength is not set")) - } - return nil -} - -func (p *BaggageRestriction) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.BaggageKey = v - } - return nil -} - -func (p *BaggageRestriction) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI32(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - p.MaxValueLength = v - } - return nil -} - -func (p *BaggageRestriction) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("BaggageRestriction"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *BaggageRestriction) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("baggageKey", thrift.STRING, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:baggageKey: ", p), err) - } - if err := oprot.WriteString(string(p.BaggageKey)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.baggageKey (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:baggageKey: ", p), err) - } - return err -} - -func (p *BaggageRestriction) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("maxValueLength", thrift.I32, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:maxValueLength: ", p), err) - } - if err := oprot.WriteI32(int32(p.MaxValueLength)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.maxValueLength (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:maxValueLength: ", p), err) - } - return err -} - -func (p *BaggageRestriction) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("BaggageRestriction(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/agent.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/agent.go deleted file mode 100644 index b32c37dd26..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/agent.go +++ /dev/null @@ -1,242 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package jaeger - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -type Agent interface { - // Parameters: - // - Batch - EmitBatch(batch *Batch) (err error) -} - -type AgentClient struct { - Transport thrift.TTransport - ProtocolFactory thrift.TProtocolFactory - InputProtocol thrift.TProtocol - OutputProtocol thrift.TProtocol - SeqId int32 -} - -func NewAgentClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *AgentClient { - return &AgentClient{Transport: t, - ProtocolFactory: f, - InputProtocol: f.GetProtocol(t), - OutputProtocol: f.GetProtocol(t), - SeqId: 0, - } -} - -func NewAgentClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *AgentClient { - return &AgentClient{Transport: t, - ProtocolFactory: nil, - InputProtocol: iprot, - OutputProtocol: oprot, - SeqId: 0, - } -} - -// Parameters: -// - Batch -func (p *AgentClient) EmitBatch(batch *Batch) (err error) { - if err = p.sendEmitBatch(batch); err != nil { - return - } - return -} - -func (p *AgentClient) sendEmitBatch(batch *Batch) (err error) { - oprot := p.OutputProtocol - if oprot == nil { - oprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.OutputProtocol = oprot - } - p.SeqId++ - if err = oprot.WriteMessageBegin("emitBatch", thrift.ONEWAY, p.SeqId); err != nil { - return - } - args := AgentEmitBatchArgs{ - Batch: batch, - } - if err = args.Write(oprot); err != nil { - return - } - if err = oprot.WriteMessageEnd(); err != nil { - return - } - return oprot.Flush() -} - -type AgentProcessor struct { - processorMap map[string]thrift.TProcessorFunction - handler Agent -} - -func (p *AgentProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { - p.processorMap[key] = processor -} - -func (p *AgentProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { - processor, ok = p.processorMap[key] - return processor, ok -} - -func (p *AgentProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { - return p.processorMap -} - -func NewAgentProcessor(handler Agent) *AgentProcessor { - - self6 := &AgentProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} - self6.processorMap["emitBatch"] = &agentProcessorEmitBatch{handler: handler} - return self6 -} - -func (p *AgentProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - name, _, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return false, err - } - if processor, ok := p.GetProcessorFunction(name); ok { - return processor.Process(seqId, iprot, oprot) - } - iprot.Skip(thrift.STRUCT) - iprot.ReadMessageEnd() - x7 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) - oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) - x7.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, x7 - -} - -type agentProcessorEmitBatch struct { - handler Agent -} - -func (p *agentProcessorEmitBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - args := AgentEmitBatchArgs{} - if err = args.Read(iprot); err != nil { - iprot.ReadMessageEnd() - return false, err - } - - iprot.ReadMessageEnd() - var err2 error - if err2 = p.handler.EmitBatch(args.Batch); err2 != nil { - return true, err2 - } - return true, nil -} - -// HELPER FUNCTIONS AND STRUCTURES - -// Attributes: -// - Batch -type AgentEmitBatchArgs struct { - Batch *Batch `thrift:"batch,1" json:"batch"` -} - -func NewAgentEmitBatchArgs() *AgentEmitBatchArgs { - return &AgentEmitBatchArgs{} -} - -var AgentEmitBatchArgs_Batch_DEFAULT *Batch - -func (p *AgentEmitBatchArgs) GetBatch() *Batch { - if !p.IsSetBatch() { - return AgentEmitBatchArgs_Batch_DEFAULT - } - return p.Batch -} -func (p *AgentEmitBatchArgs) IsSetBatch() bool { - return p.Batch != nil -} - -func (p *AgentEmitBatchArgs) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *AgentEmitBatchArgs) readField1(iprot thrift.TProtocol) error { - p.Batch = &Batch{} - if err := p.Batch.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Batch), err) - } - return nil -} - -func (p *AgentEmitBatchArgs) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("emitBatch_args"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *AgentEmitBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("batch", thrift.STRUCT, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:batch: ", p), err) - } - if err := p.Batch.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Batch), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:batch: ", p), err) - } - return err -} - -func (p *AgentEmitBatchArgs) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("AgentEmitBatchArgs(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/constants.go deleted file mode 100644 index 621b8b1c20..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/constants.go +++ /dev/null @@ -1,18 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package jaeger - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -func init() { -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go deleted file mode 100644 index d23ed2fc28..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go +++ /dev/null @@ -1,1838 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package jaeger - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -var GoUnusedProtection__ int - -type TagType int64 - -const ( - TagType_STRING TagType = 0 - TagType_DOUBLE TagType = 1 - TagType_BOOL TagType = 2 - TagType_LONG TagType = 3 - TagType_BINARY TagType = 4 -) - -func (p TagType) String() string { - switch p { - case TagType_STRING: - return "STRING" - case TagType_DOUBLE: - return "DOUBLE" - case TagType_BOOL: - return "BOOL" - case TagType_LONG: - return "LONG" - case TagType_BINARY: - return "BINARY" - } - return "" -} - -func TagTypeFromString(s string) (TagType, error) { - switch s { - case "STRING": - return TagType_STRING, nil - case "DOUBLE": - return TagType_DOUBLE, nil - case "BOOL": - return TagType_BOOL, nil - case "LONG": - return TagType_LONG, nil - case "BINARY": - return TagType_BINARY, nil - } - return TagType(0), fmt.Errorf("not a valid TagType string") -} - -func TagTypePtr(v TagType) *TagType { return &v } - -func (p TagType) MarshalText() ([]byte, error) { - return []byte(p.String()), nil -} - -func (p *TagType) UnmarshalText(text []byte) error { - q, err := TagTypeFromString(string(text)) - if err != nil { - return err - } - *p = q - return nil -} - -type SpanRefType int64 - -const ( - SpanRefType_CHILD_OF SpanRefType = 0 - SpanRefType_FOLLOWS_FROM SpanRefType = 1 -) - -func (p SpanRefType) String() string { - switch p { - case SpanRefType_CHILD_OF: - return "CHILD_OF" - case SpanRefType_FOLLOWS_FROM: - return "FOLLOWS_FROM" - } - return "" -} - -func SpanRefTypeFromString(s string) (SpanRefType, error) { - switch s { - case "CHILD_OF": - return SpanRefType_CHILD_OF, nil - case "FOLLOWS_FROM": - return SpanRefType_FOLLOWS_FROM, nil - } - return SpanRefType(0), fmt.Errorf("not a valid SpanRefType string") -} - -func SpanRefTypePtr(v SpanRefType) *SpanRefType { return &v } - -func (p SpanRefType) MarshalText() ([]byte, error) { - return []byte(p.String()), nil -} - -func (p *SpanRefType) UnmarshalText(text []byte) error { - q, err := SpanRefTypeFromString(string(text)) - if err != nil { - return err - } - *p = q - return nil -} - -// Attributes: -// - Key -// - VType -// - VStr -// - VDouble -// - VBool -// - VLong -// - VBinary -type Tag struct { - Key string `thrift:"key,1,required" json:"key"` - VType TagType `thrift:"vType,2,required" json:"vType"` - VStr *string `thrift:"vStr,3" json:"vStr,omitempty"` - VDouble *float64 `thrift:"vDouble,4" json:"vDouble,omitempty"` - VBool *bool `thrift:"vBool,5" json:"vBool,omitempty"` - VLong *int64 `thrift:"vLong,6" json:"vLong,omitempty"` - VBinary []byte `thrift:"vBinary,7" json:"vBinary,omitempty"` -} - -func NewTag() *Tag { - return &Tag{} -} - -func (p *Tag) GetKey() string { - return p.Key -} - -func (p *Tag) GetVType() TagType { - return p.VType -} - -var Tag_VStr_DEFAULT string - -func (p *Tag) GetVStr() string { - if !p.IsSetVStr() { - return Tag_VStr_DEFAULT - } - return *p.VStr -} - -var Tag_VDouble_DEFAULT float64 - -func (p *Tag) GetVDouble() float64 { - if !p.IsSetVDouble() { - return Tag_VDouble_DEFAULT - } - return *p.VDouble -} - -var Tag_VBool_DEFAULT bool - -func (p *Tag) GetVBool() bool { - if !p.IsSetVBool() { - return Tag_VBool_DEFAULT - } - return *p.VBool -} - -var Tag_VLong_DEFAULT int64 - -func (p *Tag) GetVLong() int64 { - if !p.IsSetVLong() { - return Tag_VLong_DEFAULT - } - return *p.VLong -} - -var Tag_VBinary_DEFAULT []byte - -func (p *Tag) GetVBinary() []byte { - return p.VBinary -} -func (p *Tag) IsSetVStr() bool { - return p.VStr != nil -} - -func (p *Tag) IsSetVDouble() bool { - return p.VDouble != nil -} - -func (p *Tag) IsSetVBool() bool { - return p.VBool != nil -} - -func (p *Tag) IsSetVLong() bool { - return p.VLong != nil -} - -func (p *Tag) IsSetVBinary() bool { - return p.VBinary != nil -} - -func (p *Tag) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetKey bool = false - var issetVType bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetKey = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetVType = true - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - case 4: - if err := p.readField4(iprot); err != nil { - return err - } - case 5: - if err := p.readField5(iprot); err != nil { - return err - } - case 6: - if err := p.readField6(iprot); err != nil { - return err - } - case 7: - if err := p.readField7(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetKey { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Key is not set")) - } - if !issetVType { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field VType is not set")) - } - return nil -} - -func (p *Tag) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Key = v - } - return nil -} - -func (p *Tag) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI32(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - temp := TagType(v) - p.VType = temp - } - return nil -} - -func (p *Tag) readField3(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 3: ", err) - } else { - p.VStr = &v - } - return nil -} - -func (p *Tag) readField4(iprot thrift.TProtocol) error { - if v, err := iprot.ReadDouble(); err != nil { - return thrift.PrependError("error reading field 4: ", err) - } else { - p.VDouble = &v - } - return nil -} - -func (p *Tag) readField5(iprot thrift.TProtocol) error { - if v, err := iprot.ReadBool(); err != nil { - return thrift.PrependError("error reading field 5: ", err) - } else { - p.VBool = &v - } - return nil -} - -func (p *Tag) readField6(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 6: ", err) - } else { - p.VLong = &v - } - return nil -} - -func (p *Tag) readField7(iprot thrift.TProtocol) error { - if v, err := iprot.ReadBinary(); err != nil { - return thrift.PrependError("error reading field 7: ", err) - } else { - p.VBinary = v - } - return nil -} - -func (p *Tag) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Tag"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := p.writeField4(oprot); err != nil { - return err - } - if err := p.writeField5(oprot); err != nil { - return err - } - if err := p.writeField6(oprot); err != nil { - return err - } - if err := p.writeField7(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Tag) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("key", thrift.STRING, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:key: ", p), err) - } - if err := oprot.WriteString(string(p.Key)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.key (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:key: ", p), err) - } - return err -} - -func (p *Tag) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("vType", thrift.I32, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:vType: ", p), err) - } - if err := oprot.WriteI32(int32(p.VType)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.vType (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:vType: ", p), err) - } - return err -} - -func (p *Tag) writeField3(oprot thrift.TProtocol) (err error) { - if p.IsSetVStr() { - if err := oprot.WriteFieldBegin("vStr", thrift.STRING, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:vStr: ", p), err) - } - if err := oprot.WriteString(string(*p.VStr)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.vStr (3) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:vStr: ", p), err) - } - } - return err -} - -func (p *Tag) writeField4(oprot thrift.TProtocol) (err error) { - if p.IsSetVDouble() { - if err := oprot.WriteFieldBegin("vDouble", thrift.DOUBLE, 4); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:vDouble: ", p), err) - } - if err := oprot.WriteDouble(float64(*p.VDouble)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.vDouble (4) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 4:vDouble: ", p), err) - } - } - return err -} - -func (p *Tag) writeField5(oprot thrift.TProtocol) (err error) { - if p.IsSetVBool() { - if err := oprot.WriteFieldBegin("vBool", thrift.BOOL, 5); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:vBool: ", p), err) - } - if err := oprot.WriteBool(bool(*p.VBool)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.vBool (5) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 5:vBool: ", p), err) - } - } - return err -} - -func (p *Tag) writeField6(oprot thrift.TProtocol) (err error) { - if p.IsSetVLong() { - if err := oprot.WriteFieldBegin("vLong", thrift.I64, 6); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 6:vLong: ", p), err) - } - if err := oprot.WriteI64(int64(*p.VLong)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.vLong (6) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 6:vLong: ", p), err) - } - } - return err -} - -func (p *Tag) writeField7(oprot thrift.TProtocol) (err error) { - if p.IsSetVBinary() { - if err := oprot.WriteFieldBegin("vBinary", thrift.STRING, 7); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 7:vBinary: ", p), err) - } - if err := oprot.WriteBinary(p.VBinary); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.vBinary (7) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 7:vBinary: ", p), err) - } - } - return err -} - -func (p *Tag) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Tag(%+v)", *p) -} - -// Attributes: -// - Timestamp -// - Fields -type Log struct { - Timestamp int64 `thrift:"timestamp,1,required" json:"timestamp"` - Fields []*Tag `thrift:"fields,2,required" json:"fields"` -} - -func NewLog() *Log { - return &Log{} -} - -func (p *Log) GetTimestamp() int64 { - return p.Timestamp -} - -func (p *Log) GetFields() []*Tag { - return p.Fields -} -func (p *Log) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetTimestamp bool = false - var issetFields bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetTimestamp = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetFields = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetTimestamp { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Timestamp is not set")) - } - if !issetFields { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Fields is not set")) - } - return nil -} - -func (p *Log) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Timestamp = v - } - return nil -} - -func (p *Log) readField2(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Tag, 0, size) - p.Fields = tSlice - for i := 0; i < size; i++ { - _elem0 := &Tag{} - if err := _elem0.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem0), err) - } - p.Fields = append(p.Fields, _elem0) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Log) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Log"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Log) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("timestamp", thrift.I64, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:timestamp: ", p), err) - } - if err := oprot.WriteI64(int64(p.Timestamp)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.timestamp (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:timestamp: ", p), err) - } - return err -} - -func (p *Log) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("fields", thrift.LIST, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:fields: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Fields)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Fields { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:fields: ", p), err) - } - return err -} - -func (p *Log) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Log(%+v)", *p) -} - -// Attributes: -// - RefType -// - TraceIdLow -// - TraceIdHigh -// - SpanId -type SpanRef struct { - RefType SpanRefType `thrift:"refType,1,required" json:"refType"` - TraceIdLow int64 `thrift:"traceIdLow,2,required" json:"traceIdLow"` - TraceIdHigh int64 `thrift:"traceIdHigh,3,required" json:"traceIdHigh"` - SpanId int64 `thrift:"spanId,4,required" json:"spanId"` -} - -func NewSpanRef() *SpanRef { - return &SpanRef{} -} - -func (p *SpanRef) GetRefType() SpanRefType { - return p.RefType -} - -func (p *SpanRef) GetTraceIdLow() int64 { - return p.TraceIdLow -} - -func (p *SpanRef) GetTraceIdHigh() int64 { - return p.TraceIdHigh -} - -func (p *SpanRef) GetSpanId() int64 { - return p.SpanId -} -func (p *SpanRef) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetRefType bool = false - var issetTraceIdLow bool = false - var issetTraceIdHigh bool = false - var issetSpanId bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetRefType = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetTraceIdLow = true - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - issetTraceIdHigh = true - case 4: - if err := p.readField4(iprot); err != nil { - return err - } - issetSpanId = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetRefType { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field RefType is not set")) - } - if !issetTraceIdLow { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdLow is not set")) - } - if !issetTraceIdHigh { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdHigh is not set")) - } - if !issetSpanId { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field SpanId is not set")) - } - return nil -} - -func (p *SpanRef) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI32(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - temp := SpanRefType(v) - p.RefType = temp - } - return nil -} - -func (p *SpanRef) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - p.TraceIdLow = v - } - return nil -} - -func (p *SpanRef) readField3(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 3: ", err) - } else { - p.TraceIdHigh = v - } - return nil -} - -func (p *SpanRef) readField4(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 4: ", err) - } else { - p.SpanId = v - } - return nil -} - -func (p *SpanRef) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("SpanRef"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := p.writeField4(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *SpanRef) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("refType", thrift.I32, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:refType: ", p), err) - } - if err := oprot.WriteI32(int32(p.RefType)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.refType (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:refType: ", p), err) - } - return err -} - -func (p *SpanRef) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("traceIdLow", thrift.I64, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:traceIdLow: ", p), err) - } - if err := oprot.WriteI64(int64(p.TraceIdLow)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.traceIdLow (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:traceIdLow: ", p), err) - } - return err -} - -func (p *SpanRef) writeField3(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("traceIdHigh", thrift.I64, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:traceIdHigh: ", p), err) - } - if err := oprot.WriteI64(int64(p.TraceIdHigh)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.traceIdHigh (3) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:traceIdHigh: ", p), err) - } - return err -} - -func (p *SpanRef) writeField4(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("spanId", thrift.I64, 4); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:spanId: ", p), err) - } - if err := oprot.WriteI64(int64(p.SpanId)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.spanId (4) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 4:spanId: ", p), err) - } - return err -} - -func (p *SpanRef) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("SpanRef(%+v)", *p) -} - -// Attributes: -// - TraceIdLow -// - TraceIdHigh -// - SpanId -// - ParentSpanId -// - OperationName -// - References -// - Flags -// - StartTime -// - Duration -// - Tags -// - Logs -type Span struct { - TraceIdLow int64 `thrift:"traceIdLow,1,required" json:"traceIdLow"` - TraceIdHigh int64 `thrift:"traceIdHigh,2,required" json:"traceIdHigh"` - SpanId int64 `thrift:"spanId,3,required" json:"spanId"` - ParentSpanId int64 `thrift:"parentSpanId,4,required" json:"parentSpanId"` - OperationName string `thrift:"operationName,5,required" json:"operationName"` - References []*SpanRef `thrift:"references,6" json:"references,omitempty"` - Flags int32 `thrift:"flags,7,required" json:"flags"` - StartTime int64 `thrift:"startTime,8,required" json:"startTime"` - Duration int64 `thrift:"duration,9,required" json:"duration"` - Tags []*Tag `thrift:"tags,10" json:"tags,omitempty"` - Logs []*Log `thrift:"logs,11" json:"logs,omitempty"` -} - -func NewSpan() *Span { - return &Span{} -} - -func (p *Span) GetTraceIdLow() int64 { - return p.TraceIdLow -} - -func (p *Span) GetTraceIdHigh() int64 { - return p.TraceIdHigh -} - -func (p *Span) GetSpanId() int64 { - return p.SpanId -} - -func (p *Span) GetParentSpanId() int64 { - return p.ParentSpanId -} - -func (p *Span) GetOperationName() string { - return p.OperationName -} - -var Span_References_DEFAULT []*SpanRef - -func (p *Span) GetReferences() []*SpanRef { - return p.References -} - -func (p *Span) GetFlags() int32 { - return p.Flags -} - -func (p *Span) GetStartTime() int64 { - return p.StartTime -} - -func (p *Span) GetDuration() int64 { - return p.Duration -} - -var Span_Tags_DEFAULT []*Tag - -func (p *Span) GetTags() []*Tag { - return p.Tags -} - -var Span_Logs_DEFAULT []*Log - -func (p *Span) GetLogs() []*Log { - return p.Logs -} -func (p *Span) IsSetReferences() bool { - return p.References != nil -} - -func (p *Span) IsSetTags() bool { - return p.Tags != nil -} - -func (p *Span) IsSetLogs() bool { - return p.Logs != nil -} - -func (p *Span) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetTraceIdLow bool = false - var issetTraceIdHigh bool = false - var issetSpanId bool = false - var issetParentSpanId bool = false - var issetOperationName bool = false - var issetFlags bool = false - var issetStartTime bool = false - var issetDuration bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetTraceIdLow = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetTraceIdHigh = true - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - issetSpanId = true - case 4: - if err := p.readField4(iprot); err != nil { - return err - } - issetParentSpanId = true - case 5: - if err := p.readField5(iprot); err != nil { - return err - } - issetOperationName = true - case 6: - if err := p.readField6(iprot); err != nil { - return err - } - case 7: - if err := p.readField7(iprot); err != nil { - return err - } - issetFlags = true - case 8: - if err := p.readField8(iprot); err != nil { - return err - } - issetStartTime = true - case 9: - if err := p.readField9(iprot); err != nil { - return err - } - issetDuration = true - case 10: - if err := p.readField10(iprot); err != nil { - return err - } - case 11: - if err := p.readField11(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetTraceIdLow { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdLow is not set")) - } - if !issetTraceIdHigh { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TraceIdHigh is not set")) - } - if !issetSpanId { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field SpanId is not set")) - } - if !issetParentSpanId { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field ParentSpanId is not set")) - } - if !issetOperationName { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field OperationName is not set")) - } - if !issetFlags { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Flags is not set")) - } - if !issetStartTime { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field StartTime is not set")) - } - if !issetDuration { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Duration is not set")) - } - return nil -} - -func (p *Span) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.TraceIdLow = v - } - return nil -} - -func (p *Span) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - p.TraceIdHigh = v - } - return nil -} - -func (p *Span) readField3(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 3: ", err) - } else { - p.SpanId = v - } - return nil -} - -func (p *Span) readField4(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 4: ", err) - } else { - p.ParentSpanId = v - } - return nil -} - -func (p *Span) readField5(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 5: ", err) - } else { - p.OperationName = v - } - return nil -} - -func (p *Span) readField6(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*SpanRef, 0, size) - p.References = tSlice - for i := 0; i < size; i++ { - _elem1 := &SpanRef{} - if err := _elem1.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem1), err) - } - p.References = append(p.References, _elem1) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Span) readField7(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI32(); err != nil { - return thrift.PrependError("error reading field 7: ", err) - } else { - p.Flags = v - } - return nil -} - -func (p *Span) readField8(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 8: ", err) - } else { - p.StartTime = v - } - return nil -} - -func (p *Span) readField9(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 9: ", err) - } else { - p.Duration = v - } - return nil -} - -func (p *Span) readField10(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Tag, 0, size) - p.Tags = tSlice - for i := 0; i < size; i++ { - _elem2 := &Tag{} - if err := _elem2.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem2), err) - } - p.Tags = append(p.Tags, _elem2) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Span) readField11(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Log, 0, size) - p.Logs = tSlice - for i := 0; i < size; i++ { - _elem3 := &Log{} - if err := _elem3.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem3), err) - } - p.Logs = append(p.Logs, _elem3) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Span) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Span"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := p.writeField4(oprot); err != nil { - return err - } - if err := p.writeField5(oprot); err != nil { - return err - } - if err := p.writeField6(oprot); err != nil { - return err - } - if err := p.writeField7(oprot); err != nil { - return err - } - if err := p.writeField8(oprot); err != nil { - return err - } - if err := p.writeField9(oprot); err != nil { - return err - } - if err := p.writeField10(oprot); err != nil { - return err - } - if err := p.writeField11(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Span) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("traceIdLow", thrift.I64, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:traceIdLow: ", p), err) - } - if err := oprot.WriteI64(int64(p.TraceIdLow)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.traceIdLow (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:traceIdLow: ", p), err) - } - return err -} - -func (p *Span) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("traceIdHigh", thrift.I64, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:traceIdHigh: ", p), err) - } - if err := oprot.WriteI64(int64(p.TraceIdHigh)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.traceIdHigh (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:traceIdHigh: ", p), err) - } - return err -} - -func (p *Span) writeField3(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("spanId", thrift.I64, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:spanId: ", p), err) - } - if err := oprot.WriteI64(int64(p.SpanId)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.spanId (3) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:spanId: ", p), err) - } - return err -} - -func (p *Span) writeField4(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("parentSpanId", thrift.I64, 4); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:parentSpanId: ", p), err) - } - if err := oprot.WriteI64(int64(p.ParentSpanId)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.parentSpanId (4) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 4:parentSpanId: ", p), err) - } - return err -} - -func (p *Span) writeField5(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("operationName", thrift.STRING, 5); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:operationName: ", p), err) - } - if err := oprot.WriteString(string(p.OperationName)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.operationName (5) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 5:operationName: ", p), err) - } - return err -} - -func (p *Span) writeField6(oprot thrift.TProtocol) (err error) { - if p.IsSetReferences() { - if err := oprot.WriteFieldBegin("references", thrift.LIST, 6); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 6:references: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.References)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.References { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 6:references: ", p), err) - } - } - return err -} - -func (p *Span) writeField7(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("flags", thrift.I32, 7); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 7:flags: ", p), err) - } - if err := oprot.WriteI32(int32(p.Flags)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.flags (7) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 7:flags: ", p), err) - } - return err -} - -func (p *Span) writeField8(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("startTime", thrift.I64, 8); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 8:startTime: ", p), err) - } - if err := oprot.WriteI64(int64(p.StartTime)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.startTime (8) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 8:startTime: ", p), err) - } - return err -} - -func (p *Span) writeField9(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("duration", thrift.I64, 9); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 9:duration: ", p), err) - } - if err := oprot.WriteI64(int64(p.Duration)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.duration (9) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 9:duration: ", p), err) - } - return err -} - -func (p *Span) writeField10(oprot thrift.TProtocol) (err error) { - if p.IsSetTags() { - if err := oprot.WriteFieldBegin("tags", thrift.LIST, 10); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 10:tags: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Tags)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Tags { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 10:tags: ", p), err) - } - } - return err -} - -func (p *Span) writeField11(oprot thrift.TProtocol) (err error) { - if p.IsSetLogs() { - if err := oprot.WriteFieldBegin("logs", thrift.LIST, 11); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 11:logs: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Logs)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Logs { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 11:logs: ", p), err) - } - } - return err -} - -func (p *Span) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Span(%+v)", *p) -} - -// Attributes: -// - ServiceName -// - Tags -type Process struct { - ServiceName string `thrift:"serviceName,1,required" json:"serviceName"` - Tags []*Tag `thrift:"tags,2" json:"tags,omitempty"` -} - -func NewProcess() *Process { - return &Process{} -} - -func (p *Process) GetServiceName() string { - return p.ServiceName -} - -var Process_Tags_DEFAULT []*Tag - -func (p *Process) GetTags() []*Tag { - return p.Tags -} -func (p *Process) IsSetTags() bool { - return p.Tags != nil -} - -func (p *Process) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetServiceName bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetServiceName = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetServiceName { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field ServiceName is not set")) - } - return nil -} - -func (p *Process) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.ServiceName = v - } - return nil -} - -func (p *Process) readField2(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Tag, 0, size) - p.Tags = tSlice - for i := 0; i < size; i++ { - _elem4 := &Tag{} - if err := _elem4.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem4), err) - } - p.Tags = append(p.Tags, _elem4) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Process) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Process"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Process) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("serviceName", thrift.STRING, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:serviceName: ", p), err) - } - if err := oprot.WriteString(string(p.ServiceName)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.serviceName (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:serviceName: ", p), err) - } - return err -} - -func (p *Process) writeField2(oprot thrift.TProtocol) (err error) { - if p.IsSetTags() { - if err := oprot.WriteFieldBegin("tags", thrift.LIST, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:tags: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Tags)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Tags { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:tags: ", p), err) - } - } - return err -} - -func (p *Process) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Process(%+v)", *p) -} - -// Attributes: -// - Process -// - Spans -type Batch struct { - Process *Process `thrift:"process,1,required" json:"process"` - Spans []*Span `thrift:"spans,2,required" json:"spans"` -} - -func NewBatch() *Batch { - return &Batch{} -} - -var Batch_Process_DEFAULT *Process - -func (p *Batch) GetProcess() *Process { - if !p.IsSetProcess() { - return Batch_Process_DEFAULT - } - return p.Process -} - -func (p *Batch) GetSpans() []*Span { - return p.Spans -} -func (p *Batch) IsSetProcess() bool { - return p.Process != nil -} - -func (p *Batch) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetProcess bool = false - var issetSpans bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetProcess = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetSpans = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetProcess { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Process is not set")) - } - if !issetSpans { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Spans is not set")) - } - return nil -} - -func (p *Batch) readField1(iprot thrift.TProtocol) error { - p.Process = &Process{} - if err := p.Process.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Process), err) - } - return nil -} - -func (p *Batch) readField2(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Span, 0, size) - p.Spans = tSlice - for i := 0; i < size; i++ { - _elem5 := &Span{} - if err := _elem5.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem5), err) - } - p.Spans = append(p.Spans, _elem5) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Batch) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Batch"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Batch) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("process", thrift.STRUCT, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:process: ", p), err) - } - if err := p.Process.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Process), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:process: ", p), err) - } - return err -} - -func (p *Batch) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("spans", thrift.LIST, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:spans: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Spans)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Spans { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:spans: ", p), err) - } - return err -} - -func (p *Batch) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Batch(%+v)", *p) -} - -// Attributes: -// - Ok -type BatchSubmitResponse struct { - Ok bool `thrift:"ok,1,required" json:"ok"` -} - -func NewBatchSubmitResponse() *BatchSubmitResponse { - return &BatchSubmitResponse{} -} - -func (p *BatchSubmitResponse) GetOk() bool { - return p.Ok -} -func (p *BatchSubmitResponse) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetOk bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetOk = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetOk { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Ok is not set")) - } - return nil -} - -func (p *BatchSubmitResponse) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadBool(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Ok = v - } - return nil -} - -func (p *BatchSubmitResponse) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("BatchSubmitResponse"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *BatchSubmitResponse) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("ok", thrift.BOOL, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:ok: ", p), err) - } - if err := oprot.WriteBool(bool(p.Ok)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.ok (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:ok: ", p), err) - } - return err -} - -func (p *BatchSubmitResponse) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("BatchSubmitResponse(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/constants.go deleted file mode 100644 index 0f6e3a884d..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/constants.go +++ /dev/null @@ -1,18 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package sampling - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -func init() { -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/samplingmanager.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/samplingmanager.go deleted file mode 100644 index 33179cfeb3..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/samplingmanager.go +++ /dev/null @@ -1,410 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package sampling - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -type SamplingManager interface { - // Parameters: - // - ServiceName - GetSamplingStrategy(serviceName string) (r *SamplingStrategyResponse, err error) -} - -type SamplingManagerClient struct { - Transport thrift.TTransport - ProtocolFactory thrift.TProtocolFactory - InputProtocol thrift.TProtocol - OutputProtocol thrift.TProtocol - SeqId int32 -} - -func NewSamplingManagerClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *SamplingManagerClient { - return &SamplingManagerClient{Transport: t, - ProtocolFactory: f, - InputProtocol: f.GetProtocol(t), - OutputProtocol: f.GetProtocol(t), - SeqId: 0, - } -} - -func NewSamplingManagerClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *SamplingManagerClient { - return &SamplingManagerClient{Transport: t, - ProtocolFactory: nil, - InputProtocol: iprot, - OutputProtocol: oprot, - SeqId: 0, - } -} - -// Parameters: -// - ServiceName -func (p *SamplingManagerClient) GetSamplingStrategy(serviceName string) (r *SamplingStrategyResponse, err error) { - if err = p.sendGetSamplingStrategy(serviceName); err != nil { - return - } - return p.recvGetSamplingStrategy() -} - -func (p *SamplingManagerClient) sendGetSamplingStrategy(serviceName string) (err error) { - oprot := p.OutputProtocol - if oprot == nil { - oprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.OutputProtocol = oprot - } - p.SeqId++ - if err = oprot.WriteMessageBegin("getSamplingStrategy", thrift.CALL, p.SeqId); err != nil { - return - } - args := SamplingManagerGetSamplingStrategyArgs{ - ServiceName: serviceName, - } - if err = args.Write(oprot); err != nil { - return - } - if err = oprot.WriteMessageEnd(); err != nil { - return - } - return oprot.Flush() -} - -func (p *SamplingManagerClient) recvGetSamplingStrategy() (value *SamplingStrategyResponse, err error) { - iprot := p.InputProtocol - if iprot == nil { - iprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.InputProtocol = iprot - } - method, mTypeId, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return - } - if method != "getSamplingStrategy" { - err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "getSamplingStrategy failed: wrong method name") - return - } - if p.SeqId != seqId { - err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "getSamplingStrategy failed: out of sequence response") - return - } - if mTypeId == thrift.EXCEPTION { - error1 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception") - var error2 error - error2, err = error1.Read(iprot) - if err != nil { - return - } - if err = iprot.ReadMessageEnd(); err != nil { - return - } - err = error2 - return - } - if mTypeId != thrift.REPLY { - err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "getSamplingStrategy failed: invalid message type") - return - } - result := SamplingManagerGetSamplingStrategyResult{} - if err = result.Read(iprot); err != nil { - return - } - if err = iprot.ReadMessageEnd(); err != nil { - return - } - value = result.GetSuccess() - return -} - -type SamplingManagerProcessor struct { - processorMap map[string]thrift.TProcessorFunction - handler SamplingManager -} - -func (p *SamplingManagerProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { - p.processorMap[key] = processor -} - -func (p *SamplingManagerProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { - processor, ok = p.processorMap[key] - return processor, ok -} - -func (p *SamplingManagerProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { - return p.processorMap -} - -func NewSamplingManagerProcessor(handler SamplingManager) *SamplingManagerProcessor { - - self3 := &SamplingManagerProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} - self3.processorMap["getSamplingStrategy"] = &samplingManagerProcessorGetSamplingStrategy{handler: handler} - return self3 -} - -func (p *SamplingManagerProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - name, _, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return false, err - } - if processor, ok := p.GetProcessorFunction(name); ok { - return processor.Process(seqId, iprot, oprot) - } - iprot.Skip(thrift.STRUCT) - iprot.ReadMessageEnd() - x4 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) - oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) - x4.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, x4 - -} - -type samplingManagerProcessorGetSamplingStrategy struct { - handler SamplingManager -} - -func (p *samplingManagerProcessorGetSamplingStrategy) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - args := SamplingManagerGetSamplingStrategyArgs{} - if err = args.Read(iprot); err != nil { - iprot.ReadMessageEnd() - x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) - oprot.WriteMessageBegin("getSamplingStrategy", thrift.EXCEPTION, seqId) - x.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, err - } - - iprot.ReadMessageEnd() - result := SamplingManagerGetSamplingStrategyResult{} - var retval *SamplingStrategyResponse - var err2 error - if retval, err2 = p.handler.GetSamplingStrategy(args.ServiceName); err2 != nil { - x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing getSamplingStrategy: "+err2.Error()) - oprot.WriteMessageBegin("getSamplingStrategy", thrift.EXCEPTION, seqId) - x.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return true, err2 - } else { - result.Success = retval - } - if err2 = oprot.WriteMessageBegin("getSamplingStrategy", thrift.REPLY, seqId); err2 != nil { - err = err2 - } - if err2 = result.Write(oprot); err == nil && err2 != nil { - err = err2 - } - if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { - err = err2 - } - if err2 = oprot.Flush(); err == nil && err2 != nil { - err = err2 - } - if err != nil { - return - } - return true, err -} - -// HELPER FUNCTIONS AND STRUCTURES - -// Attributes: -// - ServiceName -type SamplingManagerGetSamplingStrategyArgs struct { - ServiceName string `thrift:"serviceName,1" json:"serviceName"` -} - -func NewSamplingManagerGetSamplingStrategyArgs() *SamplingManagerGetSamplingStrategyArgs { - return &SamplingManagerGetSamplingStrategyArgs{} -} - -func (p *SamplingManagerGetSamplingStrategyArgs) GetServiceName() string { - return p.ServiceName -} -func (p *SamplingManagerGetSamplingStrategyArgs) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *SamplingManagerGetSamplingStrategyArgs) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.ServiceName = v - } - return nil -} - -func (p *SamplingManagerGetSamplingStrategyArgs) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("getSamplingStrategy_args"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *SamplingManagerGetSamplingStrategyArgs) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("serviceName", thrift.STRING, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:serviceName: ", p), err) - } - if err := oprot.WriteString(string(p.ServiceName)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.serviceName (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:serviceName: ", p), err) - } - return err -} - -func (p *SamplingManagerGetSamplingStrategyArgs) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("SamplingManagerGetSamplingStrategyArgs(%+v)", *p) -} - -// Attributes: -// - Success -type SamplingManagerGetSamplingStrategyResult struct { - Success *SamplingStrategyResponse `thrift:"success,0" json:"success,omitempty"` -} - -func NewSamplingManagerGetSamplingStrategyResult() *SamplingManagerGetSamplingStrategyResult { - return &SamplingManagerGetSamplingStrategyResult{} -} - -var SamplingManagerGetSamplingStrategyResult_Success_DEFAULT *SamplingStrategyResponse - -func (p *SamplingManagerGetSamplingStrategyResult) GetSuccess() *SamplingStrategyResponse { - if !p.IsSetSuccess() { - return SamplingManagerGetSamplingStrategyResult_Success_DEFAULT - } - return p.Success -} -func (p *SamplingManagerGetSamplingStrategyResult) IsSetSuccess() bool { - return p.Success != nil -} - -func (p *SamplingManagerGetSamplingStrategyResult) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 0: - if err := p.readField0(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *SamplingManagerGetSamplingStrategyResult) readField0(iprot thrift.TProtocol) error { - p.Success = &SamplingStrategyResponse{} - if err := p.Success.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err) - } - return nil -} - -func (p *SamplingManagerGetSamplingStrategyResult) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("getSamplingStrategy_result"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField0(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *SamplingManagerGetSamplingStrategyResult) writeField0(oprot thrift.TProtocol) (err error) { - if p.IsSetSuccess() { - if err := oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) - } - if err := p.Success.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) - } - } - return err -} - -func (p *SamplingManagerGetSamplingStrategyResult) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("SamplingManagerGetSamplingStrategyResult(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/ttypes.go deleted file mode 100644 index 9abaf0542d..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/sampling/ttypes.go +++ /dev/null @@ -1,873 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package sampling - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -var GoUnusedProtection__ int - -type SamplingStrategyType int64 - -const ( - SamplingStrategyType_PROBABILISTIC SamplingStrategyType = 0 - SamplingStrategyType_RATE_LIMITING SamplingStrategyType = 1 -) - -func (p SamplingStrategyType) String() string { - switch p { - case SamplingStrategyType_PROBABILISTIC: - return "PROBABILISTIC" - case SamplingStrategyType_RATE_LIMITING: - return "RATE_LIMITING" - } - return "" -} - -func SamplingStrategyTypeFromString(s string) (SamplingStrategyType, error) { - switch s { - case "PROBABILISTIC": - return SamplingStrategyType_PROBABILISTIC, nil - case "RATE_LIMITING": - return SamplingStrategyType_RATE_LIMITING, nil - } - return SamplingStrategyType(0), fmt.Errorf("not a valid SamplingStrategyType string") -} - -func SamplingStrategyTypePtr(v SamplingStrategyType) *SamplingStrategyType { return &v } - -func (p SamplingStrategyType) MarshalText() ([]byte, error) { - return []byte(p.String()), nil -} - -func (p *SamplingStrategyType) UnmarshalText(text []byte) error { - q, err := SamplingStrategyTypeFromString(string(text)) - if err != nil { - return err - } - *p = q - return nil -} - -// Attributes: -// - SamplingRate -type ProbabilisticSamplingStrategy struct { - SamplingRate float64 `thrift:"samplingRate,1,required" json:"samplingRate"` -} - -func NewProbabilisticSamplingStrategy() *ProbabilisticSamplingStrategy { - return &ProbabilisticSamplingStrategy{} -} - -func (p *ProbabilisticSamplingStrategy) GetSamplingRate() float64 { - return p.SamplingRate -} -func (p *ProbabilisticSamplingStrategy) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetSamplingRate bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetSamplingRate = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetSamplingRate { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field SamplingRate is not set")) - } - return nil -} - -func (p *ProbabilisticSamplingStrategy) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadDouble(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.SamplingRate = v - } - return nil -} - -func (p *ProbabilisticSamplingStrategy) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("ProbabilisticSamplingStrategy"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *ProbabilisticSamplingStrategy) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("samplingRate", thrift.DOUBLE, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:samplingRate: ", p), err) - } - if err := oprot.WriteDouble(float64(p.SamplingRate)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.samplingRate (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:samplingRate: ", p), err) - } - return err -} - -func (p *ProbabilisticSamplingStrategy) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("ProbabilisticSamplingStrategy(%+v)", *p) -} - -// Attributes: -// - MaxTracesPerSecond -type RateLimitingSamplingStrategy struct { - MaxTracesPerSecond int16 `thrift:"maxTracesPerSecond,1,required" json:"maxTracesPerSecond"` -} - -func NewRateLimitingSamplingStrategy() *RateLimitingSamplingStrategy { - return &RateLimitingSamplingStrategy{} -} - -func (p *RateLimitingSamplingStrategy) GetMaxTracesPerSecond() int16 { - return p.MaxTracesPerSecond -} -func (p *RateLimitingSamplingStrategy) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetMaxTracesPerSecond bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetMaxTracesPerSecond = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetMaxTracesPerSecond { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field MaxTracesPerSecond is not set")) - } - return nil -} - -func (p *RateLimitingSamplingStrategy) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI16(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.MaxTracesPerSecond = v - } - return nil -} - -func (p *RateLimitingSamplingStrategy) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("RateLimitingSamplingStrategy"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *RateLimitingSamplingStrategy) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("maxTracesPerSecond", thrift.I16, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:maxTracesPerSecond: ", p), err) - } - if err := oprot.WriteI16(int16(p.MaxTracesPerSecond)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.maxTracesPerSecond (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:maxTracesPerSecond: ", p), err) - } - return err -} - -func (p *RateLimitingSamplingStrategy) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("RateLimitingSamplingStrategy(%+v)", *p) -} - -// Attributes: -// - Operation -// - ProbabilisticSampling -type OperationSamplingStrategy struct { - Operation string `thrift:"operation,1,required" json:"operation"` - ProbabilisticSampling *ProbabilisticSamplingStrategy `thrift:"probabilisticSampling,2,required" json:"probabilisticSampling"` -} - -func NewOperationSamplingStrategy() *OperationSamplingStrategy { - return &OperationSamplingStrategy{} -} - -func (p *OperationSamplingStrategy) GetOperation() string { - return p.Operation -} - -var OperationSamplingStrategy_ProbabilisticSampling_DEFAULT *ProbabilisticSamplingStrategy - -func (p *OperationSamplingStrategy) GetProbabilisticSampling() *ProbabilisticSamplingStrategy { - if !p.IsSetProbabilisticSampling() { - return OperationSamplingStrategy_ProbabilisticSampling_DEFAULT - } - return p.ProbabilisticSampling -} -func (p *OperationSamplingStrategy) IsSetProbabilisticSampling() bool { - return p.ProbabilisticSampling != nil -} - -func (p *OperationSamplingStrategy) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetOperation bool = false - var issetProbabilisticSampling bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetOperation = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetProbabilisticSampling = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetOperation { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Operation is not set")) - } - if !issetProbabilisticSampling { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field ProbabilisticSampling is not set")) - } - return nil -} - -func (p *OperationSamplingStrategy) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Operation = v - } - return nil -} - -func (p *OperationSamplingStrategy) readField2(iprot thrift.TProtocol) error { - p.ProbabilisticSampling = &ProbabilisticSamplingStrategy{} - if err := p.ProbabilisticSampling.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.ProbabilisticSampling), err) - } - return nil -} - -func (p *OperationSamplingStrategy) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("OperationSamplingStrategy"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *OperationSamplingStrategy) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("operation", thrift.STRING, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:operation: ", p), err) - } - if err := oprot.WriteString(string(p.Operation)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.operation (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:operation: ", p), err) - } - return err -} - -func (p *OperationSamplingStrategy) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("probabilisticSampling", thrift.STRUCT, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:probabilisticSampling: ", p), err) - } - if err := p.ProbabilisticSampling.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.ProbabilisticSampling), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:probabilisticSampling: ", p), err) - } - return err -} - -func (p *OperationSamplingStrategy) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("OperationSamplingStrategy(%+v)", *p) -} - -// Attributes: -// - DefaultSamplingProbability -// - DefaultLowerBoundTracesPerSecond -// - PerOperationStrategies -// - DefaultUpperBoundTracesPerSecond -type PerOperationSamplingStrategies struct { - DefaultSamplingProbability float64 `thrift:"defaultSamplingProbability,1,required" json:"defaultSamplingProbability"` - DefaultLowerBoundTracesPerSecond float64 `thrift:"defaultLowerBoundTracesPerSecond,2,required" json:"defaultLowerBoundTracesPerSecond"` - PerOperationStrategies []*OperationSamplingStrategy `thrift:"perOperationStrategies,3,required" json:"perOperationStrategies"` - DefaultUpperBoundTracesPerSecond *float64 `thrift:"defaultUpperBoundTracesPerSecond,4" json:"defaultUpperBoundTracesPerSecond,omitempty"` -} - -func NewPerOperationSamplingStrategies() *PerOperationSamplingStrategies { - return &PerOperationSamplingStrategies{} -} - -func (p *PerOperationSamplingStrategies) GetDefaultSamplingProbability() float64 { - return p.DefaultSamplingProbability -} - -func (p *PerOperationSamplingStrategies) GetDefaultLowerBoundTracesPerSecond() float64 { - return p.DefaultLowerBoundTracesPerSecond -} - -func (p *PerOperationSamplingStrategies) GetPerOperationStrategies() []*OperationSamplingStrategy { - return p.PerOperationStrategies -} - -var PerOperationSamplingStrategies_DefaultUpperBoundTracesPerSecond_DEFAULT float64 - -func (p *PerOperationSamplingStrategies) GetDefaultUpperBoundTracesPerSecond() float64 { - if !p.IsSetDefaultUpperBoundTracesPerSecond() { - return PerOperationSamplingStrategies_DefaultUpperBoundTracesPerSecond_DEFAULT - } - return *p.DefaultUpperBoundTracesPerSecond -} -func (p *PerOperationSamplingStrategies) IsSetDefaultUpperBoundTracesPerSecond() bool { - return p.DefaultUpperBoundTracesPerSecond != nil -} - -func (p *PerOperationSamplingStrategies) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetDefaultSamplingProbability bool = false - var issetDefaultLowerBoundTracesPerSecond bool = false - var issetPerOperationStrategies bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetDefaultSamplingProbability = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - issetDefaultLowerBoundTracesPerSecond = true - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - issetPerOperationStrategies = true - case 4: - if err := p.readField4(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetDefaultSamplingProbability { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field DefaultSamplingProbability is not set")) - } - if !issetDefaultLowerBoundTracesPerSecond { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field DefaultLowerBoundTracesPerSecond is not set")) - } - if !issetPerOperationStrategies { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field PerOperationStrategies is not set")) - } - return nil -} - -func (p *PerOperationSamplingStrategies) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadDouble(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.DefaultSamplingProbability = v - } - return nil -} - -func (p *PerOperationSamplingStrategies) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadDouble(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - p.DefaultLowerBoundTracesPerSecond = v - } - return nil -} - -func (p *PerOperationSamplingStrategies) readField3(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*OperationSamplingStrategy, 0, size) - p.PerOperationStrategies = tSlice - for i := 0; i < size; i++ { - _elem0 := &OperationSamplingStrategy{} - if err := _elem0.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem0), err) - } - p.PerOperationStrategies = append(p.PerOperationStrategies, _elem0) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *PerOperationSamplingStrategies) readField4(iprot thrift.TProtocol) error { - if v, err := iprot.ReadDouble(); err != nil { - return thrift.PrependError("error reading field 4: ", err) - } else { - p.DefaultUpperBoundTracesPerSecond = &v - } - return nil -} - -func (p *PerOperationSamplingStrategies) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("PerOperationSamplingStrategies"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := p.writeField4(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *PerOperationSamplingStrategies) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("defaultSamplingProbability", thrift.DOUBLE, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:defaultSamplingProbability: ", p), err) - } - if err := oprot.WriteDouble(float64(p.DefaultSamplingProbability)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.defaultSamplingProbability (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:defaultSamplingProbability: ", p), err) - } - return err -} - -func (p *PerOperationSamplingStrategies) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("defaultLowerBoundTracesPerSecond", thrift.DOUBLE, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:defaultLowerBoundTracesPerSecond: ", p), err) - } - if err := oprot.WriteDouble(float64(p.DefaultLowerBoundTracesPerSecond)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.defaultLowerBoundTracesPerSecond (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:defaultLowerBoundTracesPerSecond: ", p), err) - } - return err -} - -func (p *PerOperationSamplingStrategies) writeField3(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("perOperationStrategies", thrift.LIST, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:perOperationStrategies: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.PerOperationStrategies)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.PerOperationStrategies { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:perOperationStrategies: ", p), err) - } - return err -} - -func (p *PerOperationSamplingStrategies) writeField4(oprot thrift.TProtocol) (err error) { - if p.IsSetDefaultUpperBoundTracesPerSecond() { - if err := oprot.WriteFieldBegin("defaultUpperBoundTracesPerSecond", thrift.DOUBLE, 4); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:defaultUpperBoundTracesPerSecond: ", p), err) - } - if err := oprot.WriteDouble(float64(*p.DefaultUpperBoundTracesPerSecond)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.defaultUpperBoundTracesPerSecond (4) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 4:defaultUpperBoundTracesPerSecond: ", p), err) - } - } - return err -} - -func (p *PerOperationSamplingStrategies) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("PerOperationSamplingStrategies(%+v)", *p) -} - -// Attributes: -// - StrategyType -// - ProbabilisticSampling -// - RateLimitingSampling -// - OperationSampling -type SamplingStrategyResponse struct { - StrategyType SamplingStrategyType `thrift:"strategyType,1,required" json:"strategyType"` - ProbabilisticSampling *ProbabilisticSamplingStrategy `thrift:"probabilisticSampling,2" json:"probabilisticSampling,omitempty"` - RateLimitingSampling *RateLimitingSamplingStrategy `thrift:"rateLimitingSampling,3" json:"rateLimitingSampling,omitempty"` - OperationSampling *PerOperationSamplingStrategies `thrift:"operationSampling,4" json:"operationSampling,omitempty"` -} - -func NewSamplingStrategyResponse() *SamplingStrategyResponse { - return &SamplingStrategyResponse{} -} - -func (p *SamplingStrategyResponse) GetStrategyType() SamplingStrategyType { - return p.StrategyType -} - -var SamplingStrategyResponse_ProbabilisticSampling_DEFAULT *ProbabilisticSamplingStrategy - -func (p *SamplingStrategyResponse) GetProbabilisticSampling() *ProbabilisticSamplingStrategy { - if !p.IsSetProbabilisticSampling() { - return SamplingStrategyResponse_ProbabilisticSampling_DEFAULT - } - return p.ProbabilisticSampling -} - -var SamplingStrategyResponse_RateLimitingSampling_DEFAULT *RateLimitingSamplingStrategy - -func (p *SamplingStrategyResponse) GetRateLimitingSampling() *RateLimitingSamplingStrategy { - if !p.IsSetRateLimitingSampling() { - return SamplingStrategyResponse_RateLimitingSampling_DEFAULT - } - return p.RateLimitingSampling -} - -var SamplingStrategyResponse_OperationSampling_DEFAULT *PerOperationSamplingStrategies - -func (p *SamplingStrategyResponse) GetOperationSampling() *PerOperationSamplingStrategies { - if !p.IsSetOperationSampling() { - return SamplingStrategyResponse_OperationSampling_DEFAULT - } - return p.OperationSampling -} -func (p *SamplingStrategyResponse) IsSetProbabilisticSampling() bool { - return p.ProbabilisticSampling != nil -} - -func (p *SamplingStrategyResponse) IsSetRateLimitingSampling() bool { - return p.RateLimitingSampling != nil -} - -func (p *SamplingStrategyResponse) IsSetOperationSampling() bool { - return p.OperationSampling != nil -} - -func (p *SamplingStrategyResponse) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetStrategyType bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetStrategyType = true - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - case 4: - if err := p.readField4(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetStrategyType { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field StrategyType is not set")) - } - return nil -} - -func (p *SamplingStrategyResponse) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI32(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - temp := SamplingStrategyType(v) - p.StrategyType = temp - } - return nil -} - -func (p *SamplingStrategyResponse) readField2(iprot thrift.TProtocol) error { - p.ProbabilisticSampling = &ProbabilisticSamplingStrategy{} - if err := p.ProbabilisticSampling.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.ProbabilisticSampling), err) - } - return nil -} - -func (p *SamplingStrategyResponse) readField3(iprot thrift.TProtocol) error { - p.RateLimitingSampling = &RateLimitingSamplingStrategy{} - if err := p.RateLimitingSampling.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.RateLimitingSampling), err) - } - return nil -} - -func (p *SamplingStrategyResponse) readField4(iprot thrift.TProtocol) error { - p.OperationSampling = &PerOperationSamplingStrategies{} - if err := p.OperationSampling.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.OperationSampling), err) - } - return nil -} - -func (p *SamplingStrategyResponse) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("SamplingStrategyResponse"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := p.writeField4(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *SamplingStrategyResponse) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("strategyType", thrift.I32, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:strategyType: ", p), err) - } - if err := oprot.WriteI32(int32(p.StrategyType)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.strategyType (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:strategyType: ", p), err) - } - return err -} - -func (p *SamplingStrategyResponse) writeField2(oprot thrift.TProtocol) (err error) { - if p.IsSetProbabilisticSampling() { - if err := oprot.WriteFieldBegin("probabilisticSampling", thrift.STRUCT, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:probabilisticSampling: ", p), err) - } - if err := p.ProbabilisticSampling.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.ProbabilisticSampling), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:probabilisticSampling: ", p), err) - } - } - return err -} - -func (p *SamplingStrategyResponse) writeField3(oprot thrift.TProtocol) (err error) { - if p.IsSetRateLimitingSampling() { - if err := oprot.WriteFieldBegin("rateLimitingSampling", thrift.STRUCT, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:rateLimitingSampling: ", p), err) - } - if err := p.RateLimitingSampling.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.RateLimitingSampling), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:rateLimitingSampling: ", p), err) - } - } - return err -} - -func (p *SamplingStrategyResponse) writeField4(oprot thrift.TProtocol) (err error) { - if p.IsSetOperationSampling() { - if err := oprot.WriteFieldBegin("operationSampling", thrift.STRUCT, 4); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:operationSampling: ", p), err) - } - if err := p.OperationSampling.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.OperationSampling), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 4:operationSampling: ", p), err) - } - } - return err -} - -func (p *SamplingStrategyResponse) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("SamplingStrategyResponse(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/constants.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/constants.go deleted file mode 100644 index f05144bfc6..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/constants.go +++ /dev/null @@ -1,32 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package zipkincore - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -const CLIENT_SEND = "cs" -const CLIENT_RECV = "cr" -const SERVER_SEND = "ss" -const SERVER_RECV = "sr" -const WIRE_SEND = "ws" -const WIRE_RECV = "wr" -const CLIENT_SEND_FRAGMENT = "csf" -const CLIENT_RECV_FRAGMENT = "crf" -const SERVER_SEND_FRAGMENT = "ssf" -const SERVER_RECV_FRAGMENT = "srf" -const LOCAL_COMPONENT = "lc" -const CLIENT_ADDR = "ca" -const SERVER_ADDR = "sa" - -func init() { -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go deleted file mode 100644 index 34b2b267eb..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go +++ /dev/null @@ -1,1247 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package zipkincore - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -var GoUnusedProtection__ int - -type AnnotationType int64 - -const ( - AnnotationType_BOOL AnnotationType = 0 - AnnotationType_BYTES AnnotationType = 1 - AnnotationType_I16 AnnotationType = 2 - AnnotationType_I32 AnnotationType = 3 - AnnotationType_I64 AnnotationType = 4 - AnnotationType_DOUBLE AnnotationType = 5 - AnnotationType_STRING AnnotationType = 6 -) - -func (p AnnotationType) String() string { - switch p { - case AnnotationType_BOOL: - return "BOOL" - case AnnotationType_BYTES: - return "BYTES" - case AnnotationType_I16: - return "I16" - case AnnotationType_I32: - return "I32" - case AnnotationType_I64: - return "I64" - case AnnotationType_DOUBLE: - return "DOUBLE" - case AnnotationType_STRING: - return "STRING" - } - return "" -} - -func AnnotationTypeFromString(s string) (AnnotationType, error) { - switch s { - case "BOOL": - return AnnotationType_BOOL, nil - case "BYTES": - return AnnotationType_BYTES, nil - case "I16": - return AnnotationType_I16, nil - case "I32": - return AnnotationType_I32, nil - case "I64": - return AnnotationType_I64, nil - case "DOUBLE": - return AnnotationType_DOUBLE, nil - case "STRING": - return AnnotationType_STRING, nil - } - return AnnotationType(0), fmt.Errorf("not a valid AnnotationType string") -} - -func AnnotationTypePtr(v AnnotationType) *AnnotationType { return &v } - -func (p AnnotationType) MarshalText() ([]byte, error) { - return []byte(p.String()), nil -} - -func (p *AnnotationType) UnmarshalText(text []byte) error { - q, err := AnnotationTypeFromString(string(text)) - if err != nil { - return err - } - *p = q - return nil -} - -// Indicates the network context of a service recording an annotation with two -// exceptions. -// -// When a BinaryAnnotation, and key is CLIENT_ADDR or SERVER_ADDR, -// the endpoint indicates the source or destination of an RPC. This exception -// allows zipkin to display network context of uninstrumented services, or -// clients such as web browsers. -// -// Attributes: -// - Ipv4: IPv4 host address packed into 4 bytes. -// -// Ex for the ip 1.2.3.4, it would be (1 << 24) | (2 << 16) | (3 << 8) | 4 -// - Port: IPv4 port -// -// Note: this is to be treated as an unsigned integer, so watch for negatives. -// -// Conventionally, when the port isn't known, port = 0. -// - ServiceName: Service name in lowercase, such as "memcache" or "zipkin-web" -// -// Conventionally, when the service name isn't known, service_name = "unknown". -type Endpoint struct { - Ipv4 int32 `thrift:"ipv4,1" json:"ipv4"` - Port int16 `thrift:"port,2" json:"port"` - ServiceName string `thrift:"service_name,3" json:"service_name"` -} - -func NewEndpoint() *Endpoint { - return &Endpoint{} -} - -func (p *Endpoint) GetIpv4() int32 { - return p.Ipv4 -} - -func (p *Endpoint) GetPort() int16 { - return p.Port -} - -func (p *Endpoint) GetServiceName() string { - return p.ServiceName -} -func (p *Endpoint) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *Endpoint) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI32(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Ipv4 = v - } - return nil -} - -func (p *Endpoint) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI16(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - p.Port = v - } - return nil -} - -func (p *Endpoint) readField3(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 3: ", err) - } else { - p.ServiceName = v - } - return nil -} - -func (p *Endpoint) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Endpoint"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Endpoint) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("ipv4", thrift.I32, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:ipv4: ", p), err) - } - if err := oprot.WriteI32(int32(p.Ipv4)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.ipv4 (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:ipv4: ", p), err) - } - return err -} - -func (p *Endpoint) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("port", thrift.I16, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:port: ", p), err) - } - if err := oprot.WriteI16(int16(p.Port)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.port (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:port: ", p), err) - } - return err -} - -func (p *Endpoint) writeField3(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("service_name", thrift.STRING, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:service_name: ", p), err) - } - if err := oprot.WriteString(string(p.ServiceName)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.service_name (3) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:service_name: ", p), err) - } - return err -} - -func (p *Endpoint) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Endpoint(%+v)", *p) -} - -// An annotation is similar to a log statement. It includes a host field which -// allows these events to be attributed properly, and also aggregatable. -// -// Attributes: -// - Timestamp: Microseconds from epoch. -// -// This value should use the most precise value possible. For example, -// gettimeofday or syncing nanoTime against a tick of currentTimeMillis. -// - Value -// - Host: Always the host that recorded the event. By specifying the host you allow -// rollup of all events (such as client requests to a service) by IP address. -type Annotation struct { - Timestamp int64 `thrift:"timestamp,1" json:"timestamp"` - Value string `thrift:"value,2" json:"value"` - Host *Endpoint `thrift:"host,3" json:"host,omitempty"` -} - -func NewAnnotation() *Annotation { - return &Annotation{} -} - -func (p *Annotation) GetTimestamp() int64 { - return p.Timestamp -} - -func (p *Annotation) GetValue() string { - return p.Value -} - -var Annotation_Host_DEFAULT *Endpoint - -func (p *Annotation) GetHost() *Endpoint { - if !p.IsSetHost() { - return Annotation_Host_DEFAULT - } - return p.Host -} -func (p *Annotation) IsSetHost() bool { - return p.Host != nil -} - -func (p *Annotation) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *Annotation) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Timestamp = v - } - return nil -} - -func (p *Annotation) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - p.Value = v - } - return nil -} - -func (p *Annotation) readField3(iprot thrift.TProtocol) error { - p.Host = &Endpoint{} - if err := p.Host.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Host), err) - } - return nil -} - -func (p *Annotation) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Annotation"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Annotation) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("timestamp", thrift.I64, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:timestamp: ", p), err) - } - if err := oprot.WriteI64(int64(p.Timestamp)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.timestamp (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:timestamp: ", p), err) - } - return err -} - -func (p *Annotation) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("value", thrift.STRING, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:value: ", p), err) - } - if err := oprot.WriteString(string(p.Value)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.value (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:value: ", p), err) - } - return err -} - -func (p *Annotation) writeField3(oprot thrift.TProtocol) (err error) { - if p.IsSetHost() { - if err := oprot.WriteFieldBegin("host", thrift.STRUCT, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:host: ", p), err) - } - if err := p.Host.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Host), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:host: ", p), err) - } - } - return err -} - -func (p *Annotation) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Annotation(%+v)", *p) -} - -// Binary annotations are tags applied to a Span to give it context. For -// example, a binary annotation of "http.uri" could the path to a resource in a -// RPC call. -// -// Binary annotations of type STRING are always queryable, though more a -// historical implementation detail than a structural concern. -// -// Binary annotations can repeat, and vary on the host. Similar to Annotation, -// the host indicates who logged the event. This allows you to tell the -// difference between the client and server side of the same key. For example, -// the key "http.uri" might be different on the client and server side due to -// rewriting, like "/api/v1/myresource" vs "/myresource. Via the host field, -// you can see the different points of view, which often help in debugging. -// -// Attributes: -// - Key -// - Value -// - AnnotationType -// - Host: The host that recorded tag, which allows you to differentiate between -// multiple tags with the same key. There are two exceptions to this. -// -// When the key is CLIENT_ADDR or SERVER_ADDR, host indicates the source or -// destination of an RPC. This exception allows zipkin to display network -// context of uninstrumented services, or clients such as web browsers. -type BinaryAnnotation struct { - Key string `thrift:"key,1" json:"key"` - Value []byte `thrift:"value,2" json:"value"` - AnnotationType AnnotationType `thrift:"annotation_type,3" json:"annotation_type"` - Host *Endpoint `thrift:"host,4" json:"host,omitempty"` -} - -func NewBinaryAnnotation() *BinaryAnnotation { - return &BinaryAnnotation{} -} - -func (p *BinaryAnnotation) GetKey() string { - return p.Key -} - -func (p *BinaryAnnotation) GetValue() []byte { - return p.Value -} - -func (p *BinaryAnnotation) GetAnnotationType() AnnotationType { - return p.AnnotationType -} - -var BinaryAnnotation_Host_DEFAULT *Endpoint - -func (p *BinaryAnnotation) GetHost() *Endpoint { - if !p.IsSetHost() { - return BinaryAnnotation_Host_DEFAULT - } - return p.Host -} -func (p *BinaryAnnotation) IsSetHost() bool { - return p.Host != nil -} - -func (p *BinaryAnnotation) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - case 2: - if err := p.readField2(iprot); err != nil { - return err - } - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - case 4: - if err := p.readField4(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *BinaryAnnotation) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Key = v - } - return nil -} - -func (p *BinaryAnnotation) readField2(iprot thrift.TProtocol) error { - if v, err := iprot.ReadBinary(); err != nil { - return thrift.PrependError("error reading field 2: ", err) - } else { - p.Value = v - } - return nil -} - -func (p *BinaryAnnotation) readField3(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI32(); err != nil { - return thrift.PrependError("error reading field 3: ", err) - } else { - temp := AnnotationType(v) - p.AnnotationType = temp - } - return nil -} - -func (p *BinaryAnnotation) readField4(iprot thrift.TProtocol) error { - p.Host = &Endpoint{} - if err := p.Host.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Host), err) - } - return nil -} - -func (p *BinaryAnnotation) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("BinaryAnnotation"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField2(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := p.writeField4(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *BinaryAnnotation) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("key", thrift.STRING, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:key: ", p), err) - } - if err := oprot.WriteString(string(p.Key)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.key (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:key: ", p), err) - } - return err -} - -func (p *BinaryAnnotation) writeField2(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("value", thrift.STRING, 2); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:value: ", p), err) - } - if err := oprot.WriteBinary(p.Value); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.value (2) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 2:value: ", p), err) - } - return err -} - -func (p *BinaryAnnotation) writeField3(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("annotation_type", thrift.I32, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:annotation_type: ", p), err) - } - if err := oprot.WriteI32(int32(p.AnnotationType)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.annotation_type (3) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:annotation_type: ", p), err) - } - return err -} - -func (p *BinaryAnnotation) writeField4(oprot thrift.TProtocol) (err error) { - if p.IsSetHost() { - if err := oprot.WriteFieldBegin("host", thrift.STRUCT, 4); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:host: ", p), err) - } - if err := p.Host.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Host), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 4:host: ", p), err) - } - } - return err -} - -func (p *BinaryAnnotation) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("BinaryAnnotation(%+v)", *p) -} - -// A trace is a series of spans (often RPC calls) which form a latency tree. -// -// The root span is where trace_id = id and parent_id = Nil. The root span is -// usually the longest interval in the trace, starting with a SERVER_RECV -// annotation and ending with a SERVER_SEND. -// -// Attributes: -// - TraceID -// - Name: Span name in lowercase, rpc method for example -// -// Conventionally, when the span name isn't known, name = "unknown". -// - ID -// - ParentID -// - Annotations -// - BinaryAnnotations -// - Debug -// - Timestamp: Microseconds from epoch of the creation of this span. -// -// This value should be set directly by instrumentation, using the most -// precise value possible. For example, gettimeofday or syncing nanoTime -// against a tick of currentTimeMillis. -// -// For compatibilty with instrumentation that precede this field, collectors -// or span stores can derive this via Annotation.timestamp. -// For example, SERVER_RECV.timestamp or CLIENT_SEND.timestamp. -// -// This field is optional for compatibility with old data: first-party span -// stores are expected to support this at time of introduction. -// - Duration: Measurement of duration in microseconds, used to support queries. -// -// This value should be set directly, where possible. Doing so encourages -// precise measurement decoupled from problems of clocks, such as skew or NTP -// updates causing time to move backwards. -// -// For compatibilty with instrumentation that precede this field, collectors -// or span stores can derive this by subtracting Annotation.timestamp. -// For example, SERVER_SEND.timestamp - SERVER_RECV.timestamp. -// -// If this field is persisted as unset, zipkin will continue to work, except -// duration query support will be implementation-specific. Similarly, setting -// this field non-atomically is implementation-specific. -// -// This field is i64 vs i32 to support spans longer than 35 minutes. -type Span struct { - TraceID int64 `thrift:"trace_id,1" json:"trace_id"` - // unused field # 2 - Name string `thrift:"name,3" json:"name"` - ID int64 `thrift:"id,4" json:"id"` - ParentID *int64 `thrift:"parent_id,5" json:"parent_id,omitempty"` - Annotations []*Annotation `thrift:"annotations,6" json:"annotations"` - // unused field # 7 - BinaryAnnotations []*BinaryAnnotation `thrift:"binary_annotations,8" json:"binary_annotations"` - Debug bool `thrift:"debug,9" json:"debug,omitempty"` - Timestamp *int64 `thrift:"timestamp,10" json:"timestamp,omitempty"` - Duration *int64 `thrift:"duration,11" json:"duration,omitempty"` -} - -func NewSpan() *Span { - return &Span{} -} - -func (p *Span) GetTraceID() int64 { - return p.TraceID -} - -func (p *Span) GetName() string { - return p.Name -} - -func (p *Span) GetID() int64 { - return p.ID -} - -var Span_ParentID_DEFAULT int64 - -func (p *Span) GetParentID() int64 { - if !p.IsSetParentID() { - return Span_ParentID_DEFAULT - } - return *p.ParentID -} - -func (p *Span) GetAnnotations() []*Annotation { - return p.Annotations -} - -func (p *Span) GetBinaryAnnotations() []*BinaryAnnotation { - return p.BinaryAnnotations -} - -var Span_Debug_DEFAULT bool = false - -func (p *Span) GetDebug() bool { - return p.Debug -} - -var Span_Timestamp_DEFAULT int64 - -func (p *Span) GetTimestamp() int64 { - if !p.IsSetTimestamp() { - return Span_Timestamp_DEFAULT - } - return *p.Timestamp -} - -var Span_Duration_DEFAULT int64 - -func (p *Span) GetDuration() int64 { - if !p.IsSetDuration() { - return Span_Duration_DEFAULT - } - return *p.Duration -} -func (p *Span) IsSetParentID() bool { - return p.ParentID != nil -} - -func (p *Span) IsSetDebug() bool { - return p.Debug != Span_Debug_DEFAULT -} - -func (p *Span) IsSetTimestamp() bool { - return p.Timestamp != nil -} - -func (p *Span) IsSetDuration() bool { - return p.Duration != nil -} - -func (p *Span) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - case 3: - if err := p.readField3(iprot); err != nil { - return err - } - case 4: - if err := p.readField4(iprot); err != nil { - return err - } - case 5: - if err := p.readField5(iprot); err != nil { - return err - } - case 6: - if err := p.readField6(iprot); err != nil { - return err - } - case 8: - if err := p.readField8(iprot); err != nil { - return err - } - case 9: - if err := p.readField9(iprot); err != nil { - return err - } - case 10: - if err := p.readField10(iprot); err != nil { - return err - } - case 11: - if err := p.readField11(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *Span) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.TraceID = v - } - return nil -} - -func (p *Span) readField3(iprot thrift.TProtocol) error { - if v, err := iprot.ReadString(); err != nil { - return thrift.PrependError("error reading field 3: ", err) - } else { - p.Name = v - } - return nil -} - -func (p *Span) readField4(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 4: ", err) - } else { - p.ID = v - } - return nil -} - -func (p *Span) readField5(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 5: ", err) - } else { - p.ParentID = &v - } - return nil -} - -func (p *Span) readField6(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Annotation, 0, size) - p.Annotations = tSlice - for i := 0; i < size; i++ { - _elem0 := &Annotation{} - if err := _elem0.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem0), err) - } - p.Annotations = append(p.Annotations, _elem0) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Span) readField8(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*BinaryAnnotation, 0, size) - p.BinaryAnnotations = tSlice - for i := 0; i < size; i++ { - _elem1 := &BinaryAnnotation{} - if err := _elem1.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem1), err) - } - p.BinaryAnnotations = append(p.BinaryAnnotations, _elem1) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *Span) readField9(iprot thrift.TProtocol) error { - if v, err := iprot.ReadBool(); err != nil { - return thrift.PrependError("error reading field 9: ", err) - } else { - p.Debug = v - } - return nil -} - -func (p *Span) readField10(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 10: ", err) - } else { - p.Timestamp = &v - } - return nil -} - -func (p *Span) readField11(iprot thrift.TProtocol) error { - if v, err := iprot.ReadI64(); err != nil { - return thrift.PrependError("error reading field 11: ", err) - } else { - p.Duration = &v - } - return nil -} - -func (p *Span) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Span"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := p.writeField3(oprot); err != nil { - return err - } - if err := p.writeField4(oprot); err != nil { - return err - } - if err := p.writeField5(oprot); err != nil { - return err - } - if err := p.writeField6(oprot); err != nil { - return err - } - if err := p.writeField8(oprot); err != nil { - return err - } - if err := p.writeField9(oprot); err != nil { - return err - } - if err := p.writeField10(oprot); err != nil { - return err - } - if err := p.writeField11(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Span) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("trace_id", thrift.I64, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:trace_id: ", p), err) - } - if err := oprot.WriteI64(int64(p.TraceID)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.trace_id (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:trace_id: ", p), err) - } - return err -} - -func (p *Span) writeField3(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("name", thrift.STRING, 3); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:name: ", p), err) - } - if err := oprot.WriteString(string(p.Name)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.name (3) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 3:name: ", p), err) - } - return err -} - -func (p *Span) writeField4(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("id", thrift.I64, 4); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:id: ", p), err) - } - if err := oprot.WriteI64(int64(p.ID)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.id (4) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 4:id: ", p), err) - } - return err -} - -func (p *Span) writeField5(oprot thrift.TProtocol) (err error) { - if p.IsSetParentID() { - if err := oprot.WriteFieldBegin("parent_id", thrift.I64, 5); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:parent_id: ", p), err) - } - if err := oprot.WriteI64(int64(*p.ParentID)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.parent_id (5) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 5:parent_id: ", p), err) - } - } - return err -} - -func (p *Span) writeField6(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("annotations", thrift.LIST, 6); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 6:annotations: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Annotations)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Annotations { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 6:annotations: ", p), err) - } - return err -} - -func (p *Span) writeField8(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("binary_annotations", thrift.LIST, 8); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 8:binary_annotations: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.BinaryAnnotations)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.BinaryAnnotations { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 8:binary_annotations: ", p), err) - } - return err -} - -func (p *Span) writeField9(oprot thrift.TProtocol) (err error) { - if p.IsSetDebug() { - if err := oprot.WriteFieldBegin("debug", thrift.BOOL, 9); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 9:debug: ", p), err) - } - if err := oprot.WriteBool(bool(p.Debug)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.debug (9) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 9:debug: ", p), err) - } - } - return err -} - -func (p *Span) writeField10(oprot thrift.TProtocol) (err error) { - if p.IsSetTimestamp() { - if err := oprot.WriteFieldBegin("timestamp", thrift.I64, 10); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 10:timestamp: ", p), err) - } - if err := oprot.WriteI64(int64(*p.Timestamp)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.timestamp (10) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 10:timestamp: ", p), err) - } - } - return err -} - -func (p *Span) writeField11(oprot thrift.TProtocol) (err error) { - if p.IsSetDuration() { - if err := oprot.WriteFieldBegin("duration", thrift.I64, 11); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 11:duration: ", p), err) - } - if err := oprot.WriteI64(int64(*p.Duration)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.duration (11) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 11:duration: ", p), err) - } - } - return err -} - -func (p *Span) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Span(%+v)", *p) -} - -// Attributes: -// - Ok -type Response struct { - Ok bool `thrift:"ok,1,required" json:"ok"` -} - -func NewResponse() *Response { - return &Response{} -} - -func (p *Response) GetOk() bool { - return p.Ok -} -func (p *Response) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - var issetOk bool = false - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - issetOk = true - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - if !issetOk { - return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Ok is not set")) - } - return nil -} - -func (p *Response) readField1(iprot thrift.TProtocol) error { - if v, err := iprot.ReadBool(); err != nil { - return thrift.PrependError("error reading field 1: ", err) - } else { - p.Ok = v - } - return nil -} - -func (p *Response) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("Response"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *Response) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("ok", thrift.BOOL, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:ok: ", p), err) - } - if err := oprot.WriteBool(bool(p.Ok)); err != nil { - return thrift.PrependError(fmt.Sprintf("%T.ok (1) field write error: ", p), err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:ok: ", p), err) - } - return err -} - -func (p *Response) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("Response(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/zipkincollector.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/zipkincollector.go deleted file mode 100644 index 417e883d0e..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/zipkincollector.go +++ /dev/null @@ -1,446 +0,0 @@ -// Autogenerated by Thrift Compiler (0.9.3) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -package zipkincore - -import ( - "bytes" - "fmt" - "github.com/uber/jaeger-client-go/thrift" -) - -// (needed to ensure safety because of naive import list construction.) -var _ = thrift.ZERO -var _ = fmt.Printf -var _ = bytes.Equal - -type ZipkinCollector interface { - // Parameters: - // - Spans - SubmitZipkinBatch(spans []*Span) (r []*Response, err error) -} - -type ZipkinCollectorClient struct { - Transport thrift.TTransport - ProtocolFactory thrift.TProtocolFactory - InputProtocol thrift.TProtocol - OutputProtocol thrift.TProtocol - SeqId int32 -} - -func NewZipkinCollectorClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ZipkinCollectorClient { - return &ZipkinCollectorClient{Transport: t, - ProtocolFactory: f, - InputProtocol: f.GetProtocol(t), - OutputProtocol: f.GetProtocol(t), - SeqId: 0, - } -} - -func NewZipkinCollectorClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ZipkinCollectorClient { - return &ZipkinCollectorClient{Transport: t, - ProtocolFactory: nil, - InputProtocol: iprot, - OutputProtocol: oprot, - SeqId: 0, - } -} - -// Parameters: -// - Spans -func (p *ZipkinCollectorClient) SubmitZipkinBatch(spans []*Span) (r []*Response, err error) { - if err = p.sendSubmitZipkinBatch(spans); err != nil { - return - } - return p.recvSubmitZipkinBatch() -} - -func (p *ZipkinCollectorClient) sendSubmitZipkinBatch(spans []*Span) (err error) { - oprot := p.OutputProtocol - if oprot == nil { - oprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.OutputProtocol = oprot - } - p.SeqId++ - if err = oprot.WriteMessageBegin("submitZipkinBatch", thrift.CALL, p.SeqId); err != nil { - return - } - args := ZipkinCollectorSubmitZipkinBatchArgs{ - Spans: spans, - } - if err = args.Write(oprot); err != nil { - return - } - if err = oprot.WriteMessageEnd(); err != nil { - return - } - return oprot.Flush() -} - -func (p *ZipkinCollectorClient) recvSubmitZipkinBatch() (value []*Response, err error) { - iprot := p.InputProtocol - if iprot == nil { - iprot = p.ProtocolFactory.GetProtocol(p.Transport) - p.InputProtocol = iprot - } - method, mTypeId, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return - } - if method != "submitZipkinBatch" { - err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "submitZipkinBatch failed: wrong method name") - return - } - if p.SeqId != seqId { - err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "submitZipkinBatch failed: out of sequence response") - return - } - if mTypeId == thrift.EXCEPTION { - error2 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception") - var error3 error - error3, err = error2.Read(iprot) - if err != nil { - return - } - if err = iprot.ReadMessageEnd(); err != nil { - return - } - err = error3 - return - } - if mTypeId != thrift.REPLY { - err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "submitZipkinBatch failed: invalid message type") - return - } - result := ZipkinCollectorSubmitZipkinBatchResult{} - if err = result.Read(iprot); err != nil { - return - } - if err = iprot.ReadMessageEnd(); err != nil { - return - } - value = result.GetSuccess() - return -} - -type ZipkinCollectorProcessor struct { - processorMap map[string]thrift.TProcessorFunction - handler ZipkinCollector -} - -func (p *ZipkinCollectorProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { - p.processorMap[key] = processor -} - -func (p *ZipkinCollectorProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { - processor, ok = p.processorMap[key] - return processor, ok -} - -func (p *ZipkinCollectorProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { - return p.processorMap -} - -func NewZipkinCollectorProcessor(handler ZipkinCollector) *ZipkinCollectorProcessor { - - self4 := &ZipkinCollectorProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} - self4.processorMap["submitZipkinBatch"] = &zipkinCollectorProcessorSubmitZipkinBatch{handler: handler} - return self4 -} - -func (p *ZipkinCollectorProcessor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - name, _, seqId, err := iprot.ReadMessageBegin() - if err != nil { - return false, err - } - if processor, ok := p.GetProcessorFunction(name); ok { - return processor.Process(seqId, iprot, oprot) - } - iprot.Skip(thrift.STRUCT) - iprot.ReadMessageEnd() - x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) - oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) - x5.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, x5 - -} - -type zipkinCollectorProcessorSubmitZipkinBatch struct { - handler ZipkinCollector -} - -func (p *zipkinCollectorProcessorSubmitZipkinBatch) Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { - args := ZipkinCollectorSubmitZipkinBatchArgs{} - if err = args.Read(iprot); err != nil { - iprot.ReadMessageEnd() - x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) - oprot.WriteMessageBegin("submitZipkinBatch", thrift.EXCEPTION, seqId) - x.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return false, err - } - - iprot.ReadMessageEnd() - result := ZipkinCollectorSubmitZipkinBatchResult{} - var retval []*Response - var err2 error - if retval, err2 = p.handler.SubmitZipkinBatch(args.Spans); err2 != nil { - x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing submitZipkinBatch: "+err2.Error()) - oprot.WriteMessageBegin("submitZipkinBatch", thrift.EXCEPTION, seqId) - x.Write(oprot) - oprot.WriteMessageEnd() - oprot.Flush() - return true, err2 - } else { - result.Success = retval - } - if err2 = oprot.WriteMessageBegin("submitZipkinBatch", thrift.REPLY, seqId); err2 != nil { - err = err2 - } - if err2 = result.Write(oprot); err == nil && err2 != nil { - err = err2 - } - if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { - err = err2 - } - if err2 = oprot.Flush(); err == nil && err2 != nil { - err = err2 - } - if err != nil { - return - } - return true, err -} - -// HELPER FUNCTIONS AND STRUCTURES - -// Attributes: -// - Spans -type ZipkinCollectorSubmitZipkinBatchArgs struct { - Spans []*Span `thrift:"spans,1" json:"spans"` -} - -func NewZipkinCollectorSubmitZipkinBatchArgs() *ZipkinCollectorSubmitZipkinBatchArgs { - return &ZipkinCollectorSubmitZipkinBatchArgs{} -} - -func (p *ZipkinCollectorSubmitZipkinBatchArgs) GetSpans() []*Span { - return p.Spans -} -func (p *ZipkinCollectorSubmitZipkinBatchArgs) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 1: - if err := p.readField1(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *ZipkinCollectorSubmitZipkinBatchArgs) readField1(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Span, 0, size) - p.Spans = tSlice - for i := 0; i < size; i++ { - _elem6 := &Span{} - if err := _elem6.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem6), err) - } - p.Spans = append(p.Spans, _elem6) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *ZipkinCollectorSubmitZipkinBatchArgs) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("submitZipkinBatch_args"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField1(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *ZipkinCollectorSubmitZipkinBatchArgs) writeField1(oprot thrift.TProtocol) (err error) { - if err := oprot.WriteFieldBegin("spans", thrift.LIST, 1); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:spans: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Spans)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Spans { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 1:spans: ", p), err) - } - return err -} - -func (p *ZipkinCollectorSubmitZipkinBatchArgs) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("ZipkinCollectorSubmitZipkinBatchArgs(%+v)", *p) -} - -// Attributes: -// - Success -type ZipkinCollectorSubmitZipkinBatchResult struct { - Success []*Response `thrift:"success,0" json:"success,omitempty"` -} - -func NewZipkinCollectorSubmitZipkinBatchResult() *ZipkinCollectorSubmitZipkinBatchResult { - return &ZipkinCollectorSubmitZipkinBatchResult{} -} - -var ZipkinCollectorSubmitZipkinBatchResult_Success_DEFAULT []*Response - -func (p *ZipkinCollectorSubmitZipkinBatchResult) GetSuccess() []*Response { - return p.Success -} -func (p *ZipkinCollectorSubmitZipkinBatchResult) IsSetSuccess() bool { - return p.Success != nil -} - -func (p *ZipkinCollectorSubmitZipkinBatchResult) Read(iprot thrift.TProtocol) error { - if _, err := iprot.ReadStructBegin(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) - } - - for { - _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() - if err != nil { - return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) - } - if fieldTypeId == thrift.STOP { - break - } - switch fieldId { - case 0: - if err := p.readField0(iprot); err != nil { - return err - } - default: - if err := iprot.Skip(fieldTypeId); err != nil { - return err - } - } - if err := iprot.ReadFieldEnd(); err != nil { - return err - } - } - if err := iprot.ReadStructEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) - } - return nil -} - -func (p *ZipkinCollectorSubmitZipkinBatchResult) readField0(iprot thrift.TProtocol) error { - _, size, err := iprot.ReadListBegin() - if err != nil { - return thrift.PrependError("error reading list begin: ", err) - } - tSlice := make([]*Response, 0, size) - p.Success = tSlice - for i := 0; i < size; i++ { - _elem7 := &Response{} - if err := _elem7.Read(iprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem7), err) - } - p.Success = append(p.Success, _elem7) - } - if err := iprot.ReadListEnd(); err != nil { - return thrift.PrependError("error reading list end: ", err) - } - return nil -} - -func (p *ZipkinCollectorSubmitZipkinBatchResult) Write(oprot thrift.TProtocol) error { - if err := oprot.WriteStructBegin("submitZipkinBatch_result"); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) - } - if err := p.writeField0(oprot); err != nil { - return err - } - if err := oprot.WriteFieldStop(); err != nil { - return thrift.PrependError("write field stop error: ", err) - } - if err := oprot.WriteStructEnd(); err != nil { - return thrift.PrependError("write struct stop error: ", err) - } - return nil -} - -func (p *ZipkinCollectorSubmitZipkinBatchResult) writeField0(oprot thrift.TProtocol) (err error) { - if p.IsSetSuccess() { - if err := oprot.WriteFieldBegin("success", thrift.LIST, 0); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) - } - if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Success)); err != nil { - return thrift.PrependError("error writing list begin: ", err) - } - for _, v := range p.Success { - if err := v.Write(oprot); err != nil { - return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) - } - } - if err := oprot.WriteListEnd(); err != nil { - return thrift.PrependError("error writing list end: ", err) - } - if err := oprot.WriteFieldEnd(); err != nil { - return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) - } - } - return err -} - -func (p *ZipkinCollectorSubmitZipkinBatchResult) String() string { - if p == nil { - return "" - } - return fmt.Sprintf("ZipkinCollectorSubmitZipkinBatchResult(%+v)", *p) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/README.md b/vendor/github.com/uber/jaeger-client-go/thrift/README.md deleted file mode 100644 index 1d8e642e02..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Apache Thrift - -This is a partial copy of Apache Thrift v0.10 (https://github.com/apache/thrift/commit/b2a4d4ae21c789b689dd162deb819665567f481c). - -It is vendored code to avoid compatibility issues introduced in Thrift v0.11. - -See https://github.com/jaegertracing/jaeger-client-go/pull/303. diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/application_exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/application_exception.go deleted file mode 100644 index 6655cc5a97..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/application_exception.go +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -const ( - UNKNOWN_APPLICATION_EXCEPTION = 0 - UNKNOWN_METHOD = 1 - INVALID_MESSAGE_TYPE_EXCEPTION = 2 - WRONG_METHOD_NAME = 3 - BAD_SEQUENCE_ID = 4 - MISSING_RESULT = 5 - INTERNAL_ERROR = 6 - PROTOCOL_ERROR = 7 -) - -// Application level Thrift exception -type TApplicationException interface { - TException - TypeId() int32 - Read(iprot TProtocol) (TApplicationException, error) - Write(oprot TProtocol) error -} - -type tApplicationException struct { - message string - type_ int32 -} - -func (e tApplicationException) Error() string { - return e.message -} - -func NewTApplicationException(type_ int32, message string) TApplicationException { - return &tApplicationException{message, type_} -} - -func (p *tApplicationException) TypeId() int32 { - return p.type_ -} - -func (p *tApplicationException) Read(iprot TProtocol) (TApplicationException, error) { - _, err := iprot.ReadStructBegin() - if err != nil { - return nil, err - } - - message := "" - type_ := int32(UNKNOWN_APPLICATION_EXCEPTION) - - for { - _, ttype, id, err := iprot.ReadFieldBegin() - if err != nil { - return nil, err - } - if ttype == STOP { - break - } - switch id { - case 1: - if ttype == STRING { - if message, err = iprot.ReadString(); err != nil { - return nil, err - } - } else { - if err = SkipDefaultDepth(iprot, ttype); err != nil { - return nil, err - } - } - case 2: - if ttype == I32 { - if type_, err = iprot.ReadI32(); err != nil { - return nil, err - } - } else { - if err = SkipDefaultDepth(iprot, ttype); err != nil { - return nil, err - } - } - default: - if err = SkipDefaultDepth(iprot, ttype); err != nil { - return nil, err - } - } - if err = iprot.ReadFieldEnd(); err != nil { - return nil, err - } - } - return NewTApplicationException(type_, message), iprot.ReadStructEnd() -} - -func (p *tApplicationException) Write(oprot TProtocol) (err error) { - err = oprot.WriteStructBegin("TApplicationException") - if len(p.Error()) > 0 { - err = oprot.WriteFieldBegin("message", STRING, 1) - if err != nil { - return - } - err = oprot.WriteString(p.Error()) - if err != nil { - return - } - err = oprot.WriteFieldEnd() - if err != nil { - return - } - } - err = oprot.WriteFieldBegin("type", I32, 2) - if err != nil { - return - } - err = oprot.WriteI32(p.type_) - if err != nil { - return - } - err = oprot.WriteFieldEnd() - if err != nil { - return - } - err = oprot.WriteFieldStop() - if err != nil { - return - } - err = oprot.WriteStructEnd() - return -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/binary_protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/binary_protocol.go deleted file mode 100644 index 690d341111..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/binary_protocol.go +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - "math" -) - -type TBinaryProtocol struct { - trans TRichTransport - origTransport TTransport - reader io.Reader - writer io.Writer - strictRead bool - strictWrite bool - buffer [64]byte -} - -type TBinaryProtocolFactory struct { - strictRead bool - strictWrite bool -} - -func NewTBinaryProtocolTransport(t TTransport) *TBinaryProtocol { - return NewTBinaryProtocol(t, false, true) -} - -func NewTBinaryProtocol(t TTransport, strictRead, strictWrite bool) *TBinaryProtocol { - p := &TBinaryProtocol{origTransport: t, strictRead: strictRead, strictWrite: strictWrite} - if et, ok := t.(TRichTransport); ok { - p.trans = et - } else { - p.trans = NewTRichTransport(t) - } - p.reader = p.trans - p.writer = p.trans - return p -} - -func NewTBinaryProtocolFactoryDefault() *TBinaryProtocolFactory { - return NewTBinaryProtocolFactory(false, true) -} - -func NewTBinaryProtocolFactory(strictRead, strictWrite bool) *TBinaryProtocolFactory { - return &TBinaryProtocolFactory{strictRead: strictRead, strictWrite: strictWrite} -} - -func (p *TBinaryProtocolFactory) GetProtocol(t TTransport) TProtocol { - return NewTBinaryProtocol(t, p.strictRead, p.strictWrite) -} - -/** - * Writing Methods - */ - -func (p *TBinaryProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) error { - if p.strictWrite { - version := uint32(VERSION_1) | uint32(typeId) - e := p.WriteI32(int32(version)) - if e != nil { - return e - } - e = p.WriteString(name) - if e != nil { - return e - } - e = p.WriteI32(seqId) - return e - } else { - e := p.WriteString(name) - if e != nil { - return e - } - e = p.WriteByte(int8(typeId)) - if e != nil { - return e - } - e = p.WriteI32(seqId) - return e - } - return nil -} - -func (p *TBinaryProtocol) WriteMessageEnd() error { - return nil -} - -func (p *TBinaryProtocol) WriteStructBegin(name string) error { - return nil -} - -func (p *TBinaryProtocol) WriteStructEnd() error { - return nil -} - -func (p *TBinaryProtocol) WriteFieldBegin(name string, typeId TType, id int16) error { - e := p.WriteByte(int8(typeId)) - if e != nil { - return e - } - e = p.WriteI16(id) - return e -} - -func (p *TBinaryProtocol) WriteFieldEnd() error { - return nil -} - -func (p *TBinaryProtocol) WriteFieldStop() error { - e := p.WriteByte(STOP) - return e -} - -func (p *TBinaryProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error { - e := p.WriteByte(int8(keyType)) - if e != nil { - return e - } - e = p.WriteByte(int8(valueType)) - if e != nil { - return e - } - e = p.WriteI32(int32(size)) - return e -} - -func (p *TBinaryProtocol) WriteMapEnd() error { - return nil -} - -func (p *TBinaryProtocol) WriteListBegin(elemType TType, size int) error { - e := p.WriteByte(int8(elemType)) - if e != nil { - return e - } - e = p.WriteI32(int32(size)) - return e -} - -func (p *TBinaryProtocol) WriteListEnd() error { - return nil -} - -func (p *TBinaryProtocol) WriteSetBegin(elemType TType, size int) error { - e := p.WriteByte(int8(elemType)) - if e != nil { - return e - } - e = p.WriteI32(int32(size)) - return e -} - -func (p *TBinaryProtocol) WriteSetEnd() error { - return nil -} - -func (p *TBinaryProtocol) WriteBool(value bool) error { - if value { - return p.WriteByte(1) - } - return p.WriteByte(0) -} - -func (p *TBinaryProtocol) WriteByte(value int8) error { - e := p.trans.WriteByte(byte(value)) - return NewTProtocolException(e) -} - -func (p *TBinaryProtocol) WriteI16(value int16) error { - v := p.buffer[0:2] - binary.BigEndian.PutUint16(v, uint16(value)) - _, e := p.writer.Write(v) - return NewTProtocolException(e) -} - -func (p *TBinaryProtocol) WriteI32(value int32) error { - v := p.buffer[0:4] - binary.BigEndian.PutUint32(v, uint32(value)) - _, e := p.writer.Write(v) - return NewTProtocolException(e) -} - -func (p *TBinaryProtocol) WriteI64(value int64) error { - v := p.buffer[0:8] - binary.BigEndian.PutUint64(v, uint64(value)) - _, err := p.writer.Write(v) - return NewTProtocolException(err) -} - -func (p *TBinaryProtocol) WriteDouble(value float64) error { - return p.WriteI64(int64(math.Float64bits(value))) -} - -func (p *TBinaryProtocol) WriteString(value string) error { - e := p.WriteI32(int32(len(value))) - if e != nil { - return e - } - _, err := p.trans.WriteString(value) - return NewTProtocolException(err) -} - -func (p *TBinaryProtocol) WriteBinary(value []byte) error { - e := p.WriteI32(int32(len(value))) - if e != nil { - return e - } - _, err := p.writer.Write(value) - return NewTProtocolException(err) -} - -/** - * Reading methods - */ - -func (p *TBinaryProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) { - size, e := p.ReadI32() - if e != nil { - return "", typeId, 0, NewTProtocolException(e) - } - if size < 0 { - typeId = TMessageType(size & 0x0ff) - version := int64(int64(size) & VERSION_MASK) - if version != VERSION_1 { - return name, typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, fmt.Errorf("Bad version in ReadMessageBegin")) - } - name, e = p.ReadString() - if e != nil { - return name, typeId, seqId, NewTProtocolException(e) - } - seqId, e = p.ReadI32() - if e != nil { - return name, typeId, seqId, NewTProtocolException(e) - } - return name, typeId, seqId, nil - } - if p.strictRead { - return name, typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, fmt.Errorf("Missing version in ReadMessageBegin")) - } - name, e2 := p.readStringBody(size) - if e2 != nil { - return name, typeId, seqId, e2 - } - b, e3 := p.ReadByte() - if e3 != nil { - return name, typeId, seqId, e3 - } - typeId = TMessageType(b) - seqId, e4 := p.ReadI32() - if e4 != nil { - return name, typeId, seqId, e4 - } - return name, typeId, seqId, nil -} - -func (p *TBinaryProtocol) ReadMessageEnd() error { - return nil -} - -func (p *TBinaryProtocol) ReadStructBegin() (name string, err error) { - return -} - -func (p *TBinaryProtocol) ReadStructEnd() error { - return nil -} - -func (p *TBinaryProtocol) ReadFieldBegin() (name string, typeId TType, seqId int16, err error) { - t, err := p.ReadByte() - typeId = TType(t) - if err != nil { - return name, typeId, seqId, err - } - if t != STOP { - seqId, err = p.ReadI16() - } - return name, typeId, seqId, err -} - -func (p *TBinaryProtocol) ReadFieldEnd() error { - return nil -} - -var invalidDataLength = NewTProtocolExceptionWithType(INVALID_DATA, errors.New("Invalid data length")) - -func (p *TBinaryProtocol) ReadMapBegin() (kType, vType TType, size int, err error) { - k, e := p.ReadByte() - if e != nil { - err = NewTProtocolException(e) - return - } - kType = TType(k) - v, e := p.ReadByte() - if e != nil { - err = NewTProtocolException(e) - return - } - vType = TType(v) - size32, e := p.ReadI32() - if e != nil { - err = NewTProtocolException(e) - return - } - if size32 < 0 { - err = invalidDataLength - return - } - size = int(size32) - return kType, vType, size, nil -} - -func (p *TBinaryProtocol) ReadMapEnd() error { - return nil -} - -func (p *TBinaryProtocol) ReadListBegin() (elemType TType, size int, err error) { - b, e := p.ReadByte() - if e != nil { - err = NewTProtocolException(e) - return - } - elemType = TType(b) - size32, e := p.ReadI32() - if e != nil { - err = NewTProtocolException(e) - return - } - if size32 < 0 { - err = invalidDataLength - return - } - size = int(size32) - - return -} - -func (p *TBinaryProtocol) ReadListEnd() error { - return nil -} - -func (p *TBinaryProtocol) ReadSetBegin() (elemType TType, size int, err error) { - b, e := p.ReadByte() - if e != nil { - err = NewTProtocolException(e) - return - } - elemType = TType(b) - size32, e := p.ReadI32() - if e != nil { - err = NewTProtocolException(e) - return - } - if size32 < 0 { - err = invalidDataLength - return - } - size = int(size32) - return elemType, size, nil -} - -func (p *TBinaryProtocol) ReadSetEnd() error { - return nil -} - -func (p *TBinaryProtocol) ReadBool() (bool, error) { - b, e := p.ReadByte() - v := true - if b != 1 { - v = false - } - return v, e -} - -func (p *TBinaryProtocol) ReadByte() (int8, error) { - v, err := p.trans.ReadByte() - return int8(v), err -} - -func (p *TBinaryProtocol) ReadI16() (value int16, err error) { - buf := p.buffer[0:2] - err = p.readAll(buf) - value = int16(binary.BigEndian.Uint16(buf)) - return value, err -} - -func (p *TBinaryProtocol) ReadI32() (value int32, err error) { - buf := p.buffer[0:4] - err = p.readAll(buf) - value = int32(binary.BigEndian.Uint32(buf)) - return value, err -} - -func (p *TBinaryProtocol) ReadI64() (value int64, err error) { - buf := p.buffer[0:8] - err = p.readAll(buf) - value = int64(binary.BigEndian.Uint64(buf)) - return value, err -} - -func (p *TBinaryProtocol) ReadDouble() (value float64, err error) { - buf := p.buffer[0:8] - err = p.readAll(buf) - value = math.Float64frombits(binary.BigEndian.Uint64(buf)) - return value, err -} - -func (p *TBinaryProtocol) ReadString() (value string, err error) { - size, e := p.ReadI32() - if e != nil { - return "", e - } - if size < 0 { - err = invalidDataLength - return - } - - return p.readStringBody(size) -} - -func (p *TBinaryProtocol) ReadBinary() ([]byte, error) { - size, e := p.ReadI32() - if e != nil { - return nil, e - } - if size < 0 { - return nil, invalidDataLength - } - if uint64(size) > p.trans.RemainingBytes() { - return nil, invalidDataLength - } - - isize := int(size) - buf := make([]byte, isize) - _, err := io.ReadFull(p.trans, buf) - return buf, NewTProtocolException(err) -} - -func (p *TBinaryProtocol) Flush() (err error) { - return NewTProtocolException(p.trans.Flush()) -} - -func (p *TBinaryProtocol) Skip(fieldType TType) (err error) { - return SkipDefaultDepth(p, fieldType) -} - -func (p *TBinaryProtocol) Transport() TTransport { - return p.origTransport -} - -func (p *TBinaryProtocol) readAll(buf []byte) error { - _, err := io.ReadFull(p.reader, buf) - return NewTProtocolException(err) -} - -const readLimit = 32768 - -func (p *TBinaryProtocol) readStringBody(size int32) (value string, err error) { - if size < 0 { - return "", nil - } - if uint64(size) > p.trans.RemainingBytes() { - return "", invalidDataLength - } - - var ( - buf bytes.Buffer - e error - b []byte - ) - - switch { - case int(size) <= len(p.buffer): - b = p.buffer[:size] // avoids allocation for small reads - case int(size) < readLimit: - b = make([]byte, size) - default: - b = make([]byte, readLimit) - } - - for size > 0 { - _, e = io.ReadFull(p.trans, b) - buf.Write(b) - if e != nil { - break - } - size -= readLimit - if size < readLimit && size > 0 { - b = b[:size] - } - } - return buf.String(), NewTProtocolException(e) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/compact_protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/compact_protocol.go deleted file mode 100644 index b9299f2fa1..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/compact_protocol.go +++ /dev/null @@ -1,815 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "encoding/binary" - "fmt" - "io" - "math" -) - -const ( - COMPACT_PROTOCOL_ID = 0x082 - COMPACT_VERSION = 1 - COMPACT_VERSION_MASK = 0x1f - COMPACT_TYPE_MASK = 0x0E0 - COMPACT_TYPE_BITS = 0x07 - COMPACT_TYPE_SHIFT_AMOUNT = 5 -) - -type tCompactType byte - -const ( - COMPACT_BOOLEAN_TRUE = 0x01 - COMPACT_BOOLEAN_FALSE = 0x02 - COMPACT_BYTE = 0x03 - COMPACT_I16 = 0x04 - COMPACT_I32 = 0x05 - COMPACT_I64 = 0x06 - COMPACT_DOUBLE = 0x07 - COMPACT_BINARY = 0x08 - COMPACT_LIST = 0x09 - COMPACT_SET = 0x0A - COMPACT_MAP = 0x0B - COMPACT_STRUCT = 0x0C -) - -var ( - ttypeToCompactType map[TType]tCompactType -) - -func init() { - ttypeToCompactType = map[TType]tCompactType{ - STOP: STOP, - BOOL: COMPACT_BOOLEAN_TRUE, - BYTE: COMPACT_BYTE, - I16: COMPACT_I16, - I32: COMPACT_I32, - I64: COMPACT_I64, - DOUBLE: COMPACT_DOUBLE, - STRING: COMPACT_BINARY, - LIST: COMPACT_LIST, - SET: COMPACT_SET, - MAP: COMPACT_MAP, - STRUCT: COMPACT_STRUCT, - } -} - -type TCompactProtocolFactory struct{} - -func NewTCompactProtocolFactory() *TCompactProtocolFactory { - return &TCompactProtocolFactory{} -} - -func (p *TCompactProtocolFactory) GetProtocol(trans TTransport) TProtocol { - return NewTCompactProtocol(trans) -} - -type TCompactProtocol struct { - trans TRichTransport - origTransport TTransport - - // Used to keep track of the last field for the current and previous structs, - // so we can do the delta stuff. - lastField []int - lastFieldId int - - // If we encounter a boolean field begin, save the TField here so it can - // have the value incorporated. - booleanFieldName string - booleanFieldId int16 - booleanFieldPending bool - - // If we read a field header, and it's a boolean field, save the boolean - // value here so that readBool can use it. - boolValue bool - boolValueIsNotNull bool - buffer [64]byte -} - -// Create a TCompactProtocol given a TTransport -func NewTCompactProtocol(trans TTransport) *TCompactProtocol { - p := &TCompactProtocol{origTransport: trans, lastField: []int{}} - if et, ok := trans.(TRichTransport); ok { - p.trans = et - } else { - p.trans = NewTRichTransport(trans) - } - - return p - -} - -// -// Public Writing methods. -// - -// Write a message header to the wire. Compact Protocol messages contain the -// protocol version so we can migrate forwards in the future if need be. -func (p *TCompactProtocol) WriteMessageBegin(name string, typeId TMessageType, seqid int32) error { - err := p.writeByteDirect(COMPACT_PROTOCOL_ID) - if err != nil { - return NewTProtocolException(err) - } - err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK)) - if err != nil { - return NewTProtocolException(err) - } - _, err = p.writeVarint32(seqid) - if err != nil { - return NewTProtocolException(err) - } - e := p.WriteString(name) - return e - -} - -func (p *TCompactProtocol) WriteMessageEnd() error { return nil } - -// Write a struct begin. This doesn't actually put anything on the wire. We -// use it as an opportunity to put special placeholder markers on the field -// stack so we can get the field id deltas correct. -func (p *TCompactProtocol) WriteStructBegin(name string) error { - p.lastField = append(p.lastField, p.lastFieldId) - p.lastFieldId = 0 - return nil -} - -// Write a struct end. This doesn't actually put anything on the wire. We use -// this as an opportunity to pop the last field from the current struct off -// of the field stack. -func (p *TCompactProtocol) WriteStructEnd() error { - p.lastFieldId = p.lastField[len(p.lastField)-1] - p.lastField = p.lastField[:len(p.lastField)-1] - return nil -} - -func (p *TCompactProtocol) WriteFieldBegin(name string, typeId TType, id int16) error { - if typeId == BOOL { - // we want to possibly include the value, so we'll wait. - p.booleanFieldName, p.booleanFieldId, p.booleanFieldPending = name, id, true - return nil - } - _, err := p.writeFieldBeginInternal(name, typeId, id, 0xFF) - return NewTProtocolException(err) -} - -// The workhorse of writeFieldBegin. It has the option of doing a -// 'type override' of the type header. This is used specifically in the -// boolean field case. -func (p *TCompactProtocol) writeFieldBeginInternal(name string, typeId TType, id int16, typeOverride byte) (int, error) { - // short lastField = lastField_.pop(); - - // if there's a type override, use that. - var typeToWrite byte - if typeOverride == 0xFF { - typeToWrite = byte(p.getCompactType(typeId)) - } else { - typeToWrite = typeOverride - } - // check if we can use delta encoding for the field id - fieldId := int(id) - written := 0 - if fieldId > p.lastFieldId && fieldId-p.lastFieldId <= 15 { - // write them together - err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite) - if err != nil { - return 0, err - } - } else { - // write them separate - err := p.writeByteDirect(typeToWrite) - if err != nil { - return 0, err - } - err = p.WriteI16(id) - written = 1 + 2 - if err != nil { - return 0, err - } - } - - p.lastFieldId = fieldId - // p.lastField.Push(field.id); - return written, nil -} - -func (p *TCompactProtocol) WriteFieldEnd() error { return nil } - -func (p *TCompactProtocol) WriteFieldStop() error { - err := p.writeByteDirect(STOP) - return NewTProtocolException(err) -} - -func (p *TCompactProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error { - if size == 0 { - err := p.writeByteDirect(0) - return NewTProtocolException(err) - } - _, err := p.writeVarint32(int32(size)) - if err != nil { - return NewTProtocolException(err) - } - err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType))) - return NewTProtocolException(err) -} - -func (p *TCompactProtocol) WriteMapEnd() error { return nil } - -// Write a list header. -func (p *TCompactProtocol) WriteListBegin(elemType TType, size int) error { - _, err := p.writeCollectionBegin(elemType, size) - return NewTProtocolException(err) -} - -func (p *TCompactProtocol) WriteListEnd() error { return nil } - -// Write a set header. -func (p *TCompactProtocol) WriteSetBegin(elemType TType, size int) error { - _, err := p.writeCollectionBegin(elemType, size) - return NewTProtocolException(err) -} - -func (p *TCompactProtocol) WriteSetEnd() error { return nil } - -func (p *TCompactProtocol) WriteBool(value bool) error { - v := byte(COMPACT_BOOLEAN_FALSE) - if value { - v = byte(COMPACT_BOOLEAN_TRUE) - } - if p.booleanFieldPending { - // we haven't written the field header yet - _, err := p.writeFieldBeginInternal(p.booleanFieldName, BOOL, p.booleanFieldId, v) - p.booleanFieldPending = false - return NewTProtocolException(err) - } - // we're not part of a field, so just write the value. - err := p.writeByteDirect(v) - return NewTProtocolException(err) -} - -// Write a byte. Nothing to see here! -func (p *TCompactProtocol) WriteByte(value int8) error { - err := p.writeByteDirect(byte(value)) - return NewTProtocolException(err) -} - -// Write an I16 as a zigzag varint. -func (p *TCompactProtocol) WriteI16(value int16) error { - _, err := p.writeVarint32(p.int32ToZigzag(int32(value))) - return NewTProtocolException(err) -} - -// Write an i32 as a zigzag varint. -func (p *TCompactProtocol) WriteI32(value int32) error { - _, err := p.writeVarint32(p.int32ToZigzag(value)) - return NewTProtocolException(err) -} - -// Write an i64 as a zigzag varint. -func (p *TCompactProtocol) WriteI64(value int64) error { - _, err := p.writeVarint64(p.int64ToZigzag(value)) - return NewTProtocolException(err) -} - -// Write a double to the wire as 8 bytes. -func (p *TCompactProtocol) WriteDouble(value float64) error { - buf := p.buffer[0:8] - binary.LittleEndian.PutUint64(buf, math.Float64bits(value)) - _, err := p.trans.Write(buf) - return NewTProtocolException(err) -} - -// Write a string to the wire with a varint size preceding. -func (p *TCompactProtocol) WriteString(value string) error { - _, e := p.writeVarint32(int32(len(value))) - if e != nil { - return NewTProtocolException(e) - } - if len(value) > 0 { - } - _, e = p.trans.WriteString(value) - return e -} - -// Write a byte array, using a varint for the size. -func (p *TCompactProtocol) WriteBinary(bin []byte) error { - _, e := p.writeVarint32(int32(len(bin))) - if e != nil { - return NewTProtocolException(e) - } - if len(bin) > 0 { - _, e = p.trans.Write(bin) - return NewTProtocolException(e) - } - return nil -} - -// -// Reading methods. -// - -// Read a message header. -func (p *TCompactProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) { - - protocolId, err := p.readByteDirect() - if err != nil { - return - } - - if protocolId != COMPACT_PROTOCOL_ID { - e := fmt.Errorf("Expected protocol id %02x but got %02x", COMPACT_PROTOCOL_ID, protocolId) - return "", typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, e) - } - - versionAndType, err := p.readByteDirect() - if err != nil { - return - } - - version := versionAndType & COMPACT_VERSION_MASK - typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS) - if version != COMPACT_VERSION { - e := fmt.Errorf("Expected version %02x but got %02x", COMPACT_VERSION, version) - err = NewTProtocolExceptionWithType(BAD_VERSION, e) - return - } - seqId, e := p.readVarint32() - if e != nil { - err = NewTProtocolException(e) - return - } - name, err = p.ReadString() - return -} - -func (p *TCompactProtocol) ReadMessageEnd() error { return nil } - -// Read a struct begin. There's nothing on the wire for this, but it is our -// opportunity to push a new struct begin marker onto the field stack. -func (p *TCompactProtocol) ReadStructBegin() (name string, err error) { - p.lastField = append(p.lastField, p.lastFieldId) - p.lastFieldId = 0 - return -} - -// Doesn't actually consume any wire data, just removes the last field for -// this struct from the field stack. -func (p *TCompactProtocol) ReadStructEnd() error { - // consume the last field we read off the wire. - p.lastFieldId = p.lastField[len(p.lastField)-1] - p.lastField = p.lastField[:len(p.lastField)-1] - return nil -} - -// Read a field header off the wire. -func (p *TCompactProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err error) { - t, err := p.readByteDirect() - if err != nil { - return - } - - // if it's a stop, then we can return immediately, as the struct is over. - if (t & 0x0f) == STOP { - return "", STOP, 0, nil - } - - // mask off the 4 MSB of the type header. it could contain a field id delta. - modifier := int16((t & 0xf0) >> 4) - if modifier == 0 { - // not a delta. look ahead for the zigzag varint field id. - id, err = p.ReadI16() - if err != nil { - return - } - } else { - // has a delta. add the delta to the last read field id. - id = int16(p.lastFieldId) + modifier - } - typeId, e := p.getTType(tCompactType(t & 0x0f)) - if e != nil { - err = NewTProtocolException(e) - return - } - - // if this happens to be a boolean field, the value is encoded in the type - if p.isBoolType(t) { - // save the boolean value in a special instance variable. - p.boolValue = (byte(t)&0x0f == COMPACT_BOOLEAN_TRUE) - p.boolValueIsNotNull = true - } - - // push the new field onto the field stack so we can keep the deltas going. - p.lastFieldId = int(id) - return -} - -func (p *TCompactProtocol) ReadFieldEnd() error { return nil } - -// Read a map header off the wire. If the size is zero, skip reading the key -// and value type. This means that 0-length maps will yield TMaps without the -// "correct" types. -func (p *TCompactProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err error) { - size32, e := p.readVarint32() - if e != nil { - err = NewTProtocolException(e) - return - } - if size32 < 0 { - err = invalidDataLength - return - } - size = int(size32) - - keyAndValueType := byte(STOP) - if size != 0 { - keyAndValueType, err = p.readByteDirect() - if err != nil { - return - } - } - keyType, _ = p.getTType(tCompactType(keyAndValueType >> 4)) - valueType, _ = p.getTType(tCompactType(keyAndValueType & 0xf)) - return -} - -func (p *TCompactProtocol) ReadMapEnd() error { return nil } - -// Read a list header off the wire. If the list size is 0-14, the size will -// be packed into the element type header. If it's a longer list, the 4 MSB -// of the element type header will be 0xF, and a varint will follow with the -// true size. -func (p *TCompactProtocol) ReadListBegin() (elemType TType, size int, err error) { - size_and_type, err := p.readByteDirect() - if err != nil { - return - } - size = int((size_and_type >> 4) & 0x0f) - if size == 15 { - size2, e := p.readVarint32() - if e != nil { - err = NewTProtocolException(e) - return - } - if size2 < 0 { - err = invalidDataLength - return - } - size = int(size2) - } - elemType, e := p.getTType(tCompactType(size_and_type)) - if e != nil { - err = NewTProtocolException(e) - return - } - return -} - -func (p *TCompactProtocol) ReadListEnd() error { return nil } - -// Read a set header off the wire. If the set size is 0-14, the size will -// be packed into the element type header. If it's a longer set, the 4 MSB -// of the element type header will be 0xF, and a varint will follow with the -// true size. -func (p *TCompactProtocol) ReadSetBegin() (elemType TType, size int, err error) { - return p.ReadListBegin() -} - -func (p *TCompactProtocol) ReadSetEnd() error { return nil } - -// Read a boolean off the wire. If this is a boolean field, the value should -// already have been read during readFieldBegin, so we'll just consume the -// pre-stored value. Otherwise, read a byte. -func (p *TCompactProtocol) ReadBool() (value bool, err error) { - if p.boolValueIsNotNull { - p.boolValueIsNotNull = false - return p.boolValue, nil - } - v, err := p.readByteDirect() - return v == COMPACT_BOOLEAN_TRUE, err -} - -// Read a single byte off the wire. Nothing interesting here. -func (p *TCompactProtocol) ReadByte() (int8, error) { - v, err := p.readByteDirect() - if err != nil { - return 0, NewTProtocolException(err) - } - return int8(v), err -} - -// Read an i16 from the wire as a zigzag varint. -func (p *TCompactProtocol) ReadI16() (value int16, err error) { - v, err := p.ReadI32() - return int16(v), err -} - -// Read an i32 from the wire as a zigzag varint. -func (p *TCompactProtocol) ReadI32() (value int32, err error) { - v, e := p.readVarint32() - if e != nil { - return 0, NewTProtocolException(e) - } - value = p.zigzagToInt32(v) - return value, nil -} - -// Read an i64 from the wire as a zigzag varint. -func (p *TCompactProtocol) ReadI64() (value int64, err error) { - v, e := p.readVarint64() - if e != nil { - return 0, NewTProtocolException(e) - } - value = p.zigzagToInt64(v) - return value, nil -} - -// No magic here - just read a double off the wire. -func (p *TCompactProtocol) ReadDouble() (value float64, err error) { - longBits := p.buffer[0:8] - _, e := io.ReadFull(p.trans, longBits) - if e != nil { - return 0.0, NewTProtocolException(e) - } - return math.Float64frombits(p.bytesToUint64(longBits)), nil -} - -// Reads a []byte (via readBinary), and then UTF-8 decodes it. -func (p *TCompactProtocol) ReadString() (value string, err error) { - length, e := p.readVarint32() - if e != nil { - return "", NewTProtocolException(e) - } - if length < 0 { - return "", invalidDataLength - } - if uint64(length) > p.trans.RemainingBytes() { - return "", invalidDataLength - } - - if length == 0 { - return "", nil - } - var buf []byte - if length <= int32(len(p.buffer)) { - buf = p.buffer[0:length] - } else { - buf = make([]byte, length) - } - _, e = io.ReadFull(p.trans, buf) - return string(buf), NewTProtocolException(e) -} - -// Read a []byte from the wire. -func (p *TCompactProtocol) ReadBinary() (value []byte, err error) { - length, e := p.readVarint32() - if e != nil { - return nil, NewTProtocolException(e) - } - if length == 0 { - return []byte{}, nil - } - if length < 0 { - return nil, invalidDataLength - } - if uint64(length) > p.trans.RemainingBytes() { - return nil, invalidDataLength - } - - buf := make([]byte, length) - _, e = io.ReadFull(p.trans, buf) - return buf, NewTProtocolException(e) -} - -func (p *TCompactProtocol) Flush() (err error) { - return NewTProtocolException(p.trans.Flush()) -} - -func (p *TCompactProtocol) Skip(fieldType TType) (err error) { - return SkipDefaultDepth(p, fieldType) -} - -func (p *TCompactProtocol) Transport() TTransport { - return p.origTransport -} - -// -// Internal writing methods -// - -// Abstract method for writing the start of lists and sets. List and sets on -// the wire differ only by the type indicator. -func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, error) { - if size <= 14 { - return 1, p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType)))) - } - err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType))) - if err != nil { - return 0, err - } - m, err := p.writeVarint32(int32(size)) - return 1 + m, err -} - -// Write an i32 as a varint. Results in 1-5 bytes on the wire. -// TODO(pomack): make a permanent buffer like writeVarint64? -func (p *TCompactProtocol) writeVarint32(n int32) (int, error) { - i32buf := p.buffer[0:5] - idx := 0 - for { - if (n & ^0x7F) == 0 { - i32buf[idx] = byte(n) - idx++ - // p.writeByteDirect(byte(n)); - break - // return; - } else { - i32buf[idx] = byte((n & 0x7F) | 0x80) - idx++ - // p.writeByteDirect(byte(((n & 0x7F) | 0x80))); - u := uint32(n) - n = int32(u >> 7) - } - } - return p.trans.Write(i32buf[0:idx]) -} - -// Write an i64 as a varint. Results in 1-10 bytes on the wire. -func (p *TCompactProtocol) writeVarint64(n int64) (int, error) { - varint64out := p.buffer[0:10] - idx := 0 - for { - if (n & ^0x7F) == 0 { - varint64out[idx] = byte(n) - idx++ - break - } else { - varint64out[idx] = byte((n & 0x7F) | 0x80) - idx++ - u := uint64(n) - n = int64(u >> 7) - } - } - return p.trans.Write(varint64out[0:idx]) -} - -// Convert l into a zigzag long. This allows negative numbers to be -// represented compactly as a varint. -func (p *TCompactProtocol) int64ToZigzag(l int64) int64 { - return (l << 1) ^ (l >> 63) -} - -// Convert l into a zigzag long. This allows negative numbers to be -// represented compactly as a varint. -func (p *TCompactProtocol) int32ToZigzag(n int32) int32 { - return (n << 1) ^ (n >> 31) -} - -func (p *TCompactProtocol) fixedUint64ToBytes(n uint64, buf []byte) { - binary.LittleEndian.PutUint64(buf, n) -} - -func (p *TCompactProtocol) fixedInt64ToBytes(n int64, buf []byte) { - binary.LittleEndian.PutUint64(buf, uint64(n)) -} - -// Writes a byte without any possibility of all that field header nonsense. -// Used internally by other writing methods that know they need to write a byte. -func (p *TCompactProtocol) writeByteDirect(b byte) error { - return p.trans.WriteByte(b) -} - -// Writes a byte without any possibility of all that field header nonsense. -func (p *TCompactProtocol) writeIntAsByteDirect(n int) (int, error) { - return 1, p.writeByteDirect(byte(n)) -} - -// -// Internal reading methods -// - -// Read an i32 from the wire as a varint. The MSB of each byte is set -// if there is another byte to follow. This can read up to 5 bytes. -func (p *TCompactProtocol) readVarint32() (int32, error) { - // if the wire contains the right stuff, this will just truncate the i64 we - // read and get us the right sign. - v, err := p.readVarint64() - return int32(v), err -} - -// Read an i64 from the wire as a proper varint. The MSB of each byte is set -// if there is another byte to follow. This can read up to 10 bytes. -func (p *TCompactProtocol) readVarint64() (int64, error) { - shift := uint(0) - result := int64(0) - for { - b, err := p.readByteDirect() - if err != nil { - return 0, err - } - result |= int64(b&0x7f) << shift - if (b & 0x80) != 0x80 { - break - } - shift += 7 - } - return result, nil -} - -// Read a byte, unlike ReadByte that reads Thrift-byte that is i8. -func (p *TCompactProtocol) readByteDirect() (byte, error) { - return p.trans.ReadByte() -} - -// -// encoding helpers -// - -// Convert from zigzag int to int. -func (p *TCompactProtocol) zigzagToInt32(n int32) int32 { - u := uint32(n) - return int32(u>>1) ^ -(n & 1) -} - -// Convert from zigzag long to long. -func (p *TCompactProtocol) zigzagToInt64(n int64) int64 { - u := uint64(n) - return int64(u>>1) ^ -(n & 1) -} - -// Note that it's important that the mask bytes are long literals, -// otherwise they'll default to ints, and when you shift an int left 56 bits, -// you just get a messed up int. -func (p *TCompactProtocol) bytesToInt64(b []byte) int64 { - return int64(binary.LittleEndian.Uint64(b)) -} - -// Note that it's important that the mask bytes are long literals, -// otherwise they'll default to ints, and when you shift an int left 56 bits, -// you just get a messed up int. -func (p *TCompactProtocol) bytesToUint64(b []byte) uint64 { - return binary.LittleEndian.Uint64(b) -} - -// -// type testing and converting -// - -func (p *TCompactProtocol) isBoolType(b byte) bool { - return (b&0x0f) == COMPACT_BOOLEAN_TRUE || (b&0x0f) == COMPACT_BOOLEAN_FALSE -} - -// Given a tCompactType constant, convert it to its corresponding -// TType value. -func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) { - switch byte(t) & 0x0f { - case STOP: - return STOP, nil - case COMPACT_BOOLEAN_FALSE, COMPACT_BOOLEAN_TRUE: - return BOOL, nil - case COMPACT_BYTE: - return BYTE, nil - case COMPACT_I16: - return I16, nil - case COMPACT_I32: - return I32, nil - case COMPACT_I64: - return I64, nil - case COMPACT_DOUBLE: - return DOUBLE, nil - case COMPACT_BINARY: - return STRING, nil - case COMPACT_LIST: - return LIST, nil - case COMPACT_SET: - return SET, nil - case COMPACT_MAP: - return MAP, nil - case COMPACT_STRUCT: - return STRUCT, nil - } - return STOP, TException(fmt.Errorf("don't know what type: %d", t&0x0f)) -} - -// Given a TType value, find the appropriate TCompactProtocol.Types constant. -func (p *TCompactProtocol) getCompactType(t TType) tCompactType { - return ttypeToCompactType[t] -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/exception.go deleted file mode 100644 index ea8d6f6611..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/exception.go +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "errors" -) - -// Generic Thrift exception -type TException interface { - error -} - -// Prepends additional information to an error without losing the Thrift exception interface -func PrependError(prepend string, err error) error { - if t, ok := err.(TTransportException); ok { - return NewTTransportException(t.TypeId(), prepend+t.Error()) - } - if t, ok := err.(TProtocolException); ok { - return NewTProtocolExceptionWithType(t.TypeId(), errors.New(prepend+err.Error())) - } - if t, ok := err.(TApplicationException); ok { - return NewTApplicationException(t.TypeId(), prepend+t.Error()) - } - - return errors.New(prepend + err.Error()) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/memory_buffer.go b/vendor/github.com/uber/jaeger-client-go/thrift/memory_buffer.go deleted file mode 100644 index b62fd56f06..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/memory_buffer.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "bytes" -) - -// Memory buffer-based implementation of the TTransport interface. -type TMemoryBuffer struct { - *bytes.Buffer - size int -} - -type TMemoryBufferTransportFactory struct { - size int -} - -func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) TTransport { - if trans != nil { - t, ok := trans.(*TMemoryBuffer) - if ok && t.size > 0 { - return NewTMemoryBufferLen(t.size) - } - } - return NewTMemoryBufferLen(p.size) -} - -func NewTMemoryBufferTransportFactory(size int) *TMemoryBufferTransportFactory { - return &TMemoryBufferTransportFactory{size: size} -} - -func NewTMemoryBuffer() *TMemoryBuffer { - return &TMemoryBuffer{Buffer: &bytes.Buffer{}, size: 0} -} - -func NewTMemoryBufferLen(size int) *TMemoryBuffer { - buf := make([]byte, 0, size) - return &TMemoryBuffer{Buffer: bytes.NewBuffer(buf), size: size} -} - -func (p *TMemoryBuffer) IsOpen() bool { - return true -} - -func (p *TMemoryBuffer) Open() error { - return nil -} - -func (p *TMemoryBuffer) Close() error { - p.Buffer.Reset() - return nil -} - -// Flushing a memory buffer is a no-op -func (p *TMemoryBuffer) Flush() error { - return nil -} - -func (p *TMemoryBuffer) RemainingBytes() (num_bytes uint64) { - return uint64(p.Buffer.Len()) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/messagetype.go b/vendor/github.com/uber/jaeger-client-go/thrift/messagetype.go deleted file mode 100644 index 25ab2e98a2..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/messagetype.go +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -// Message type constants in the Thrift protocol. -type TMessageType int32 - -const ( - INVALID_TMESSAGE_TYPE TMessageType = 0 - CALL TMessageType = 1 - REPLY TMessageType = 2 - EXCEPTION TMessageType = 3 - ONEWAY TMessageType = 4 -) diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/numeric.go b/vendor/github.com/uber/jaeger-client-go/thrift/numeric.go deleted file mode 100644 index aa8daa9b54..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/numeric.go +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "math" - "strconv" -) - -type Numeric interface { - Int64() int64 - Int32() int32 - Int16() int16 - Byte() byte - Int() int - Float64() float64 - Float32() float32 - String() string - isNull() bool -} - -type numeric struct { - iValue int64 - dValue float64 - sValue string - isNil bool -} - -var ( - INFINITY Numeric - NEGATIVE_INFINITY Numeric - NAN Numeric - ZERO Numeric - NUMERIC_NULL Numeric -) - -func NewNumericFromDouble(dValue float64) Numeric { - if math.IsInf(dValue, 1) { - return INFINITY - } - if math.IsInf(dValue, -1) { - return NEGATIVE_INFINITY - } - if math.IsNaN(dValue) { - return NAN - } - iValue := int64(dValue) - sValue := strconv.FormatFloat(dValue, 'g', 10, 64) - isNil := false - return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil} -} - -func NewNumericFromI64(iValue int64) Numeric { - dValue := float64(iValue) - sValue := string(iValue) - isNil := false - return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil} -} - -func NewNumericFromI32(iValue int32) Numeric { - dValue := float64(iValue) - sValue := string(iValue) - isNil := false - return &numeric{iValue: int64(iValue), dValue: dValue, sValue: sValue, isNil: isNil} -} - -func NewNumericFromString(sValue string) Numeric { - if sValue == INFINITY.String() { - return INFINITY - } - if sValue == NEGATIVE_INFINITY.String() { - return NEGATIVE_INFINITY - } - if sValue == NAN.String() { - return NAN - } - iValue, _ := strconv.ParseInt(sValue, 10, 64) - dValue, _ := strconv.ParseFloat(sValue, 64) - isNil := len(sValue) == 0 - return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil} -} - -func NewNumericFromJSONString(sValue string, isNull bool) Numeric { - if isNull { - return NewNullNumeric() - } - if sValue == JSON_INFINITY { - return INFINITY - } - if sValue == JSON_NEGATIVE_INFINITY { - return NEGATIVE_INFINITY - } - if sValue == JSON_NAN { - return NAN - } - iValue, _ := strconv.ParseInt(sValue, 10, 64) - dValue, _ := strconv.ParseFloat(sValue, 64) - return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNull} -} - -func NewNullNumeric() Numeric { - return &numeric{iValue: 0, dValue: 0.0, sValue: "", isNil: true} -} - -func (p *numeric) Int64() int64 { - return p.iValue -} - -func (p *numeric) Int32() int32 { - return int32(p.iValue) -} - -func (p *numeric) Int16() int16 { - return int16(p.iValue) -} - -func (p *numeric) Byte() byte { - return byte(p.iValue) -} - -func (p *numeric) Int() int { - return int(p.iValue) -} - -func (p *numeric) Float64() float64 { - return p.dValue -} - -func (p *numeric) Float32() float32 { - return float32(p.dValue) -} - -func (p *numeric) String() string { - return p.sValue -} - -func (p *numeric) isNull() bool { - return p.isNil -} - -func init() { - INFINITY = &numeric{iValue: 0, dValue: math.Inf(1), sValue: "Infinity", isNil: false} - NEGATIVE_INFINITY = &numeric{iValue: 0, dValue: math.Inf(-1), sValue: "-Infinity", isNil: false} - NAN = &numeric{iValue: 0, dValue: math.NaN(), sValue: "NaN", isNil: false} - ZERO = &numeric{iValue: 0, dValue: 0, sValue: "0", isNil: false} - NUMERIC_NULL = &numeric{iValue: 0, dValue: 0, sValue: "0", isNil: true} -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/processor.go b/vendor/github.com/uber/jaeger-client-go/thrift/processor.go deleted file mode 100644 index ca0d3faf20..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/processor.go +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -// A processor is a generic object which operates upon an input stream and -// writes to some output stream. -type TProcessor interface { - Process(in, out TProtocol) (bool, TException) -} - -type TProcessorFunction interface { - Process(seqId int32, in, out TProtocol) (bool, TException) -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/protocol.go deleted file mode 100644 index 45fa202e74..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/protocol.go +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "errors" -) - -const ( - VERSION_MASK = 0xffff0000 - VERSION_1 = 0x80010000 -) - -type TProtocol interface { - WriteMessageBegin(name string, typeId TMessageType, seqid int32) error - WriteMessageEnd() error - WriteStructBegin(name string) error - WriteStructEnd() error - WriteFieldBegin(name string, typeId TType, id int16) error - WriteFieldEnd() error - WriteFieldStop() error - WriteMapBegin(keyType TType, valueType TType, size int) error - WriteMapEnd() error - WriteListBegin(elemType TType, size int) error - WriteListEnd() error - WriteSetBegin(elemType TType, size int) error - WriteSetEnd() error - WriteBool(value bool) error - WriteByte(value int8) error - WriteI16(value int16) error - WriteI32(value int32) error - WriteI64(value int64) error - WriteDouble(value float64) error - WriteString(value string) error - WriteBinary(value []byte) error - - ReadMessageBegin() (name string, typeId TMessageType, seqid int32, err error) - ReadMessageEnd() error - ReadStructBegin() (name string, err error) - ReadStructEnd() error - ReadFieldBegin() (name string, typeId TType, id int16, err error) - ReadFieldEnd() error - ReadMapBegin() (keyType TType, valueType TType, size int, err error) - ReadMapEnd() error - ReadListBegin() (elemType TType, size int, err error) - ReadListEnd() error - ReadSetBegin() (elemType TType, size int, err error) - ReadSetEnd() error - ReadBool() (value bool, err error) - ReadByte() (value int8, err error) - ReadI16() (value int16, err error) - ReadI32() (value int32, err error) - ReadI64() (value int64, err error) - ReadDouble() (value float64, err error) - ReadString() (value string, err error) - ReadBinary() (value []byte, err error) - - Skip(fieldType TType) (err error) - Flush() (err error) - - Transport() TTransport -} - -// The maximum recursive depth the skip() function will traverse -const DEFAULT_RECURSION_DEPTH = 64 - -// Skips over the next data element from the provided input TProtocol object. -func SkipDefaultDepth(prot TProtocol, typeId TType) (err error) { - return Skip(prot, typeId, DEFAULT_RECURSION_DEPTH) -} - -// Skips over the next data element from the provided input TProtocol object. -func Skip(self TProtocol, fieldType TType, maxDepth int) (err error) { - - if maxDepth <= 0 { - return NewTProtocolExceptionWithType( DEPTH_LIMIT, errors.New("Depth limit exceeded")) - } - - switch fieldType { - case STOP: - return - case BOOL: - _, err = self.ReadBool() - return - case BYTE: - _, err = self.ReadByte() - return - case I16: - _, err = self.ReadI16() - return - case I32: - _, err = self.ReadI32() - return - case I64: - _, err = self.ReadI64() - return - case DOUBLE: - _, err = self.ReadDouble() - return - case STRING: - _, err = self.ReadString() - return - case STRUCT: - if _, err = self.ReadStructBegin(); err != nil { - return err - } - for { - _, typeId, _, _ := self.ReadFieldBegin() - if typeId == STOP { - break - } - err := Skip(self, typeId, maxDepth-1) - if err != nil { - return err - } - self.ReadFieldEnd() - } - return self.ReadStructEnd() - case MAP: - keyType, valueType, size, err := self.ReadMapBegin() - if err != nil { - return err - } - for i := 0; i < size; i++ { - err := Skip(self, keyType, maxDepth-1) - if err != nil { - return err - } - self.Skip(valueType) - } - return self.ReadMapEnd() - case SET: - elemType, size, err := self.ReadSetBegin() - if err != nil { - return err - } - for i := 0; i < size; i++ { - err := Skip(self, elemType, maxDepth-1) - if err != nil { - return err - } - } - return self.ReadSetEnd() - case LIST: - elemType, size, err := self.ReadListBegin() - if err != nil { - return err - } - for i := 0; i < size; i++ { - err := Skip(self, elemType, maxDepth-1) - if err != nil { - return err - } - } - return self.ReadListEnd() - } - return nil -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/protocol_exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/protocol_exception.go deleted file mode 100644 index 6e357ee890..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/protocol_exception.go +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "encoding/base64" -) - -// Thrift Protocol exception -type TProtocolException interface { - TException - TypeId() int -} - -const ( - UNKNOWN_PROTOCOL_EXCEPTION = 0 - INVALID_DATA = 1 - NEGATIVE_SIZE = 2 - SIZE_LIMIT = 3 - BAD_VERSION = 4 - NOT_IMPLEMENTED = 5 - DEPTH_LIMIT = 6 -) - -type tProtocolException struct { - typeId int - message string -} - -func (p *tProtocolException) TypeId() int { - return p.typeId -} - -func (p *tProtocolException) String() string { - return p.message -} - -func (p *tProtocolException) Error() string { - return p.message -} - -func NewTProtocolException(err error) TProtocolException { - if err == nil { - return nil - } - if e,ok := err.(TProtocolException); ok { - return e - } - if _, ok := err.(base64.CorruptInputError); ok { - return &tProtocolException{INVALID_DATA, err.Error()} - } - return &tProtocolException{UNKNOWN_PROTOCOL_EXCEPTION, err.Error()} -} - -func NewTProtocolExceptionWithType(errType int, err error) TProtocolException { - if err == nil { - return nil - } - return &tProtocolException{errType, err.Error()} -} - diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/protocol_factory.go b/vendor/github.com/uber/jaeger-client-go/thrift/protocol_factory.go deleted file mode 100644 index c40f796d88..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/protocol_factory.go +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -// Factory interface for constructing protocol instances. -type TProtocolFactory interface { - GetProtocol(trans TTransport) TProtocol -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/rich_transport.go b/vendor/github.com/uber/jaeger-client-go/thrift/rich_transport.go deleted file mode 100644 index 8e296a99b5..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/rich_transport.go +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import "io" - -type RichTransport struct { - TTransport -} - -// Wraps Transport to provide TRichTransport interface -func NewTRichTransport(trans TTransport) *RichTransport { - return &RichTransport{trans} -} - -func (r *RichTransport) ReadByte() (c byte, err error) { - return readByte(r.TTransport) -} - -func (r *RichTransport) WriteByte(c byte) error { - return writeByte(r.TTransport, c) -} - -func (r *RichTransport) WriteString(s string) (n int, err error) { - return r.Write([]byte(s)) -} - -func (r *RichTransport) RemainingBytes() (num_bytes uint64) { - return r.TTransport.RemainingBytes() -} - -func readByte(r io.Reader) (c byte, err error) { - v := [1]byte{0} - n, err := r.Read(v[0:1]) - if n > 0 && (err == nil || err == io.EOF) { - return v[0], nil - } - if n > 0 && err != nil { - return v[0], err - } - if err != nil { - return 0, err - } - return v[0], nil -} - -func writeByte(w io.Writer, c byte) error { - v := [1]byte{c} - _, err := w.Write(v[0:1]) - return err -} - diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/serializer.go b/vendor/github.com/uber/jaeger-client-go/thrift/serializer.go deleted file mode 100644 index 7712229990..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/serializer.go +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -type TSerializer struct { - Transport *TMemoryBuffer - Protocol TProtocol -} - -type TStruct interface { - Write(p TProtocol) error - Read(p TProtocol) error -} - -func NewTSerializer() *TSerializer { - transport := NewTMemoryBufferLen(1024) - protocol := NewTBinaryProtocolFactoryDefault().GetProtocol(transport) - - return &TSerializer{ - transport, - protocol} -} - -func (t *TSerializer) WriteString(msg TStruct) (s string, err error) { - t.Transport.Reset() - - if err = msg.Write(t.Protocol); err != nil { - return - } - - if err = t.Protocol.Flush(); err != nil { - return - } - if err = t.Transport.Flush(); err != nil { - return - } - - return t.Transport.String(), nil -} - -func (t *TSerializer) Write(msg TStruct) (b []byte, err error) { - t.Transport.Reset() - - if err = msg.Write(t.Protocol); err != nil { - return - } - - if err = t.Protocol.Flush(); err != nil { - return - } - - if err = t.Transport.Flush(); err != nil { - return - } - - b = append(b, t.Transport.Bytes()...) - return -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go b/vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go deleted file mode 100644 index 412a482d05..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/simple_json_protocol.go +++ /dev/null @@ -1,1337 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "bufio" - "bytes" - "encoding/base64" - "encoding/json" - "fmt" - "io" - "math" - "strconv" -) - -type _ParseContext int - -const ( - _CONTEXT_IN_TOPLEVEL _ParseContext = 1 - _CONTEXT_IN_LIST_FIRST _ParseContext = 2 - _CONTEXT_IN_LIST _ParseContext = 3 - _CONTEXT_IN_OBJECT_FIRST _ParseContext = 4 - _CONTEXT_IN_OBJECT_NEXT_KEY _ParseContext = 5 - _CONTEXT_IN_OBJECT_NEXT_VALUE _ParseContext = 6 -) - -func (p _ParseContext) String() string { - switch p { - case _CONTEXT_IN_TOPLEVEL: - return "TOPLEVEL" - case _CONTEXT_IN_LIST_FIRST: - return "LIST-FIRST" - case _CONTEXT_IN_LIST: - return "LIST" - case _CONTEXT_IN_OBJECT_FIRST: - return "OBJECT-FIRST" - case _CONTEXT_IN_OBJECT_NEXT_KEY: - return "OBJECT-NEXT-KEY" - case _CONTEXT_IN_OBJECT_NEXT_VALUE: - return "OBJECT-NEXT-VALUE" - } - return "UNKNOWN-PARSE-CONTEXT" -} - -// JSON protocol implementation for thrift. -// -// This protocol produces/consumes a simple output format -// suitable for parsing by scripting languages. It should not be -// confused with the full-featured TJSONProtocol. -// -type TSimpleJSONProtocol struct { - trans TTransport - - parseContextStack []int - dumpContext []int - - writer *bufio.Writer - reader *bufio.Reader -} - -// Constructor -func NewTSimpleJSONProtocol(t TTransport) *TSimpleJSONProtocol { - v := &TSimpleJSONProtocol{trans: t, - writer: bufio.NewWriter(t), - reader: bufio.NewReader(t), - } - v.parseContextStack = append(v.parseContextStack, int(_CONTEXT_IN_TOPLEVEL)) - v.dumpContext = append(v.dumpContext, int(_CONTEXT_IN_TOPLEVEL)) - return v -} - -// Factory -type TSimpleJSONProtocolFactory struct{} - -func (p *TSimpleJSONProtocolFactory) GetProtocol(trans TTransport) TProtocol { - return NewTSimpleJSONProtocol(trans) -} - -func NewTSimpleJSONProtocolFactory() *TSimpleJSONProtocolFactory { - return &TSimpleJSONProtocolFactory{} -} - -var ( - JSON_COMMA []byte - JSON_COLON []byte - JSON_LBRACE []byte - JSON_RBRACE []byte - JSON_LBRACKET []byte - JSON_RBRACKET []byte - JSON_QUOTE byte - JSON_QUOTE_BYTES []byte - JSON_NULL []byte - JSON_TRUE []byte - JSON_FALSE []byte - JSON_INFINITY string - JSON_NEGATIVE_INFINITY string - JSON_NAN string - JSON_INFINITY_BYTES []byte - JSON_NEGATIVE_INFINITY_BYTES []byte - JSON_NAN_BYTES []byte - json_nonbase_map_elem_bytes []byte -) - -func init() { - JSON_COMMA = []byte{','} - JSON_COLON = []byte{':'} - JSON_LBRACE = []byte{'{'} - JSON_RBRACE = []byte{'}'} - JSON_LBRACKET = []byte{'['} - JSON_RBRACKET = []byte{']'} - JSON_QUOTE = '"' - JSON_QUOTE_BYTES = []byte{'"'} - JSON_NULL = []byte{'n', 'u', 'l', 'l'} - JSON_TRUE = []byte{'t', 'r', 'u', 'e'} - JSON_FALSE = []byte{'f', 'a', 'l', 's', 'e'} - JSON_INFINITY = "Infinity" - JSON_NEGATIVE_INFINITY = "-Infinity" - JSON_NAN = "NaN" - JSON_INFINITY_BYTES = []byte{'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'} - JSON_NEGATIVE_INFINITY_BYTES = []byte{'-', 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'} - JSON_NAN_BYTES = []byte{'N', 'a', 'N'} - json_nonbase_map_elem_bytes = []byte{']', ',', '['} -} - -func jsonQuote(s string) string { - b, _ := json.Marshal(s) - s1 := string(b) - return s1 -} - -func jsonUnquote(s string) (string, bool) { - s1 := new(string) - err := json.Unmarshal([]byte(s), s1) - return *s1, err == nil -} - -func mismatch(expected, actual string) error { - return fmt.Errorf("Expected '%s' but found '%s' while parsing JSON.", expected, actual) -} - -func (p *TSimpleJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) error { - p.resetContextStack() // THRIFT-3735 - if e := p.OutputListBegin(); e != nil { - return e - } - if e := p.WriteString(name); e != nil { - return e - } - if e := p.WriteByte(int8(typeId)); e != nil { - return e - } - if e := p.WriteI32(seqId); e != nil { - return e - } - return nil -} - -func (p *TSimpleJSONProtocol) WriteMessageEnd() error { - return p.OutputListEnd() -} - -func (p *TSimpleJSONProtocol) WriteStructBegin(name string) error { - if e := p.OutputObjectBegin(); e != nil { - return e - } - return nil -} - -func (p *TSimpleJSONProtocol) WriteStructEnd() error { - return p.OutputObjectEnd() -} - -func (p *TSimpleJSONProtocol) WriteFieldBegin(name string, typeId TType, id int16) error { - if e := p.WriteString(name); e != nil { - return e - } - return nil -} - -func (p *TSimpleJSONProtocol) WriteFieldEnd() error { - //return p.OutputListEnd() - return nil -} - -func (p *TSimpleJSONProtocol) WriteFieldStop() error { return nil } - -func (p *TSimpleJSONProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error { - if e := p.OutputListBegin(); e != nil { - return e - } - if e := p.WriteByte(int8(keyType)); e != nil { - return e - } - if e := p.WriteByte(int8(valueType)); e != nil { - return e - } - return p.WriteI32(int32(size)) -} - -func (p *TSimpleJSONProtocol) WriteMapEnd() error { - return p.OutputListEnd() -} - -func (p *TSimpleJSONProtocol) WriteListBegin(elemType TType, size int) error { - return p.OutputElemListBegin(elemType, size) -} - -func (p *TSimpleJSONProtocol) WriteListEnd() error { - return p.OutputListEnd() -} - -func (p *TSimpleJSONProtocol) WriteSetBegin(elemType TType, size int) error { - return p.OutputElemListBegin(elemType, size) -} - -func (p *TSimpleJSONProtocol) WriteSetEnd() error { - return p.OutputListEnd() -} - -func (p *TSimpleJSONProtocol) WriteBool(b bool) error { - return p.OutputBool(b) -} - -func (p *TSimpleJSONProtocol) WriteByte(b int8) error { - return p.WriteI32(int32(b)) -} - -func (p *TSimpleJSONProtocol) WriteI16(v int16) error { - return p.WriteI32(int32(v)) -} - -func (p *TSimpleJSONProtocol) WriteI32(v int32) error { - return p.OutputI64(int64(v)) -} - -func (p *TSimpleJSONProtocol) WriteI64(v int64) error { - return p.OutputI64(int64(v)) -} - -func (p *TSimpleJSONProtocol) WriteDouble(v float64) error { - return p.OutputF64(v) -} - -func (p *TSimpleJSONProtocol) WriteString(v string) error { - return p.OutputString(v) -} - -func (p *TSimpleJSONProtocol) WriteBinary(v []byte) error { - // JSON library only takes in a string, - // not an arbitrary byte array, to ensure bytes are transmitted - // efficiently we must convert this into a valid JSON string - // therefore we use base64 encoding to avoid excessive escaping/quoting - if e := p.OutputPreValue(); e != nil { - return e - } - if _, e := p.write(JSON_QUOTE_BYTES); e != nil { - return NewTProtocolException(e) - } - writer := base64.NewEncoder(base64.StdEncoding, p.writer) - if _, e := writer.Write(v); e != nil { - p.writer.Reset(p.trans) // THRIFT-3735 - return NewTProtocolException(e) - } - if e := writer.Close(); e != nil { - return NewTProtocolException(e) - } - if _, e := p.write(JSON_QUOTE_BYTES); e != nil { - return NewTProtocolException(e) - } - return p.OutputPostValue() -} - -// Reading methods. -func (p *TSimpleJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) { - p.resetContextStack() // THRIFT-3735 - if isNull, err := p.ParseListBegin(); isNull || err != nil { - return name, typeId, seqId, err - } - if name, err = p.ReadString(); err != nil { - return name, typeId, seqId, err - } - bTypeId, err := p.ReadByte() - typeId = TMessageType(bTypeId) - if err != nil { - return name, typeId, seqId, err - } - if seqId, err = p.ReadI32(); err != nil { - return name, typeId, seqId, err - } - return name, typeId, seqId, nil -} - -func (p *TSimpleJSONProtocol) ReadMessageEnd() error { - return p.ParseListEnd() -} - -func (p *TSimpleJSONProtocol) ReadStructBegin() (name string, err error) { - _, err = p.ParseObjectStart() - return "", err -} - -func (p *TSimpleJSONProtocol) ReadStructEnd() error { - return p.ParseObjectEnd() -} - -func (p *TSimpleJSONProtocol) ReadFieldBegin() (string, TType, int16, error) { - if err := p.ParsePreValue(); err != nil { - return "", STOP, 0, err - } - b, _ := p.reader.Peek(1) - if len(b) > 0 { - switch b[0] { - case JSON_RBRACE[0]: - return "", STOP, 0, nil - case JSON_QUOTE: - p.reader.ReadByte() - name, err := p.ParseStringBody() - // simplejson is not meant to be read back into thrift - // - see http://wiki.apache.org/thrift/ThriftUsageJava - // - use JSON instead - if err != nil { - return name, STOP, 0, err - } - return name, STOP, -1, p.ParsePostValue() - /* - if err = p.ParsePostValue(); err != nil { - return name, STOP, 0, err - } - if isNull, err := p.ParseListBegin(); isNull || err != nil { - return name, STOP, 0, err - } - bType, err := p.ReadByte() - thetype := TType(bType) - if err != nil { - return name, thetype, 0, err - } - id, err := p.ReadI16() - return name, thetype, id, err - */ - } - e := fmt.Errorf("Expected \"}\" or '\"', but found: '%s'", string(b)) - return "", STOP, 0, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - return "", STOP, 0, NewTProtocolException(io.EOF) -} - -func (p *TSimpleJSONProtocol) ReadFieldEnd() error { - return nil - //return p.ParseListEnd() -} - -func (p *TSimpleJSONProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, e error) { - if isNull, e := p.ParseListBegin(); isNull || e != nil { - return VOID, VOID, 0, e - } - - // read keyType - bKeyType, e := p.ReadByte() - keyType = TType(bKeyType) - if e != nil { - return keyType, valueType, size, e - } - - // read valueType - bValueType, e := p.ReadByte() - valueType = TType(bValueType) - if e != nil { - return keyType, valueType, size, e - } - - // read size - iSize, err := p.ReadI64() - size = int(iSize) - return keyType, valueType, size, err -} - -func (p *TSimpleJSONProtocol) ReadMapEnd() error { - return p.ParseListEnd() -} - -func (p *TSimpleJSONProtocol) ReadListBegin() (elemType TType, size int, e error) { - return p.ParseElemListBegin() -} - -func (p *TSimpleJSONProtocol) ReadListEnd() error { - return p.ParseListEnd() -} - -func (p *TSimpleJSONProtocol) ReadSetBegin() (elemType TType, size int, e error) { - return p.ParseElemListBegin() -} - -func (p *TSimpleJSONProtocol) ReadSetEnd() error { - return p.ParseListEnd() -} - -func (p *TSimpleJSONProtocol) ReadBool() (bool, error) { - var value bool - - if err := p.ParsePreValue(); err != nil { - return value, err - } - f, _ := p.reader.Peek(1) - if len(f) > 0 { - switch f[0] { - case JSON_TRUE[0]: - b := make([]byte, len(JSON_TRUE)) - _, err := p.reader.Read(b) - if err != nil { - return false, NewTProtocolException(err) - } - if string(b) == string(JSON_TRUE) { - value = true - } else { - e := fmt.Errorf("Expected \"true\" but found: %s", string(b)) - return value, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - break - case JSON_FALSE[0]: - b := make([]byte, len(JSON_FALSE)) - _, err := p.reader.Read(b) - if err != nil { - return false, NewTProtocolException(err) - } - if string(b) == string(JSON_FALSE) { - value = false - } else { - e := fmt.Errorf("Expected \"false\" but found: %s", string(b)) - return value, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - break - case JSON_NULL[0]: - b := make([]byte, len(JSON_NULL)) - _, err := p.reader.Read(b) - if err != nil { - return false, NewTProtocolException(err) - } - if string(b) == string(JSON_NULL) { - value = false - } else { - e := fmt.Errorf("Expected \"null\" but found: %s", string(b)) - return value, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - default: - e := fmt.Errorf("Expected \"true\", \"false\", or \"null\" but found: %s", string(f)) - return value, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } - return value, p.ParsePostValue() -} - -func (p *TSimpleJSONProtocol) ReadByte() (int8, error) { - v, err := p.ReadI64() - return int8(v), err -} - -func (p *TSimpleJSONProtocol) ReadI16() (int16, error) { - v, err := p.ReadI64() - return int16(v), err -} - -func (p *TSimpleJSONProtocol) ReadI32() (int32, error) { - v, err := p.ReadI64() - return int32(v), err -} - -func (p *TSimpleJSONProtocol) ReadI64() (int64, error) { - v, _, err := p.ParseI64() - return v, err -} - -func (p *TSimpleJSONProtocol) ReadDouble() (float64, error) { - v, _, err := p.ParseF64() - return v, err -} - -func (p *TSimpleJSONProtocol) ReadString() (string, error) { - var v string - if err := p.ParsePreValue(); err != nil { - return v, err - } - f, _ := p.reader.Peek(1) - if len(f) > 0 && f[0] == JSON_QUOTE { - p.reader.ReadByte() - value, err := p.ParseStringBody() - v = value - if err != nil { - return v, err - } - } else if len(f) > 0 && f[0] == JSON_NULL[0] { - b := make([]byte, len(JSON_NULL)) - _, err := p.reader.Read(b) - if err != nil { - return v, NewTProtocolException(err) - } - if string(b) != string(JSON_NULL) { - e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b)) - return v, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } else { - e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f)) - return v, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - return v, p.ParsePostValue() -} - -func (p *TSimpleJSONProtocol) ReadBinary() ([]byte, error) { - var v []byte - if err := p.ParsePreValue(); err != nil { - return nil, err - } - f, _ := p.reader.Peek(1) - if len(f) > 0 && f[0] == JSON_QUOTE { - p.reader.ReadByte() - value, err := p.ParseBase64EncodedBody() - v = value - if err != nil { - return v, err - } - } else if len(f) > 0 && f[0] == JSON_NULL[0] { - b := make([]byte, len(JSON_NULL)) - _, err := p.reader.Read(b) - if err != nil { - return v, NewTProtocolException(err) - } - if string(b) != string(JSON_NULL) { - e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b)) - return v, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } else { - e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f)) - return v, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - - return v, p.ParsePostValue() -} - -func (p *TSimpleJSONProtocol) Flush() (err error) { - return NewTProtocolException(p.writer.Flush()) -} - -func (p *TSimpleJSONProtocol) Skip(fieldType TType) (err error) { - return SkipDefaultDepth(p, fieldType) -} - -func (p *TSimpleJSONProtocol) Transport() TTransport { - return p.trans -} - -func (p *TSimpleJSONProtocol) OutputPreValue() error { - cxt := _ParseContext(p.dumpContext[len(p.dumpContext)-1]) - switch cxt { - case _CONTEXT_IN_LIST, _CONTEXT_IN_OBJECT_NEXT_KEY: - if _, e := p.write(JSON_COMMA); e != nil { - return NewTProtocolException(e) - } - break - case _CONTEXT_IN_OBJECT_NEXT_VALUE: - if _, e := p.write(JSON_COLON); e != nil { - return NewTProtocolException(e) - } - break - } - return nil -} - -func (p *TSimpleJSONProtocol) OutputPostValue() error { - cxt := _ParseContext(p.dumpContext[len(p.dumpContext)-1]) - switch cxt { - case _CONTEXT_IN_LIST_FIRST: - p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] - p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_LIST)) - break - case _CONTEXT_IN_OBJECT_FIRST: - p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] - p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_VALUE)) - break - case _CONTEXT_IN_OBJECT_NEXT_KEY: - p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] - p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_VALUE)) - break - case _CONTEXT_IN_OBJECT_NEXT_VALUE: - p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] - p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_NEXT_KEY)) - break - } - return nil -} - -func (p *TSimpleJSONProtocol) OutputBool(value bool) error { - if e := p.OutputPreValue(); e != nil { - return e - } - var v string - if value { - v = string(JSON_TRUE) - } else { - v = string(JSON_FALSE) - } - switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) { - case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: - v = jsonQuote(v) - default: - } - if e := p.OutputStringData(v); e != nil { - return e - } - return p.OutputPostValue() -} - -func (p *TSimpleJSONProtocol) OutputNull() error { - if e := p.OutputPreValue(); e != nil { - return e - } - if _, e := p.write(JSON_NULL); e != nil { - return NewTProtocolException(e) - } - return p.OutputPostValue() -} - -func (p *TSimpleJSONProtocol) OutputF64(value float64) error { - if e := p.OutputPreValue(); e != nil { - return e - } - var v string - if math.IsNaN(value) { - v = string(JSON_QUOTE) + JSON_NAN + string(JSON_QUOTE) - } else if math.IsInf(value, 1) { - v = string(JSON_QUOTE) + JSON_INFINITY + string(JSON_QUOTE) - } else if math.IsInf(value, -1) { - v = string(JSON_QUOTE) + JSON_NEGATIVE_INFINITY + string(JSON_QUOTE) - } else { - v = strconv.FormatFloat(value, 'g', -1, 64) - switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) { - case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: - v = string(JSON_QUOTE) + v + string(JSON_QUOTE) - default: - } - } - if e := p.OutputStringData(v); e != nil { - return e - } - return p.OutputPostValue() -} - -func (p *TSimpleJSONProtocol) OutputI64(value int64) error { - if e := p.OutputPreValue(); e != nil { - return e - } - v := strconv.FormatInt(value, 10) - switch _ParseContext(p.dumpContext[len(p.dumpContext)-1]) { - case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: - v = jsonQuote(v) - default: - } - if e := p.OutputStringData(v); e != nil { - return e - } - return p.OutputPostValue() -} - -func (p *TSimpleJSONProtocol) OutputString(s string) error { - if e := p.OutputPreValue(); e != nil { - return e - } - if e := p.OutputStringData(jsonQuote(s)); e != nil { - return e - } - return p.OutputPostValue() -} - -func (p *TSimpleJSONProtocol) OutputStringData(s string) error { - _, e := p.write([]byte(s)) - return NewTProtocolException(e) -} - -func (p *TSimpleJSONProtocol) OutputObjectBegin() error { - if e := p.OutputPreValue(); e != nil { - return e - } - if _, e := p.write(JSON_LBRACE); e != nil { - return NewTProtocolException(e) - } - p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_FIRST)) - return nil -} - -func (p *TSimpleJSONProtocol) OutputObjectEnd() error { - if _, e := p.write(JSON_RBRACE); e != nil { - return NewTProtocolException(e) - } - p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] - if e := p.OutputPostValue(); e != nil { - return e - } - return nil -} - -func (p *TSimpleJSONProtocol) OutputListBegin() error { - if e := p.OutputPreValue(); e != nil { - return e - } - if _, e := p.write(JSON_LBRACKET); e != nil { - return NewTProtocolException(e) - } - p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_LIST_FIRST)) - return nil -} - -func (p *TSimpleJSONProtocol) OutputListEnd() error { - if _, e := p.write(JSON_RBRACKET); e != nil { - return NewTProtocolException(e) - } - p.dumpContext = p.dumpContext[:len(p.dumpContext)-1] - if e := p.OutputPostValue(); e != nil { - return e - } - return nil -} - -func (p *TSimpleJSONProtocol) OutputElemListBegin(elemType TType, size int) error { - if e := p.OutputListBegin(); e != nil { - return e - } - if e := p.WriteByte(int8(elemType)); e != nil { - return e - } - if e := p.WriteI64(int64(size)); e != nil { - return e - } - return nil -} - -func (p *TSimpleJSONProtocol) ParsePreValue() error { - if e := p.readNonSignificantWhitespace(); e != nil { - return NewTProtocolException(e) - } - cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) - b, _ := p.reader.Peek(1) - switch cxt { - case _CONTEXT_IN_LIST: - if len(b) > 0 { - switch b[0] { - case JSON_RBRACKET[0]: - return nil - case JSON_COMMA[0]: - p.reader.ReadByte() - if e := p.readNonSignificantWhitespace(); e != nil { - return NewTProtocolException(e) - } - return nil - default: - e := fmt.Errorf("Expected \"]\" or \",\" in list context, but found \"%s\"", string(b)) - return NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } - break - case _CONTEXT_IN_OBJECT_NEXT_KEY: - if len(b) > 0 { - switch b[0] { - case JSON_RBRACE[0]: - return nil - case JSON_COMMA[0]: - p.reader.ReadByte() - if e := p.readNonSignificantWhitespace(); e != nil { - return NewTProtocolException(e) - } - return nil - default: - e := fmt.Errorf("Expected \"}\" or \",\" in object context, but found \"%s\"", string(b)) - return NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } - break - case _CONTEXT_IN_OBJECT_NEXT_VALUE: - if len(b) > 0 { - switch b[0] { - case JSON_COLON[0]: - p.reader.ReadByte() - if e := p.readNonSignificantWhitespace(); e != nil { - return NewTProtocolException(e) - } - return nil - default: - e := fmt.Errorf("Expected \":\" in object context, but found \"%s\"", string(b)) - return NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } - break - } - return nil -} - -func (p *TSimpleJSONProtocol) ParsePostValue() error { - if e := p.readNonSignificantWhitespace(); e != nil { - return NewTProtocolException(e) - } - cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) - switch cxt { - case _CONTEXT_IN_LIST_FIRST: - p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] - p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_LIST)) - break - case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY: - p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] - p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_NEXT_VALUE)) - break - case _CONTEXT_IN_OBJECT_NEXT_VALUE: - p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] - p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_NEXT_KEY)) - break - } - return nil -} - -func (p *TSimpleJSONProtocol) readNonSignificantWhitespace() error { - for { - b, _ := p.reader.Peek(1) - if len(b) < 1 { - return nil - } - switch b[0] { - case ' ', '\r', '\n', '\t': - p.reader.ReadByte() - continue - default: - break - } - break - } - return nil -} - -func (p *TSimpleJSONProtocol) ParseStringBody() (string, error) { - line, err := p.reader.ReadString(JSON_QUOTE) - if err != nil { - return "", NewTProtocolException(err) - } - l := len(line) - // count number of escapes to see if we need to keep going - i := 1 - for ; i < l; i++ { - if line[l-i-1] != '\\' { - break - } - } - if i&0x01 == 1 { - v, ok := jsonUnquote(string(JSON_QUOTE) + line) - if !ok { - return "", NewTProtocolException(err) - } - return v, nil - } - s, err := p.ParseQuotedStringBody() - if err != nil { - return "", NewTProtocolException(err) - } - str := string(JSON_QUOTE) + line + s - v, ok := jsonUnquote(str) - if !ok { - e := fmt.Errorf("Unable to parse as JSON string %s", str) - return "", NewTProtocolExceptionWithType(INVALID_DATA, e) - } - return v, nil -} - -func (p *TSimpleJSONProtocol) ParseQuotedStringBody() (string, error) { - line, err := p.reader.ReadString(JSON_QUOTE) - if err != nil { - return "", NewTProtocolException(err) - } - l := len(line) - // count number of escapes to see if we need to keep going - i := 1 - for ; i < l; i++ { - if line[l-i-1] != '\\' { - break - } - } - if i&0x01 == 1 { - return line, nil - } - s, err := p.ParseQuotedStringBody() - if err != nil { - return "", NewTProtocolException(err) - } - v := line + s - return v, nil -} - -func (p *TSimpleJSONProtocol) ParseBase64EncodedBody() ([]byte, error) { - line, err := p.reader.ReadBytes(JSON_QUOTE) - if err != nil { - return line, NewTProtocolException(err) - } - line2 := line[0 : len(line)-1] - l := len(line2) - if (l % 4) != 0 { - pad := 4 - (l % 4) - fill := [...]byte{'=', '=', '='} - line2 = append(line2, fill[:pad]...) - l = len(line2) - } - output := make([]byte, base64.StdEncoding.DecodedLen(l)) - n, err := base64.StdEncoding.Decode(output, line2) - return output[0:n], NewTProtocolException(err) -} - -func (p *TSimpleJSONProtocol) ParseI64() (int64, bool, error) { - if err := p.ParsePreValue(); err != nil { - return 0, false, err - } - var value int64 - var isnull bool - if p.safePeekContains(JSON_NULL) { - p.reader.Read(make([]byte, len(JSON_NULL))) - isnull = true - } else { - num, err := p.readNumeric() - isnull = (num == nil) - if !isnull { - value = num.Int64() - } - if err != nil { - return value, isnull, err - } - } - return value, isnull, p.ParsePostValue() -} - -func (p *TSimpleJSONProtocol) ParseF64() (float64, bool, error) { - if err := p.ParsePreValue(); err != nil { - return 0, false, err - } - var value float64 - var isnull bool - if p.safePeekContains(JSON_NULL) { - p.reader.Read(make([]byte, len(JSON_NULL))) - isnull = true - } else { - num, err := p.readNumeric() - isnull = (num == nil) - if !isnull { - value = num.Float64() - } - if err != nil { - return value, isnull, err - } - } - return value, isnull, p.ParsePostValue() -} - -func (p *TSimpleJSONProtocol) ParseObjectStart() (bool, error) { - if err := p.ParsePreValue(); err != nil { - return false, err - } - var b []byte - b, err := p.reader.Peek(1) - if err != nil { - return false, err - } - if len(b) > 0 && b[0] == JSON_LBRACE[0] { - p.reader.ReadByte() - p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_FIRST)) - return false, nil - } else if p.safePeekContains(JSON_NULL) { - return true, nil - } - e := fmt.Errorf("Expected '{' or null, but found '%s'", string(b)) - return false, NewTProtocolExceptionWithType(INVALID_DATA, e) -} - -func (p *TSimpleJSONProtocol) ParseObjectEnd() error { - if isNull, err := p.readIfNull(); isNull || err != nil { - return err - } - cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) - if (cxt != _CONTEXT_IN_OBJECT_FIRST) && (cxt != _CONTEXT_IN_OBJECT_NEXT_KEY) { - e := fmt.Errorf("Expected to be in the Object Context, but not in Object Context (%d)", cxt) - return NewTProtocolExceptionWithType(INVALID_DATA, e) - } - line, err := p.reader.ReadString(JSON_RBRACE[0]) - if err != nil { - return NewTProtocolException(err) - } - for _, char := range line { - switch char { - default: - e := fmt.Errorf("Expecting end of object \"}\", but found: \"%s\"", line) - return NewTProtocolExceptionWithType(INVALID_DATA, e) - case ' ', '\n', '\r', '\t', '}': - break - } - } - p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] - return p.ParsePostValue() -} - -func (p *TSimpleJSONProtocol) ParseListBegin() (isNull bool, err error) { - if e := p.ParsePreValue(); e != nil { - return false, e - } - var b []byte - b, err = p.reader.Peek(1) - if err != nil { - return false, err - } - if len(b) >= 1 && b[0] == JSON_LBRACKET[0] { - p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_LIST_FIRST)) - p.reader.ReadByte() - isNull = false - } else if p.safePeekContains(JSON_NULL) { - isNull = true - } else { - err = fmt.Errorf("Expected \"null\" or \"[\", received %q", b) - } - return isNull, NewTProtocolExceptionWithType(INVALID_DATA, err) -} - -func (p *TSimpleJSONProtocol) ParseElemListBegin() (elemType TType, size int, e error) { - if isNull, e := p.ParseListBegin(); isNull || e != nil { - return VOID, 0, e - } - bElemType, err := p.ReadByte() - elemType = TType(bElemType) - if err != nil { - return elemType, size, err - } - nSize, err2 := p.ReadI64() - size = int(nSize) - return elemType, size, err2 -} - -func (p *TSimpleJSONProtocol) ParseListEnd() error { - if isNull, err := p.readIfNull(); isNull || err != nil { - return err - } - cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) - if cxt != _CONTEXT_IN_LIST { - e := fmt.Errorf("Expected to be in the List Context, but not in List Context (%d)", cxt) - return NewTProtocolExceptionWithType(INVALID_DATA, e) - } - line, err := p.reader.ReadString(JSON_RBRACKET[0]) - if err != nil { - return NewTProtocolException(err) - } - for _, char := range line { - switch char { - default: - e := fmt.Errorf("Expecting end of list \"]\", but found: \"%s\"", line) - return NewTProtocolExceptionWithType(INVALID_DATA, e) - case ' ', '\n', '\r', '\t', rune(JSON_RBRACKET[0]): - break - } - } - p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1] - if _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) == _CONTEXT_IN_TOPLEVEL { - return nil - } - return p.ParsePostValue() -} - -func (p *TSimpleJSONProtocol) readSingleValue() (interface{}, TType, error) { - e := p.readNonSignificantWhitespace() - if e != nil { - return nil, VOID, NewTProtocolException(e) - } - b, e := p.reader.Peek(1) - if len(b) > 0 { - c := b[0] - switch c { - case JSON_NULL[0]: - buf := make([]byte, len(JSON_NULL)) - _, e := p.reader.Read(buf) - if e != nil { - return nil, VOID, NewTProtocolException(e) - } - if string(JSON_NULL) != string(buf) { - e = mismatch(string(JSON_NULL), string(buf)) - return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - return nil, VOID, nil - case JSON_QUOTE: - p.reader.ReadByte() - v, e := p.ParseStringBody() - if e != nil { - return v, UTF8, NewTProtocolException(e) - } - if v == JSON_INFINITY { - return INFINITY, DOUBLE, nil - } else if v == JSON_NEGATIVE_INFINITY { - return NEGATIVE_INFINITY, DOUBLE, nil - } else if v == JSON_NAN { - return NAN, DOUBLE, nil - } - return v, UTF8, nil - case JSON_TRUE[0]: - buf := make([]byte, len(JSON_TRUE)) - _, e := p.reader.Read(buf) - if e != nil { - return true, BOOL, NewTProtocolException(e) - } - if string(JSON_TRUE) != string(buf) { - e := mismatch(string(JSON_TRUE), string(buf)) - return true, BOOL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - return true, BOOL, nil - case JSON_FALSE[0]: - buf := make([]byte, len(JSON_FALSE)) - _, e := p.reader.Read(buf) - if e != nil { - return false, BOOL, NewTProtocolException(e) - } - if string(JSON_FALSE) != string(buf) { - e := mismatch(string(JSON_FALSE), string(buf)) - return false, BOOL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - return false, BOOL, nil - case JSON_LBRACKET[0]: - _, e := p.reader.ReadByte() - return make([]interface{}, 0), LIST, NewTProtocolException(e) - case JSON_LBRACE[0]: - _, e := p.reader.ReadByte() - return make(map[string]interface{}), STRUCT, NewTProtocolException(e) - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-', JSON_INFINITY[0], JSON_NAN[0]: - // assume numeric - v, e := p.readNumeric() - return v, DOUBLE, e - default: - e := fmt.Errorf("Expected element in list but found '%s' while parsing JSON.", string(c)) - return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } - e = fmt.Errorf("Cannot read a single element while parsing JSON.") - return nil, VOID, NewTProtocolExceptionWithType(INVALID_DATA, e) - -} - -func (p *TSimpleJSONProtocol) readIfNull() (bool, error) { - cont := true - for cont { - b, _ := p.reader.Peek(1) - if len(b) < 1 { - return false, nil - } - switch b[0] { - default: - return false, nil - case JSON_NULL[0]: - cont = false - break - case ' ', '\n', '\r', '\t': - p.reader.ReadByte() - break - } - } - if p.safePeekContains(JSON_NULL) { - p.reader.Read(make([]byte, len(JSON_NULL))) - return true, nil - } - return false, nil -} - -func (p *TSimpleJSONProtocol) readQuoteIfNext() { - b, _ := p.reader.Peek(1) - if len(b) > 0 && b[0] == JSON_QUOTE { - p.reader.ReadByte() - } -} - -func (p *TSimpleJSONProtocol) readNumeric() (Numeric, error) { - isNull, err := p.readIfNull() - if isNull || err != nil { - return NUMERIC_NULL, err - } - hasDecimalPoint := false - nextCanBeSign := true - hasE := false - MAX_LEN := 40 - buf := bytes.NewBuffer(make([]byte, 0, MAX_LEN)) - continueFor := true - inQuotes := false - for continueFor { - c, err := p.reader.ReadByte() - if err != nil { - if err == io.EOF { - break - } - return NUMERIC_NULL, NewTProtocolException(err) - } - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - buf.WriteByte(c) - nextCanBeSign = false - case '.': - if hasDecimalPoint { - e := fmt.Errorf("Unable to parse number with multiple decimal points '%s.'", buf.String()) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - if hasE { - e := fmt.Errorf("Unable to parse number with decimal points in the exponent '%s.'", buf.String()) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - buf.WriteByte(c) - hasDecimalPoint, nextCanBeSign = true, false - case 'e', 'E': - if hasE { - e := fmt.Errorf("Unable to parse number with multiple exponents '%s%c'", buf.String(), c) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - buf.WriteByte(c) - hasE, nextCanBeSign = true, true - case '-', '+': - if !nextCanBeSign { - e := fmt.Errorf("Negative sign within number") - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - buf.WriteByte(c) - nextCanBeSign = false - case ' ', 0, '\t', '\n', '\r', JSON_RBRACE[0], JSON_RBRACKET[0], JSON_COMMA[0], JSON_COLON[0]: - p.reader.UnreadByte() - continueFor = false - case JSON_NAN[0]: - if buf.Len() == 0 { - buffer := make([]byte, len(JSON_NAN)) - buffer[0] = c - _, e := p.reader.Read(buffer[1:]) - if e != nil { - return NUMERIC_NULL, NewTProtocolException(e) - } - if JSON_NAN != string(buffer) { - e := mismatch(JSON_NAN, string(buffer)) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - if inQuotes { - p.readQuoteIfNext() - } - return NAN, nil - } else { - e := fmt.Errorf("Unable to parse number starting with character '%c'", c) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - case JSON_INFINITY[0]: - if buf.Len() == 0 || (buf.Len() == 1 && buf.Bytes()[0] == '+') { - buffer := make([]byte, len(JSON_INFINITY)) - buffer[0] = c - _, e := p.reader.Read(buffer[1:]) - if e != nil { - return NUMERIC_NULL, NewTProtocolException(e) - } - if JSON_INFINITY != string(buffer) { - e := mismatch(JSON_INFINITY, string(buffer)) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - if inQuotes { - p.readQuoteIfNext() - } - return INFINITY, nil - } else if buf.Len() == 1 && buf.Bytes()[0] == JSON_NEGATIVE_INFINITY[0] { - buffer := make([]byte, len(JSON_NEGATIVE_INFINITY)) - buffer[0] = JSON_NEGATIVE_INFINITY[0] - buffer[1] = c - _, e := p.reader.Read(buffer[2:]) - if e != nil { - return NUMERIC_NULL, NewTProtocolException(e) - } - if JSON_NEGATIVE_INFINITY != string(buffer) { - e := mismatch(JSON_NEGATIVE_INFINITY, string(buffer)) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - if inQuotes { - p.readQuoteIfNext() - } - return NEGATIVE_INFINITY, nil - } else { - e := fmt.Errorf("Unable to parse number starting with character '%c' due to existing buffer %s", c, buf.String()) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - case JSON_QUOTE: - if !inQuotes { - inQuotes = true - } else { - break - } - default: - e := fmt.Errorf("Unable to parse number starting with character '%c'", c) - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - } - if buf.Len() == 0 { - e := fmt.Errorf("Unable to parse number from empty string ''") - return NUMERIC_NULL, NewTProtocolExceptionWithType(INVALID_DATA, e) - } - return NewNumericFromJSONString(buf.String(), false), nil -} - -// Safely peeks into the buffer, reading only what is necessary -func (p *TSimpleJSONProtocol) safePeekContains(b []byte) bool { - for i := 0; i < len(b); i++ { - a, _ := p.reader.Peek(i + 1) - if len(a) == 0 || a[i] != b[i] { - return false - } - } - return true -} - -// Reset the context stack to its initial state. -func (p *TSimpleJSONProtocol) resetContextStack() { - p.parseContextStack = []int{int(_CONTEXT_IN_TOPLEVEL)} - p.dumpContext = []int{int(_CONTEXT_IN_TOPLEVEL)} -} - -func (p *TSimpleJSONProtocol) write(b []byte) (int, error) { - n, err := p.writer.Write(b) - if err != nil { - p.writer.Reset(p.trans) // THRIFT-3735 - } - return n, err -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/transport.go b/vendor/github.com/uber/jaeger-client-go/thrift/transport.go deleted file mode 100644 index 453899651f..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/transport.go +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "errors" - "io" -) - -var errTransportInterrupted = errors.New("Transport Interrupted") - -type Flusher interface { - Flush() (err error) -} - -type ReadSizeProvider interface { - RemainingBytes() (num_bytes uint64) -} - - -// Encapsulates the I/O layer -type TTransport interface { - io.ReadWriteCloser - Flusher - ReadSizeProvider - - // Opens the transport for communication - Open() error - - // Returns true if the transport is open - IsOpen() bool -} - -type stringWriter interface { - WriteString(s string) (n int, err error) -} - - -// This is "enchanced" transport with extra capabilities. You need to use one of these -// to construct protocol. -// Notably, TSocket does not implement this interface, and it is always a mistake to use -// TSocket directly in protocol. -type TRichTransport interface { - io.ReadWriter - io.ByteReader - io.ByteWriter - stringWriter - Flusher - ReadSizeProvider -} - diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/transport_exception.go b/vendor/github.com/uber/jaeger-client-go/thrift/transport_exception.go deleted file mode 100644 index 9505b44612..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/transport_exception.go +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -import ( - "errors" - "io" -) - -type timeoutable interface { - Timeout() bool -} - -// Thrift Transport exception -type TTransportException interface { - TException - TypeId() int - Err() error -} - -const ( - UNKNOWN_TRANSPORT_EXCEPTION = 0 - NOT_OPEN = 1 - ALREADY_OPEN = 2 - TIMED_OUT = 3 - END_OF_FILE = 4 -) - -type tTransportException struct { - typeId int - err error -} - -func (p *tTransportException) TypeId() int { - return p.typeId -} - -func (p *tTransportException) Error() string { - return p.err.Error() -} - -func (p *tTransportException) Err() error { - return p.err -} - -func NewTTransportException(t int, e string) TTransportException { - return &tTransportException{typeId: t, err: errors.New(e)} -} - -func NewTTransportExceptionFromError(e error) TTransportException { - if e == nil { - return nil - } - - if t, ok := e.(TTransportException); ok { - return t - } - - switch v := e.(type) { - case TTransportException: - return v - case timeoutable: - if v.Timeout() { - return &tTransportException{typeId: TIMED_OUT, err: e} - } - } - - if e == io.EOF { - return &tTransportException{typeId: END_OF_FILE, err: e} - } - - return &tTransportException{typeId: UNKNOWN_TRANSPORT_EXCEPTION, err: e} -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/transport_factory.go b/vendor/github.com/uber/jaeger-client-go/thrift/transport_factory.go deleted file mode 100644 index 533d1b4375..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/transport_factory.go +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -// Factory class used to create wrapped instance of Transports. -// This is used primarily in servers, which get Transports from -// a ServerTransport and then may want to mutate them (i.e. create -// a BufferedTransport from the underlying base transport) -type TTransportFactory interface { - GetTransport(trans TTransport) TTransport -} - -type tTransportFactory struct{} - -// Return a wrapped instance of the base Transport. -func (p *tTransportFactory) GetTransport(trans TTransport) TTransport { - return trans -} - -func NewTTransportFactory() TTransportFactory { - return &tTransportFactory{} -} diff --git a/vendor/github.com/uber/jaeger-client-go/thrift/type.go b/vendor/github.com/uber/jaeger-client-go/thrift/type.go deleted file mode 100644 index 4292ffcadb..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/thrift/type.go +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package thrift - -// Type constants in the Thrift protocol -type TType byte - -const ( - STOP = 0 - VOID = 1 - BOOL = 2 - BYTE = 3 - I08 = 3 - DOUBLE = 4 - I16 = 6 - I32 = 8 - I64 = 10 - STRING = 11 - UTF7 = 11 - STRUCT = 12 - MAP = 13 - SET = 14 - LIST = 15 - UTF8 = 16 - UTF16 = 17 - //BINARY = 18 wrong and unusued -) - -var typeNames = map[int]string{ - STOP: "STOP", - VOID: "VOID", - BOOL: "BOOL", - BYTE: "BYTE", - DOUBLE: "DOUBLE", - I16: "I16", - I32: "I32", - I64: "I64", - STRING: "STRING", - STRUCT: "STRUCT", - MAP: "MAP", - SET: "SET", - LIST: "LIST", - UTF8: "UTF8", - UTF16: "UTF16", -} - -func (p TType) String() string { - if s, ok := typeNames[int(p)]; ok { - return s - } - return "Unknown" -} diff --git a/vendor/github.com/uber/jaeger-client-go/tracer.go b/vendor/github.com/uber/jaeger-client-go/tracer.go deleted file mode 100644 index 198c32eb4f..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/tracer.go +++ /dev/null @@ -1,431 +0,0 @@ -// Copyright (c) 2017-2018 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "fmt" - "io" - "os" - "reflect" - "strconv" - "sync" - "time" - - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - - "github.com/uber/jaeger-client-go/internal/baggage" - "github.com/uber/jaeger-client-go/internal/throttler" - "github.com/uber/jaeger-client-go/log" - "github.com/uber/jaeger-client-go/utils" -) - -// Tracer implements opentracing.Tracer. -type Tracer struct { - serviceName string - hostIPv4 uint32 // this is for zipkin endpoint conversion - - sampler Sampler - reporter Reporter - metrics Metrics - logger log.Logger - - timeNow func() time.Time - randomNumber func() uint64 - - options struct { - poolSpans bool - gen128Bit bool // whether to generate 128bit trace IDs - zipkinSharedRPCSpan bool - highTraceIDGenerator func() uint64 // custom high trace ID generator - maxTagValueLength int - // more options to come - } - // pool for Span objects - spanPool sync.Pool - - injectors map[interface{}]Injector - extractors map[interface{}]Extractor - - observer compositeObserver - - tags []Tag - process Process - - baggageRestrictionManager baggage.RestrictionManager - baggageSetter *baggageSetter - - debugThrottler throttler.Throttler -} - -// NewTracer creates Tracer implementation that reports tracing to Jaeger. -// The returned io.Closer can be used in shutdown hooks to ensure that the internal -// queue of the Reporter is drained and all buffered spans are submitted to collectors. -func NewTracer( - serviceName string, - sampler Sampler, - reporter Reporter, - options ...TracerOption, -) (opentracing.Tracer, io.Closer) { - t := &Tracer{ - serviceName: serviceName, - sampler: sampler, - reporter: reporter, - injectors: make(map[interface{}]Injector), - extractors: make(map[interface{}]Extractor), - metrics: *NewNullMetrics(), - spanPool: sync.Pool{New: func() interface{} { - return &Span{} - }}, - } - - for _, option := range options { - option(t) - } - - // register default injectors/extractors unless they are already provided via options - textPropagator := newTextMapPropagator(getDefaultHeadersConfig(), t.metrics) - t.addCodec(opentracing.TextMap, textPropagator, textPropagator) - - httpHeaderPropagator := newHTTPHeaderPropagator(getDefaultHeadersConfig(), t.metrics) - t.addCodec(opentracing.HTTPHeaders, httpHeaderPropagator, httpHeaderPropagator) - - binaryPropagator := newBinaryPropagator(t) - t.addCodec(opentracing.Binary, binaryPropagator, binaryPropagator) - - // TODO remove after TChannel supports OpenTracing - interopPropagator := &jaegerTraceContextPropagator{tracer: t} - t.addCodec(SpanContextFormat, interopPropagator, interopPropagator) - - zipkinPropagator := &zipkinPropagator{tracer: t} - t.addCodec(ZipkinSpanFormat, zipkinPropagator, zipkinPropagator) - - if t.baggageRestrictionManager != nil { - t.baggageSetter = newBaggageSetter(t.baggageRestrictionManager, &t.metrics) - } else { - t.baggageSetter = newBaggageSetter(baggage.NewDefaultRestrictionManager(0), &t.metrics) - } - if t.debugThrottler == nil { - t.debugThrottler = throttler.DefaultThrottler{} - } - - if t.randomNumber == nil { - rng := utils.NewRand(time.Now().UnixNano()) - t.randomNumber = func() uint64 { - return uint64(rng.Int63()) - } - } - if t.timeNow == nil { - t.timeNow = time.Now - } - if t.logger == nil { - t.logger = log.NullLogger - } - // Set tracer-level tags - t.tags = append(t.tags, Tag{key: JaegerClientVersionTagKey, value: JaegerClientVersion}) - if hostname, err := os.Hostname(); err == nil { - t.tags = append(t.tags, Tag{key: TracerHostnameTagKey, value: hostname}) - } - if ip, err := utils.HostIP(); err == nil { - t.tags = append(t.tags, Tag{key: TracerIPTagKey, value: ip.String()}) - t.hostIPv4 = utils.PackIPAsUint32(ip) - } else { - t.logger.Error("Unable to determine this host's IP address: " + err.Error()) - } - - if t.options.gen128Bit { - if t.options.highTraceIDGenerator == nil { - t.options.highTraceIDGenerator = t.randomNumber - } - } else if t.options.highTraceIDGenerator != nil { - t.logger.Error("Overriding high trace ID generator but not generating " + - "128 bit trace IDs, consider enabling the \"Gen128Bit\" option") - } - if t.options.maxTagValueLength == 0 { - t.options.maxTagValueLength = DefaultMaxTagValueLength - } - t.process = Process{ - Service: serviceName, - UUID: strconv.FormatUint(t.randomNumber(), 16), - Tags: t.tags, - } - if throttler, ok := t.debugThrottler.(ProcessSetter); ok { - throttler.SetProcess(t.process) - } - - return t, t -} - -// addCodec adds registers injector and extractor for given propagation format if not already defined. -func (t *Tracer) addCodec(format interface{}, injector Injector, extractor Extractor) { - if _, ok := t.injectors[format]; !ok { - t.injectors[format] = injector - } - if _, ok := t.extractors[format]; !ok { - t.extractors[format] = extractor - } -} - -// StartSpan implements StartSpan() method of opentracing.Tracer. -func (t *Tracer) StartSpan( - operationName string, - options ...opentracing.StartSpanOption, -) opentracing.Span { - sso := opentracing.StartSpanOptions{} - for _, o := range options { - o.Apply(&sso) - } - return t.startSpanWithOptions(operationName, sso) -} - -func (t *Tracer) startSpanWithOptions( - operationName string, - options opentracing.StartSpanOptions, -) opentracing.Span { - if options.StartTime.IsZero() { - options.StartTime = t.timeNow() - } - - // Predicate whether the given span context is a valid reference - // which may be used as parent / debug ID / baggage items source - isValidReference := func(ctx SpanContext) bool { - return ctx.IsValid() || ctx.isDebugIDContainerOnly() || len(ctx.baggage) != 0 - } - - var references []Reference - var parent SpanContext - var hasParent bool // need this because `parent` is a value, not reference - for _, ref := range options.References { - ctx, ok := ref.ReferencedContext.(SpanContext) - if !ok { - t.logger.Error(fmt.Sprintf( - "Reference contains invalid type of SpanReference: %s", - reflect.ValueOf(ref.ReferencedContext))) - continue - } - if !isValidReference(ctx) { - continue - } - references = append(references, Reference{Type: ref.Type, Context: ctx}) - if !hasParent { - parent = ctx - hasParent = ref.Type == opentracing.ChildOfRef - } - } - if !hasParent && isValidReference(parent) { - // If ChildOfRef wasn't found but a FollowFromRef exists, use the context from - // the FollowFromRef as the parent - hasParent = true - } - - rpcServer := false - if v, ok := options.Tags[ext.SpanKindRPCServer.Key]; ok { - rpcServer = (v == ext.SpanKindRPCServerEnum || v == string(ext.SpanKindRPCServerEnum)) - } - - var samplerTags []Tag - var ctx SpanContext - newTrace := false - if !hasParent || !parent.IsValid() { - newTrace = true - ctx.traceID.Low = t.randomID() - if t.options.gen128Bit { - ctx.traceID.High = t.options.highTraceIDGenerator() - } - ctx.spanID = SpanID(ctx.traceID.Low) - ctx.parentID = 0 - ctx.flags = byte(0) - if hasParent && parent.isDebugIDContainerOnly() && t.isDebugAllowed(operationName) { - ctx.flags |= (flagSampled | flagDebug) - samplerTags = []Tag{{key: JaegerDebugHeader, value: parent.debugID}} - } else if sampled, tags := t.sampler.IsSampled(ctx.traceID, operationName); sampled { - ctx.flags |= flagSampled - samplerTags = tags - } - } else { - ctx.traceID = parent.traceID - if rpcServer && t.options.zipkinSharedRPCSpan { - // Support Zipkin's one-span-per-RPC model - ctx.spanID = parent.spanID - ctx.parentID = parent.parentID - } else { - ctx.spanID = SpanID(t.randomID()) - ctx.parentID = parent.spanID - } - ctx.flags = parent.flags - } - if hasParent { - // copy baggage items - if l := len(parent.baggage); l > 0 { - ctx.baggage = make(map[string]string, len(parent.baggage)) - for k, v := range parent.baggage { - ctx.baggage[k] = v - } - } - } - - sp := t.newSpan() - sp.context = ctx - sp.observer = t.observer.OnStartSpan(sp, operationName, options) - return t.startSpanInternal( - sp, - operationName, - options.StartTime, - samplerTags, - options.Tags, - newTrace, - rpcServer, - references, - ) -} - -// Inject implements Inject() method of opentracing.Tracer -func (t *Tracer) Inject(ctx opentracing.SpanContext, format interface{}, carrier interface{}) error { - c, ok := ctx.(SpanContext) - if !ok { - return opentracing.ErrInvalidSpanContext - } - if injector, ok := t.injectors[format]; ok { - return injector.Inject(c, carrier) - } - return opentracing.ErrUnsupportedFormat -} - -// Extract implements Extract() method of opentracing.Tracer -func (t *Tracer) Extract( - format interface{}, - carrier interface{}, -) (opentracing.SpanContext, error) { - if extractor, ok := t.extractors[format]; ok { - return extractor.Extract(carrier) - } - return nil, opentracing.ErrUnsupportedFormat -} - -// Close releases all resources used by the Tracer and flushes any remaining buffered spans. -func (t *Tracer) Close() error { - t.reporter.Close() - t.sampler.Close() - if mgr, ok := t.baggageRestrictionManager.(io.Closer); ok { - mgr.Close() - } - if throttler, ok := t.debugThrottler.(io.Closer); ok { - throttler.Close() - } - return nil -} - -// Tags returns a slice of tracer-level tags. -func (t *Tracer) Tags() []opentracing.Tag { - tags := make([]opentracing.Tag, len(t.tags)) - for i, tag := range t.tags { - tags[i] = opentracing.Tag{Key: tag.key, Value: tag.value} - } - return tags -} - -// newSpan returns an instance of a clean Span object. -// If options.PoolSpans is true, the spans are retrieved from an object pool. -func (t *Tracer) newSpan() *Span { - if !t.options.poolSpans { - return &Span{} - } - sp := t.spanPool.Get().(*Span) - sp.context = emptyContext - sp.tracer = nil - sp.tags = nil - sp.logs = nil - return sp -} - -func (t *Tracer) startSpanInternal( - sp *Span, - operationName string, - startTime time.Time, - internalTags []Tag, - tags opentracing.Tags, - newTrace bool, - rpcServer bool, - references []Reference, -) *Span { - sp.tracer = t - sp.operationName = operationName - sp.startTime = startTime - sp.duration = 0 - sp.references = references - sp.firstInProcess = rpcServer || sp.context.parentID == 0 - if len(tags) > 0 || len(internalTags) > 0 { - sp.tags = make([]Tag, len(internalTags), len(tags)+len(internalTags)) - copy(sp.tags, internalTags) - for k, v := range tags { - sp.observer.OnSetTag(k, v) - if k == string(ext.SamplingPriority) && !setSamplingPriority(sp, v) { - continue - } - sp.setTagNoLocking(k, v) - } - } - // emit metrics - if sp.context.IsSampled() { - t.metrics.SpansStartedSampled.Inc(1) - if newTrace { - // We cannot simply check for parentID==0 because in Zipkin model the - // server-side RPC span has the exact same trace/span/parent IDs as the - // calling client-side span, but obviously the server side span is - // no longer a root span of the trace. - t.metrics.TracesStartedSampled.Inc(1) - } else if sp.firstInProcess { - t.metrics.TracesJoinedSampled.Inc(1) - } - } else { - t.metrics.SpansStartedNotSampled.Inc(1) - if newTrace { - t.metrics.TracesStartedNotSampled.Inc(1) - } else if sp.firstInProcess { - t.metrics.TracesJoinedNotSampled.Inc(1) - } - } - return sp -} - -func (t *Tracer) reportSpan(sp *Span) { - t.metrics.SpansFinished.Inc(1) - if sp.context.IsSampled() { - t.reporter.Report(sp) - } - if t.options.poolSpans { - t.spanPool.Put(sp) - } -} - -// randomID generates a random trace/span ID, using tracer.random() generator. -// It never returns 0. -func (t *Tracer) randomID() uint64 { - val := t.randomNumber() - for val == 0 { - val = t.randomNumber() - } - return val -} - -// (NB) span must hold the lock before making this call -func (t *Tracer) setBaggage(sp *Span, key, value string) { - t.baggageSetter.setBaggage(sp, key, value) -} - -// (NB) span must hold the lock before making this call -func (t *Tracer) isDebugAllowed(operation string) bool { - return t.debugThrottler.IsAllowed(operation) -} diff --git a/vendor/github.com/uber/jaeger-client-go/tracer_options.go b/vendor/github.com/uber/jaeger-client-go/tracer_options.go deleted file mode 100644 index a90265f031..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/tracer_options.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "time" - - "github.com/opentracing/opentracing-go" - - "github.com/uber/jaeger-client-go/internal/baggage" - "github.com/uber/jaeger-client-go/internal/throttler" -) - -// TracerOption is a function that sets some option on the tracer -type TracerOption func(tracer *Tracer) - -// TracerOptions is a factory for all available TracerOption's -var TracerOptions tracerOptions - -type tracerOptions struct{} - -// Metrics creates a TracerOption that initializes Metrics on the tracer, -// which is used to emit statistics. -func (tracerOptions) Metrics(m *Metrics) TracerOption { - return func(tracer *Tracer) { - tracer.metrics = *m - } -} - -// Logger creates a TracerOption that gives the tracer a Logger. -func (tracerOptions) Logger(logger Logger) TracerOption { - return func(tracer *Tracer) { - tracer.logger = logger - } -} - -func (tracerOptions) CustomHeaderKeys(headerKeys *HeadersConfig) TracerOption { - return func(tracer *Tracer) { - if headerKeys == nil { - return - } - textPropagator := newTextMapPropagator(headerKeys.applyDefaults(), tracer.metrics) - tracer.addCodec(opentracing.TextMap, textPropagator, textPropagator) - - httpHeaderPropagator := newHTTPHeaderPropagator(headerKeys.applyDefaults(), tracer.metrics) - tracer.addCodec(opentracing.HTTPHeaders, httpHeaderPropagator, httpHeaderPropagator) - } -} - -// TimeNow creates a TracerOption that gives the tracer a function -// used to generate timestamps for spans. -func (tracerOptions) TimeNow(timeNow func() time.Time) TracerOption { - return func(tracer *Tracer) { - tracer.timeNow = timeNow - } -} - -// RandomNumber creates a TracerOption that gives the tracer -// a thread-safe random number generator function for generating trace IDs. -func (tracerOptions) RandomNumber(randomNumber func() uint64) TracerOption { - return func(tracer *Tracer) { - tracer.randomNumber = randomNumber - } -} - -// PoolSpans creates a TracerOption that tells the tracer whether it should use -// an object pool to minimize span allocations. -// This should be used with care, only if the service is not running any async tasks -// that can access parent spans after those spans have been finished. -func (tracerOptions) PoolSpans(poolSpans bool) TracerOption { - return func(tracer *Tracer) { - tracer.options.poolSpans = poolSpans - } -} - -// Deprecated: HostIPv4 creates a TracerOption that identifies the current service/process. -// If not set, the factory method will obtain the current IP address. -// The TracerOption is deprecated; the tracer will attempt to automatically detect the IP. -func (tracerOptions) HostIPv4(hostIPv4 uint32) TracerOption { - return func(tracer *Tracer) { - tracer.hostIPv4 = hostIPv4 - } -} - -func (tracerOptions) Injector(format interface{}, injector Injector) TracerOption { - return func(tracer *Tracer) { - tracer.injectors[format] = injector - } -} - -func (tracerOptions) Extractor(format interface{}, extractor Extractor) TracerOption { - return func(tracer *Tracer) { - tracer.extractors[format] = extractor - } -} - -func (t tracerOptions) Observer(observer Observer) TracerOption { - return t.ContribObserver(&oldObserver{obs: observer}) -} - -func (tracerOptions) ContribObserver(observer ContribObserver) TracerOption { - return func(tracer *Tracer) { - tracer.observer.append(observer) - } -} - -func (tracerOptions) Gen128Bit(gen128Bit bool) TracerOption { - return func(tracer *Tracer) { - tracer.options.gen128Bit = gen128Bit - } -} - -func (tracerOptions) HighTraceIDGenerator(highTraceIDGenerator func() uint64) TracerOption { - return func(tracer *Tracer) { - tracer.options.highTraceIDGenerator = highTraceIDGenerator - } -} - -func (tracerOptions) MaxTagValueLength(maxTagValueLength int) TracerOption { - return func(tracer *Tracer) { - tracer.options.maxTagValueLength = maxTagValueLength - } -} - -func (tracerOptions) ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) TracerOption { - return func(tracer *Tracer) { - tracer.options.zipkinSharedRPCSpan = zipkinSharedRPCSpan - } -} - -func (tracerOptions) Tag(key string, value interface{}) TracerOption { - return func(tracer *Tracer) { - tracer.tags = append(tracer.tags, Tag{key: key, value: value}) - } -} - -func (tracerOptions) BaggageRestrictionManager(mgr baggage.RestrictionManager) TracerOption { - return func(tracer *Tracer) { - tracer.baggageRestrictionManager = mgr - } -} - -func (tracerOptions) DebugThrottler(throttler throttler.Throttler) TracerOption { - return func(tracer *Tracer) { - tracer.debugThrottler = throttler - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/transport.go b/vendor/github.com/uber/jaeger-client-go/transport.go deleted file mode 100644 index c5f5b19551..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/transport.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "io" -) - -// Transport abstracts the method of sending spans out of process. -// Implementations are NOT required to be thread-safe; the RemoteReporter -// is expected to only call methods on the Transport from the same go-routine. -type Transport interface { - // Append converts the span to the wire representation and adds it - // to sender's internal buffer. If the buffer exceeds its designated - // size, the transport should call Flush() and return the number of spans - // flushed, otherwise return 0. If error is returned, the returned number - // of spans is treated as failed span, and reported to metrics accordingly. - Append(span *Span) (int, error) - - // Flush submits the internal buffer to the remote server. It returns the - // number of spans flushed. If error is returned, the returned number of - // spans is treated as failed span, and reported to metrics accordingly. - Flush() (int, error) - - io.Closer -} diff --git a/vendor/github.com/uber/jaeger-client-go/transport_udp.go b/vendor/github.com/uber/jaeger-client-go/transport_udp.go deleted file mode 100644 index 7b9ccf9374..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/transport_udp.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "errors" - "fmt" - - "github.com/uber/jaeger-client-go/thrift" - - j "github.com/uber/jaeger-client-go/thrift-gen/jaeger" - "github.com/uber/jaeger-client-go/utils" -) - -// Empirically obtained constant for how many bytes in the message are used for envelope. -// The total datagram size is: -// sizeof(Span) * numSpans + processByteSize + emitBatchOverhead <= maxPacketSize -// There is a unit test `TestEmitBatchOverhead` that validates this number. -// Note that due to the use of Compact Thrift protocol, overhead grows with the number of spans -// in the batch, because the length of the list is encoded as varint32, as well as SeqId. -const emitBatchOverhead = 30 - -var errSpanTooLarge = errors.New("Span is too large") - -type udpSender struct { - client *utils.AgentClientUDP - maxPacketSize int // max size of datagram in bytes - maxSpanBytes int // max number of bytes to record spans (excluding envelope) in the datagram - byteBufferSize int // current number of span bytes accumulated in the buffer - spanBuffer []*j.Span // spans buffered before a flush - thriftBuffer *thrift.TMemoryBuffer // buffer used to calculate byte size of a span - thriftProtocol thrift.TProtocol - process *j.Process - processByteSize int -} - -// NewUDPTransport creates a reporter that submits spans to jaeger-agent -func NewUDPTransport(hostPort string, maxPacketSize int) (Transport, error) { - if len(hostPort) == 0 { - hostPort = fmt.Sprintf("%s:%d", DefaultUDPSpanServerHost, DefaultUDPSpanServerPort) - } - if maxPacketSize == 0 { - maxPacketSize = utils.UDPPacketMaxLength - } - - protocolFactory := thrift.NewTCompactProtocolFactory() - - // Each span is first written to thriftBuffer to determine its size in bytes. - thriftBuffer := thrift.NewTMemoryBufferLen(maxPacketSize) - thriftProtocol := protocolFactory.GetProtocol(thriftBuffer) - - client, err := utils.NewAgentClientUDP(hostPort, maxPacketSize) - if err != nil { - return nil, err - } - - sender := &udpSender{ - client: client, - maxSpanBytes: maxPacketSize - emitBatchOverhead, - thriftBuffer: thriftBuffer, - thriftProtocol: thriftProtocol} - return sender, nil -} - -func (s *udpSender) calcSizeOfSerializedThrift(thriftStruct thrift.TStruct) int { - s.thriftBuffer.Reset() - thriftStruct.Write(s.thriftProtocol) - return s.thriftBuffer.Len() -} - -func (s *udpSender) Append(span *Span) (int, error) { - if s.process == nil { - s.process = BuildJaegerProcessThrift(span) - s.processByteSize = s.calcSizeOfSerializedThrift(s.process) - s.byteBufferSize += s.processByteSize - } - jSpan := BuildJaegerThrift(span) - spanSize := s.calcSizeOfSerializedThrift(jSpan) - if spanSize > s.maxSpanBytes { - return 1, errSpanTooLarge - } - - s.byteBufferSize += spanSize - if s.byteBufferSize <= s.maxSpanBytes { - s.spanBuffer = append(s.spanBuffer, jSpan) - if s.byteBufferSize < s.maxSpanBytes { - return 0, nil - } - return s.Flush() - } - // the latest span did not fit in the buffer - n, err := s.Flush() - s.spanBuffer = append(s.spanBuffer, jSpan) - s.byteBufferSize = spanSize + s.processByteSize - return n, err -} - -func (s *udpSender) Flush() (int, error) { - n := len(s.spanBuffer) - if n == 0 { - return 0, nil - } - err := s.client.EmitBatch(&j.Batch{Process: s.process, Spans: s.spanBuffer}) - s.resetBuffers() - - return n, err -} - -func (s *udpSender) Close() error { - return s.client.Close() -} - -func (s *udpSender) resetBuffers() { - for i := range s.spanBuffer { - s.spanBuffer[i] = nil - } - s.spanBuffer = s.spanBuffer[:0] - s.byteBufferSize = s.processByteSize -} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/http_json.go b/vendor/github.com/uber/jaeger-client-go/utils/http_json.go deleted file mode 100644 index 237211f822..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/utils/http_json.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" -) - -// GetJSON makes an HTTP call to the specified URL and parses the returned JSON into `out`. -func GetJSON(url string, out interface{}) error { - resp, err := http.Get(url) - if err != nil { - return err - } - return ReadJSON(resp, out) -} - -// ReadJSON reads JSON from http.Response and parses it into `out` -func ReadJSON(resp *http.Response, out interface{}) error { - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - return fmt.Errorf("StatusCode: %d, Body: %s", resp.StatusCode, body) - } - - if out == nil { - io.Copy(ioutil.Discard, resp.Body) - return nil - } - - decoder := json.NewDecoder(resp.Body) - return decoder.Decode(out) -} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/localip.go b/vendor/github.com/uber/jaeger-client-go/utils/localip.go deleted file mode 100644 index b51af7713f..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/utils/localip.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "errors" - "net" -) - -// This code is borrowed from https://github.com/uber/tchannel-go/blob/dev/localip.go - -// scoreAddr scores how likely the given addr is to be a remote address and returns the -// IP to use when listening. Any address which receives a negative score should not be used. -// Scores are calculated as: -// -1 for any unknown IP addresses. -// +300 for IPv4 addresses -// +100 for non-local addresses, extra +100 for "up" interaces. -func scoreAddr(iface net.Interface, addr net.Addr) (int, net.IP) { - var ip net.IP - if netAddr, ok := addr.(*net.IPNet); ok { - ip = netAddr.IP - } else if netIP, ok := addr.(*net.IPAddr); ok { - ip = netIP.IP - } else { - return -1, nil - } - - var score int - if ip.To4() != nil { - score += 300 - } - if iface.Flags&net.FlagLoopback == 0 && !ip.IsLoopback() { - score += 100 - if iface.Flags&net.FlagUp != 0 { - score += 100 - } - } - return score, ip -} - -// HostIP tries to find an IP that can be used by other machines to reach this machine. -func HostIP() (net.IP, error) { - interfaces, err := net.Interfaces() - if err != nil { - return nil, err - } - - bestScore := -1 - var bestIP net.IP - // Select the highest scoring IP as the best IP. - for _, iface := range interfaces { - addrs, err := iface.Addrs() - if err != nil { - // Skip this interface if there is an error. - continue - } - - for _, addr := range addrs { - score, ip := scoreAddr(iface, addr) - if score > bestScore { - bestScore = score - bestIP = ip - } - } - } - - if bestScore == -1 { - return nil, errors.New("no addresses to listen on") - } - - return bestIP, nil -} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/rand.go b/vendor/github.com/uber/jaeger-client-go/utils/rand.go deleted file mode 100644 index 9875f7f55c..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/utils/rand.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "math/rand" - "sync" -) - -// lockedSource allows a random number generator to be used by multiple goroutines concurrently. -// The code is very similar to math/rand.lockedSource, which is unfortunately not exposed. -type lockedSource struct { - mut sync.Mutex - src rand.Source -} - -// NewRand returns a rand.Rand that is threadsafe. -func NewRand(seed int64) *rand.Rand { - return rand.New(&lockedSource{src: rand.NewSource(seed)}) -} - -func (r *lockedSource) Int63() (n int64) { - r.mut.Lock() - n = r.src.Int63() - r.mut.Unlock() - return -} - -// Seed implements Seed() of Source -func (r *lockedSource) Seed(seed int64) { - r.mut.Lock() - r.src.Seed(seed) - r.mut.Unlock() -} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go b/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go deleted file mode 100644 index 1b8db97584..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "sync" - "time" -) - -// RateLimiter is a filter used to check if a message that is worth itemCost units is within the rate limits. -type RateLimiter interface { - CheckCredit(itemCost float64) bool -} - -type rateLimiter struct { - sync.Mutex - - creditsPerSecond float64 - balance float64 - maxBalance float64 - lastTick time.Time - - timeNow func() time.Time -} - -// NewRateLimiter creates a new rate limiter based on leaky bucket algorithm, formulated in terms of a -// credits balance that is replenished every time CheckCredit() method is called (tick) by the amount proportional -// to the time elapsed since the last tick, up to max of creditsPerSecond. A call to CheckCredit() takes a cost -// of an item we want to pay with the balance. If the balance exceeds the cost of the item, the item is "purchased" -// and the balance reduced, indicated by returned value of true. Otherwise the balance is unchanged and return false. -// -// This can be used to limit a rate of messages emitted by a service by instantiating the Rate Limiter with the -// max number of messages a service is allowed to emit per second, and calling CheckCredit(1.0) for each message -// to determine if the message is within the rate limit. -// -// It can also be used to limit the rate of traffic in bytes, by setting creditsPerSecond to desired throughput -// as bytes/second, and calling CheckCredit() with the actual message size. -func NewRateLimiter(creditsPerSecond, maxBalance float64) RateLimiter { - return &rateLimiter{ - creditsPerSecond: creditsPerSecond, - balance: maxBalance, - maxBalance: maxBalance, - lastTick: time.Now(), - timeNow: time.Now} -} - -func (b *rateLimiter) CheckCredit(itemCost float64) bool { - b.Lock() - defer b.Unlock() - // calculate how much time passed since the last tick, and update current tick - currentTime := b.timeNow() - elapsedTime := currentTime.Sub(b.lastTick) - b.lastTick = currentTime - // calculate how much credit have we accumulated since the last tick - b.balance += elapsedTime.Seconds() * b.creditsPerSecond - if b.balance > b.maxBalance { - b.balance = b.maxBalance - } - // if we have enough credits to pay for current item, then reduce balance and allow - if b.balance >= itemCost { - b.balance -= itemCost - return true - } - return false -} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go b/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go deleted file mode 100644 index 6f042073d6..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "errors" - "fmt" - "io" - "net" - - "github.com/uber/jaeger-client-go/thrift" - - "github.com/uber/jaeger-client-go/thrift-gen/agent" - "github.com/uber/jaeger-client-go/thrift-gen/jaeger" - "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" -) - -// UDPPacketMaxLength is the max size of UDP packet we want to send, synced with jaeger-agent -const UDPPacketMaxLength = 65000 - -// AgentClientUDP is a UDP client to Jaeger agent that implements agent.Agent interface. -type AgentClientUDP struct { - agent.Agent - io.Closer - - connUDP *net.UDPConn - client *agent.AgentClient - maxPacketSize int // max size of datagram in bytes - thriftBuffer *thrift.TMemoryBuffer // buffer used to calculate byte size of a span -} - -// NewAgentClientUDP creates a client that sends spans to Jaeger Agent over UDP. -func NewAgentClientUDP(hostPort string, maxPacketSize int) (*AgentClientUDP, error) { - if maxPacketSize == 0 { - maxPacketSize = UDPPacketMaxLength - } - - thriftBuffer := thrift.NewTMemoryBufferLen(maxPacketSize) - protocolFactory := thrift.NewTCompactProtocolFactory() - client := agent.NewAgentClientFactory(thriftBuffer, protocolFactory) - - destAddr, err := net.ResolveUDPAddr("udp", hostPort) - if err != nil { - return nil, err - } - - connUDP, err := net.DialUDP(destAddr.Network(), nil, destAddr) - if err != nil { - return nil, err - } - if err := connUDP.SetWriteBuffer(maxPacketSize); err != nil { - return nil, err - } - - clientUDP := &AgentClientUDP{ - connUDP: connUDP, - client: client, - maxPacketSize: maxPacketSize, - thriftBuffer: thriftBuffer} - return clientUDP, nil -} - -// EmitZipkinBatch implements EmitZipkinBatch() of Agent interface -func (a *AgentClientUDP) EmitZipkinBatch(spans []*zipkincore.Span) error { - return errors.New("Not implemented") -} - -// EmitBatch implements EmitBatch() of Agent interface -func (a *AgentClientUDP) EmitBatch(batch *jaeger.Batch) error { - a.thriftBuffer.Reset() - a.client.SeqId = 0 // we have no need for distinct SeqIds for our one-way UDP messages - if err := a.client.EmitBatch(batch); err != nil { - return err - } - if a.thriftBuffer.Len() > a.maxPacketSize { - return fmt.Errorf("Data does not fit within one UDP packet; size %d, max %d, spans %d", - a.thriftBuffer.Len(), a.maxPacketSize, len(batch.Spans)) - } - _, err := a.connUDP.Write(a.thriftBuffer.Bytes()) - return err -} - -// Close implements Close() of io.Closer and closes the underlying UDP connection. -func (a *AgentClientUDP) Close() error { - return a.connUDP.Close() -} diff --git a/vendor/github.com/uber/jaeger-client-go/utils/utils.go b/vendor/github.com/uber/jaeger-client-go/utils/utils.go deleted file mode 100644 index ac3c325d1e..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/utils/utils.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "encoding/binary" - "errors" - "net" - "strconv" - "strings" - "time" -) - -var ( - // ErrEmptyIP an error for empty ip strings - ErrEmptyIP = errors.New("empty string given for ip") - - // ErrNotHostColonPort an error for invalid host port string - ErrNotHostColonPort = errors.New("expecting host:port") - - // ErrNotFourOctets an error for the wrong number of octets after splitting a string - ErrNotFourOctets = errors.New("Wrong number of octets") -) - -// ParseIPToUint32 converts a string ip (e.g. "x.y.z.w") to an uint32 -func ParseIPToUint32(ip string) (uint32, error) { - if ip == "" { - return 0, ErrEmptyIP - } - - if ip == "localhost" { - return 127<<24 | 1, nil - } - - octets := strings.Split(ip, ".") - if len(octets) != 4 { - return 0, ErrNotFourOctets - } - - var intIP uint32 - for i := 0; i < 4; i++ { - octet, err := strconv.Atoi(octets[i]) - if err != nil { - return 0, err - } - intIP = (intIP << 8) | uint32(octet) - } - - return intIP, nil -} - -// ParsePort converts port number from string to uin16 -func ParsePort(portString string) (uint16, error) { - port, err := strconv.ParseUint(portString, 10, 16) - return uint16(port), err -} - -// PackIPAsUint32 packs an IPv4 as uint32 -func PackIPAsUint32(ip net.IP) uint32 { - if ipv4 := ip.To4(); ipv4 != nil { - return binary.BigEndian.Uint32(ipv4) - } - return 0 -} - -// TimeToMicrosecondsSinceEpochInt64 converts Go time.Time to a long -// representing time since epoch in microseconds, which is used expected -// in the Jaeger spans encoded as Thrift. -func TimeToMicrosecondsSinceEpochInt64(t time.Time) int64 { - // ^^^ Passing time.Time by value is faster than passing a pointer! - // BenchmarkTimeByValue-8 2000000000 1.37 ns/op - // BenchmarkTimeByPtr-8 2000000000 1.98 ns/op - - return t.UnixNano() / 1000 -} diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin.go b/vendor/github.com/uber/jaeger-client-go/zipkin.go deleted file mode 100644 index 636952b7f1..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/zipkin.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "github.com/opentracing/opentracing-go" -) - -// ZipkinSpanFormat is an OpenTracing carrier format constant -const ZipkinSpanFormat = "zipkin-span-format" - -// ExtractableZipkinSpan is a type of Carrier used for integration with Zipkin-aware -// RPC frameworks (like TChannel). It does not support baggage, only trace IDs. -type ExtractableZipkinSpan interface { - TraceID() uint64 - SpanID() uint64 - ParentID() uint64 - Flags() byte -} - -// InjectableZipkinSpan is a type of Carrier used for integration with Zipkin-aware -// RPC frameworks (like TChannel). It does not support baggage, only trace IDs. -type InjectableZipkinSpan interface { - SetTraceID(traceID uint64) - SetSpanID(spanID uint64) - SetParentID(parentID uint64) - SetFlags(flags byte) -} - -type zipkinPropagator struct { - tracer *Tracer -} - -func (p *zipkinPropagator) Inject( - ctx SpanContext, - abstractCarrier interface{}, -) error { - carrier, ok := abstractCarrier.(InjectableZipkinSpan) - if !ok { - return opentracing.ErrInvalidCarrier - } - - carrier.SetTraceID(ctx.TraceID().Low) // TODO this cannot work with 128bit IDs - carrier.SetSpanID(uint64(ctx.SpanID())) - carrier.SetParentID(uint64(ctx.ParentID())) - carrier.SetFlags(ctx.flags) - return nil -} - -func (p *zipkinPropagator) Extract(abstractCarrier interface{}) (SpanContext, error) { - carrier, ok := abstractCarrier.(ExtractableZipkinSpan) - if !ok { - return emptyContext, opentracing.ErrInvalidCarrier - } - if carrier.TraceID() == 0 { - return emptyContext, opentracing.ErrSpanContextNotFound - } - var ctx SpanContext - ctx.traceID.Low = carrier.TraceID() - ctx.spanID = SpanID(carrier.SpanID()) - ctx.parentID = SpanID(carrier.ParentID()) - ctx.flags = carrier.Flags() - return ctx, nil -} diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go deleted file mode 100644 index dce58b4331..0000000000 --- a/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jaeger - -import ( - "encoding/binary" - "fmt" - "time" - - "github.com/opentracing/opentracing-go/ext" - - "github.com/uber/jaeger-client-go/internal/spanlog" - z "github.com/uber/jaeger-client-go/thrift-gen/zipkincore" - "github.com/uber/jaeger-client-go/utils" -) - -const ( - // Zipkin UI does not work well with non-string tag values - allowPackedNumbers = false -) - -var specialTagHandlers = map[string]func(*zipkinSpan, interface{}){ - string(ext.SpanKind): setSpanKind, - string(ext.PeerHostIPv4): setPeerIPv4, - string(ext.PeerPort): setPeerPort, - string(ext.PeerService): setPeerService, - TracerIPTagKey: removeTag, -} - -// BuildZipkinThrift builds thrift span based on internal span. -func BuildZipkinThrift(s *Span) *z.Span { - span := &zipkinSpan{Span: s} - span.handleSpecialTags() - parentID := int64(span.context.parentID) - var ptrParentID *int64 - if parentID != 0 { - ptrParentID = &parentID - } - timestamp := utils.TimeToMicrosecondsSinceEpochInt64(span.startTime) - duration := span.duration.Nanoseconds() / int64(time.Microsecond) - endpoint := &z.Endpoint{ - ServiceName: span.tracer.serviceName, - Ipv4: int32(span.tracer.hostIPv4)} - thriftSpan := &z.Span{ - TraceID: int64(span.context.traceID.Low), // TODO upgrade zipkin thrift and use TraceIdHigh - ID: int64(span.context.spanID), - ParentID: ptrParentID, - Name: span.operationName, - Timestamp: ×tamp, - Duration: &duration, - Debug: span.context.IsDebug(), - Annotations: buildAnnotations(span, endpoint), - BinaryAnnotations: buildBinaryAnnotations(span, endpoint)} - return thriftSpan -} - -func buildAnnotations(span *zipkinSpan, endpoint *z.Endpoint) []*z.Annotation { - // automatically adding 2 Zipkin CoreAnnotations - annotations := make([]*z.Annotation, 0, 2+len(span.logs)) - var startLabel, endLabel string - if span.spanKind == string(ext.SpanKindRPCClientEnum) { - startLabel, endLabel = z.CLIENT_SEND, z.CLIENT_RECV - } else if span.spanKind == string(ext.SpanKindRPCServerEnum) { - startLabel, endLabel = z.SERVER_RECV, z.SERVER_SEND - } - if !span.startTime.IsZero() && startLabel != "" { - start := &z.Annotation{ - Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(span.startTime), - Value: startLabel, - Host: endpoint} - annotations = append(annotations, start) - if span.duration != 0 { - endTs := span.startTime.Add(span.duration) - end := &z.Annotation{ - Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(endTs), - Value: endLabel, - Host: endpoint} - annotations = append(annotations, end) - } - } - for _, log := range span.logs { - anno := &z.Annotation{ - Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(log.Timestamp), - Host: endpoint} - if content, err := spanlog.MaterializeWithJSON(log.Fields); err == nil { - anno.Value = truncateString(string(content), span.tracer.options.maxTagValueLength) - } else { - anno.Value = err.Error() - } - annotations = append(annotations, anno) - } - return annotations -} - -func buildBinaryAnnotations(span *zipkinSpan, endpoint *z.Endpoint) []*z.BinaryAnnotation { - // automatically adding local component or server/client address tag, and client version - annotations := make([]*z.BinaryAnnotation, 0, 2+len(span.tags)) - - if span.peerDefined() && span.isRPC() { - peer := z.Endpoint{ - Ipv4: span.peer.Ipv4, - Port: span.peer.Port, - ServiceName: span.peer.ServiceName} - label := z.CLIENT_ADDR - if span.isRPCClient() { - label = z.SERVER_ADDR - } - anno := &z.BinaryAnnotation{ - Key: label, - Value: []byte{1}, - AnnotationType: z.AnnotationType_BOOL, - Host: &peer} - annotations = append(annotations, anno) - } - if !span.isRPC() { - componentName := endpoint.ServiceName - for _, tag := range span.tags { - if tag.key == string(ext.Component) { - componentName = stringify(tag.value) - break - } - } - local := &z.BinaryAnnotation{ - Key: z.LOCAL_COMPONENT, - Value: []byte(componentName), - AnnotationType: z.AnnotationType_STRING, - Host: endpoint} - annotations = append(annotations, local) - } - for _, tag := range span.tags { - // "Special tags" are already handled by this point, we'd be double reporting the - // tags if we don't skip here - if _, ok := specialTagHandlers[tag.key]; ok { - continue - } - if anno := buildBinaryAnnotation(tag.key, tag.value, span.tracer.options.maxTagValueLength, nil); anno != nil { - annotations = append(annotations, anno) - } - } - return annotations -} - -func buildBinaryAnnotation(key string, val interface{}, maxTagValueLength int, endpoint *z.Endpoint) *z.BinaryAnnotation { - bann := &z.BinaryAnnotation{Key: key, Host: endpoint} - if value, ok := val.(string); ok { - bann.Value = []byte(truncateString(value, maxTagValueLength)) - bann.AnnotationType = z.AnnotationType_STRING - } else if value, ok := val.([]byte); ok { - if len(value) > maxTagValueLength { - value = value[:maxTagValueLength] - } - bann.Value = value - bann.AnnotationType = z.AnnotationType_BYTES - } else if value, ok := val.(int32); ok && allowPackedNumbers { - bann.Value = int32ToBytes(value) - bann.AnnotationType = z.AnnotationType_I32 - } else if value, ok := val.(int64); ok && allowPackedNumbers { - bann.Value = int64ToBytes(value) - bann.AnnotationType = z.AnnotationType_I64 - } else if value, ok := val.(int); ok && allowPackedNumbers { - bann.Value = int64ToBytes(int64(value)) - bann.AnnotationType = z.AnnotationType_I64 - } else if value, ok := val.(bool); ok { - bann.Value = []byte{boolToByte(value)} - bann.AnnotationType = z.AnnotationType_BOOL - } else { - value := stringify(val) - bann.Value = []byte(truncateString(value, maxTagValueLength)) - bann.AnnotationType = z.AnnotationType_STRING - } - return bann -} - -func stringify(value interface{}) string { - if s, ok := value.(string); ok { - return s - } - return fmt.Sprintf("%+v", value) -} - -func truncateString(value string, maxLength int) string { - // we ignore the problem of utf8 runes possibly being sliced in the middle, - // as it is rather expensive to iterate through each tag just to find rune - // boundaries. - if len(value) > maxLength { - return value[:maxLength] - } - return value -} - -func boolToByte(b bool) byte { - if b { - return 1 - } - return 0 -} - -// int32ToBytes converts int32 to bytes. -func int32ToBytes(i int32) []byte { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, uint32(i)) - return buf -} - -// int64ToBytes converts int64 to bytes. -func int64ToBytes(i int64) []byte { - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, uint64(i)) - return buf -} - -type zipkinSpan struct { - *Span - - // peer points to the peer service participating in this span, - // e.g. the Client if this span is a server span, - // or Server if this span is a client span - peer struct { - Ipv4 int32 - Port int16 - ServiceName string - } - - // used to distinguish local vs. RPC Server vs. RPC Client spans - spanKind string -} - -func (s *zipkinSpan) handleSpecialTags() { - s.Lock() - defer s.Unlock() - if s.firstInProcess { - // append the process tags - s.tags = append(s.tags, s.tracer.tags...) - } - filteredTags := make([]Tag, 0, len(s.tags)) - for _, tag := range s.tags { - if handler, ok := specialTagHandlers[tag.key]; ok { - handler(s, tag.value) - } else { - filteredTags = append(filteredTags, tag) - } - } - s.tags = filteredTags -} - -func setSpanKind(s *zipkinSpan, value interface{}) { - if val, ok := value.(string); ok { - s.spanKind = val - return - } - if val, ok := value.(ext.SpanKindEnum); ok { - s.spanKind = string(val) - } -} - -func setPeerIPv4(s *zipkinSpan, value interface{}) { - if val, ok := value.(string); ok { - if ip, err := utils.ParseIPToUint32(val); err == nil { - s.peer.Ipv4 = int32(ip) - return - } - } - if val, ok := value.(uint32); ok { - s.peer.Ipv4 = int32(val) - return - } - if val, ok := value.(int32); ok { - s.peer.Ipv4 = val - } -} - -func setPeerPort(s *zipkinSpan, value interface{}) { - if val, ok := value.(string); ok { - if port, err := utils.ParsePort(val); err == nil { - s.peer.Port = int16(port) - return - } - } - if val, ok := value.(uint16); ok { - s.peer.Port = int16(val) - return - } - if val, ok := value.(int); ok { - s.peer.Port = int16(val) - } -} - -func setPeerService(s *zipkinSpan, value interface{}) { - if val, ok := value.(string); ok { - s.peer.ServiceName = val - } -} - -func removeTag(s *zipkinSpan, value interface{}) {} - -func (s *zipkinSpan) peerDefined() bool { - return s.peer.ServiceName != "" || s.peer.Ipv4 != 0 || s.peer.Port != 0 -} - -func (s *zipkinSpan) isRPC() bool { - s.RLock() - defer s.RUnlock() - return s.spanKind == string(ext.SpanKindRPCClientEnum) || s.spanKind == string(ext.SpanKindRPCServerEnum) -} - -func (s *zipkinSpan) isRPCClient() bool { - s.RLock() - defer s.RUnlock() - return s.spanKind == string(ext.SpanKindRPCClientEnum) -} diff --git a/vendor/github.com/uber/jaeger-lib/LICENSE b/vendor/github.com/uber/jaeger-lib/LICENSE deleted file mode 100644 index 261eeb9e9f..0000000000 --- a/vendor/github.com/uber/jaeger-lib/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/uber/jaeger-lib/metrics/counter.go b/vendor/github.com/uber/jaeger-lib/metrics/counter.go deleted file mode 100644 index 2a6a43efdb..0000000000 --- a/vendor/github.com/uber/jaeger-lib/metrics/counter.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -// Counter tracks the number of times an event has occurred -type Counter interface { - // Inc adds the given value to the counter. - Inc(int64) -} - -// NullCounter counter that does nothing -var NullCounter Counter = nullCounter{} - -type nullCounter struct{} - -func (nullCounter) Inc(int64) {} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/factory.go b/vendor/github.com/uber/jaeger-lib/metrics/factory.go deleted file mode 100644 index a744a890df..0000000000 --- a/vendor/github.com/uber/jaeger-lib/metrics/factory.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -// Factory creates new metrics -type Factory interface { - Counter(name string, tags map[string]string) Counter - Timer(name string, tags map[string]string) Timer - Gauge(name string, tags map[string]string) Gauge - - // Namespace returns a nested metrics factory. - Namespace(name string, tags map[string]string) Factory -} - -// NullFactory is a metrics factory that returns NullCounter, NullTimer, and NullGauge. -var NullFactory Factory = nullFactory{} - -type nullFactory struct{} - -func (nullFactory) Counter(name string, tags map[string]string) Counter { return NullCounter } -func (nullFactory) Timer(name string, tags map[string]string) Timer { return NullTimer } -func (nullFactory) Gauge(name string, tags map[string]string) Gauge { return NullGauge } -func (nullFactory) Namespace(name string, tags map[string]string) Factory { return NullFactory } diff --git a/vendor/github.com/uber/jaeger-lib/metrics/gauge.go b/vendor/github.com/uber/jaeger-lib/metrics/gauge.go deleted file mode 100644 index 3c606391a0..0000000000 --- a/vendor/github.com/uber/jaeger-lib/metrics/gauge.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -// Gauge returns instantaneous measurements of something as an int64 value -type Gauge interface { - // Update the gauge to the value passed in. - Update(int64) -} - -// NullGauge gauge that does nothing -var NullGauge Gauge = nullGauge{} - -type nullGauge struct{} - -func (nullGauge) Update(int64) {} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/local.go b/vendor/github.com/uber/jaeger-lib/metrics/local.go deleted file mode 100644 index 217d30600a..0000000000 --- a/vendor/github.com/uber/jaeger-lib/metrics/local.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -import ( - "sort" - "sync" - "sync/atomic" - "time" - - "github.com/codahale/hdrhistogram" -) - -// This is intentionally very similar to github.com/codahale/metrics, the -// main difference being that counters/gauges are scoped to the provider -// rather than being global (to facilitate testing). - -// A LocalBackend is a metrics provider which aggregates data in-vm, and -// allows exporting snapshots to shove the data into a remote collector -type LocalBackend struct { - cm sync.Mutex - gm sync.Mutex - tm sync.Mutex - counters map[string]*int64 - gauges map[string]*int64 - timers map[string]*localBackendTimer - stop chan struct{} - wg sync.WaitGroup - TagsSep string - TagKVSep string -} - -// NewLocalBackend returns a new LocalBackend. The collectionInterval is the histogram -// time window for each timer. -func NewLocalBackend(collectionInterval time.Duration) *LocalBackend { - b := &LocalBackend{ - counters: make(map[string]*int64), - gauges: make(map[string]*int64), - timers: make(map[string]*localBackendTimer), - stop: make(chan struct{}), - TagsSep: "|", - TagKVSep: "=", - } - if collectionInterval == 0 { - // Use one histogram time window for all timers - return b - } - b.wg.Add(1) - go b.runLoop(collectionInterval) - return b -} - -// Clear discards accumulated stats -func (b *LocalBackend) Clear() { - b.cm.Lock() - defer b.cm.Unlock() - b.gm.Lock() - defer b.gm.Unlock() - b.tm.Lock() - defer b.tm.Unlock() - b.counters = make(map[string]*int64) - b.gauges = make(map[string]*int64) - b.timers = make(map[string]*localBackendTimer) -} - -func (b *LocalBackend) runLoop(collectionInterval time.Duration) { - defer b.wg.Done() - ticker := time.NewTicker(collectionInterval) - for { - select { - case <-ticker.C: - b.tm.Lock() - timers := make(map[string]*localBackendTimer, len(b.timers)) - for timerName, timer := range b.timers { - timers[timerName] = timer - } - b.tm.Unlock() - - for _, t := range timers { - t.Lock() - t.hist.Rotate() - t.Unlock() - } - case <-b.stop: - ticker.Stop() - return - } - } -} - -// IncCounter increments a counter value -func (b *LocalBackend) IncCounter(name string, tags map[string]string, delta int64) { - name = GetKey(name, tags, b.TagsSep, b.TagKVSep) - b.cm.Lock() - defer b.cm.Unlock() - counter := b.counters[name] - if counter == nil { - b.counters[name] = new(int64) - *b.counters[name] = delta - return - } - atomic.AddInt64(counter, delta) -} - -// UpdateGauge updates the value of a gauge -func (b *LocalBackend) UpdateGauge(name string, tags map[string]string, value int64) { - name = GetKey(name, tags, b.TagsSep, b.TagKVSep) - b.gm.Lock() - defer b.gm.Unlock() - gauge := b.gauges[name] - if gauge == nil { - b.gauges[name] = new(int64) - *b.gauges[name] = value - return - } - atomic.StoreInt64(gauge, value) -} - -// RecordTimer records a timing duration -func (b *LocalBackend) RecordTimer(name string, tags map[string]string, d time.Duration) { - name = GetKey(name, tags, b.TagsSep, b.TagKVSep) - timer := b.findOrCreateTimer(name) - timer.Lock() - timer.hist.Current.RecordValue(int64(d / time.Millisecond)) - timer.Unlock() -} - -func (b *LocalBackend) findOrCreateTimer(name string) *localBackendTimer { - b.tm.Lock() - defer b.tm.Unlock() - if t, ok := b.timers[name]; ok { - return t - } - - t := &localBackendTimer{ - hist: hdrhistogram.NewWindowed(5, 0, int64((5*time.Minute)/time.Millisecond), 1), - } - b.timers[name] = t - return t -} - -type localBackendTimer struct { - sync.Mutex - hist *hdrhistogram.WindowedHistogram -} - -var ( - percentiles = map[string]float64{ - "P50": 50, - "P75": 75, - "P90": 90, - "P95": 95, - "P99": 99, - "P999": 99.9, - } -) - -// Snapshot captures a snapshot of the current counter and gauge values -func (b *LocalBackend) Snapshot() (counters, gauges map[string]int64) { - b.cm.Lock() - defer b.cm.Unlock() - - counters = make(map[string]int64, len(b.counters)) - for name, value := range b.counters { - counters[name] = atomic.LoadInt64(value) - } - - b.gm.Lock() - defer b.gm.Unlock() - - gauges = make(map[string]int64, len(b.gauges)) - for name, value := range b.gauges { - gauges[name] = atomic.LoadInt64(value) - } - - b.tm.Lock() - timers := make(map[string]*localBackendTimer) - for timerName, timer := range b.timers { - timers[timerName] = timer - } - b.tm.Unlock() - - for timerName, timer := range timers { - timer.Lock() - hist := timer.hist.Merge() - timer.Unlock() - for name, q := range percentiles { - gauges[timerName+"."+name] = hist.ValueAtQuantile(q) - } - } - - return -} - -// Stop cleanly closes the background goroutine spawned by NewLocalBackend. -func (b *LocalBackend) Stop() { - close(b.stop) - b.wg.Wait() -} - -// GetKey converts name+tags into a single string of the form -// "name|tag1=value1|...|tagN=valueN", where tag names are -// sorted alphabetically. -func GetKey(name string, tags map[string]string, tagsSep string, tagKVSep string) string { - keys := make([]string, 0, len(tags)) - for k := range tags { - keys = append(keys, k) - } - sort.Strings(keys) - key := name - for _, k := range keys { - key = key + tagsSep + k + tagKVSep + tags[k] - } - return key -} - -type stats struct { - name string - tags map[string]string - localBackend *LocalBackend -} - -type localTimer struct { - stats -} - -func (l *localTimer) Record(d time.Duration) { - l.localBackend.RecordTimer(l.name, l.tags, d) -} - -type localCounter struct { - stats -} - -func (l *localCounter) Inc(delta int64) { - l.localBackend.IncCounter(l.name, l.tags, delta) -} - -type localGauge struct { - stats -} - -func (l *localGauge) Update(value int64) { - l.localBackend.UpdateGauge(l.name, l.tags, value) -} - -// LocalFactory stats factory that creates metrics that are stored locally -type LocalFactory struct { - *LocalBackend - namespace string - tags map[string]string -} - -// NewLocalFactory returns a new LocalMetricsFactory -func NewLocalFactory(collectionInterval time.Duration) *LocalFactory { - return &LocalFactory{ - LocalBackend: NewLocalBackend(collectionInterval), - } -} - -// appendTags adds the tags to the namespace tags and returns a combined map. -func (l *LocalFactory) appendTags(tags map[string]string) map[string]string { - newTags := make(map[string]string) - for k, v := range l.tags { - newTags[k] = v - } - for k, v := range tags { - newTags[k] = v - } - return newTags -} - -func (l *LocalFactory) newNamespace(name string) string { - if l.namespace == "" { - return name - } - - if name == "" { - return l.namespace - } - - return l.namespace + "." + name -} - -// Counter returns a local stats counter -func (l *LocalFactory) Counter(name string, tags map[string]string) Counter { - return &localCounter{ - stats{ - name: l.newNamespace(name), - tags: l.appendTags(tags), - localBackend: l.LocalBackend, - }, - } -} - -// Timer returns a local stats timer. -func (l *LocalFactory) Timer(name string, tags map[string]string) Timer { - return &localTimer{ - stats{ - name: l.newNamespace(name), - tags: l.appendTags(tags), - localBackend: l.LocalBackend, - }, - } -} - -// Gauge returns a local stats gauge. -func (l *LocalFactory) Gauge(name string, tags map[string]string) Gauge { - return &localGauge{ - stats{ - name: l.newNamespace(name), - tags: l.appendTags(tags), - localBackend: l.LocalBackend, - }, - } -} - -// Namespace returns a new namespace. -func (l *LocalFactory) Namespace(name string, tags map[string]string) Factory { - return &LocalFactory{ - namespace: l.newNamespace(name), - tags: l.appendTags(tags), - LocalBackend: l.LocalBackend, - } -} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/metrics.go b/vendor/github.com/uber/jaeger-lib/metrics/metrics.go deleted file mode 100644 index 0b97707b07..0000000000 --- a/vendor/github.com/uber/jaeger-lib/metrics/metrics.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -import ( - "fmt" - "reflect" - "strings" -) - -// Init initializes the passed in metrics and initializes its fields using the passed in factory. -func Init(metrics interface{}, factory Factory, globalTags map[string]string) { - if err := initMetrics(metrics, factory, globalTags); err != nil { - panic(err.Error()) - } -} - -// initMetrics uses reflection to initialize a struct containing metrics fields -// by assigning new Counter/Gauge/Timer values with the metric name retrieved -// from the `metric` tag and stats tags retrieved from the `tags` tag. -// -// Note: all fields of the struct must be exported, have a `metric` tag, and be -// of type Counter or Gauge or Timer. -func initMetrics(m interface{}, factory Factory, globalTags map[string]string) error { - // Allow user to opt out of reporting metrics by passing in nil. - if factory == nil { - factory = NullFactory - } - - counterPtrType := reflect.TypeOf((*Counter)(nil)).Elem() - gaugePtrType := reflect.TypeOf((*Gauge)(nil)).Elem() - timerPtrType := reflect.TypeOf((*Timer)(nil)).Elem() - - v := reflect.ValueOf(m).Elem() - t := v.Type() - for i := 0; i < t.NumField(); i++ { - tags := make(map[string]string) - for k, v := range globalTags { - tags[k] = v - } - field := t.Field(i) - metric := field.Tag.Get("metric") - if metric == "" { - return fmt.Errorf("Field %s is missing a tag 'metric'", field.Name) - } - if tagString := field.Tag.Get("tags"); tagString != "" { - tagPairs := strings.Split(tagString, ",") - for _, tagPair := range tagPairs { - tag := strings.Split(tagPair, "=") - if len(tag) != 2 { - return fmt.Errorf( - "Field [%s]: Tag [%s] is not of the form key=value in 'tags' string [%s]", - field.Name, tagPair, tagString) - } - tags[tag[0]] = tag[1] - } - } - var obj interface{} - if field.Type.AssignableTo(counterPtrType) { - obj = factory.Counter(metric, tags) - } else if field.Type.AssignableTo(gaugePtrType) { - obj = factory.Gauge(metric, tags) - } else if field.Type.AssignableTo(timerPtrType) { - obj = factory.Timer(metric, tags) - } else { - return fmt.Errorf( - "Field %s is not a pointer to timer, gauge, or counter", - field.Name) - } - v.Field(i).Set(reflect.ValueOf(obj)) - } - return nil -} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go b/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go deleted file mode 100644 index 4a8abdb539..0000000000 --- a/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -import ( - "time" -) - -// StartStopwatch begins recording the executing time of an event, returning -// a Stopwatch that should be used to stop the recording the time for -// that event. Multiple events can be occurring simultaneously each -// represented by different active Stopwatches -func StartStopwatch(timer Timer) Stopwatch { - return Stopwatch{t: timer, start: time.Now()} -} - -// A Stopwatch tracks the execution time of a specific event -type Stopwatch struct { - t Timer - start time.Time -} - -// Stop stops executing of the stopwatch and records the amount of elapsed time -func (s Stopwatch) Stop() { - s.t.Record(s.ElapsedTime()) -} - -// ElapsedTime returns the amount of elapsed time (in time.Duration) -func (s Stopwatch) ElapsedTime() time.Duration { - return time.Since(s.start) -} diff --git a/vendor/github.com/uber/jaeger-lib/metrics/timer.go b/vendor/github.com/uber/jaeger-lib/metrics/timer.go deleted file mode 100644 index e18d222abb..0000000000 --- a/vendor/github.com/uber/jaeger-lib/metrics/timer.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metrics - -import ( - "time" -) - -// Timer accumulates observations about how long some operation took, -// and also maintains a historgam of percentiles. -type Timer interface { - // Records the time passed in. - Record(time.Duration) -} - -// NullTimer timer that does nothing -var NullTimer Timer = nullTimer{} - -type nullTimer struct{} - -func (nullTimer) Record(time.Duration) {} diff --git a/vendor/vendor.json b/vendor/vendor.json index a1f21f0e17..2d477e8eb5 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2,24 +2,6 @@ "comment": "", "ignore": "test", "package": [ - { - "checksumSHA1": "b5bkSc2hlmUV7PlLY6JlLwiJpiE=", - "path": "bazil.org/fuse", - "revision": "371fbbdaa8987b715bdd21d6adc4c9b20155f748", - "revisionTime": "2016-08-11T21:22:31Z" - }, - { - "checksumSHA1": "389JFJTJADMtZkTIfdSnsmHVOUs=", - "path": "bazil.org/fuse/fs", - "revision": "371fbbdaa8987b715bdd21d6adc4c9b20155f748", - "revisionTime": "2016-08-11T21:22:31Z" - }, - { - "checksumSHA1": "NPgkh9UWMsaTtsAAs3kPrclHT9Y=", - "path": "bazil.org/fuse/fuseutil", - "revision": "371fbbdaa8987b715bdd21d6adc4c9b20155f748", - "revisionTime": "2016-08-11T21:22:31Z" - }, { "checksumSHA1": "z+M6FYl9EKsoZZMLcT0Ktwfk8pI=", "path": "github.com/Azure/azure-pipeline-go/pipeline", @@ -74,12 +56,6 @@ "revision": "165db2f241fd235aec29ba6d9b1ccd5f1c14637c", "revisionTime": "2015-01-22T07:26:53Z" }, - { - "checksumSHA1": "7gK+lSShSu1NRw83/A95BcgMqsI=", - "path": "github.com/codahale/hdrhistogram", - "revision": "3a0bb77429bd3a61596f5e8a3172445844342120", - "revisionTime": "2016-10-10T02:54:55Z" - }, { "checksumSHA1": "dvabztWVQX8f6oMLRyv4dLH+TGY=", "path": "github.com/davecgh/go-spew/spew", @@ -544,108 +520,6 @@ "revision": "dbb3b84ba2ef14e894f5e33d6c6e43641e665738", "revisionTime": "2018-10-17T06:06:43Z" }, - { - "checksumSHA1": "nD6S4KB0S+YHxVMDDE+w3PyXaMk=", - "path": "github.com/uber/jaeger-client-go", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "cjhPfiQbTqfkHmZM3Bi+Bm8qgN4=", - "path": "github.com/uber/jaeger-client-go/config", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "KM5UXTWkHULmw0dDRNuk8ogWyGs=", - "path": "github.com/uber/jaeger-client-go/internal/baggage", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "tZqlcHV1XoLdZp9jfnydzsZAvYo=", - "path": "github.com/uber/jaeger-client-go/internal/baggage/remote", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "QB0L0GrzyMGQp6ivkkxp7a1DPsE=", - "path": "github.com/uber/jaeger-client-go/internal/spanlog", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "79HRO/+ekkpwqDB/OMiW+AHJtlE=", - "path": "github.com/uber/jaeger-client-go/internal/throttler", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "OVQDWFtFMs+NODe0F/S5kYViQco=", - "path": "github.com/uber/jaeger-client-go/internal/throttler/remote", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "tMP/vxbHwNAbOEaUhic5/meKfac=", - "path": "github.com/uber/jaeger-client-go/log", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "j4WrA/B2SJCqHxttCQ+TYbmtQqE=", - "path": "github.com/uber/jaeger-client-go/rpcmetrics", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "+ffspyTBQLql2UiU6muvfWR/m1o=", - "path": "github.com/uber/jaeger-client-go/thrift", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "fMIQ4sJFCkqFYhXvvLKIlofqxvY=", - "path": "github.com/uber/jaeger-client-go/thrift-gen/agent", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "fRR2p+JAp7paApf32YuQuWU7yzY=", - "path": "github.com/uber/jaeger-client-go/thrift-gen/baggage", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "JZkMEOmiOFFEuGCsDOVLK5RzvMM=", - "path": "github.com/uber/jaeger-client-go/thrift-gen/jaeger", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "0teQUhTqTE1fLs+vbnTTzWOqdEQ=", - "path": "github.com/uber/jaeger-client-go/thrift-gen/sampling", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "Nx5witfz05BSO2YlFzh2Gno6bA0=", - "path": "github.com/uber/jaeger-client-go/thrift-gen/zipkincore", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "DKwwIk9vq53IKO7RKccat9cnqeo=", - "path": "github.com/uber/jaeger-client-go/utils", - "revision": "f7e0d4744fa6d5287c53b8ac8d4f83089ce07ce8", - "revisionTime": "2018-06-07T15:18:42Z" - }, - { - "checksumSHA1": "k1iaOSBmLp3TpGvHNnRQXyJfwyI=", - "path": "github.com/uber/jaeger-lib/metrics", - "revision": "a51202d6f4a7e5a219e3841a43614ff7187ae7f1", - "revisionTime": "2018-06-15T20:27:29Z" - }, { "checksumSHA1": "GLCPuvePAkWT+opcWq3mNdhOfGM=", "path": "github.com/wsddn/go-ecdh", From 6f80629383b2e725fb882c345ae4221574643a32 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Sat, 8 Jun 2019 15:19:26 +0200 Subject: [PATCH 47/47] accounts: added transactorFromKeyStore (#19685) --- accounts/abi/bind/auth.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go index e6bb0c3b52..ad482abc02 100644 --- a/accounts/abi/bind/auth.go +++ b/accounts/abi/bind/auth.go @@ -22,6 +22,7 @@ import ( "io" "io/ioutil" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -42,6 +43,24 @@ func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) { return NewKeyedTransactor(key.PrivateKey), nil } +// NewTransactor is a utility method to easily create a transaction signer from +// an decrypted key from a keystore +func NewTransactorFromKeyStore(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) { + return &TransactOpts{ + From: account.Address, + Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) { + if address != account.Address { + return nil, errors.New("not authorized to sign this account") + } + signature, err := keystore.SignHash(account, signer.Hash(tx).Bytes()) + if err != nil { + return nil, err + } + return tx.WithSignature(signer, signature) + }, + }, nil +} + // NewKeyedTransactor is a utility method to easily create a transaction signer // from a single private key. func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {